[llvm] [VectorCombine] Fold Deinterleave/Interleave Pairs (PR #211022)
Graham Hunter via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 7 09:50:54 PDT 2026
================
@@ -5882,6 +5883,265 @@ bool VectorCombine::foldInsExtVectorToShuffle(Instruction &I) {
return true;
}
+namespace {
+
+class InterleavedElementwiseChain {
+ struct ElementwiseStep {
+ SmallVector<Instruction *, 8> Insts;
+ unsigned ChainOperand;
+
+ ElementwiseStep(ArrayRef<Instruction *> Insts, unsigned ChainOperand)
+ : Insts(Insts.begin(), Insts.end()), ChainOperand(ChainOperand) {}
+ };
+
+ IRBuilderBase &Builder;
+ Value *Root;
+ SmallVector<ElementwiseStep, 4> Steps;
+
+ static unsigned getNumDataOperands(Instruction *Inst) {
+ if (auto *II = dyn_cast<IntrinsicInst>(Inst))
+ return II->arg_size();
+ return Inst->getNumOperands();
+ }
+
+ static Value *getSplatOrScalar(Value *V) {
+ return isa<VectorType>(V->getType()) ? getSplatValue(V) : V;
+ }
+
+ static bool isSupportedElementwise(Instruction *Inst) {
+ auto *ResultTy = dyn_cast<VectorType>(Inst->getType());
+ if (!ResultTy)
+ return false;
+
+ if (auto *II = dyn_cast<IntrinsicInst>(Inst)) {
+ if (II->hasOperandBundles() ||
+ !isTriviallyVectorizable(II->getIntrinsicID()))
+ return false;
+ } else if (!isa<BinaryOperator, UnaryOperator, CastInst, CmpInst,
+ SelectInst, FreezeInst>(Inst)) {
+ return false;
+ }
+
+ // Reject operations that change the element-count.
+ for (unsigned Op = 0, E = getNumDataOperands(Inst); Op != E; ++Op) {
+ auto *OperandTy = dyn_cast<VectorType>(Inst->getOperand(Op)->getType());
+ if (OperandTy &&
+ OperandTy->getElementCount() != ResultTy->getElementCount())
+ return false;
+ }
+
+ return true;
+ }
+
+ Value *createWideInstruction(Instruction *NarrowInst,
+ ArrayRef<Value *> NewOperands,
+ VectorType *WideResultTy) {
+ if (isa<BinaryOperator, UnaryOperator>(NarrowInst))
+ return Builder.CreateNAryOp(NarrowInst->getOpcode(), NewOperands);
+ if (auto *Cast = dyn_cast<CastInst>(NarrowInst))
+ return Builder.CreateCast(Cast->getOpcode(), NewOperands[0],
+ WideResultTy);
+ if (auto *Cmp = dyn_cast<CmpInst>(NarrowInst))
+ return Builder.CreateCmp(Cmp->getPredicate(), NewOperands[0],
+ NewOperands[1]);
+ if (isa<SelectInst>(NarrowInst))
+ return Builder.CreateSelect(NewOperands[0], NewOperands[1],
+ NewOperands[2]);
+ if (isa<FreezeInst>(NarrowInst))
+ return Builder.CreateFreeze(NewOperands[0]);
+ if (auto *II = dyn_cast<IntrinsicInst>(NarrowInst))
+ return Builder.CreateIntrinsic(WideResultTy, II->getIntrinsicID(),
+ NewOperands);
+ llvm_unreachable("Unsupported instruction");
+ }
+
+public:
+ InterleavedElementwiseChain(IRBuilderBase &Builder, Value *Root)
+ : Builder(Builder), Root(Root) {}
+
+ /// Visit a list of instructions and check if they can be rewritten as a
+ /// single wider instruction. If so, the list is appened to \p Steps.
+ bool visitInstLevel(ArrayRef<Instruction *> Insts,
+ ArrayRef<unsigned> OperandNumbers) {
+ if (Insts.empty() || Insts.size() != OperandNumbers.size())
+ return false;
+
+ Instruction *FirstInst = Insts.front();
+ unsigned ChainOperand = OperandNumbers.front();
+
+ if (!isSupportedElementwise(FirstInst))
+ return false;
+
+ for (unsigned Index = 1; Index != Insts.size(); ++Index)
+ if (OperandNumbers[Index] != ChainOperand ||
+ !FirstInst->isSameOperationAs(Insts[Index]))
+ return false;
----------------
huntergr-arm wrote:
With `Use`, this could just become a `any_of` operation over the arrayref (with a drop_front)
https://github.com/llvm/llvm-project/pull/211022
More information about the llvm-commits
mailing list