// This function is *almost* as-is from instcombine, avoiding silly // cases that should already have been optimized. bool BackendCanonicalize::visitInsertElementInst(InsertElementInst &IE) { Value *ScalarOp = IE.getOperand(1); Value *IdxOp = IE.getOperand(2); // If the inserted element was extracted from some other vector, and if the // indexes are constant, try to turn this into a shufflevector operation. if (ExtractElementInst *EI = dyn_cast<ExtractElementInst>(ScalarOp)) { if (isa<ConstantInt>(EI->getOperand(1)) && isa<ConstantInt>(IdxOp)) { unsigned NumInsertVectorElts = IE.getType()->getNumElements(); unsigned NumExtractVectorElts = EI->getOperand(0)->getType()->getVectorNumElements(); unsigned ExtractedIdx = cast<ConstantInt>(EI->getOperand(1))->getZExtValue(); unsigned InsertedIdx = cast<ConstantInt>(IdxOp)->getZExtValue(); if (ExtractedIdx >= NumExtractVectorElts) // Out of range extract. return false; if (InsertedIdx >= NumInsertVectorElts) // Out of range insert. return false; // If this insertelement isn't used by some other insertelement, turn it // (and any insertelements it points to), into one big shuffle. if (!IE.hasOneUse() || !isa<InsertElementInst>(IE.user_back())) { typedef SmallVector<Constant *, 16> MaskT; MaskT Mask; Value *LHS, *RHS; std::tie(LHS, RHS) = CollectShuffleElements(&IE, Mask, nullptr); if (!RHS) RHS = UndefValue::get(LHS->getType()); // We now have a shuffle of LHS, RHS, Mask. if (isa<UndefValue>(LHS) && !isa<UndefValue>(RHS)) { // Canonicalize shufflevector to always have undef on the RHS, // and adjust the mask. std::swap(LHS, RHS); for (MaskT::iterator I = Mask.begin(), E = Mask.end(); I != E; ++I) { unsigned Idx = cast<ConstantInt>(*I)->getZExtValue(); unsigned NewIdx = Idx >= NumInsertVectorElts ? Idx - NumInsertVectorElts : Idx + NumInsertVectorElts; *I = ConstantInt::get(Type::getInt32Ty(RHS->getContext()), NewIdx); } } IRBuilder<> IRB(&IE); IE.replaceAllUsesWith( IRB.CreateShuffleVector(LHS, RHS, ConstantVector::get(Mask))); // The chain of now-dead insertelement / extractelement // instructions can be deleted. Kill.push_back(&IE); return true; } } } return false; }