[llvm-branch-commits] [llvm] 5d5589f - Revert "[LICM] Allow hoisting of InsertElementInst's past non-hoistable Inser…"

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Fri Jun 12 12:17:45 PDT 2026


Author: Ryan Buchner
Date: 2026-06-12T12:17:41-07:00
New Revision: 5d5589f73533660f6e2054e787fb45fa9e13186e

URL: https://github.com/llvm/llvm-project/commit/5d5589f73533660f6e2054e787fb45fa9e13186e
DIFF: https://github.com/llvm/llvm-project/commit/5d5589f73533660f6e2054e787fb45fa9e13186e.diff

LOG: Revert "[LICM] Allow hoisting of InsertElementInst's past non-hoistable Inser…"

This reverts commit 06bc3b75f3697e848662201ac9e7769ccc2467ed.

Added: 
    

Modified: 
    llvm/lib/Transforms/Scalar/LICM.cpp

Removed: 
    llvm/test/Transforms/LICM/vector-insert.ll


################################################################################
diff  --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp
index 53b9a04e5c5bb..c7e29b70662d8 100644
--- a/llvm/lib/Transforms/Scalar/LICM.cpp
+++ b/llvm/lib/Transforms/Scalar/LICM.cpp
@@ -204,12 +204,6 @@ static bool hoistArithmetics(Instruction &I, Loop &L,
                              ICFLoopSafetyInfo &SafetyInfo,
                              MemorySSAUpdater &MSSAU, AssumptionCache *AC,
                              DominatorTree *DT);
-static bool
-hoistInsertPastInsert(InsertElementInst *Ins, Loop *CurLoop, DominatorTree *DT,
-                      BasicBlock *HoistDest, ICFLoopSafetyInfo *SafetyInfo,
-                      MemorySSAUpdater &MSSAU, ScalarEvolution *SE,
-                      OptimizationRemarkEmitter *ORE,
-                      SmallVectorImpl<Instruction *> &HoistedInstructions);
 static Instruction *cloneInstructionInExitBlock(
     Instruction &I, BasicBlock &ExitBlock, PHINode &PN, const LoopInfo *LI,
     const LoopSafetyInfo *SafetyInfo, MemorySSAUpdater &MSSAU);
@@ -942,14 +936,6 @@ bool llvm::hoistRegion(DomTreeNode *N, AAResults *AA, LoopInfo *LI,
         continue;
       }
 
-      if (auto *Ins = dyn_cast<InsertElementInst>(&I))
-        if (hoistInsertPastInsert(Ins, CurLoop, DT,
-                                  CFH.getOrCreateHoistedBlock(BB), SafetyInfo,
-                                  MSSAU, SE, ORE, HoistedInstructions)) {
-          Changed = true;
-          continue;
-        }
-
       // Attempt to remove floating point division out of the loop by
       // converting it to a reciprocal multiplication.
       if (I.getOpcode() == Instruction::FDiv && I.hasAllowReciprocal() &&
@@ -1072,79 +1058,6 @@ bool llvm::hoistRegion(DomTreeNode *N, AAResults *AA, LoopInfo *LI,
   return Changed;
 }
 
-static std::optional<uint64_t>
-getConstantInsertionIndex(InsertElementInst *Ins) {
-  // Must have constant insertion lane.
-  auto *InsertedIdxCI = dyn_cast<ConstantInt>(Ins->getOperand(2));
-  if (!InsertedIdxCI)
-    return std::nullopt;
-  auto *VecTy = cast<VectorType>(Ins->getType());
-
-  // Avoid hoisting past out of bounds inserts.
-  if (InsertedIdxCI->isNegative() ||
-      InsertedIdxCI->getValue().uge(
-          VecTy->getElementCount().getKnownMinValue()))
-    return std::nullopt;
-  return InsertedIdxCI->getValue().getLimitedValue();
-}
-
-static bool
-hoistInsertPastInsert(InsertElementInst *Ins, Loop *CurLoop, DominatorTree *DT,
-                      BasicBlock *HoistDest, ICFLoopSafetyInfo *SafetyInfo,
-                      MemorySSAUpdater &MSSAU, ScalarEvolution *SE,
-                      OptimizationRemarkEmitter *ORE,
-                      SmallVectorImpl<Instruction *> &HoistedInstructions) {
-  // Canonicalize:
-  //   %inner = insertelement %base, %variant, C1
-  //   %outer = insertelement %inner, %invariant, C2
-  // into:
-  //   %outer = insertelement %base, %invariant, C2
-  //   %inner = insertelement %outer, %variant, C1
-  // so we can hoist %outer
-
-  // The instruction we are hoisting must have invariant insertion data
-  Value *InsertedElt = Ins->getOperand(1);
-  if (!CurLoop->isLoopInvariant(InsertedElt))
-    return false;
-
-  std::optional<uint64_t> HoistIdx = getConstantInsertionIndex(Ins);
-  if (!HoistIdx)
-    return false;
-
-  InsertElementInst *Inner = Ins;
-  while (!CurLoop->isLoopInvariant(Inner->getOperand(0))) {
-    // If the inner value isn't invariant, check to see if it is another insert
-    // All instructions in the chain must be in the same basic block
-    auto *InnerIns = dyn_cast<InsertElementInst>(Inner->getOperand(0));
-    if (!InnerIns || InnerIns->getParent() != Ins->getParent())
-      return false;
-
-    // Make sure not hoisting past insertions into the same lane
-    std::optional<uint64_t> InsertIdx = getConstantInsertionIndex(InnerIns);
-    if (!InsertIdx || *InsertIdx == *HoistIdx)
-      return false;
-
-    // Instruction being hoisted past must only have one use
-    if (!InnerIns->hasOneUse())
-      return false;
-
-    Inner = InnerIns;
-  }
-
-  // Base case of `insertelement <4 x i8> %invar0, i8 %invar1, i32 2` handled in
-  // base LICM logic
-  if (Inner == Ins)
-    return false;
-
-  Ins->replaceAllUsesWith(Ins->getOperand(0));
-  Ins->moveBefore(Inner->getIterator());
-  Ins->setOperand(0, Inner->getOperand(0));
-  Inner->setOperand(0, Ins);
-  hoist(*Ins, DT, CurLoop, HoistDest, SafetyInfo, MSSAU, SE, ORE);
-  HoistedInstructions.push_back(Ins);
-  return true;
-}
-
 // Return true if LI is invariant within scope of the loop. LI is invariant if
 // CurLoop is dominated by an invariant.start representing the same memory
 // location and size as the memory location LI loads from, and also the

diff  --git a/llvm/test/Transforms/LICM/vector-insert.ll b/llvm/test/Transforms/LICM/vector-insert.ll
deleted file mode 100644
index a7762a0bb9a81..0000000000000
--- a/llvm/test/Transforms/LICM/vector-insert.ll
+++ /dev/null
@@ -1,572 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
-; RUN: opt -passes=licm -S < %s | FileCheck %s
-
-define <16 x i1> @iss195497(ptr %1, <16 x ptr> %2, ptr %store, ptr %scevgep90, <2 x ptr> %17, <4 x ptr> %18, <8 x ptr> %19, <2 x ptr> %25, <4 x ptr> %26, <8 x ptr> %27) {
-; CHECK-LABEL: define <16 x i1> @iss195497(
-; CHECK-SAME: ptr [[TMP0:%.*]], <16 x ptr> [[TMP1:%.*]], ptr [[STORE:%.*]], ptr [[SCEVGEP90:%.*]], <2 x ptr> [[TMP2:%.*]], <4 x ptr> [[TMP3:%.*]], <8 x ptr> [[TMP4:%.*]], <2 x ptr> [[TMP5:%.*]], <4 x ptr> [[TMP6:%.*]], <8 x ptr> [[TMP7:%.*]]) {
-; CHECK-NEXT:  [[ENTRY:.*]]:
-; CHECK-NEXT:    [[TMP8:%.*]] = shufflevector <8 x ptr> [[TMP7]], <8 x ptr> poison, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
-; CHECK-NEXT:    [[TMP9:%.*]] = shufflevector <4 x ptr> [[TMP6]], <4 x ptr> poison, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
-; CHECK-NEXT:    [[TMP10:%.*]] = shufflevector <2 x ptr> [[TMP5]], <2 x ptr> poison, <16 x i32> <i32 0, i32 1, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
-; CHECK-NEXT:    [[TMP11:%.*]] = shufflevector <2 x ptr> [[TMP2]], <2 x ptr> poison, <16 x i32> <i32 poison, i32 poison, i32 0, i32 1, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
-; CHECK-NEXT:    [[TMP12:%.*]] = shufflevector <8 x ptr> [[TMP4]], <8 x ptr> poison, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
-; CHECK-NEXT:    [[TMP13:%.*]] = shufflevector <4 x ptr> [[TMP3]], <4 x ptr> poison, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
-; CHECK-NEXT:    [[TMP14:%.*]] = insertelement <16 x ptr> poison, ptr [[SCEVGEP90]], i64 1
-; CHECK-NEXT:    br label %[[LOOP:.*]]
-; CHECK:       [[LOOP]]:
-; CHECK-NEXT:    [[CNT:%.*]] = phi i64 [ [[CNT_NEW:%.*]], %[[LOOP]] ], [ 0, %[[ENTRY]] ]
-; CHECK-NEXT:    [[SCEVGEP89:%.*]] = getelementptr i8, ptr [[TMP0]], i64 [[CNT]]
-; CHECK-NEXT:    [[TMP15:%.*]] = insertelement <16 x ptr> [[TMP14]], ptr [[SCEVGEP89]], i64 0
-; CHECK-NEXT:    [[TMP16:%.*]] = shufflevector <16 x ptr> [[TMP15]], <16 x ptr> [[TMP8]], <16 x i32> <i32 0, i32 1, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 16, i32 17, i32 18, i32 19, i32 20, i32 21, i32 22, i32 23>
-; CHECK-NEXT:    [[TMP17:%.*]] = shufflevector <16 x ptr> [[TMP16]], <16 x ptr> [[TMP9]], <16 x i32> <i32 0, i32 1, i32 poison, i32 poison, i32 16, i32 17, i32 18, i32 19, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
-; CHECK-NEXT:    [[TMP18:%.*]] = shufflevector <16 x ptr> [[TMP17]], <16 x ptr> [[TMP10]], <16 x i32> <i32 0, i32 1, i32 16, i32 17, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
-; CHECK-NEXT:    [[TMP19:%.*]] = icmp ult <16 x ptr> [[TMP1]], [[TMP18]]
-; CHECK-NEXT:    [[STORE_GEP:%.*]] = getelementptr <16 x i1>, ptr [[STORE]], i64 [[CNT]]
-; CHECK-NEXT:    store volatile <16 x i1> [[TMP19]], ptr [[STORE_GEP]], align 2
-; CHECK-NEXT:    [[DONE:%.*]] = icmp eq i64 [[CNT]], 100
-; CHECK-NEXT:    [[CNT_NEW]] = add i64 [[CNT]], 1
-; CHECK-NEXT:    br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
-; CHECK:       [[EXIT]]:
-; CHECK-NEXT:    [[DOTLCSSA:%.*]] = phi <16 x i1> [ [[TMP19]], %[[LOOP]] ]
-; CHECK-NEXT:    ret <16 x i1> [[DOTLCSSA]]
-;
-entry:
-  %30 = shufflevector <8 x ptr> %27, <8 x ptr> poison, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
-  %31 = shufflevector <4 x ptr> %26, <4 x ptr> poison, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
-  %32 = shufflevector <2 x ptr> %25, <2 x ptr> poison, <16 x i32> <i32 0, i32 1, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
-  %33 = shufflevector <2 x ptr> %17, <2 x ptr> poison, <16 x i32> <i32 poison, i32 poison, i32 0, i32 1, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
-  %34 = shufflevector <8 x ptr> %19, <8 x ptr> poison, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
-  %35 = shufflevector <4 x ptr> %18, <4 x ptr> poison, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison>
-  br label %loop
-
-loop:
-  %cnt = phi i64 [ %cnt_new, %loop ], [ 0, %entry ]
-  %scevgep89 = getelementptr i8, ptr %1, i64 %cnt
-  %92 = insertelement <16 x ptr> poison, ptr %scevgep89, i64 0
-  %93 = insertelement <16 x ptr> %92, ptr %scevgep90, i64 1
-  %94 = shufflevector <16 x ptr> %93, <16 x ptr> %30, <16 x i32> <i32 0, i32 1, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 poison, i32 16, i32 17, i32 18, i32 19, i32 20, i32 21, i32 22, i32 23>
-  %95 = shufflevector <16 x ptr> %94, <16 x ptr> %31, <16 x i32> <i32 0, i32 1, i32 poison, i32 poison, i32 16, i32 17, i32 18, i32 19, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
-  %96 = shufflevector <16 x ptr> %95, <16 x ptr> %32, <16 x i32> <i32 0, i32 1, i32 16, i32 17, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
-  %97 = icmp ult <16 x ptr> %2, %96
-  %store.gep = getelementptr <16 x i1>, ptr %store, i64 %cnt
-  store volatile <16 x i1> %97, ptr %store.gep
-  %done = icmp eq i64 %cnt, 100
-  %cnt_new = add i64 %cnt, 1
-  br i1 %done, label %exit, label %loop
-exit:
-  ret <16 x i1> %97
-}
-
-; Basic positive case: simple 4xi32, invariant inserted at lane 1 over variant at lane 0.
-; The inner insertelement (lane 0, variant) should be hoisted.
-define <4 x i32> @hoist_simple_swap(ptr %base, i32 %inv, i32 %n) {
-; CHECK-LABEL: define <4 x i32> @hoist_simple_swap(
-; CHECK-SAME: ptr [[BASE:%.*]], i32 [[INV:%.*]], i32 [[N:%.*]]) {
-; CHECK-NEXT:  [[ENTRY:.*]]:
-; CHECK-NEXT:    [[INNER:%.*]] = insertelement <4 x i32> poison, i32 [[INV]], i32 1
-; CHECK-NEXT:    br label %[[LOOP:.*]]
-; CHECK:       [[LOOP]]:
-; CHECK-NEXT:    [[IV_LCSSA:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
-; CHECK-NEXT:    [[IDX_LE:%.*]] = getelementptr inbounds i32, ptr [[BASE]], i32 [[IV_LCSSA]]
-; CHECK-NEXT:    [[VARIANT_LE:%.*]] = load i32, ptr [[IDX_LE]], align 4
-; CHECK-NEXT:    [[OUTER_LE:%.*]] = insertelement <4 x i32> [[INNER]], i32 [[VARIANT_LE]], i32 0
-; CHECK-NEXT:    store <4 x i32> [[OUTER_LE]], ptr [[IDX_LE]], align 16
-; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV_LCSSA]], 1
-; CHECK-NEXT:    [[DONE:%.*]] = icmp eq i32 [[IV_LCSSA]], [[N]]
-; CHECK-NEXT:    br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
-; CHECK:       [[EXIT]]:
-; CHECK-NEXT:    [[OUTER_LCSSA:%.*]] = phi <4 x i32> [ [[OUTER_LE]], %[[LOOP]] ]
-; CHECK-NEXT:    ret <4 x i32> [[OUTER_LCSSA]]
-;
-entry:
-  br label %loop
-loop:
-  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
-  %idx = getelementptr inbounds i32, ptr %base, i32 %iv
-  %variant = load i32, ptr %idx, align 4
-  %inner = insertelement <4 x i32> poison, i32 %variant, i32 0
-  %outer = insertelement <4 x i32> %inner, i32 %inv, i32 1
-  store <4 x i32> %outer, ptr %idx
-  %iv.next = add i32 %iv, 1
-  %done = icmp eq i32 %iv, %n
-  br i1 %done, label %exit, label %loop
-exit:
-  ret <4 x i32> %outer
-}
-
-; Positive: wide constant index type should not crash and should still hoist/swap.
-define <4 x i32> @hoist_simple_swap_wide_index_ty(ptr %base, i32 %inv, i32 %n) {
-; CHECK-LABEL: define <4 x i32> @hoist_simple_swap_wide_index_ty(
-; CHECK-SAME: ptr [[BASE:%.*]], i32 [[INV:%.*]], i32 [[N:%.*]]) {
-; CHECK-NEXT:  [[ENTRY:.*]]:
-; CHECK-NEXT:    [[INNER:%.*]] = insertelement <4 x i32> poison, i32 [[INV]], i128 1
-; CHECK-NEXT:    br label %[[LOOP:.*]]
-; CHECK:       [[LOOP]]:
-; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
-; CHECK-NEXT:    [[IDX:%.*]] = getelementptr inbounds i32, ptr [[BASE]], i32 [[IV]]
-; CHECK-NEXT:    [[VARIANT:%.*]] = load i32, ptr [[IDX]], align 4
-; CHECK-NEXT:    [[OUTER:%.*]] = insertelement <4 x i32> [[INNER]], i32 [[VARIANT]], i128 0
-; CHECK-NEXT:    store <4 x i32> [[OUTER]], ptr [[IDX]], align 16
-; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
-; CHECK-NEXT:    [[DONE:%.*]] = icmp eq i32 [[IV]], [[N]]
-; CHECK-NEXT:    br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
-; CHECK:       [[EXIT]]:
-; CHECK-NEXT:    [[OUTER_LCSSA:%.*]] = phi <4 x i32> [ [[OUTER]], %[[LOOP]] ]
-; CHECK-NEXT:    ret <4 x i32> [[OUTER_LCSSA]]
-;
-entry:
-  br label %loop
-loop:
-  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
-  %idx = getelementptr inbounds i32, ptr %base, i32 %iv
-  %variant = load i32, ptr %idx, align 4
-  %inner = insertelement <4 x i32> poison, i32 %variant, i128 0
-  %outer = insertelement <4 x i32> %inner, i32 %inv, i128 1
-  store <4 x i32> %outer, ptr %idx
-  %iv.next = add i32 %iv, 1
-  %done = icmp eq i32 %iv, %n
-  br i1 %done, label %exit, label %loop
-exit:
-  ret <4 x i32> %outer
-}
-
-; Positive: The initial vector is invariant
-define <4 x i32> @hoist_simple_swap_basevec(ptr %base, i32 %inv, i32 %n, <4 x i32> %basevec) {
-; CHECK-LABEL: define <4 x i32> @hoist_simple_swap_basevec(
-; CHECK-SAME: ptr [[BASE:%.*]], i32 [[INV:%.*]], i32 [[N:%.*]], <4 x i32> [[BASEVEC:%.*]]) {
-; CHECK-NEXT:  [[ENTRY:.*]]:
-; CHECK-NEXT:    [[INNER:%.*]] = insertelement <4 x i32> [[BASEVEC]], i32 [[INV]], i32 1
-; CHECK-NEXT:    br label %[[LOOP:.*]]
-; CHECK:       [[LOOP]]:
-; CHECK-NEXT:    [[IV_LCSSA:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
-; CHECK-NEXT:    [[IDX_LE:%.*]] = getelementptr inbounds i32, ptr [[BASE]], i32 [[IV_LCSSA]]
-; CHECK-NEXT:    [[VARIANT_LE:%.*]] = load i32, ptr [[IDX_LE]], align 4
-; CHECK-NEXT:    [[OUTER_LE:%.*]] = insertelement <4 x i32> [[INNER]], i32 [[VARIANT_LE]], i32 0
-; CHECK-NEXT:    store <4 x i32> [[OUTER_LE]], ptr [[IDX_LE]], align 16
-; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV_LCSSA]], 1
-; CHECK-NEXT:    [[DONE:%.*]] = icmp eq i32 [[IV_LCSSA]], [[N]]
-; CHECK-NEXT:    br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
-; CHECK:       [[EXIT]]:
-; CHECK-NEXT:    [[OUTER_LCSSA:%.*]] = phi <4 x i32> [ [[OUTER_LE]], %[[LOOP]] ]
-; CHECK-NEXT:    ret <4 x i32> [[OUTER_LCSSA]]
-;
-entry:
-  br label %loop
-loop:
-  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
-  %idx = getelementptr inbounds i32, ptr %base, i32 %iv
-  %variant = load i32, ptr %idx, align 4
-  %inner = insertelement <4 x i32> %basevec, i32 %variant, i32 0
-  %outer = insertelement <4 x i32> %inner, i32 %inv, i32 1
-  store <4 x i32> %outer, ptr %idx
-  %iv.next = add i32 %iv, 1
-  %done = icmp eq i32 %iv, %n
-  br i1 %done, label %exit, label %loop
-exit:
-  ret <4 x i32> %outer
-}
-
-; Positive: Have to jump through multiple insert vectors
-define <4 x i32> @hoist_multiple_variants(ptr %base, i32 %inv, i32 %n) {
-; CHECK-LABEL: define <4 x i32> @hoist_multiple_variants(
-; CHECK-SAME: ptr [[BASE:%.*]], i32 [[INV:%.*]], i32 [[N:%.*]]) {
-; CHECK-NEXT:  [[ENTRY:.*]]:
-; CHECK-NEXT:    [[INNER_LE:%.*]] = insertelement <4 x i32> poison, i32 [[INV]], i32 2
-; CHECK-NEXT:    br label %[[LOOP:.*]]
-; CHECK:       [[LOOP]]:
-; CHECK-NEXT:    [[IV_LCSSA:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
-; CHECK-NEXT:    [[IDX_LE:%.*]] = getelementptr inbounds i32, ptr [[BASE]], i32 [[IV_LCSSA]]
-; CHECK-NEXT:    [[VARIANT_LE:%.*]] = load i32, ptr [[IDX_LE]], align 4
-; CHECK-NEXT:    [[INNER:%.*]] = insertelement <4 x i32> [[INNER_LE]], i32 [[VARIANT_LE]], i32 0
-; CHECK-NEXT:    [[OUTER_LE:%.*]] = insertelement <4 x i32> [[INNER]], i32 [[VARIANT_LE]], i32 1
-; CHECK-NEXT:    store <4 x i32> [[OUTER_LE]], ptr [[IDX_LE]], align 16
-; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV_LCSSA]], 1
-; CHECK-NEXT:    [[DONE:%.*]] = icmp eq i32 [[IV_LCSSA]], [[N]]
-; CHECK-NEXT:    br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
-; CHECK:       [[EXIT]]:
-; CHECK-NEXT:    [[OUTER_LCSSA:%.*]] = phi <4 x i32> [ [[OUTER_LE]], %[[LOOP]] ]
-; CHECK-NEXT:    ret <4 x i32> [[OUTER_LCSSA]]
-;
-entry:
-  br label %loop
-loop:
-  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
-  %idx = getelementptr inbounds i32, ptr %base, i32 %iv
-  %variant = load i32, ptr %idx, align 4
-  %inner = insertelement <4 x i32> poison, i32 %variant, i32 0
-  %inner2 = insertelement <4 x i32> %inner, i32 %variant, i32 1
-  %outer = insertelement <4 x i32> %inner2, i32 %inv, i32 2
-  store <4 x i32> %outer, ptr %idx
-  %iv.next = add i32 %iv, 1
-  %done = icmp eq i32 %iv, %n
-  br i1 %done, label %exit, label %loop
-exit:
-  ret <4 x i32> %outer
-}
-
-; Positive: Multiple invariant inserts
-define <4 x i32> @hoist_multiple_invariants(ptr %base, i32 %inv, i32 %n) {
-; CHECK-LABEL: define <4 x i32> @hoist_multiple_invariants(
-; CHECK-SAME: ptr [[BASE:%.*]], i32 [[INV:%.*]], i32 [[N:%.*]]) {
-; CHECK-NEXT:  [[ENTRY:.*]]:
-; CHECK-NEXT:    [[INNER:%.*]] = insertelement <4 x i32> poison, i32 [[INV]], i32 1
-; CHECK-NEXT:    [[OUTER:%.*]] = insertelement <4 x i32> [[INNER]], i32 [[INV]], i32 2
-; CHECK-NEXT:    br label %[[LOOP:.*]]
-; CHECK:       [[LOOP]]:
-; CHECK-NEXT:    [[IV_LCSSA:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
-; CHECK-NEXT:    [[IDX_LE:%.*]] = getelementptr inbounds i32, ptr [[BASE]], i32 [[IV_LCSSA]]
-; CHECK-NEXT:    [[VARIANT_LE:%.*]] = load i32, ptr [[IDX_LE]], align 4
-; CHECK-NEXT:    [[OUTER2_LE:%.*]] = insertelement <4 x i32> [[OUTER]], i32 [[VARIANT_LE]], i32 0
-; CHECK-NEXT:    store <4 x i32> [[OUTER2_LE]], ptr [[IDX_LE]], align 16
-; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV_LCSSA]], 1
-; CHECK-NEXT:    [[DONE:%.*]] = icmp eq i32 [[IV_LCSSA]], [[N]]
-; CHECK-NEXT:    br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
-; CHECK:       [[EXIT]]:
-; CHECK-NEXT:    [[OUTER2_LCSSA:%.*]] = phi <4 x i32> [ [[OUTER2_LE]], %[[LOOP]] ]
-; CHECK-NEXT:    ret <4 x i32> [[OUTER2_LCSSA]]
-;
-entry:
-  br label %loop
-loop:
-  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
-  %idx = getelementptr inbounds i32, ptr %base, i32 %iv
-  %variant = load i32, ptr %idx, align 4
-  %inner = insertelement <4 x i32> poison, i32 %variant, i32 0
-  %outer = insertelement <4 x i32> %inner, i32 %inv, i32 1
-  %outer2 = insertelement <4 x i32> %outer, i32 %inv, i32 2
-  store <4 x i32> %outer2, ptr %idx
-  %iv.next = add i32 %iv, 1
-  %done = icmp eq i32 %iv, %n
-  br i1 %done, label %exit, label %loop
-exit:
-  ret <4 x i32> %outer2
-}
-
-define <4 x i32> @no_hoist_variant_basevec(ptr %base, i32 %inv, i32 %n) {
-; CHECK-LABEL: define <4 x i32> @no_hoist_variant_basevec(
-; CHECK-SAME: ptr [[BASE:%.*]], i32 [[INV:%.*]], i32 [[N:%.*]]) {
-; CHECK-NEXT:  [[ENTRY:.*]]:
-; CHECK-NEXT:    br label %[[LOOP:.*]]
-; CHECK:       [[LOOP]]:
-; CHECK-NEXT:    [[IV_LCSSA:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
-; CHECK-NEXT:    [[IDX_LE:%.*]] = getelementptr inbounds i32, ptr [[BASE]], i32 [[IV_LCSSA]]
-; CHECK-NEXT:    [[VARIANT_LE:%.*]] = load i32, ptr [[IDX_LE]], align 4
-; CHECK-NEXT:    [[BASEVEC_LE:%.*]] = load <4 x i32>, ptr [[IDX_LE]], align 4
-; CHECK-NEXT:    [[INNER_LE:%.*]] = insertelement <4 x i32> [[BASEVEC_LE]], i32 [[VARIANT_LE]], i32 0
-; CHECK-NEXT:    [[OUTER_LE:%.*]] = insertelement <4 x i32> [[INNER_LE]], i32 [[INV]], i32 1
-; CHECK-NEXT:    store <4 x i32> [[OUTER_LE]], ptr [[IDX_LE]], align 16
-; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV_LCSSA]], 1
-; CHECK-NEXT:    [[DONE:%.*]] = icmp eq i32 [[IV_LCSSA]], [[N]]
-; CHECK-NEXT:    br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
-; CHECK:       [[EXIT]]:
-; CHECK-NEXT:    [[OUTER_LCSSA:%.*]] = phi <4 x i32> [ [[OUTER_LE]], %[[LOOP]] ]
-; CHECK-NEXT:    ret <4 x i32> [[OUTER_LCSSA]]
-;
-entry:
-  br label %loop
-loop:
-  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
-  %idx = getelementptr inbounds i32, ptr %base, i32 %iv
-  %variant = load i32, ptr %idx, align 4
-  %basevec = load <4 x i32>, ptr %idx, align 4
-  %inner = insertelement <4 x i32> %basevec, i32 %variant, i32 0
-  %outer = insertelement <4 x i32> %inner, i32 %inv, i32 1
-  store <4 x i32> %outer, ptr %idx
-  %iv.next = add i32 %iv, 1
-  %done = icmp eq i32 %iv, %n
-  br i1 %done, label %exit, label %loop
-exit:
-  ret <4 x i32> %outer
-}
-
-; Negative: outer index is not a constant — no hoist.
-define <4 x i32> @no_hoist_nonconstant_outer_idx(ptr %base, i32 %inv, i32 %vidx, i32 %n) {
-; CHECK-LABEL: define <4 x i32> @no_hoist_nonconstant_outer_idx(
-; CHECK-SAME: ptr [[BASE:%.*]], i32 [[INV:%.*]], i32 [[VIDX:%.*]], i32 [[N:%.*]]) {
-; CHECK-NEXT:  [[ENTRY:.*]]:
-; CHECK-NEXT:    br label %[[LOOP:.*]]
-; CHECK:       [[LOOP]]:
-; CHECK-NEXT:    [[IV_LCSSA:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
-; CHECK-NEXT:    [[IDX_LE:%.*]] = getelementptr inbounds i32, ptr [[BASE]], i32 [[IV_LCSSA]]
-; CHECK-NEXT:    [[VARIANT_LE:%.*]] = load i32, ptr [[IDX_LE]], align 4
-; CHECK-NEXT:    [[INNER_LE:%.*]] = insertelement <4 x i32> poison, i32 [[VARIANT_LE]], i32 0
-; CHECK-NEXT:    [[OUTER_LE:%.*]] = insertelement <4 x i32> [[INNER_LE]], i32 [[INV]], i32 [[VIDX]]
-; CHECK-NEXT:    store <4 x i32> [[OUTER_LE]], ptr [[IDX_LE]], align 16
-; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV_LCSSA]], 1
-; CHECK-NEXT:    [[DONE:%.*]] = icmp eq i32 [[IV_LCSSA]], [[N]]
-; CHECK-NEXT:    br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
-; CHECK:       [[EXIT]]:
-; CHECK-NEXT:    [[OUTER_LCSSA:%.*]] = phi <4 x i32> [ [[OUTER_LE]], %[[LOOP]] ]
-; CHECK-NEXT:    ret <4 x i32> [[OUTER_LCSSA]]
-;
-entry:
-  br label %loop
-loop:
-  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
-  %idx = getelementptr inbounds i32, ptr %base, i32 %iv
-  %variant = load i32, ptr %idx, align 4
-  %inner = insertelement <4 x i32> poison, i32 %variant, i32 0
-  %outer = insertelement <4 x i32> %inner, i32 %inv, i32 %vidx
-  store <4 x i32> %outer, ptr %idx
-  %iv.next = add i32 %iv, 1
-  %done = icmp eq i32 %iv, %n
-  br i1 %done, label %exit, label %loop
-exit:
-  ret <4 x i32> %outer
-}
-
-; Negative: inner index is not a constant — no hoist.
-define <4 x i32> @no_hoist_nonconstant_inner_idx(ptr %base, i32 %inv, i32 %vidx, i32 %n) {
-; CHECK-LABEL: define <4 x i32> @no_hoist_nonconstant_inner_idx(
-; CHECK-SAME: ptr [[BASE:%.*]], i32 [[INV:%.*]], i32 [[VIDX:%.*]], i32 [[N:%.*]]) {
-; CHECK-NEXT:  [[ENTRY:.*]]:
-; CHECK-NEXT:    br label %[[LOOP:.*]]
-; CHECK:       [[LOOP]]:
-; CHECK-NEXT:    [[IV_LCSSA:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
-; CHECK-NEXT:    [[IDX_LE:%.*]] = getelementptr inbounds i32, ptr [[BASE]], i32 [[IV_LCSSA]]
-; CHECK-NEXT:    [[VARIANT_LE:%.*]] = load i32, ptr [[IDX_LE]], align 4
-; CHECK-NEXT:    [[INNER_LE:%.*]] = insertelement <4 x i32> poison, i32 [[VARIANT_LE]], i32 [[VIDX]]
-; CHECK-NEXT:    [[OUTER_LE:%.*]] = insertelement <4 x i32> [[INNER_LE]], i32 [[INV]], i32 1
-; CHECK-NEXT:    store <4 x i32> [[OUTER_LE]], ptr [[IDX_LE]], align 16
-; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV_LCSSA]], 1
-; CHECK-NEXT:    [[DONE:%.*]] = icmp eq i32 [[IV_LCSSA]], [[N]]
-; CHECK-NEXT:    br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
-; CHECK:       [[EXIT]]:
-; CHECK-NEXT:    [[OUTER_LCSSA:%.*]] = phi <4 x i32> [ [[OUTER_LE]], %[[LOOP]] ]
-; CHECK-NEXT:    ret <4 x i32> [[OUTER_LCSSA]]
-;
-entry:
-  br label %loop
-loop:
-  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
-  %idx = getelementptr inbounds i32, ptr %base, i32 %iv
-  %variant = load i32, ptr %idx, align 4
-  %inner = insertelement <4 x i32> poison, i32 %variant, i32 %vidx
-  %outer = insertelement <4 x i32> %inner, i32 %inv, i32 1
-  store <4 x i32> %outer, ptr %idx
-  %iv.next = add i32 %iv, 1
-  %done = icmp eq i32 %iv, %n
-  br i1 %done, label %exit, label %loop
-exit:
-  ret <4 x i32> %outer
-}
-
-; Negative: outer element is loop-variant — no hoist.
-define <4 x i32> @no_hoist_variant_outer_elt(ptr %base, ptr %base2, i32 %n) {
-; CHECK-LABEL: define <4 x i32> @no_hoist_variant_outer_elt(
-; CHECK-SAME: ptr [[BASE:%.*]], ptr [[BASE2:%.*]], i32 [[N:%.*]]) {
-; CHECK-NEXT:  [[ENTRY:.*]]:
-; CHECK-NEXT:    br label %[[LOOP:.*]]
-; CHECK:       [[LOOP]]:
-; CHECK-NEXT:    [[IV_LCSSA1:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
-; CHECK-NEXT:    [[IDX_LE:%.*]] = getelementptr inbounds i32, ptr [[BASE]], i32 [[IV_LCSSA1]]
-; CHECK-NEXT:    [[IDX2_LE:%.*]] = getelementptr inbounds i32, ptr [[BASE2]], i32 [[IV_LCSSA1]]
-; CHECK-NEXT:    [[VARIANT_LE:%.*]] = load i32, ptr [[IDX_LE]], align 4
-; CHECK-NEXT:    [[VARIANT2_LE:%.*]] = load i32, ptr [[IDX2_LE]], align 4
-; CHECK-NEXT:    [[INNER_LE:%.*]] = insertelement <4 x i32> poison, i32 [[VARIANT_LE]], i32 0
-; CHECK-NEXT:    [[OUTER_LE:%.*]] = insertelement <4 x i32> [[INNER_LE]], i32 [[VARIANT2_LE]], i32 1
-; CHECK-NEXT:    store <4 x i32> [[OUTER_LE]], ptr [[IDX_LE]], align 16
-; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV_LCSSA1]], 1
-; CHECK-NEXT:    [[DONE:%.*]] = icmp eq i32 [[IV_LCSSA1]], [[N]]
-; CHECK-NEXT:    br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
-; CHECK:       [[EXIT]]:
-; CHECK-NEXT:    [[OUTER_LCSSA:%.*]] = phi <4 x i32> [ [[OUTER_LE]], %[[LOOP]] ]
-; CHECK-NEXT:    ret <4 x i32> [[OUTER_LCSSA]]
-;
-entry:
-  br label %loop
-loop:
-  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
-  %idx = getelementptr inbounds i32, ptr %base, i32 %iv
-  %idx2 = getelementptr inbounds i32, ptr %base2, i32 %iv
-  %variant = load i32, ptr %idx, align 4
-  %variant2 = load i32, ptr %idx2, align 4
-  %inner = insertelement <4 x i32> poison, i32 %variant, i32 0
-  %outer = insertelement <4 x i32> %inner, i32 %variant2, i32 1
-  store <4 x i32> %outer, ptr %idx
-  %iv.next = add i32 %iv, 1
-  %done = icmp eq i32 %iv, %n
-  br i1 %done, label %exit, label %loop
-exit:
-  ret <4 x i32> %outer
-}
-
-; Negative: inner has multiple uses — no hoist.
-define <4 x i32> @no_hoist_inner_multiuse(ptr %base, i32 %inv, ptr %store, i32 %n) {
-; CHECK-LABEL: define <4 x i32> @no_hoist_inner_multiuse(
-; CHECK-SAME: ptr [[BASE:%.*]], i32 [[INV:%.*]], ptr [[STORE:%.*]], i32 [[N:%.*]]) {
-; CHECK-NEXT:  [[ENTRY:.*]]:
-; CHECK-NEXT:    br label %[[LOOP:.*]]
-; CHECK:       [[LOOP]]:
-; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
-; CHECK-NEXT:    [[IDX:%.*]] = getelementptr inbounds i32, ptr [[BASE]], i32 [[IV]]
-; CHECK-NEXT:    [[VARIANT:%.*]] = load i32, ptr [[IDX]], align 4
-; CHECK-NEXT:    [[INNER:%.*]] = insertelement <4 x i32> poison, i32 [[VARIANT]], i32 0
-; CHECK-NEXT:    [[OUTER:%.*]] = insertelement <4 x i32> [[INNER]], i32 [[INV]], i32 1
-; CHECK-NEXT:    store volatile <4 x i32> [[INNER]], ptr [[STORE]], align 16
-; CHECK-NEXT:    store <4 x i32> [[OUTER]], ptr [[IDX]], align 16
-; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
-; CHECK-NEXT:    [[DONE:%.*]] = icmp eq i32 [[IV]], [[N]]
-; CHECK-NEXT:    br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
-; CHECK:       [[EXIT]]:
-; CHECK-NEXT:    [[OUTER_LE:%.*]] = phi <4 x i32> [ [[OUTER]], %[[LOOP]] ]
-; CHECK-NEXT:    ret <4 x i32> [[OUTER_LE]]
-;
-entry:
-  br label %loop
-loop:
-  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
-  %idx = getelementptr inbounds i32, ptr %base, i32 %iv
-  %variant = load i32, ptr %idx, align 4
-  %inner = insertelement <4 x i32> poison, i32 %variant, i32 0
-  %outer = insertelement <4 x i32> %inner, i32 %inv, i32 1
-  store volatile <4 x i32> %inner, ptr %store
-  store <4 x i32> %outer, ptr %idx
-  %iv.next = add i32 %iv, 1
-  %done = icmp eq i32 %iv, %n
-  br i1 %done, label %exit, label %loop
-exit:
-  ret <4 x i32> %outer
-}
-
-; Negative: inner and outer use the same index — no hoist.
-define <4 x i32> @no_hoist_same_index(ptr %base, i32 %inv, i32 %n) {
-; CHECK-LABEL: define <4 x i32> @no_hoist_same_index(
-; CHECK-SAME: ptr [[BASE:%.*]], i32 [[INV:%.*]], i32 [[N:%.*]]) {
-; CHECK-NEXT:  [[ENTRY:.*]]:
-; CHECK-NEXT:    br label %[[LOOP:.*]]
-; CHECK:       [[LOOP]]:
-; CHECK-NEXT:    [[IV_LCSSA:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
-; CHECK-NEXT:    [[IDX_LE:%.*]] = getelementptr inbounds i32, ptr [[BASE]], i32 [[IV_LCSSA]]
-; CHECK-NEXT:    [[VARIANT_LE:%.*]] = load i32, ptr [[IDX_LE]], align 4
-; CHECK-NEXT:    [[INNER_LE:%.*]] = insertelement <4 x i32> poison, i32 [[VARIANT_LE]], i32 0
-; CHECK-NEXT:    [[OUTER_LE:%.*]] = insertelement <4 x i32> [[INNER_LE]], i32 [[INV]], i32 0
-; CHECK-NEXT:    store <4 x i32> [[OUTER_LE]], ptr [[IDX_LE]], align 16
-; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV_LCSSA]], 1
-; CHECK-NEXT:    [[DONE:%.*]] = icmp eq i32 [[IV_LCSSA]], [[N]]
-; CHECK-NEXT:    br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
-; CHECK:       [[EXIT]]:
-; CHECK-NEXT:    [[OUTER_LCSSA:%.*]] = phi <4 x i32> [ [[OUTER_LE]], %[[LOOP]] ]
-; CHECK-NEXT:    ret <4 x i32> [[OUTER_LCSSA]]
-;
-entry:
-  br label %loop
-loop:
-  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
-  %idx = getelementptr inbounds i32, ptr %base, i32 %iv
-  %variant = load i32, ptr %idx, align 4
-  %inner = insertelement <4 x i32> poison, i32 %variant, i32 0
-  %outer = insertelement <4 x i32> %inner, i32 %inv, i32 0
-  store <4 x i32> %outer, ptr %idx
-  %iv.next = add i32 %iv, 1
-  %done = icmp eq i32 %iv, %n
-  br i1 %done, label %exit, label %loop
-exit:
-  ret <4 x i32> %outer
-}
-
-; Negative: outer index is out-of-range constant — no hoist/swap.
-define <4 x i32> @no_hoist_out_of_range_outer_idx(ptr %base, i32 %inv, i32 %n) {
-; CHECK-LABEL: define <4 x i32> @no_hoist_out_of_range_outer_idx(
-; CHECK-SAME: ptr [[BASE:%.*]], i32 [[INV:%.*]], i32 [[N:%.*]]) {
-; CHECK-NEXT:  [[ENTRY:.*]]:
-; CHECK-NEXT:    br label %[[LOOP:.*]]
-; CHECK:       [[LOOP]]:
-; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
-; CHECK-NEXT:    [[IDX:%.*]] = getelementptr inbounds i32, ptr [[BASE]], i32 [[IV]]
-; CHECK-NEXT:    [[VARIANT:%.*]] = load i32, ptr [[IDX]], align 4
-; CHECK-NEXT:    [[INNER:%.*]] = insertelement <4 x i32> poison, i32 [[VARIANT]], i32 0
-; CHECK-NEXT:    [[OUTER:%.*]] = insertelement <4 x i32> [[INNER]], i32 [[INV]], i32 7
-; CHECK-NEXT:    store <4 x i32> [[OUTER]], ptr [[IDX]], align 16
-; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
-; CHECK-NEXT:    [[DONE:%.*]] = icmp eq i32 [[IV]], [[N]]
-; CHECK-NEXT:    br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
-; CHECK:       [[EXIT]]:
-; CHECK-NEXT:    [[OUTER_LCSSA:%.*]] = phi <4 x i32> [ [[OUTER]], %[[LOOP]] ]
-; CHECK-NEXT:    ret <4 x i32> [[OUTER_LCSSA]]
-;
-entry:
-  br label %loop
-loop:
-  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
-  %idx = getelementptr inbounds i32, ptr %base, i32 %iv
-  %variant = load i32, ptr %idx, align 4
-  %inner = insertelement <4 x i32> poison, i32 %variant, i32 0
-  %outer = insertelement <4 x i32> %inner, i32 %inv, i32 7
-  store <4 x i32> %outer, ptr %idx
-  %iv.next = add i32 %iv, 1
-  %done = icmp eq i32 %iv, %n
-  br i1 %done, label %exit, label %loop
-exit:
-  ret <4 x i32> %outer
-}
-
-; Negative: inner element is loop-invariant — nothing to swap, no hoist.
-define <4 x i32> @no_hoist_inner_invariant_elt(ptr %base, i32 %inv1, i32 %inv2, i32 %n) {
-; CHECK-LABEL: define <4 x i32> @no_hoist_inner_invariant_elt(
-; CHECK-SAME: ptr [[BASE:%.*]], i32 [[INV1:%.*]], i32 [[INV2:%.*]], i32 [[N:%.*]]) {
-; CHECK-NEXT:  [[ENTRY:.*]]:
-; CHECK-NEXT:    [[INNER:%.*]] = insertelement <4 x i32> poison, i32 [[INV1]], i32 0
-; CHECK-NEXT:    [[OUTER:%.*]] = insertelement <4 x i32> [[INNER]], i32 [[INV2]], i32 1
-; CHECK-NEXT:    br label %[[LOOP:.*]]
-; CHECK:       [[LOOP]]:
-; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
-; CHECK-NEXT:    [[IDX:%.*]] = getelementptr inbounds i32, ptr [[BASE]], i32 [[IV]]
-; CHECK-NEXT:    store <4 x i32> [[OUTER]], ptr [[IDX]], align 16
-; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
-; CHECK-NEXT:    [[DONE:%.*]] = icmp eq i32 [[IV]], [[N]]
-; CHECK-NEXT:    br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
-; CHECK:       [[EXIT]]:
-; CHECK-NEXT:    [[OUTER_LE:%.*]] = phi <4 x i32> [ [[OUTER]], %[[LOOP]] ]
-; CHECK-NEXT:    ret <4 x i32> [[OUTER_LE]]
-;
-entry:
-  br label %loop
-loop:
-  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
-  %inner = insertelement <4 x i32> poison, i32 %inv1, i32 0
-  %outer = insertelement <4 x i32> %inner, i32 %inv2, i32 1
-  %idx = getelementptr inbounds i32, ptr %base, i32 %iv
-  store <4 x i32> %outer, ptr %idx
-  %iv.next = add i32 %iv, 1
-  %done = icmp eq i32 %iv, %n
-  br i1 %done, label %exit, label %loop
-exit:
-  ret <4 x i32> %outer
-}
-
-; Basic positive case with scalable vectors
-define <vscale x 4 x i32> @hoist_scalable_swap(ptr %base, i32 %inv, i32 %n) {
-; CHECK-LABEL: define <vscale x 4 x i32> @hoist_scalable_swap(
-; CHECK-SAME: ptr [[BASE:%.*]], i32 [[INV:%.*]], i32 [[N:%.*]]) {
-; CHECK-NEXT:  [[ENTRY:.*]]:
-; CHECK-NEXT:    [[OUTER:%.*]] = insertelement <vscale x 4 x i32> poison, i32 [[INV]], i32 1
-; CHECK-NEXT:    br label %[[LOOP:.*]]
-; CHECK:       [[LOOP]]:
-; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
-; CHECK-NEXT:    [[IDX:%.*]] = getelementptr inbounds i32, ptr [[BASE]], i32 [[IV]]
-; CHECK-NEXT:    [[VARIANT:%.*]] = load i32, ptr [[IDX]], align 4
-; CHECK-NEXT:    [[INNER:%.*]] = insertelement <vscale x 4 x i32> [[OUTER]], i32 [[VARIANT]], i32 0
-; CHECK-NEXT:    store <vscale x 4 x i32> [[INNER]], ptr [[IDX]], align 16
-; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 1
-; CHECK-NEXT:    [[DONE:%.*]] = icmp eq i32 [[IV]], [[N]]
-; CHECK-NEXT:    br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
-; CHECK:       [[EXIT]]:
-; CHECK-NEXT:    [[OUTER_LCSSA:%.*]] = phi <vscale x 4 x i32> [ [[INNER]], %[[LOOP]] ]
-; CHECK-NEXT:    ret <vscale x 4 x i32> [[OUTER_LCSSA]]
-;
-entry:
-  br label %loop
-loop:
-  %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
-  %idx = getelementptr inbounds i32, ptr %base, i32 %iv
-  %variant = load i32, ptr %idx, align 4
-  %inner = insertelement <vscale x 4 x i32> poison, i32 %variant, i32 0
-  %outer = insertelement <vscale x 4 x i32> %inner, i32 %inv, i32 1
-  store <vscale x 4 x i32> %outer, ptr %idx
-  %iv.next = add i32 %iv, 1
-  %done = icmp eq i32 %iv, %n
-  br i1 %done, label %exit, label %loop
-exit:
-  ret <vscale x 4 x i32> %outer
-}


        


More information about the llvm-branch-commits mailing list