Skip to content

Commit 1c02e6a

Browse files
committed
[InstCombine] Fold mul (lshr exact (X, 2^N + 1)), N -> add (X , lshr (X, N))
Alive2 Proofs: https://alive2.llvm.org/ce/z/LVqGEo https://alive2.llvm.org/ce/z/dyeGEv
1 parent 190aaa4 commit 1c02e6a

File tree

2 files changed

+68
-9
lines changed

2 files changed

+68
-9
lines changed

llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,38 @@ Instruction *InstCombinerImpl::visitMul(BinaryOperator &I) {
255255
}
256256
}
257257

258+
{
259+
// mul (lshr exact X, N), (2^N + 1) -> add (X , lshr (X, N))
260+
Value *NewOp;
261+
const APInt *ShiftC;
262+
const APInt *MulAP;
263+
if ((HasNSW || HasNUW) &&
264+
match(&I, m_Mul(m_CombineOr(m_LShr(m_Value(NewOp), m_APInt(ShiftC)),
265+
m_AShr(m_Value(NewOp), m_APInt(ShiftC))),
266+
m_APInt(MulAP)))) {
267+
if (BitWidth > 2 && (*MulAP - 1).isPowerOf2() &&
268+
MulAP->logBase2() == ShiftC->getZExtValue()) {
269+
BinaryOperator *OpBO = cast<BinaryOperator>(Op0);
270+
if (OpBO->isExact()) {
271+
Value *BinOp = Op0;
272+
if (HasNUW && OpBO->getOpcode() == Instruction::AShr &&
273+
OpBO->hasOneUse())
274+
BinOp = Builder.CreateLShr(
275+
NewOp, ConstantInt::get(Ty, ShiftC->getZExtValue()), "",
276+
/*isExact=*/true);
277+
278+
auto *NewAdd = BinaryOperator::CreateAdd(NewOp, BinOp);
279+
if (HasNSW && (OpBO->getOpcode() == Instruction::LShr ||
280+
ShiftC->getZExtValue() < BitWidth - 1))
281+
NewAdd->setHasNoSignedWrap(true);
282+
283+
NewAdd->setHasNoUnsignedWrap(HasNUW);
284+
return NewAdd;
285+
}
286+
}
287+
}
288+
}
289+
258290
if (Op0->hasOneUse() && match(Op1, m_NegatedPower2())) {
259291
// Interpret X * (-1<<C) as (-X) * (1<<C) and try to sink the negation.
260292
// The "* (1<<C)" thus becomes a potential shifting opportunity.

llvm/test/Transforms/InstCombine/ashr-lshr.ll

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -875,8 +875,8 @@ define i32 @ashr_shift_mul(i32 %x) {
875875

876876
define i32 @ashr_shift_mul_nuw(i32 %x) {
877877
; CHECK-LABEL: @ashr_shift_mul_nuw(
878-
; CHECK-NEXT: [[A:%.*]] = ashr exact i32 [[X:%.*]], 3
879-
; CHECK-NEXT: [[RES:%.*]] = mul nuw i32 [[A]], 9
878+
; CHECK-NEXT: [[TMP1:%.*]] = lshr exact i32 [[X:%.*]], 3
879+
; CHECK-NEXT: [[RES:%.*]] = add nuw i32 [[TMP1]], [[X]]
880880
; CHECK-NEXT: ret i32 [[RES]]
881881
;
882882
%a = ashr exact i32 %x, 3
@@ -887,7 +887,7 @@ define i32 @ashr_shift_mul_nuw(i32 %x) {
887887
define i32 @ashr_shift_mul_nsw(i32 %x) {
888888
; CHECK-LABEL: @ashr_shift_mul_nsw(
889889
; CHECK-NEXT: [[A:%.*]] = ashr exact i32 [[X:%.*]], 3
890-
; CHECK-NEXT: [[RES:%.*]] = mul nsw i32 [[A]], 9
890+
; CHECK-NEXT: [[RES:%.*]] = add nsw i32 [[A]], [[X]]
891891
; CHECK-NEXT: ret i32 [[RES]]
892892
;
893893
%a = ashr exact i32 %x, 3
@@ -898,7 +898,7 @@ define i32 @ashr_shift_mul_nsw(i32 %x) {
898898
define i32 @lshr_shift_mul_nuw(i32 %x) {
899899
; CHECK-LABEL: @lshr_shift_mul_nuw(
900900
; CHECK-NEXT: [[A:%.*]] = lshr exact i32 [[X:%.*]], 3
901-
; CHECK-NEXT: [[RES:%.*]] = mul nuw i32 [[A]], 9
901+
; CHECK-NEXT: [[RES:%.*]] = add nuw i32 [[A]], [[X]]
902902
; CHECK-NEXT: ret i32 [[RES]]
903903
;
904904
%a = lshr exact i32 %x, 3
@@ -920,7 +920,7 @@ define i32 @lshr_shift_mul(i32 %x) {
920920
define i32 @lshr_shift_mul_nsw(i32 %x) {
921921
; CHECK-LABEL: @lshr_shift_mul_nsw(
922922
; CHECK-NEXT: [[A:%.*]] = lshr exact i32 [[X:%.*]], 3
923-
; CHECK-NEXT: [[RES:%.*]] = mul nuw nsw i32 [[A]], 9
923+
; CHECK-NEXT: [[RES:%.*]] = add nsw i32 [[A]], [[X]]
924924
; CHECK-NEXT: ret i32 [[RES]]
925925
;
926926
%a = lshr exact i32 %x, 3
@@ -954,13 +954,11 @@ define i32 @ashr_no_exact(i32 %x) {
954954
ret i32 %res
955955
}
956956

957-
; Negative test
958-
959957
define i32 @lshr_multiuse(i32 %x) {
960958
; CHECK-LABEL: @lshr_multiuse(
961959
; CHECK-NEXT: [[A:%.*]] = lshr exact i32 [[X:%.*]], 3
962960
; CHECK-NEXT: call void @use(i32 [[A]])
963-
; CHECK-NEXT: [[RES:%.*]] = mul nuw nsw i32 [[A]], 9
961+
; CHECK-NEXT: [[RES:%.*]] = add nsw i32 [[A]], [[X]]
964962
; CHECK-NEXT: ret i32 [[RES]]
965963
;
966964
%a = lshr exact i32 %x, 3
@@ -969,13 +967,42 @@ define i32 @lshr_multiuse(i32 %x) {
969967
ret i32 %res
970968
}
971969

970+
971+
; Negative test
972+
973+
define i32 @lshr_multiuse_no_flags(i32 %x) {
974+
; CHECK-LABEL: @lshr_multiuse_no_flags(
975+
; CHECK-NEXT: [[A:%.*]] = lshr exact i32 [[X:%.*]], 3
976+
; CHECK-NEXT: call void @use(i32 [[A]])
977+
; CHECK-NEXT: [[RES:%.*]] = mul i32 [[A]], 9
978+
; CHECK-NEXT: ret i32 [[RES]]
979+
;
980+
%a = lshr exact i32 %x, 3
981+
call void @use(i32 %a)
982+
%res = mul i32 %a, 9
983+
ret i32 %res
984+
}
985+
972986
; Negative test
973987

988+
define i32 @ashr_multiuse_no_flags(i32 %x) {
989+
; CHECK-LABEL: @ashr_multiuse_no_flags(
990+
; CHECK-NEXT: [[A:%.*]] = ashr exact i32 [[X:%.*]], 3
991+
; CHECK-NEXT: call void @use(i32 [[A]])
992+
; CHECK-NEXT: [[RES:%.*]] = mul i32 [[A]], 9
993+
; CHECK-NEXT: ret i32 [[RES]]
994+
;
995+
%a = ashr exact i32 %x, 3
996+
call void @use(i32 %a)
997+
%res = mul i32 %a, 9
998+
ret i32 %res
999+
}
1000+
9741001
define i32 @ashr_multiuse(i32 %x) {
9751002
; CHECK-LABEL: @ashr_multiuse(
9761003
; CHECK-NEXT: [[A:%.*]] = ashr exact i32 [[X:%.*]], 3
9771004
; CHECK-NEXT: call void @use(i32 [[A]])
978-
; CHECK-NEXT: [[RES:%.*]] = mul nsw i32 [[A]], 9
1005+
; CHECK-NEXT: [[RES:%.*]] = add nsw i32 [[A]], [[X]]
9791006
; CHECK-NEXT: ret i32 [[RES]]
9801007
;
9811008
%a = ashr exact i32 %x, 3

0 commit comments

Comments
 (0)