[llvm] [SLP]Initial support for copyable elements (non-schedulable only) (PR #140279)
Simon Pilgrim via llvm-commits
llvm-commits at lists.llvm.org
Wed Jun 11 08:47:52 PDT 2025
================
@@ -9740,13 +9831,112 @@ bool BoUpSLP::canBuildSplitNode(ArrayRef<Value *> VL,
}
namespace {
-/// Class accepts incoming list of values and generates the list of values
-/// for scheduling and list of operands for the new nodes.
+/// Class accepts incoming list of values, checks if it is able to model
+/// "copyable" values as compatible operations, and generates the list of values
+/// for scheduling and list of operands doe the new nodes.
class InstructionsCompatibilityAnalysis {
DominatorTree &DT;
const DataLayout &DL;
const TargetTransformInfo &TTI;
const TargetLibraryInfo &TLI;
+ unsigned MainOpcode = 0;
+ Instruction *MainOp = nullptr;
+
+ /// Identifies the best candidate value, which represents main opcode
+ /// operation.
+ /// Currently the best candidate is the Add instruction with the parent
+ /// block with the highest DFS incoming number (block, that dominates other).
+ void findAndSetMainInstruction(ArrayRef<Value *> VL) {
+ BasicBlock *Parent = nullptr;
+ // Checks if the instruction has supported opcode.
+ auto IsSupportedOpcode = [](Instruction *I) {
+ return I && I->getOpcode() == Instruction::Add;
+ };
+ for (Value *V : VL) {
+ auto *I = dyn_cast<Instruction>(V);
+ if (!I)
+ continue;
+ if (!DT.isReachableFromEntry(I->getParent()))
+ continue;
+ if (!MainOp) {
+ MainOp = I;
+ Parent = I->getParent();
+ continue;
+ }
+ if (Parent == I->getParent()) {
+ if (!IsSupportedOpcode(MainOp))
+ MainOp = I;
+ if (MainOp->getOpcode() == I->getOpcode() &&
+ doesNotNeedToBeScheduled(MainOp) && !doesNotNeedToBeScheduled(I))
+ MainOp = I;
+ continue;
+ }
+ auto *NodeA = DT.getNode(Parent);
+ auto *NodeB = DT.getNode(I->getParent());
+ assert(NodeA && "Should only process reachable instructions");
+ assert(NodeB && "Should only process reachable instructions");
+ assert((NodeA == NodeB) ==
+ (NodeA->getDFSNumIn() == NodeB->getDFSNumIn()) &&
+ "Different nodes should have different DFS numbers");
+ if (NodeA->getDFSNumIn() < NodeB->getDFSNumIn()) {
+ MainOp = I;
+ Parent = I->getParent();
+ }
+ }
+ // FIXME: remove second part of the check, once the scheduling support
+ // for copyable instructions is landed.
+ if (!IsSupportedOpcode(MainOp) || any_of(VL, [&](Value *V) {
+ auto *I = dyn_cast<Instruction>(V);
+ return I && I->getOpcode() != MainOp->getOpcode() &&
+ I->getParent() == MainOp->getParent() && !isa<PHINode>(I) &&
+ !doesNotNeedToBeScheduled(I);
+ })) {
+ MainOp = nullptr;
+ return;
+ }
+ MainOpcode = MainOp->getOpcode();
+ }
+
+ /// Returns the idempotent value for the \p MainOp with the detected \p
+ /// MainOpcode. For Add, returns 0. For Or, it should choose between false and
+ /// the operand itself, since V or V == V.
+ Value *selectBestIdempotentValue() const {
+ switch (MainOpcode) {
+ case Instruction::Add:
+ return ConstantInt::getNullValue(MainOp->getType());
+ default:
+ break;
+ }
+ llvm_unreachable("Unsupported opcode");
+ }
+
+ unsigned getNumberOfOperands() const {
+ switch (MainOpcode) {
+ case Instruction::Add:
+ return 2;
+ default:
+ break;
+ }
+ llvm_unreachable("Unsupported opcode");
+ }
+
+ /// Returns the value and operands for the \p V, considering if it is original
+ /// instruction and its actual operands should be returned, or it is a
+ /// copyable element and its should be represented as idempotent instruction.
+ SmallVector<Value *> getOperands(const InstructionsState &S, Value *V) const {
+ bool MatchesMainOp = !S.isCopyableElement(V);
+ switch (MainOpcode) {
+ case Instruction::Add:
+ if (isa<PoisonValue>(V))
+ return {V, V};
----------------
RKSimon wrote:
Does this mean we'll end up building poison handling for every opcode? is there nothing generic that can already do it for us?
https://github.com/llvm/llvm-project/pull/140279
More information about the llvm-commits
mailing list