diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -935,6 +935,15 @@ return Builder.CreateTrunc(NegA, I->getType(), I->getName() + ".neg"); return nullptr; + // 0-(A*B) => (0-A)*B + // 0-(A*B) => A*(0-B) + case Instruction::Mul: + if (Value *NegA = freelyNegateValue(I->getOperand(0))) + return Builder.CreateMul(NegA, I->getOperand(1), V->getName() + ".neg"); + if (Value *NegB = freelyNegateValue(I->getOperand(1))) + return Builder.CreateMul(I->getOperand(0), NegB, V->getName() + ".neg"); + return nullptr; + default: return nullptr; } 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 @@ -456,10 +456,9 @@ define i32 @test_mul_canonicalize_op1(i32 %x, i32 %z) { ; CHECK-LABEL: @test_mul_canonicalize_op1( -; CHECK-NEXT: [[Y:%.*]] = mul i32 [[Z:%.*]], 3 -; CHECK-NEXT: [[TMP1:%.*]] = mul i32 [[Y]], [[X:%.*]] -; CHECK-NEXT: [[MUL:%.*]] = sub i32 0, [[TMP1]] -; CHECK-NEXT: ret i32 [[MUL]] +; CHECK-NEXT: [[Y_NEG:%.*]] = mul i32 [[Z:%.*]], -3 +; CHECK-NEXT: [[DOTNEG:%.*]] = mul i32 [[Y_NEG]], [[X:%.*]] +; CHECK-NEXT: ret i32 [[DOTNEG]] ; %y = mul i32 %z, 3 %neg = sub i32 0, %x diff --git a/llvm/test/Transforms/InstCombine/sub.ll b/llvm/test/Transforms/InstCombine/sub.ll --- a/llvm/test/Transforms/InstCombine/sub.ll +++ b/llvm/test/Transforms/InstCombine/sub.ll @@ -689,10 +689,9 @@ define i64 @test_neg_mul_sub(i64 %a, i64 %b, i64 %c) { ; CHECK-LABEL: @test_neg_mul_sub( -; CHECK-NEXT: [[SUB:%.*]] = sub i64 [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[MUL:%.*]] = mul i64 [[SUB]], [[C:%.*]] -; CHECK-NEXT: [[NEG:%.*]] = sub i64 0, [[MUL]] -; CHECK-NEXT: ret i64 [[NEG]] +; CHECK-NEXT: [[SUB_NEG:%.*]] = sub i64 [[B:%.*]], [[A:%.*]] +; CHECK-NEXT: [[MUL_NEG:%.*]] = mul i64 [[SUB_NEG]], [[C:%.*]] +; CHECK-NEXT: ret i64 [[MUL_NEG]] ; %sub = sub i64 %a, %b %mul = mul i64 %sub, %c @@ -700,13 +699,12 @@ ret i64 %neg } -define i64 @test_neg_mul_sub_communted(i64 %a, i64 %b, i64 %c) { -; CHECK-LABEL: @test_neg_mul_sub_communted( +define i64 @test_neg_mul_sub_commuted(i64 %a, i64 %b, i64 %c) { +; CHECK-LABEL: @test_neg_mul_sub_commuted( ; CHECK-NEXT: [[COMPLEX:%.*]] = mul i64 [[C:%.*]], [[C]] -; CHECK-NEXT: [[SUB:%.*]] = sub i64 [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[MUL:%.*]] = mul i64 [[COMPLEX]], [[SUB]] -; CHECK-NEXT: [[NEG:%.*]] = sub i64 0, [[MUL]] -; CHECK-NEXT: ret i64 [[NEG]] +; CHECK-NEXT: [[SUB_NEG:%.*]] = sub i64 [[B:%.*]], [[A:%.*]] +; CHECK-NEXT: [[MUL_NEG:%.*]] = mul i64 [[COMPLEX]], [[SUB_NEG]] +; CHECK-NEXT: ret i64 [[MUL_NEG]] ; %complex = mul i64 %c, %c %sub = sub i64 %a, %b