diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -6033,31 +6033,34 @@ default: return true; case Instruction::UDiv: - case Instruction::URem: { - // x / y is undefined if y == 0. - const APInt *V; - if (match(Inst->getOperand(1), m_APInt(V))) - return *V != 0; - return false; - } + case Instruction::URem: case Instruction::SDiv: case Instruction::SRem: { - // x / y is undefined if y == 0 or x == INT_MIN and y == -1 - const APInt *Numerator, *Denominator; - if (!match(Inst->getOperand(1), m_APInt(Denominator))) - return false; - // We cannot hoist this division if the denominator is 0. - if (*Denominator == 0) + // x / y is undefined if y == 0 or y is poison. + const DataLayout &DL = Inst->getModule()->getDataLayout(); + if (!isGuaranteedNotToBePoison(Inst->getOperand(1), AC, CtxI, DT) || + !isKnownNonZero(Inst->getOperand(1), DL, /*Depth*/ 0, AC, CtxI, DT)) return false; + + // Unsigned case only needs to avoid denominator == 0 or poison. + if (Opcode == Instruction::UDiv || Opcode == Instruction::URem) + return true; + + // x s/ y is also undefined if x == INT_MIN and y == -1 + KnownBits KnownDenominator = + computeKnownBits(Inst->getOperand(1), DL, /*Depth*/ 0, AC, CtxI, DT); + // It's safe to hoist if the denominator is not 0 or -1. - if (!Denominator->isAllOnes()) + if (!KnownDenominator.Zero.isZero()) return true; - // At this point we know that the denominator is -1. It is safe to hoist as - // long we know that the numerator is not INT_MIN. - if (match(Inst->getOperand(0), m_APInt(Numerator))) - return !Numerator->isMinSignedValue(); - // The numerator *might* be MinSignedValue. - return false; + + // At this point denominator may be -1. It is safe to hoist as + // long we know that the numerator is neither poison nor INT_MIN. + if (!isGuaranteedNotToBePoison(Inst->getOperand(0), AC, CtxI, DT)) + return false; + KnownBits KnownNumerator = + computeKnownBits(Inst->getOperand(0), DL, /*Depth*/ 0, AC, CtxI, DT); + return !KnownNumerator.getSignedMinValue().isMinSignedValue(); } case Instruction::Load: { const LoadInst *LI = dyn_cast(Inst); diff --git a/llvm/test/Transforms/LICM/speculate-div.ll b/llvm/test/Transforms/LICM/speculate-div.ll --- a/llvm/test/Transforms/LICM/speculate-div.ll +++ b/llvm/test/Transforms/LICM/speculate-div.ll @@ -4,7 +4,7 @@ declare void @maythrow() declare void @use(i16) -define void @sdiv_not_ok(i16 %n, i16 %xx) { +define void @sdiv_not_ok(i16 %n, i16 noundef %xx) { ; CHECK-LABEL: @sdiv_not_ok( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[X:%.*]] = or i16 [[XX:%.*]], 1 @@ -25,7 +25,7 @@ br label %loop } -define void @srem_not_ok2(i16 %nn, i16 %x) { +define void @srem_not_ok2(i16 %nn, i16 noundef %x) { ; CHECK-LABEL: @srem_not_ok2( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[N:%.*]] = and i16 [[NN:%.*]], 1323 @@ -46,15 +46,15 @@ br label %loop } -define void @sdiv_ok(i16 %n, i16 %xx) { +define void @sdiv_ok(i16 %n, i16 noundef %xx) { ; CHECK-LABEL: @sdiv_ok( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[XO:%.*]] = or i16 [[XX:%.*]], 1 ; CHECK-NEXT: [[X:%.*]] = and i16 [[XO]], 123 +; CHECK-NEXT: [[DIV:%.*]] = sdiv i16 [[N:%.*]], [[X]] ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: call void @maythrow() -; CHECK-NEXT: [[DIV:%.*]] = sdiv i16 [[N:%.*]], [[X]] ; CHECK-NEXT: call void @use(i16 [[DIV]]) ; CHECK-NEXT: br label [[LOOP]] ; @@ -69,15 +69,15 @@ br label %loop } -define void @srem_ok2(i16 %nn, i16 %xx) { +define void @srem_ok2(i16 noundef %nn, i16 noundef %xx) { ; CHECK-LABEL: @srem_ok2( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[N:%.*]] = and i16 [[NN:%.*]], 123 ; CHECK-NEXT: [[X:%.*]] = or i16 [[XX:%.*]], 1 +; CHECK-NEXT: [[DIV:%.*]] = srem i16 [[N]], [[X]] ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: call void @maythrow() -; CHECK-NEXT: [[DIV:%.*]] = srem i16 [[N]], [[X]] ; CHECK-NEXT: call void @use(i16 [[DIV]]) ; CHECK-NEXT: br label [[LOOP]] ; @@ -92,7 +92,53 @@ br label %loop } -define void @udiv_not_ok(i16 %n, i16 %xx) { +define void @sdiv_not_ok3_maybe_poison_denum(i16 noundef %nn, i16 %xx) { +; CHECK-LABEL: @sdiv_not_ok3_maybe_poison_denum( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[N:%.*]] = and i16 [[NN:%.*]], 123 +; CHECK-NEXT: [[X:%.*]] = or i16 [[XX:%.*]], 1 +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loop: +; CHECK-NEXT: call void @maythrow() +; CHECK-NEXT: [[DIV:%.*]] = sdiv i16 [[N]], [[X]] +; CHECK-NEXT: call void @use(i16 [[DIV]]) +; CHECK-NEXT: br label [[LOOP]] +; +entry: + %n = and i16 %nn, 123 + %x = or i16 %xx, 1 + br label %loop +loop: + call void @maythrow() + %div = sdiv i16 %n, %x + call void @use(i16 %div) + br label %loop +} + +define void @sdiv_not_ok3_maybe_poison_num(i16 %nn, i16 noundef %xx) { +; CHECK-LABEL: @sdiv_not_ok3_maybe_poison_num( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[N:%.*]] = and i16 [[NN:%.*]], 123 +; CHECK-NEXT: [[X:%.*]] = or i16 [[XX:%.*]], 1 +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loop: +; CHECK-NEXT: call void @maythrow() +; CHECK-NEXT: [[DIV:%.*]] = sdiv i16 [[N]], [[X]] +; CHECK-NEXT: call void @use(i16 [[DIV]]) +; CHECK-NEXT: br label [[LOOP]] +; +entry: + %n = and i16 %nn, 123 + %x = or i16 %xx, 1 + br label %loop +loop: + call void @maythrow() + %div = sdiv i16 %n, %x + call void @use(i16 %div) + br label %loop +} + +define void @udiv_not_ok(i16 %n, i16 noundef %xx) { ; CHECK-LABEL: @udiv_not_ok( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[X:%.*]] = xor i16 [[XX:%.*]], 1 @@ -113,10 +159,31 @@ br label %loop } -define void @udiv_ok(i16 %n, i16 %xx) { +define void @udiv_ok(i16 %n, i16 noundef %xx) { ; CHECK-LABEL: @udiv_ok( ; CHECK-NEXT: entry: ; CHECK-NEXT: [[X:%.*]] = or i16 [[XX:%.*]], 1 +; CHECK-NEXT: [[DIV:%.*]] = udiv i16 [[N:%.*]], [[X]] +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loop: +; CHECK-NEXT: call void @maythrow() +; CHECK-NEXT: call void @use(i16 [[DIV]]) +; CHECK-NEXT: br label [[LOOP]] +; +entry: + %x = or i16 %xx, 1 + br label %loop +loop: + call void @maythrow() + %div = udiv i16 %n, %x + call void @use(i16 %div) + br label %loop +} + +define void @urem_not_ok_maybe_poison(i16 %n, i16 %xx) { +; CHECK-LABEL: @urem_not_ok_maybe_poison( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[X:%.*]] = or i16 [[XX:%.*]], 1 ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: call void @maythrow()