Index: llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -221,16 +221,20 @@ return replaceInstUsesWith(I, FoldedMul); // Simplify mul instructions with a constant RHS. - if (isa(Op1)) { + if (match(Op1, m_ImmConstant())) { // Canonicalize (X+C1)*CI -> X*CI+C1*CI. + // Canonicalize (X|C1)*CI -> X*CI+C1*CI. Value *X; Constant *C1; - if (match(Op0, m_OneUse(m_Add(m_Value(X), m_Constant(C1))))) { + if ((match(Op0, m_OneUse(m_Add(m_Value(X), m_ImmConstant(C1))))) || + (match(Op0, m_OneUse(m_Or(m_Value(X), m_ImmConstant(C1)))) && + haveNoCommonBitsSet(X, C1, DL, &AC, &I, &DT))) { 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); + // C1*CI simplifies to a tidier constant. + auto *BO = BinaryOperator::CreateAdd(Builder.CreateMul(X, Op1), Mul); + if (I.hasNoUnsignedWrap()) + BO->setHasNoUnsignedWrap(); + return BO; } } Index: llvm/test/Transforms/InstCombine/mul.ll =================================================================== --- llvm/test/Transforms/InstCombine/mul.ll +++ llvm/test/Transforms/InstCombine/mul.ll @@ -624,6 +624,71 @@ ret i32 %mul } +define i32 @PR57278_shl(i32 %a) { +; CHECK-LABEL: @PR57278_shl( +; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[A:%.*]], 12 +; CHECK-NEXT: [[MUL:%.*]] = add i32 [[TMP1]], 9 +; CHECK-NEXT: ret i32 [[MUL]] +; + %shl = shl nsw i32 %a, 2 + %add = or i32 %shl, 3 + %mul = mul nsw i32 %add, 3 + ret i32 %mul +} + +; Negative test: Have common bits set +define i32 @PR57278_shl_1(i32 %a) { +; CHECK-LABEL: @PR57278_shl_1( +; CHECK-NEXT: [[SHL:%.*]] = shl nsw i32 [[A:%.*]], 2 +; CHECK-NEXT: [[ADD:%.*]] = or i32 [[SHL]], 4 +; CHECK-NEXT: [[MUL:%.*]] = mul nsw i32 [[ADD]], 3 +; CHECK-NEXT: ret i32 [[MUL]] +; + %shl = shl nsw i32 %a, 2 + %add = or i32 %shl, 4 + %mul = mul nsw i32 %add, 3 + ret i32 %mul +} + +; Keep nuw flag in this change, https://alive2.llvm.org/ce/z/awsQrx +define i32 @PR57278_mul(i32 %a) { +; CHECK-LABEL: @PR57278_mul( +; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[A:%.*]], 36 +; CHECK-NEXT: [[MUL:%.*]] = add nuw i32 [[TMP1]], 9 +; CHECK-NEXT: ret i32 [[MUL]] +; + %mul0 = mul nuw i32 %a, 12 + %add = or i32 %mul0, 3 + %mul = mul nuw i32 %add, 3 + ret i32 %mul +} + +; Negative test: Have common bits set +define i32 @PR57278_mul_1(i32 %a) { +; CHECK-LABEL: @PR57278_mul_1( +; CHECK-NEXT: [[MUL0:%.*]] = mul nuw i32 [[A:%.*]], 12 +; CHECK-NEXT: [[ADD:%.*]] = or i32 [[MUL0]], 4 +; CHECK-NEXT: [[MUL:%.*]] = mul nuw i32 [[ADD]], 3 +; CHECK-NEXT: ret i32 [[MUL]] +; + %mul0 = mul nuw i32 %a, 12 + %add = or i32 %mul0, 4 + %mul = mul nuw i32 %add, 3 + ret i32 %mul +} + +define <2 x i32> @PR57278_shl_vec(<2 x i32> %v1) { +; CHECK-LABEL: @PR57278_shl_vec( +; CHECK-NEXT: [[TMP1:%.*]] = mul <2 x i32> [[V1:%.*]], +; CHECK-NEXT: [[MUL:%.*]] = add nuw <2 x i32> [[TMP1]], +; CHECK-NEXT: ret <2 x i32> [[MUL]] +; + %shl = shl nuw <2 x i32> %v1, + %add = or <2 x i32> %shl, + %mul = mul nuw <2 x i32> %add, + ret <2 x 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:%.*]]