// 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;
}