aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/llvm/lib/Transforms/Scalar/Reassociate.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Transforms/Scalar/Reassociate.cpp')
-rw-r--r--contrib/llvm-project/llvm/lib/Transforms/Scalar/Reassociate.cpp114
1 files changed, 110 insertions, 4 deletions
diff --git a/contrib/llvm-project/llvm/lib/Transforms/Scalar/Reassociate.cpp b/contrib/llvm-project/llvm/lib/Transforms/Scalar/Reassociate.cpp
index ba7f367267fe..dffeb7cc227b 100644
--- a/contrib/llvm-project/llvm/lib/Transforms/Scalar/Reassociate.cpp
+++ b/contrib/llvm-project/llvm/lib/Transforms/Scalar/Reassociate.cpp
@@ -920,6 +920,100 @@ static Value *NegateValue(Value *V, Instruction *BI,
return NewNeg;
}
+// See if this `or` looks like an load widening reduction, i.e. that it
+// consists of an `or`/`shl`/`zext`/`load` nodes only. Note that we don't
+// ensure that the pattern is *really* a load widening reduction,
+// we do not ensure that it can really be replaced with a widened load,
+// only that it mostly looks like one.
+static bool isLoadCombineCandidate(Instruction *Or) {
+ SmallVector<Instruction *, 8> Worklist;
+ SmallSet<Instruction *, 8> Visited;
+
+ auto Enqueue = [&](Value *V) {
+ auto *I = dyn_cast<Instruction>(V);
+ // Each node of an `or` reduction must be an instruction,
+ if (!I)
+ return false; // Node is certainly not part of an `or` load reduction.
+ // Only process instructions we have never processed before.
+ if (Visited.insert(I).second)
+ Worklist.emplace_back(I);
+ return true; // Will need to look at parent nodes.
+ };
+
+ if (!Enqueue(Or))
+ return false; // Not an `or` reduction pattern.
+
+ while (!Worklist.empty()) {
+ auto *I = Worklist.pop_back_val();
+
+ // Okay, which instruction is this node?
+ switch (I->getOpcode()) {
+ case Instruction::Or:
+ // Got an `or` node. That's fine, just recurse into it's operands.
+ for (Value *Op : I->operands())
+ if (!Enqueue(Op))
+ return false; // Not an `or` reduction pattern.
+ continue;
+
+ case Instruction::Shl:
+ case Instruction::ZExt:
+ // `shl`/`zext` nodes are fine, just recurse into their base operand.
+ if (!Enqueue(I->getOperand(0)))
+ return false; // Not an `or` reduction pattern.
+ continue;
+
+ case Instruction::Load:
+ // Perfect, `load` node means we've reached an edge of the graph.
+ continue;
+
+ default: // Unknown node.
+ return false; // Not an `or` reduction pattern.
+ }
+ }
+
+ return true;
+}
+
+/// Return true if it may be profitable to convert this (X|Y) into (X+Y).
+static bool ShouldConvertOrWithNoCommonBitsToAdd(Instruction *Or) {
+ // Don't bother to convert this up unless either the LHS is an associable add
+ // or subtract or mul or if this is only used by one of the above.
+ // This is only a compile-time improvement, it is not needed for correctness!
+ auto isInteresting = [](Value *V) {
+ for (auto Op : {Instruction::Add, Instruction::Sub, Instruction::Mul})
+ if (isReassociableOp(V, Op))
+ return true;
+ return false;
+ };
+
+ if (any_of(Or->operands(), isInteresting))
+ return true;
+
+ Value *VB = Or->user_back();
+ if (Or->hasOneUse() && isInteresting(VB))
+ return true;
+
+ return false;
+}
+
+/// If we have (X|Y), and iff X and Y have no common bits set,
+/// transform this into (X+Y) to allow arithmetics reassociation.
+static BinaryOperator *ConvertOrWithNoCommonBitsToAdd(Instruction *Or) {
+ // Convert an or into an add.
+ BinaryOperator *New =
+ CreateAdd(Or->getOperand(0), Or->getOperand(1), "", Or, Or);
+ New->setHasNoSignedWrap();
+ New->setHasNoUnsignedWrap();
+ New->takeName(Or);
+
+ // Everyone now refers to the add instruction.
+ Or->replaceAllUsesWith(New);
+ New->setDebugLoc(Or->getDebugLoc());
+
+ LLVM_DEBUG(dbgs() << "Converted or into an add: " << *New << '\n');
+ return New;
+}
+
/// Return true if we should break up this subtract of X-Y into (X + -Y).
static bool ShouldBreakUpSubtract(Instruction *Sub) {
// If this is a negation, we can't split it up!
@@ -1034,8 +1128,7 @@ static Value *EmitAddTreeOfValues(Instruction *I,
SmallVectorImpl<WeakTrackingVH> &Ops) {
if (Ops.size() == 1) return Ops.back();
- Value *V1 = Ops.back();
- Ops.pop_back();
+ Value *V1 = Ops.pop_back_val();
Value *V2 = EmitAddTreeOfValues(I, Ops);
return CreateAdd(V2, V1, "reass.add", I, I);
}
@@ -1899,7 +1992,7 @@ Value *ReassociatePass::OptimizeExpression(BinaryOperator *I,
void ReassociatePass::RecursivelyEraseDeadInsts(Instruction *I,
OrderedSet &Insts) {
assert(isInstructionTriviallyDead(I) && "Trivially dead instructions only!");
- SmallVector<Value *, 4> Ops(I->op_begin(), I->op_end());
+ SmallVector<Value *, 4> Ops(I->operands());
ValueRankMap.erase(I);
Insts.remove(I);
RedoInsts.remove(I);
@@ -1916,7 +2009,7 @@ void ReassociatePass::EraseInst(Instruction *I) {
assert(isInstructionTriviallyDead(I) && "Trivially dead instructions only!");
LLVM_DEBUG(dbgs() << "Erasing dead inst: "; I->dump());
- SmallVector<Value*, 8> Ops(I->op_begin(), I->op_end());
+ SmallVector<Value *, 8> Ops(I->operands());
// Erase the dead instruction.
ValueRankMap.erase(I);
RedoInsts.remove(I);
@@ -2116,6 +2209,19 @@ void ReassociatePass::OptimizeInst(Instruction *I) {
if (I->getType()->isIntegerTy(1))
return;
+ // If this is a bitwise or instruction of operands
+ // with no common bits set, convert it to X+Y.
+ if (I->getOpcode() == Instruction::Or &&
+ ShouldConvertOrWithNoCommonBitsToAdd(I) && !isLoadCombineCandidate(I) &&
+ haveNoCommonBitsSet(I->getOperand(0), I->getOperand(1),
+ I->getModule()->getDataLayout(), /*AC=*/nullptr, I,
+ /*DT=*/nullptr)) {
+ Instruction *NI = ConvertOrWithNoCommonBitsToAdd(I);
+ RedoInsts.insert(I);
+ MadeChange = true;
+ I = NI;
+ }
+
// If this is a subtract instruction which is not already in negate form,
// see if we can convert it to X+-Y.
if (I->getOpcode() == Instruction::Sub) {