[llvm] [SLP][NFC]Extract values state/operands analysis into separate class (PR #138724)
Alexey Bataev via llvm-commits
llvm-commits at lists.llvm.org
Thu May 8 09:29:08 PDT 2025
================
@@ -9734,16 +9725,201 @@ bool BoUpSLP::canBuildSplitNode(ArrayRef<Value *> VL,
return true;
}
+namespace {
+/// Class accepts incoming list of values and generates the list of values
+/// for scheduling and list of operands for the new nodes.
+class InstructionsCompatibilityAnalysis {
+ DominatorTree &DT;
+ const DataLayout &DL;
+ const TargetTransformInfo &TTI;
+ const TargetLibraryInfo &TLI;
+
+ /// Builds operands for the original instructions.
+ void
+ buildOriginalOperands(const InstructionsState &S, ArrayRef<Value *> VL,
+ SmallVectorImpl<BoUpSLP::ValueList> &Operands) const {
+
+ unsigned ShuffleOrOp =
+ S.isAltShuffle() ? (unsigned)Instruction::ShuffleVector : S.getOpcode();
+ Instruction *VL0 = S.getMainOp();
+
+ switch (ShuffleOrOp) {
+ case Instruction::PHI: {
+ auto *PH = cast<PHINode>(VL0);
+
+ // Keeps the reordered operands to avoid code duplication.
+ PHIHandler Handler(DT, PH, VL);
+ Handler.buildOperands();
+ Operands.assign(PH->getNumOperands(), {});
+ for (unsigned I : seq<unsigned>(PH->getNumOperands()))
+ Operands[I].assign(Handler.getOperands(I).begin(),
+ Handler.getOperands(I).end());
+ return;
+ }
+ case Instruction::ExtractValue:
+ case Instruction::ExtractElement:
+ // This is a special case, as it does not gather, but at the same time
+ // we are not extending buildTree_rec() towards the operands.
+ Operands.assign(1, {VL.size(), VL0->getOperand(0)});
+ return;
+ case Instruction::InsertElement:
+ Operands.assign(2, {VL.size(), nullptr});
+ for (auto [Idx, V] : enumerate(VL)) {
+ auto *IE = cast<InsertElementInst>(V);
+ for (auto [OpIdx, Ops] : enumerate(Operands))
+ Ops[Idx] = IE->getOperand(OpIdx);
+ }
+ return;
+ case Instruction::Load:
+ Operands.assign(
+ 1, {VL.size(),
+ PoisonValue::get(cast<LoadInst>(VL0)->getPointerOperandType())});
+ for (auto [V, Op] : zip(VL, Operands.back())) {
+ auto *LI = dyn_cast<LoadInst>(V);
+ if (!LI)
+ continue;
+ Op = LI->getPointerOperand();
+ }
+ return;
+ case Instruction::ZExt:
+ case Instruction::SExt:
+ case Instruction::FPToUI:
+ case Instruction::FPToSI:
+ case Instruction::FPExt:
+ case Instruction::PtrToInt:
+ case Instruction::IntToPtr:
+ case Instruction::SIToFP:
+ case Instruction::UIToFP:
+ case Instruction::Trunc:
+ case Instruction::FPTrunc:
+ case Instruction::BitCast:
+ case Instruction::ICmp:
+ case Instruction::FCmp:
+ case Instruction::Select:
+ case Instruction::FNeg:
+ case Instruction::Add:
+ case Instruction::FAdd:
+ case Instruction::Sub:
+ case Instruction::FSub:
+ case Instruction::Mul:
+ case Instruction::FMul:
+ case Instruction::UDiv:
+ case Instruction::SDiv:
+ case Instruction::FDiv:
+ case Instruction::URem:
+ case Instruction::SRem:
+ case Instruction::FRem:
+ case Instruction::Shl:
+ case Instruction::LShr:
+ case Instruction::AShr:
+ case Instruction::And:
+ case Instruction::Or:
+ case Instruction::Xor:
+ case Instruction::Freeze:
+ case Instruction::Store:
+ case Instruction::ShuffleVector:
+ Operands.assign(VL0->getNumOperands(), {VL.size(), nullptr});
+ for (auto [Idx, V] : enumerate(VL)) {
+ auto *I = dyn_cast<Instruction>(V);
+ if (!I) {
+ for (auto [OpIdx, Ops] : enumerate(Operands))
+ Ops[Idx] = PoisonValue::get(VL0->getOperand(OpIdx)->getType());
+ continue;
+ }
+ auto [Op, ConvertedOps] = convertTo(I, S);
+ for (auto [OpIdx, Ops] : enumerate(Operands))
+ Ops[Idx] = ConvertedOps[OpIdx];
+ }
+ return;
+ case Instruction::GetElementPtr: {
+ Operands.assign(2, {VL.size(), nullptr});
+ // Need to cast all indices to the same type before vectorization to
+ // avoid crash.
+ // Required to be able to find correct matches between different gather
+ // nodes and reuse the vectorized values rather than trying to gather them
+ // again.
+ const unsigned IndexIdx = 1;
+ Type *VL0Ty = VL0->getOperand(IndexIdx)->getType();
+ Type *Ty = all_of(VL,
+ [VL0Ty](Value *V) {
+ auto *GEP = dyn_cast<GetElementPtrInst>(V);
+ if (!GEP)
+ return true;
+ return VL0Ty == GEP->getOperand(IndexIdx)->getType();
+ })
+ ? VL0Ty
+ : DL.getIndexType(cast<GetElementPtrInst>(VL0)
+ ->getPointerOperandType()
+ ->getScalarType());
+ for (auto [Idx, V] : enumerate(VL)) {
+ auto *GEP = dyn_cast<GetElementPtrInst>(V);
+ if (!GEP) {
+ Operands[0][Idx] = V;
+ Operands[1][Idx] = ConstantInt::getNullValue(Ty);
+ continue;
+ }
+ Operands[0][Idx] = GEP->getPointerOperand();
+ auto *Op = GEP->getOperand(IndexIdx);
+ auto *CI = dyn_cast<ConstantInt>(Op);
+ Operands[1][Idx] = CI ? ConstantFoldIntegerCast(
+ CI, Ty, CI->getValue().isSignBitSet(), DL)
+ : Op;
+ }
+ return;
+ }
+ case Instruction::Call: {
+ auto *CI = cast<CallInst>(VL0);
+ Intrinsic::ID ID = getVectorIntrinsicIDForCall(CI, &TLI);
+ for (unsigned Idx : seq<unsigned>(CI->arg_size())) {
+ if (isVectorIntrinsicWithScalarOpAtArg(ID, Idx, &TTI))
+ continue;
+ auto &Ops = Operands.emplace_back();
+ for (Value *V : VL) {
+ auto *I = dyn_cast<Instruction>(V);
+ Ops.push_back(I ? I->getOperand(Idx)
+ : PoisonValue::get(VL0->getOperand(Idx)->getType()));
+ }
+ }
+ return;
+ }
+ default:
+ break;
+ }
+ llvm_unreachable("Unexpected vectorization of the instructions.");
+ }
+
+public:
+ InstructionsCompatibilityAnalysis(DominatorTree &DT, const DataLayout &DL,
+ const TargetTransformInfo &TTI,
+ const TargetLibraryInfo &TLI)
+ : DT(DT), DL(DL), TTI(TTI), TLI(TLI) {}
+
+ InstructionsState buildInstructionsState(ArrayRef<Value *> VL) {
+ InstructionsState S = getSameOpcode(VL, TLI);
+ return S;
+ }
----------------
alexey-bataev wrote:
Done
https://github.com/llvm/llvm-project/pull/138724
More information about the llvm-commits
mailing list