-
-
Save nikic/07bfd88af3607cdb4ba84bdaf299b07f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp | |
index 3f14bb90e669..d2e043ef1ee5 100644 | |
--- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp | |
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp | |
@@ -2113,7 +2113,9 @@ Instruction *InstCombinerImpl::visitSub(BinaryOperator &I) { | |
m_Select(m_Value(), m_Specific(Op1), m_Specific(&I))) || | |
match(UI, m_Select(m_Value(), m_Specific(&I), m_Specific(Op1))); | |
})) { | |
- if (Value *NegOp1 = Negator::Negate(IsNegation, Op1, *this)) | |
+ if (Value *NegOp1 = Negator::Negate(IsNegation, /* IsNSW */ IsNegation && | |
+ I.hasNoSignedWrap(), | |
+ Op1, *this)) | |
return BinaryOperator::CreateAdd(NegOp1, Op0); | |
} | |
if (IsNegation) | |
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h | |
index 7e9b916783a0..eb8216ab4239 100644 | |
--- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h | |
+++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h | |
@@ -713,13 +713,13 @@ class Negator final { | |
std::array<Value *, 2> getSortedOperandsOfBinOp(Instruction *I); | |
- [[nodiscard]] Value *visitImpl(Value *V, unsigned Depth); | |
+ [[nodiscard]] Value *visitImpl(Value *V, bool IsNSW, unsigned Depth); | |
- [[nodiscard]] Value *negate(Value *V, unsigned Depth); | |
+ [[nodiscard]] Value *negate(Value *V, bool IsNSW, unsigned Depth); | |
/// Recurse depth-first and attempt to sink the negation. | |
/// FIXME: use worklist? | |
- [[nodiscard]] std::optional<Result> run(Value *Root); | |
+ [[nodiscard]] std::optional<Result> run(Value *Root, bool IsNSW); | |
Negator(const Negator &) = delete; | |
Negator(Negator &&) = delete; | |
@@ -729,7 +729,7 @@ class Negator final { | |
public: | |
/// Attempt to negate \p Root. Retuns nullptr if negation can't be performed, | |
/// otherwise returns negated value. | |
- [[nodiscard]] static Value *Negate(bool LHSIsZero, Value *Root, | |
+ [[nodiscard]] static Value *Negate(bool LHSIsZero, bool IsNSW, Value *Root, | |
InstCombinerImpl &IC); | |
}; | |
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp | |
index 50458e2773e6..cc426d22218c 100644 | |
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp | |
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp | |
@@ -258,7 +258,8 @@ Instruction *InstCombinerImpl::visitMul(BinaryOperator &I) { | |
if (Op0->hasOneUse() && match(Op1, m_NegatedPower2())) { | |
// Interpret X * (-1<<C) as (-X) * (1<<C) and try to sink the negation. | |
// The "* (1<<C)" thus becomes a potential shifting opportunity. | |
- if (Value *NegOp0 = Negator::Negate(/*IsNegation*/ true, Op0, *this)) | |
+ if (Value *NegOp0 = | |
+ Negator::Negate(/*IsNegation*/ true, /* IsNSW */ false, Op0, *this)) | |
return BinaryOperator::CreateMul( | |
NegOp0, ConstantExpr::getNeg(cast<Constant>(Op1)), I.getName()); | |
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp b/llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp | |
index e24abc48424d..e5b7636cc848 100644 | |
--- a/llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp | |
+++ b/llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp | |
@@ -128,7 +128,7 @@ std::array<Value *, 2> Negator::getSortedOperandsOfBinOp(Instruction *I) { | |
// FIXME: can this be reworked into a worklist-based algorithm while preserving | |
// the depth-first, early bailout traversal? | |
-[[nodiscard]] Value *Negator::visitImpl(Value *V, unsigned Depth) { | |
+[[nodiscard]] Value *Negator::visitImpl(Value *V, bool IsNSW, unsigned Depth) { | |
// -(undef) -> undef. | |
if (match(V, m_Undef())) | |
return V; | |
@@ -237,7 +237,8 @@ std::array<Value *, 2> Negator::getSortedOperandsOfBinOp(Instruction *I) { | |
// However, only do this either if the old `sub` doesn't stick around, or | |
// it was subtracting from a constant. Otherwise, this isn't profitable. | |
return Builder.CreateSub(I->getOperand(1), I->getOperand(0), | |
- I->getName() + ".neg"); | |
+ I->getName() + ".neg", /* HasNUW */ false, | |
+ IsNSW && I->hasNoSignedWrap()); | |
} | |
// Some other cases, while still don't require recursion, | |
@@ -302,7 +303,7 @@ std::array<Value *, 2> Negator::getSortedOperandsOfBinOp(Instruction *I) { | |
switch (I->getOpcode()) { | |
case Instruction::Freeze: { | |
// `freeze` is negatible if its operand is negatible. | |
- Value *NegOp = negate(I->getOperand(0), Depth + 1); | |
+ Value *NegOp = negate(I->getOperand(0), /* IsNSW */ false, Depth + 1); | |
if (!NegOp) // Early return. | |
return nullptr; | |
return Builder.CreateFreeze(NegOp, I->getName() + ".neg"); | |
@@ -313,7 +314,7 @@ std::array<Value *, 2> Negator::getSortedOperandsOfBinOp(Instruction *I) { | |
SmallVector<Value *, 4> NegatedIncomingValues(PHI->getNumOperands()); | |
for (auto I : zip(PHI->incoming_values(), NegatedIncomingValues)) { | |
if (!(std::get<1>(I) = | |
- negate(std::get<0>(I), Depth + 1))) // Early return. | |
+ negate(std::get<0>(I), IsNSW, Depth + 1))) // Early return. | |
return nullptr; | |
} | |
// All incoming values are indeed negatible. Create negated PHI node. | |
@@ -336,10 +337,10 @@ std::array<Value *, 2> Negator::getSortedOperandsOfBinOp(Instruction *I) { | |
return NewSelect; | |
} | |
// `select` is negatible if both hands of `select` are negatible. | |
- Value *NegOp1 = negate(I->getOperand(1), Depth + 1); | |
+ Value *NegOp1 = negate(I->getOperand(1), IsNSW, Depth + 1); | |
if (!NegOp1) // Early return. | |
return nullptr; | |
- Value *NegOp2 = negate(I->getOperand(2), Depth + 1); | |
+ Value *NegOp2 = negate(I->getOperand(2), IsNSW, Depth + 1); | |
if (!NegOp2) | |
return nullptr; | |
// Do preserve the metadata! | |
@@ -349,10 +350,10 @@ std::array<Value *, 2> Negator::getSortedOperandsOfBinOp(Instruction *I) { | |
case Instruction::ShuffleVector: { | |
// `shufflevector` is negatible if both operands are negatible. | |
auto *Shuf = cast<ShuffleVectorInst>(I); | |
- Value *NegOp0 = negate(I->getOperand(0), Depth + 1); | |
+ Value *NegOp0 = negate(I->getOperand(0), IsNSW, Depth + 1); | |
if (!NegOp0) // Early return. | |
return nullptr; | |
- Value *NegOp1 = negate(I->getOperand(1), Depth + 1); | |
+ Value *NegOp1 = negate(I->getOperand(1), IsNSW, Depth + 1); | |
if (!NegOp1) | |
return nullptr; | |
return Builder.CreateShuffleVector(NegOp0, NegOp1, Shuf->getShuffleMask(), | |
@@ -361,7 +362,7 @@ std::array<Value *, 2> Negator::getSortedOperandsOfBinOp(Instruction *I) { | |
case Instruction::ExtractElement: { | |
// `extractelement` is negatible if source operand is negatible. | |
auto *EEI = cast<ExtractElementInst>(I); | |
- Value *NegVector = negate(EEI->getVectorOperand(), Depth + 1); | |
+ Value *NegVector = negate(EEI->getVectorOperand(), IsNSW, Depth + 1); | |
if (!NegVector) // Early return. | |
return nullptr; | |
return Builder.CreateExtractElement(NegVector, EEI->getIndexOperand(), | |
@@ -371,10 +372,10 @@ std::array<Value *, 2> Negator::getSortedOperandsOfBinOp(Instruction *I) { | |
// `insertelement` is negatible if both the source vector and | |
// element-to-be-inserted are negatible. | |
auto *IEI = cast<InsertElementInst>(I); | |
- Value *NegVector = negate(IEI->getOperand(0), Depth + 1); | |
+ Value *NegVector = negate(IEI->getOperand(0), IsNSW, Depth + 1); | |
if (!NegVector) // Early return. | |
return nullptr; | |
- Value *NegNewElt = negate(IEI->getOperand(1), Depth + 1); | |
+ Value *NegNewElt = negate(IEI->getOperand(1), IsNSW, Depth + 1); | |
if (!NegNewElt) // Early return. | |
return nullptr; | |
return Builder.CreateInsertElement(NegVector, NegNewElt, IEI->getOperand(2), | |
@@ -382,15 +383,17 @@ std::array<Value *, 2> Negator::getSortedOperandsOfBinOp(Instruction *I) { | |
} | |
case Instruction::Trunc: { | |
// `trunc` is negatible if its operand is negatible. | |
- Value *NegOp = negate(I->getOperand(0), Depth + 1); | |
+ Value *NegOp = negate(I->getOperand(0), /* IsNSW */ false, Depth + 1); | |
if (!NegOp) // Early return. | |
return nullptr; | |
return Builder.CreateTrunc(NegOp, I->getType(), I->getName() + ".neg"); | |
} | |
case Instruction::Shl: { | |
// `shl` is negatible if the first operand is negatible. | |
- if (Value *NegOp0 = negate(I->getOperand(0), Depth + 1)) | |
- return Builder.CreateShl(NegOp0, I->getOperand(1), I->getName() + ".neg"); | |
+ IsNSW &= I->hasNoSignedWrap(); | |
+ if (Value *NegOp0 = negate(I->getOperand(0), IsNSW, Depth + 1)) | |
+ return Builder.CreateShl(NegOp0, I->getOperand(1), I->getName() + ".neg", | |
+ /* HasNUW */ false, IsNSW); | |
// Otherwise, `shl %x, C` can be interpreted as `mul %x, 1<<C`. | |
auto *Op1C = dyn_cast<Constant>(I->getOperand(1)); | |
if (!Op1C || !IsTrulyNegation) | |
@@ -398,7 +401,7 @@ std::array<Value *, 2> Negator::getSortedOperandsOfBinOp(Instruction *I) { | |
return Builder.CreateMul( | |
I->getOperand(0), | |
ConstantExpr::getShl(Constant::getAllOnesValue(Op1C->getType()), Op1C), | |
- I->getName() + ".neg"); | |
+ I->getName() + ".neg", /* HasNUW */ false, IsNSW); | |
} | |
case Instruction::Or: { | |
if (!haveNoCommonBitsSet(I->getOperand(0), I->getOperand(1), DL, &AC, I, | |
@@ -417,7 +420,7 @@ std::array<Value *, 2> Negator::getSortedOperandsOfBinOp(Instruction *I) { | |
SmallVector<Value *, 2> NegatedOps, NonNegatedOps; | |
for (Value *Op : I->operands()) { | |
// Can we sink the negation into this operand? | |
- if (Value *NegOp = negate(Op, Depth + 1)) { | |
+ if (Value *NegOp = negate(Op, /* IsNSW */ false, Depth + 1)) { | |
NegatedOps.emplace_back(NegOp); // Successfully negated operand! | |
continue; | |
} | |
@@ -458,16 +461,17 @@ std::array<Value *, 2> Negator::getSortedOperandsOfBinOp(Instruction *I) { | |
Value *NegatedOp, *OtherOp; | |
// First try the second operand, in case it's a constant it will be best to | |
// just invert it instead of sinking the `neg` deeper. | |
- if (Value *NegOp1 = negate(Ops[1], Depth + 1)) { | |
+ if (Value *NegOp1 = negate(Ops[1], /* IsNSW */ false, Depth + 1)) { | |
NegatedOp = NegOp1; | |
OtherOp = Ops[0]; | |
- } else if (Value *NegOp0 = negate(Ops[0], Depth + 1)) { | |
+ } else if (Value *NegOp0 = negate(Ops[0], /* IsNSW */ false, Depth + 1)) { | |
NegatedOp = NegOp0; | |
OtherOp = Ops[1]; | |
} else | |
// Can't negate either of them. | |
return nullptr; | |
- return Builder.CreateMul(NegatedOp, OtherOp, I->getName() + ".neg"); | |
+ return Builder.CreateMul(NegatedOp, OtherOp, I->getName() + ".neg", | |
+ /* HasNUW */ false, IsNSW && I->hasNoSignedWrap()); | |
} | |
default: | |
return nullptr; // Don't know, likely not negatible for free. | |
@@ -476,7 +480,7 @@ std::array<Value *, 2> Negator::getSortedOperandsOfBinOp(Instruction *I) { | |
llvm_unreachable("Can't get here. We always return from switch."); | |
} | |
-[[nodiscard]] Value *Negator::negate(Value *V, unsigned Depth) { | |
+[[nodiscard]] Value *Negator::negate(Value *V, bool IsNSW, unsigned Depth) { | |
NegatorMaxDepthVisited.updateMax(Depth); | |
++NegatorNumValuesVisited; | |
@@ -506,15 +510,16 @@ std::array<Value *, 2> Negator::getSortedOperandsOfBinOp(Instruction *I) { | |
#endif | |
// No luck. Try negating it for real. | |
- Value *NegatedV = visitImpl(V, Depth); | |
+ Value *NegatedV = visitImpl(V, IsNSW, Depth); | |
// And cache the (real) result for the future. | |
NegationsCache[V] = NegatedV; | |
return NegatedV; | |
} | |
-[[nodiscard]] std::optional<Negator::Result> Negator::run(Value *Root) { | |
- Value *Negated = negate(Root, /*Depth=*/0); | |
+[[nodiscard]] std::optional<Negator::Result> Negator::run(Value *Root, | |
+ bool IsNSW) { | |
+ Value *Negated = negate(Root, IsNSW, /*Depth=*/0); | |
if (!Negated) { | |
// We must cleanup newly-inserted instructions, to avoid any potential | |
// endless combine looping. | |
@@ -525,7 +530,7 @@ std::array<Value *, 2> Negator::getSortedOperandsOfBinOp(Instruction *I) { | |
return std::make_pair(ArrayRef<Instruction *>(NewInstructions), Negated); | |
} | |
-[[nodiscard]] Value *Negator::Negate(bool LHSIsZero, Value *Root, | |
+[[nodiscard]] Value *Negator::Negate(bool LHSIsZero, bool IsNSW, Value *Root, | |
InstCombinerImpl &IC) { | |
++NegatorTotalNegationsAttempted; | |
LLVM_DEBUG(dbgs() << "Negator: attempting to sink negation into " << *Root | |
@@ -536,7 +541,7 @@ std::array<Value *, 2> Negator::getSortedOperandsOfBinOp(Instruction *I) { | |
Negator N(Root->getContext(), IC.getDataLayout(), IC.getAssumptionCache(), | |
IC.getDominatorTree(), LHSIsZero); | |
- std::optional<Result> Res = N.run(Root); | |
+ std::optional<Result> Res = N.run(Root, IsNSW); | |
if (!Res) { // Negation failed. | |
LLVM_DEBUG(dbgs() << "Negator: failed to sink negation into " << *Root | |
<< "\n"); | |
diff --git a/llvm/test/Transforms/InstCombine/abs-intrinsic.ll b/llvm/test/Transforms/InstCombine/abs-intrinsic.ll | |
index 50bdd643528d..7fe34d923764 100644 | |
--- a/llvm/test/Transforms/InstCombine/abs-intrinsic.ll | |
+++ b/llvm/test/Transforms/InstCombine/abs-intrinsic.ll | |
@@ -486,7 +486,7 @@ define i32 @sub_abs_sgeT_swap(i32 %x, i32 %y) { | |
; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp slt i32 [[Y:%.*]], [[X:%.*]] | |
; CHECK-NEXT: br i1 [[CMP_NOT]], label [[COND_END:%.*]], label [[COND_TRUE:%.*]] | |
; CHECK: cond.true: | |
-; CHECK-NEXT: [[SUB_NEG:%.*]] = sub i32 [[Y]], [[X]] | |
+; CHECK-NEXT: [[SUB_NEG:%.*]] = sub nsw i32 [[Y]], [[X]] | |
; CHECK-NEXT: br label [[COND_END]] | |
; CHECK: cond.end: | |
; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[SUB_NEG]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ] | |
@@ -513,7 +513,7 @@ define i32 @sub_abs_sgeT_false(i32 %x, i32 %y) { | |
; CHECK-NEXT: [[CMP_NOT_NOT:%.*]] = icmp slt i32 [[X:%.*]], [[Y:%.*]] | |
; CHECK-NEXT: br i1 [[CMP_NOT_NOT]], label [[COND_FALSE:%.*]], label [[COND_END:%.*]] | |
; CHECK: cond.false: | |
-; CHECK-NEXT: [[SUB_NEG:%.*]] = sub i32 [[Y]], [[X]] | |
+; CHECK-NEXT: [[SUB_NEG:%.*]] = sub nsw i32 [[Y]], [[X]] | |
; CHECK-NEXT: br label [[COND_END]] | |
; CHECK: cond.end: | |
; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[SUB_NEG]], [[COND_FALSE]] ], [ 0, [[ENTRY:%.*]] ] | |
@@ -539,7 +539,7 @@ define i32 @sub_abs_lt(i32 %x, i32 %y) { | |
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X:%.*]], [[Y:%.*]] | |
; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]] | |
; CHECK: cond.true: | |
-; CHECK-NEXT: [[SUB_NEG:%.*]] = sub i32 [[Y]], [[X]] | |
+; CHECK-NEXT: [[SUB_NEG:%.*]] = sub nsw i32 [[Y]], [[X]] | |
; CHECK-NEXT: br label [[COND_END]] | |
; CHECK: cond.end: | |
; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[SUB_NEG]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ] | |
@@ -566,7 +566,7 @@ define i32 @sub_abs_sle(i32 %x, i32 %y) { | |
; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp sgt i32 [[X:%.*]], [[Y:%.*]] | |
; CHECK-NEXT: br i1 [[CMP_NOT]], label [[COND_END:%.*]], label [[COND_TRUE:%.*]] | |
; CHECK: cond.true: | |
-; CHECK-NEXT: [[SUB_NEG:%.*]] = sub i32 [[Y]], [[X]] | |
+; CHECK-NEXT: [[SUB_NEG:%.*]] = sub nsw i32 [[Y]], [[X]] | |
; CHECK-NEXT: br label [[COND_END]] | |
; CHECK: cond.end: | |
; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[SUB_NEG]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ] | |
@@ -619,7 +619,7 @@ define i8 @sub_abs_sleT(i8 %x, i8 %y) { | |
; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp sgt i8 [[X:%.*]], [[Y:%.*]] | |
; CHECK-NEXT: br i1 [[CMP_NOT]], label [[COND_END:%.*]], label [[COND_TRUE:%.*]] | |
; CHECK: cond.true: | |
-; CHECK-NEXT: [[SUB_NEG:%.*]] = sub i8 [[Y]], [[X]] | |
+; CHECK-NEXT: [[SUB_NEG:%.*]] = sub nsw i8 [[Y]], [[X]] | |
; CHECK-NEXT: br label [[COND_END]] | |
; CHECK: cond.end: | |
; CHECK-NEXT: [[R:%.*]] = phi i8 [ [[SUB_NEG]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ] | |
diff --git a/llvm/test/Transforms/InstCombine/nsw.ll b/llvm/test/Transforms/InstCombine/nsw.ll | |
index c3c7b127a464..f37892e58a47 100644 | |
--- a/llvm/test/Transforms/InstCombine/nsw.ll | |
+++ b/llvm/test/Transforms/InstCombine/nsw.ll | |
@@ -145,7 +145,7 @@ define <vscale x 2 x i64> @mul_nuw_nsw_shuffle_constant_expr(<vscale x 2 x i8> % | |
define i32 @neg_sub0_sub_nsw_nsw(i32 %a, i32 %b) { | |
; CHECK-LABEL: @neg_sub0_sub_nsw_nsw( | |
-; CHECK-NEXT: [[C_NEG:%.*]] = sub i32 [[B:%.*]], [[A:%.*]] | |
+; CHECK-NEXT: [[C_NEG:%.*]] = sub nsw i32 [[B:%.*]], [[A:%.*]] | |
; CHECK-NEXT: ret i32 [[C_NEG]] | |
; | |
%c = sub nsw i32 %a, %b | |
@@ -181,7 +181,7 @@ define i32 @neg_sub_sub_nsw1(i32 %a, i32 %b) { | |
define i32 @neg_mul_sub_nsw_nsw(i32 %a, i32 %b) { | |
; CHECK-LABEL: @neg_mul_sub_nsw_nsw( | |
-; CHECK-NEXT: [[C_NEG:%.*]] = sub i32 [[B:%.*]], [[A:%.*]] | |
+; CHECK-NEXT: [[C_NEG:%.*]] = sub nsw i32 [[B:%.*]], [[A:%.*]] | |
; CHECK-NEXT: ret i32 [[C_NEG]] | |
; | |
%c = sub nsw i32 %a, %b |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment