[llvm] [LICM] Allow hoisting of InsertElementInst's past non-hoistable InsertElementInsts (PR #200532)

Ryan Buchner via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 8 08:27:10 PDT 2026


================
@@ -1058,6 +1074,82 @@ bool llvm::hoistRegion(DomTreeNode *N, AAResults *AA, LoopInfo *LI,
   return Changed;
 }
 
+static InsertElementInst *canBypassInsert(InsertElementInst *CurrIns,
+                                          Loop *CurLoop,
+                                          SmallSet<uint64_t, 4> &SeenIndices) {
+  // Must have constant insertion lane
+  auto *InsertedIdxCI = dyn_cast<ConstantInt>(CurrIns->getOperand(2));
+  if (!InsertedIdxCI)
+    return nullptr;
+  auto *VecTy = cast<VectorType>(CurrIns->getType());
+
+  // Avoid hoisting past out of bounds inserts
+  if (InsertedIdxCI->isNegative() ||
+      InsertedIdxCI->getValue().uge(
+          VecTy->getElementCount().getKnownMinValue()))
+    return nullptr;
+
+  // Make sure not hoisting past insertions into the same lane
+  if (!SeenIndices.insert(InsertedIdxCI->getValue().getLimitedValue()).second)
+    return nullptr;
+
+  Value *InnerVal = CurrIns->getOperand(0);
+  // If the value we are inserting into is not invariant/poison, recurse
+  // if it is another insert
+  if (!CurLoop->isLoopInvariant(InnerVal) && !isa<PoisonValue>(InnerVal)) {
+    // Only hoist past other insertions
+    // All instructions in the chain must be in the same basic block
+    auto *InnerIns = dyn_cast<InsertElementInst>(InnerVal);
+    if (!InnerIns || InnerIns->getParent() != CurrIns->getParent())
+      return nullptr;
+
+    // Instruction being hoisted past must only have one use
+    if (!InnerIns->hasOneUse())
+      return nullptr;
+
+    return canBypassInsert(InnerIns, CurLoop, SeenIndices);
+  }
+  return CurrIns;
+}
+
+static bool hoistInsertPastInsert(
+    InsertElementInst *Ins, Loop *CurLoop, AAResults *AA, DominatorTree *DT,
+    const TargetLibraryInfo *TLI, BasicBlock *Preheader, BasicBlock *HoistDest,
+    ICFLoopSafetyInfo *SafetyInfo, MemorySSAUpdater &MSSAU, AssumptionCache *AC,
+    ScalarEvolution *SE, SinkAndHoistLICMFlags &Flags,
+    OptimizationRemarkEmitter *ORE,
+    SmallVectorImpl<Instruction *> &HoistedInstructions,
+    bool AllowSpeculation) {
+  // Canonicalize:
+  //   %inner = insertelement %base, %variant, C1
+  //   %outer = insertelement %inner, %invariant, C2
+  // into:
+  //   %inner' = insertelement %base, %invariant, C2
+  //   %outer' = insertelement %inner', %variant, C1
+  // so we can push the variant insertelement through the shuffle.
+
+  // The instruction we are hoisting must have invariant insertion data
+  Value *InsertedElt = Ins->getOperand(1);
+  if (!CurLoop->isLoopInvariant(InsertedElt))
+    return false;
+
+  SmallSet<uint64_t, 4> SeenIndices;
----------------
bababuck wrote:

I don't think I actually need a set here, I don't think there is any harm in hoisting `%3` in the following case:
```
%1 = insertelement <4 x i32> poison, i32 %x, i32 2
%2 = insertelement <4 x i32> poison, i32 %y, i32 2
%3 = insertelement <4 x i32> poison, i32 %invariant, i32 3
```

https://github.com/llvm/llvm-project/pull/200532


More information about the llvm-commits mailing list