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 @@ -221,16 +221,23 @@ return replaceInstUsesWith(I, FoldedMul); // Simplify mul instructions with a constant RHS. - if (isa(Op1)) { - // Canonicalize (X+C1)*CI -> X*CI+C1*CI. + Constant *MulC; + if (match(Op1, m_ImmConstant(MulC))) { + // Canonicalize (X+C1)*MulC -> X*MulC+C1*MulC. Value *X; Constant *C1; - if (match(Op0, m_OneUse(m_Add(m_Value(X), m_Constant(C1))))) { - Value *Mul = Builder.CreateMul(C1, Op1); - // Only go forward with the transform if C1*CI simplifies to a tidier - // constant. - if (!match(Mul, m_Mul(m_Value(), m_Value()))) - return BinaryOperator::CreateAdd(Builder.CreateMul(X, Op1), Mul); + if (match(Op0, m_OneUse(m_Add(m_Value(X), m_ImmConstant(C1))))) { + // C1*MulC simplifies to a tidier constant. + Value *NewC = Builder.CreateMul(C1, MulC); + auto *BOp0 = cast(Op0); + Value *NewMul = Builder.CreateMul(X, MulC); + auto *BO = BinaryOperator::CreateAdd(NewMul, NewC); + auto *NewMulBO = dyn_cast(NewMul); + if (I.hasNoUnsignedWrap() && BOp0->hasNoUnsignedWrap() && NewMulBO) { + NewMulBO->setHasNoUnsignedWrap(); + BO->setHasNoUnsignedWrap(); + } + return BO; } } diff --git a/llvm/test/Transforms/InstCombine/mul.ll b/llvm/test/Transforms/InstCombine/mul.ll --- a/llvm/test/Transforms/InstCombine/mul.ll +++ b/llvm/test/Transforms/InstCombine/mul.ll @@ -624,6 +624,53 @@ ret i32 %mul } +; Keep nuw flag in this change, https://alive2.llvm.org/ce/z/-Wowpk +define i32 @add_mul_nuw(i32 %a) { +; CHECK-LABEL: @add_mul_nuw( +; CHECK-NEXT: [[TMP1:%.*]] = mul nuw i32 [[A:%.*]], 3 +; CHECK-NEXT: [[MUL:%.*]] = add nuw i32 [[TMP1]], 9 +; CHECK-NEXT: ret i32 [[MUL]] +; + %add = add nuw i32 %a, 3 + %mul = mul nuw i32 %add, 3 + ret i32 %mul +} + +; Don't propagate nsw flag in this change +define i32 @add_mul_nsw(i32 %a) { +; CHECK-LABEL: @add_mul_nsw( +; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[A:%.*]], 3 +; CHECK-NEXT: [[MUL:%.*]] = add i32 [[TMP1]], 9 +; CHECK-NEXT: ret i32 [[MUL]] +; + %add = add nsw i32 %a, 3 + %mul = mul nsw i32 %add, 3 + ret i32 %mul +} + +; Only the add or only the mul has nuw, https://alive2.llvm.org/ce/z/vPwbEa +define i32 @only_add_nuw(i32 %a) { +; CHECK-LABEL: @only_add_nuw( +; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[A:%.*]], 3 +; CHECK-NEXT: [[MUL:%.*]] = add i32 [[TMP1]], 9 +; CHECK-NEXT: ret i32 [[MUL]] +; + %add = add nuw i32 %a, 3 + %mul = mul i32 %add, 3 + ret i32 %mul +} + +define i32 @only_mul_nuw(i32 %a) { +; CHECK-LABEL: @only_mul_nuw( +; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[A:%.*]], 3 +; CHECK-NEXT: [[MUL:%.*]] = add i32 [[TMP1]], 9 +; CHECK-NEXT: ret i32 [[MUL]] +; + %add = add i32 %a, 3 + %mul = mul nuw i32 %add, 3 + ret i32 %mul +} + define <2 x i1> @test21(<2 x i1> %A, <2 x i1> %B) { ; CHECK-LABEL: @test21( ; CHECK-NEXT: [[C:%.*]] = and <2 x i1> [[A:%.*]], [[B:%.*]]