@@ -108,6 +108,7 @@ class VectorCombine {
108108 Instruction &I);
109109 bool foldExtractExtract (Instruction &I);
110110 bool foldInsExtFNeg (Instruction &I);
111+ bool foldInsExtBinop (Instruction &I);
111112 bool foldInsExtVectorToShuffle (Instruction &I);
112113 bool foldBitcastShuffle (Instruction &I);
113114 bool scalarizeBinopOrCmp (Instruction &I);
@@ -738,6 +739,64 @@ bool VectorCombine::foldInsExtFNeg(Instruction &I) {
738739 return true ;
739740}
740741
742+ // / Try to fold insert(binop(x,y),binop(a,b),idx)
743+ // / --> binop(insert(x,a,idx),insert(y,b,idx))
744+ bool VectorCombine::foldInsExtBinop (Instruction &I) {
745+ BinaryOperator *VecBinOp, *SclBinOp;
746+ uint64_t Index;
747+ if (!match (&I,
748+ m_InsertElt (m_OneUse (m_BinOp (VecBinOp)),
749+ m_OneUse (m_BinOp (SclBinOp)), m_ConstantInt (Index))))
750+ return false ;
751+
752+ // TODO: Add support for addlike etc.
753+ Instruction::BinaryOps BinOpcode = VecBinOp->getOpcode ();
754+ if (BinOpcode != SclBinOp->getOpcode ())
755+ return false ;
756+
757+ auto *ResultTy = dyn_cast<FixedVectorType>(I.getType ());
758+ if (!ResultTy)
759+ return false ;
760+
761+ // TODO: Attempt to detect m_ExtractElt for scalar operands and convert to
762+ // shuffle?
763+
764+ InstructionCost OldCost = TTI.getInstructionCost (&I, CostKind) +
765+ TTI.getInstructionCost (VecBinOp, CostKind) +
766+ TTI.getInstructionCost (SclBinOp, CostKind);
767+ InstructionCost NewCost =
768+ TTI.getArithmeticInstrCost (BinOpcode, ResultTy, CostKind) +
769+ TTI.getVectorInstrCost (Instruction::InsertElement, ResultTy, CostKind,
770+ Index, VecBinOp->getOperand (0 ),
771+ SclBinOp->getOperand (0 )) +
772+ TTI.getVectorInstrCost (Instruction::InsertElement, ResultTy, CostKind,
773+ Index, VecBinOp->getOperand (1 ),
774+ SclBinOp->getOperand (1 ));
775+
776+ LLVM_DEBUG (dbgs () << " Found an insertion of two binops: " << I
777+ << " \n OldCost: " << OldCost << " vs NewCost: " << NewCost
778+ << " \n " );
779+ if (NewCost > OldCost)
780+ return false ;
781+
782+ Value *NewIns0 = Builder.CreateInsertElement (VecBinOp->getOperand (0 ),
783+ SclBinOp->getOperand (0 ), Index);
784+ Value *NewIns1 = Builder.CreateInsertElement (VecBinOp->getOperand (1 ),
785+ SclBinOp->getOperand (1 ), Index);
786+ Value *NewBO = Builder.CreateBinOp (BinOpcode, NewIns0, NewIns1);
787+
788+ // Intersect flags from the old binops.
789+ if (auto *NewInst = dyn_cast<Instruction>(NewBO)) {
790+ NewInst->copyIRFlags (VecBinOp);
791+ NewInst->andIRFlags (SclBinOp);
792+ }
793+
794+ Worklist.pushValue (NewIns0);
795+ Worklist.pushValue (NewIns1);
796+ replaceValue (I, *NewBO);
797+ return true ;
798+ }
799+
741800// / If this is a bitcast of a shuffle, try to bitcast the source vector to the
742801// / destination type followed by shuffle. This can enable further transforms by
743802// / moving bitcasts or shuffles together.
@@ -3206,6 +3265,7 @@ bool VectorCombine::run() {
32063265 switch (Opcode) {
32073266 case Instruction::InsertElement:
32083267 MadeChange |= foldInsExtFNeg (I);
3268+ MadeChange |= foldInsExtBinop (I);
32093269 MadeChange |= foldInsExtVectorToShuffle (I);
32103270 break ;
32113271 case Instruction::ShuffleVector:
0 commit comments