diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -1985,7 +1985,7 @@ // 0 - (X << Y) -> (-X << Y) when X is freely negatable. if (match(Op1, m_Shl(m_Value(X), m_Value(Y))) && match(Op0, m_Zero())) - if (Value *XNeg = dyn_castNegVal(X)) + if (Value *XNeg = freelyNegateValue(X)) return BinaryOperator::CreateShl(XNeg, Y); // Subtracting -1/0 is the same as adding 1/0: diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h --- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h +++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h @@ -474,6 +474,7 @@ bool shouldChangeType(unsigned FromBitWidth, unsigned ToBitWidth) const; bool shouldChangeType(Type *From, Type *To) const; Value *dyn_castNegVal(Value *V) const; + Value *freelyNegateValue(Value *V); Type *FindElementAtOffset(PointerType *PtrTy, int64_t Offset, SmallVectorImpl &NewIndices); 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 @@ -856,6 +856,23 @@ return nullptr; } +/// Get negated V (that is 0-V) without increasing instruction count, +/// assuming that the original V will become unused. +Value *InstCombiner::freelyNegateValue(Value *V) { + if (Value *NegV = dyn_castNegVal(V)) + return NegV; + + if (!V->hasOneUse()) + return nullptr; + + Value *A, *B; + // 0-(A-B) => B-A + if (match(V, m_Sub(m_Value(A), m_Value(B)))) + return Builder.CreateSub(B, A); + + return nullptr; +} + static Value *foldOperationIntoSelectOperand(Instruction &I, Value *SO, InstCombiner::BuilderTy &Builder) { if (auto *Cast = dyn_cast(&I)) 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 @@ -543,9 +543,8 @@ define i64 @test_neg_shl_sub(i64 %a, i64 %b) { ; CHECK-LABEL: @test_neg_shl_sub( -; CHECK-NEXT: [[SUB:%.*]] = sub i64 [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[MUL:%.*]] = shl i64 [[SUB]], 2 -; CHECK-NEXT: [[NEG:%.*]] = sub i64 0, [[MUL]] +; CHECK-NEXT: [[TMP1:%.*]] = sub i64 [[B:%.*]], [[A:%.*]] +; CHECK-NEXT: [[NEG:%.*]] = shl i64 [[TMP1]], 2 ; CHECK-NEXT: ret i64 [[NEG]] ; %sub = sub i64 %a, %b