diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -1332,7 +1332,15 @@ ConstantInt::getAllOnesValue(Ty)); } - if (isKnownNonNegative(Op0, DL, 0, &AC, &I, &DT)) { + KnownBits KnownDividend = computeKnownBits(Op0, 0, &I); + if (!I.isExact() && + (match(Op1, m_Power2(Op1C)) || match(Op1, m_NegatedPower2(Op1C))) && + KnownDividend.countMinTrailingZeros() >= Op1C->countTrailingZeros()) { + I.setIsExact(); + return &I; + } + + if (KnownDividend.isNonNegative()) { // If both operands are unsigned, turn this into a udiv. if (isKnownNonNegative(Op1, DL, 0, &AC, &I, &DT)) { auto *BO = BinaryOperator::CreateUDiv(Op0, Op1, I.getName()); diff --git a/llvm/test/Transforms/InstCombine/sdiv-exact-by-negative-power-of-two.ll b/llvm/test/Transforms/InstCombine/sdiv-exact-by-negative-power-of-two.ll --- a/llvm/test/Transforms/InstCombine/sdiv-exact-by-negative-power-of-two.ll +++ b/llvm/test/Transforms/InstCombine/sdiv-exact-by-negative-power-of-two.ll @@ -64,8 +64,9 @@ define i8 @prove_exact_with_high_mask(i8 %x, i8 %y) { ; CHECK-LABEL: @prove_exact_with_high_mask( -; CHECK-NEXT: [[A:%.*]] = and i8 [[X:%.*]], -32 -; CHECK-NEXT: [[D:%.*]] = sdiv i8 [[A]], -4 +; CHECK-NEXT: [[A:%.*]] = ashr i8 [[X:%.*]], 2 +; CHECK-NEXT: [[D_NEG:%.*]] = and i8 [[A]], -8 +; CHECK-NEXT: [[D:%.*]] = sub nsw i8 0, [[D_NEG]] ; CHECK-NEXT: ret i8 [[D]] ; %a = and i8 %x, -32 @@ -75,8 +76,8 @@ define i8 @prove_exact_with_high_mask_limit(i8 %x, i8 %y) { ; CHECK-LABEL: @prove_exact_with_high_mask_limit( -; CHECK-NEXT: [[A:%.*]] = and i8 [[X:%.*]], -32 -; CHECK-NEXT: [[D:%.*]] = sdiv i8 [[A]], -32 +; CHECK-NEXT: [[A:%.*]] = ashr i8 [[X:%.*]], 5 +; CHECK-NEXT: [[D:%.*]] = sub nsw i8 0, [[A]] ; CHECK-NEXT: ret i8 [[D]] ; %a = and i8 %x, -32 @@ -84,6 +85,8 @@ ret i8 %d } +; negative test - not enough low zeros in dividend + define i8 @not_prove_exact_with_high_mask(i8 %x, i8 %y) { ; CHECK-LABEL: @not_prove_exact_with_high_mask( ; CHECK-NEXT: [[A:%.*]] = and i8 [[X:%.*]], -32 @@ -98,7 +101,8 @@ define <2 x i8> @prove_exact_with_high_mask_splat_vec(<2 x i8> %x, <2 x i8> %y) { ; CHECK-LABEL: @prove_exact_with_high_mask_splat_vec( ; CHECK-NEXT: [[A:%.*]] = shl <2 x i8> [[X:%.*]], -; CHECK-NEXT: [[D:%.*]] = sdiv <2 x i8> [[A]], +; CHECK-NEXT: [[D_NEG:%.*]] = ashr exact <2 x i8> [[A]], +; CHECK-NEXT: [[D:%.*]] = sub nsw <2 x i8> zeroinitializer, [[D_NEG]] ; CHECK-NEXT: ret <2 x i8> [[D]] ; %a = shl <2 x i8> %x, @@ -106,6 +110,8 @@ ret <2 x i8> %d } +; TODO: Needs knownbits to handle arbitrary vector constants. + define <2 x i8> @prove_exact_with_high_mask_vec(<2 x i8> %x, <2 x i8> %y) { ; CHECK-LABEL: @prove_exact_with_high_mask_vec( ; CHECK-NEXT: [[A:%.*]] = shl <2 x i8> [[X:%.*]], diff --git a/llvm/test/Transforms/InstCombine/sdiv-exact-by-power-of-two.ll b/llvm/test/Transforms/InstCombine/sdiv-exact-by-power-of-two.ll --- a/llvm/test/Transforms/InstCombine/sdiv-exact-by-power-of-two.ll +++ b/llvm/test/Transforms/InstCombine/sdiv-exact-by-power-of-two.ll @@ -110,8 +110,8 @@ define i8 @prove_exact_with_high_mask(i8 %x, i8 %y) { ; CHECK-LABEL: @prove_exact_with_high_mask( -; CHECK-NEXT: [[A:%.*]] = and i8 [[X:%.*]], -8 -; CHECK-NEXT: [[D:%.*]] = sdiv i8 [[A]], 4 +; CHECK-NEXT: [[A:%.*]] = ashr i8 [[X:%.*]], 2 +; CHECK-NEXT: [[D:%.*]] = and i8 [[A]], -2 ; CHECK-NEXT: ret i8 [[D]] ; %a = and i8 %x, -8 @@ -121,15 +121,16 @@ define i8 @prove_exact_with_high_mask_limit(i8 %x, i8 %y) { ; CHECK-LABEL: @prove_exact_with_high_mask_limit( -; CHECK-NEXT: [[A:%.*]] = and i8 [[X:%.*]], -8 -; CHECK-NEXT: [[D:%.*]] = sdiv i8 [[A]], 8 -; CHECK-NEXT: ret i8 [[D]] +; CHECK-NEXT: [[A:%.*]] = ashr i8 [[X:%.*]], 3 +; CHECK-NEXT: ret i8 [[A]] ; %a = and i8 %x, -8 %d = sdiv i8 %a, 8 ret i8 %d } +; negative test - not enough low zeros in dividend + define i8 @not_prove_exact_with_high_mask(i8 %x, i8 %y) { ; CHECK-LABEL: @not_prove_exact_with_high_mask( ; CHECK-NEXT: [[A:%.*]] = and i8 [[X:%.*]], -8 @@ -144,7 +145,7 @@ define <2 x i8> @prove_exact_with_high_mask_splat_vec(<2 x i8> %x, <2 x i8> %y) { ; CHECK-LABEL: @prove_exact_with_high_mask_splat_vec( ; CHECK-NEXT: [[A:%.*]] = shl <2 x i8> [[X:%.*]], -; CHECK-NEXT: [[D:%.*]] = sdiv <2 x i8> [[A]], +; CHECK-NEXT: [[D:%.*]] = ashr exact <2 x i8> [[A]], ; CHECK-NEXT: ret <2 x i8> [[D]] ; %a = shl <2 x i8> %x, @@ -152,6 +153,8 @@ ret <2 x i8> %d } +; TODO: Needs knownbits to handle arbitrary vector constants. + define <2 x i8> @prove_exact_with_high_mask_vec(<2 x i8> %x, <2 x i8> %y) { ; CHECK-LABEL: @prove_exact_with_high_mask_vec( ; CHECK-NEXT: [[A:%.*]] = shl <2 x i8> [[X:%.*]],