diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Transforms/Scalar/Reassociate.cpp')
-rw-r--r-- | contrib/llvm-project/llvm/lib/Transforms/Scalar/Reassociate.cpp | 114 |
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) { |