diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index 6f1ab31fe03b..a53f825f43a8 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -2814,8 +2814,15 @@ Instruction *InstCombinerImpl::foldICmpDivConstant(ICmpInst &Cmp, // (x /u C2) isStrictlyPositive() || + !isKnownNonNegative(X, SQ.getWithInstruction(&Cmp))) + return nullptr; + DivIsSigned = false; + } // The ProdOV computation fails on divide by 0 and divide by -1. Cases with // INT_MIN will also fail if the divisor is 1. Although folds of all these diff --git a/llvm/test/Transforms/InstCombine/icmp-sdiv-assume.ll b/llvm/test/Transforms/InstCombine/icmp-sdiv-assume.ll new file mode 100644 index 000000000000..27c0ff485c5e --- /dev/null +++ b/llvm/test/Transforms/InstCombine/icmp-sdiv-assume.ll @@ -0,0 +1,209 @@ +; 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 +}