; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -passes=instcombine -S | FileCheck %s ; Test that foldICmpDivConstant can treat sdiv as udiv when the dividend ; is known non-negative (e.g. via a dominating condition), allowing the ; fold to proceed despite a signed div / unsigned icmp mismatch. ; Non-power-of-two divisors are used to prevent sdiv->lshr conversion. ; The sdiv is placed in the entry block where x's sign is unknown, and ; the icmp is in a block dominated by a condition that proves x >= 0. declare void @use(i32) ; Positive test: x > 255 dominates the icmp, proving x non-negative. ; sdiv(x, 65) = udiv(x, 65) when x >= 0, and udiv(x, 65) > 2 when x >= 195. ; Since x > 255 >= 195, the result folds to true. define i1 @icmp_sdiv_domcond(i32 %x) { ; CHECK-LABEL: @icmp_sdiv_domcond( ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[X:%.*]], 65 ; CHECK-NEXT: call void @use(i32 [[DIV]]) ; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[X]], 255 ; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] ; CHECK: if.true: ; CHECK-NEXT: ret i1 true ; CHECK: if.false: ; CHECK-NEXT: ret i1 false ; %div = sdiv i32 %x, 65 call void @use(i32 %div) %cond = icmp sgt i32 %x, 255 br i1 %cond, label %if.true, label %if.false if.true: %cmp = icmp samesign ugt i32 %div, 2 ret i1 %cmp if.false: ret i1 false } ; Positive test: add+sdiv pattern (mirrors real-world kernel case). ; x+63 > 255 dominates the icmp, proving x+63 non-negative. define i1 @icmp_add_sdiv_domcond(i32 %x) { ; CHECK-LABEL: @icmp_add_sdiv_domcond( ; CHECK-NEXT: [[ADD:%.*]] = add i32 [[X:%.*]], 63 ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[ADD]], 65 ; CHECK-NEXT: call void @use(i32 [[DIV]]) ; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[ADD]], 255 ; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] ; CHECK: if.true: ; CHECK-NEXT: ret i1 true ; CHECK: if.false: ; CHECK-NEXT: ret i1 false ; %add = add i32 %x, 63 %div = sdiv i32 %add, 65 call void @use(i32 %div) %cond = icmp sgt i32 %add, 255 br i1 %cond, label %if.true, label %if.false if.true: %cmp = icmp samesign ugt i32 %div, 2 ret i1 %cmp if.false: ret i1 false } ; Positive test: udiv case (no signedness mismatch, baseline behavior). define i1 @icmp_udiv_domcond(i32 %x) { ; CHECK-LABEL: @icmp_udiv_domcond( ; CHECK-NEXT: [[DIV:%.*]] = udiv i32 [[X:%.*]], 65 ; CHECK-NEXT: call void @use(i32 [[DIV]]) ; CHECK-NEXT: [[COND:%.*]] = icmp ugt i32 [[X]], 255 ; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] ; CHECK: if.true: ; CHECK-NEXT: ret i1 true ; CHECK: if.false: ; CHECK-NEXT: ret i1 false ; %div = udiv i32 %x, 65 call void @use(i32 %div) %cond = icmp ugt i32 %x, 255 br i1 %cond, label %if.true, label %if.false if.true: %cmp = icmp ugt i32 %div, 2 ret i1 %cmp if.false: ret i1 false } ; Negative test: dominating condition is too weak. ; x > 127 does NOT prove sdiv(x, 65) > 2 (e.g. x=128, sdiv(128,65)=1). define i1 @icmp_sdiv_domcond_too_weak(i32 %x) { ; CHECK-LABEL: @icmp_sdiv_domcond_too_weak( ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[X:%.*]], 65 ; CHECK-NEXT: call void @use(i32 [[DIV]]) ; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[X]], 127 ; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] ; CHECK: if.true: ; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[X]], 194 ; CHECK-NEXT: ret i1 [[CMP]] ; CHECK: if.false: ; CHECK-NEXT: ret i1 false ; %div = sdiv i32 %x, 65 call void @use(i32 %div) %cond = icmp sgt i32 %x, 127 br i1 %cond, label %if.true, label %if.false if.true: %cmp = icmp samesign ugt i32 %div, 2 ret i1 %cmp if.false: ret i1 false } ; Negative test: no dominating condition, x's sign is unknown. define i1 @icmp_sdiv_no_domcond(i32 %x) { ; CHECK-LABEL: @icmp_sdiv_no_domcond( ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[X:%.*]], 65 ; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ugt i32 [[DIV]], 2 ; CHECK-NEXT: ret i1 [[CMP]] ; %div = sdiv i32 %x, 65 %cmp = icmp samesign ugt i32 %div, 2 ret i1 %cmp } ; Negative test: comparison is on the boundary. ; x > 194 means x >= 195, sdiv(195, 65) = 3, but 3 > 3 is false. define i1 @icmp_sdiv_domcond_boundary(i32 %x) { ; CHECK-LABEL: @icmp_sdiv_domcond_boundary( ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[X:%.*]], 65 ; CHECK-NEXT: call void @use(i32 [[DIV]]) ; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[X]], 194 ; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] ; CHECK: if.true: ; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[X]], 259 ; CHECK-NEXT: ret i1 [[CMP]] ; CHECK: if.false: ; CHECK-NEXT: ret i1 false ; %div = sdiv i32 %x, 65 call void @use(i32 %div) %cond = icmp sgt i32 %x, 194 br i1 %cond, label %if.true, label %if.false if.true: %cmp = icmp samesign ugt i32 %div, 3 ret i1 %cmp if.false: ret i1 false } ; Negative test: dividend is known negative, sdiv != udiv. define i1 @icmp_sdiv_negative_dividend(i32 %x) { ; CHECK-LABEL: @icmp_sdiv_negative_dividend( ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[X:%.*]], 65 ; CHECK-NEXT: call void @use(i32 [[DIV]]) ; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[X]], -100 ; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] ; CHECK: if.true: ; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ugt i32 [[DIV]], 2 ; CHECK-NEXT: ret i1 [[CMP]] ; CHECK: if.false: ; CHECK-NEXT: ret i1 false ; %div = sdiv i32 %x, 65 call void @use(i32 %div) %cond = icmp slt i32 %x, -100 br i1 %cond, label %if.true, label %if.false if.true: %cmp = icmp samesign ugt i32 %div, 2 ret i1 %cmp if.false: ret i1 false } ; Negative test: divisor is negative, sdiv(x, -65) != udiv(x, -65). define i1 @icmp_sdiv_negative_divisor(i32 %x) { ; CHECK-LABEL: @icmp_sdiv_negative_divisor( ; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[X:%.*]], -65 ; CHECK-NEXT: call void @use(i32 [[DIV]]) ; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[X]], 255 ; CHECK-NEXT: br i1 [[COND]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] ; CHECK: if.true: ; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ugt i32 [[DIV]], 2 ; CHECK-NEXT: ret i1 [[CMP]] ; CHECK: if.false: ; CHECK-NEXT: ret i1 false ; %div = sdiv i32 %x, -65 call void @use(i32 %div) %cond = icmp sgt i32 %x, 255 br i1 %cond, label %if.true, label %if.false if.true: %cmp = icmp samesign ugt i32 %div, 2 ret i1 %cmp if.false: ret i1 false }