Bug type: crash
Component: LoopVectorize
Bug location: llvm/lib/Transforms/Vectorize/LoopVectorize.cpp: LoopVectorizationCostModel::collectLoopUniforms
VPReplicateRecipe::execute
Issue title: [VPlan] Report "Assertion `!State->VF.isScalable() && "VF is assumed to be non scalable."' failed"
Labels: vectorizers
crash
Reported by: eastB233

The IR is put at the end.

Compile command is `opt -passes=loop-vectorize -prefer-predicate-over-epilogue=predicate-else-scalar-epilogue`

The error is
```
opt: /root/llvm-project/llvm/lib/Transforms/Vectorize/VPlan.cpp:734: virtual void llvm::VPRegionBlock::execute(llvm::VPTransformState*): Assertion `!State->VF.isScalable() && "VF is assumed to be non scalable."' failed.
```

It can be seen at  https://godbolt.org/z/s4bqzdKPP

```
; ModuleID = 'test.cpp'
source_filename = "test.cpp"
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
target triple = "aarch64-unknown-linux-gnu"

%struct.ident_t = type { i32, i32, i32, i32, ptr }

@0 = private unnamed_addr constant [23 x i8] c";unknown;unknown;0;0;;\00", align 1
@1 = private unnamed_addr constant %struct.ident_t { i32 0, i32 514, i32 0, i32 22, ptr @0 }, align 8
@2 = private unnamed_addr constant %struct.ident_t { i32 0, i32 2, i32 0, i32 22, ptr @0 }, align 8

; Function Attrs: mustprogress nounwind uwtable vscale_range(1,16)
define dso_local void @_Z4testiiPdS_(i32 noundef %nx, i32 noundef %ik, ptr noundef %out, ptr noundef %rspace) local_unnamed_addr #0 {
entry:
  %nx.addr = alloca i32, align 4
  %ik.addr = alloca i32, align 4
  %out.addr = alloca ptr, align 8
  %rspace.addr = alloca ptr, align 8
  store i32 %nx, ptr %nx.addr, align 4
  store i32 %ik, ptr %ik.addr, align 4
  store ptr %out, ptr %out.addr, align 8
  store ptr %rspace, ptr %rspace.addr, align 8
  call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr nonnull @2, i32 4, ptr nonnull @_Z4testiiPdS_.omp_outlined, ptr nonnull %nx.addr, ptr nonnull %ik.addr, ptr nonnull %out.addr, ptr nonnull %rspace.addr)
  ret void
}

; Function Attrs: alwaysinline norecurse nounwind uwtable vscale_range(1,16)
define internal void @_Z4testiiPdS_.omp_outlined(ptr noalias nocapture noundef readonly %.global_tid., ptr noalias nocapture noundef readnone %.bound_tid., ptr noalias nocapture noundef nonnull readonly align 4 dereferenceable(4) %nx, ptr noalias nocapture noundef nonnull readonly align 4 dereferenceable(4) %ik, ptr noalias nocapture noundef nonnull readonly align 8 dereferenceable(8) %out, ptr noalias nocapture noundef nonnull readonly align 8 dereferenceable(8) %rspace) #1 {
entry:
  %.omp.lb = alloca i64, align 8
  %.omp.ub = alloca i64, align 8
  %.omp.stride = alloca i64, align 8
  %.omp.is_last = alloca i32, align 4
  %0 = load i32, ptr %nx, align 4
  %1 = load i32, ptr %ik, align 4
  %cmp = icmp sgt i32 %0, 0
  %cmp8 = icmp sgt i32 %1, 0
  %or.cond = select i1 %cmp, i1 %cmp8, i1 false
  br i1 %or.cond, label %omp.precond.then, label %omp.precond.end

omp.precond.then:                                 ; preds = %entry
  %conv = zext i32 %0 to i64
  %conv6 = zext i32 %1 to i64
  %mul = mul nuw nsw i64 %conv6, %conv
  %sub7 = add nsw i64 %mul, -1
  call void @llvm.lifetime.start.p0(i64 8, ptr nonnull %.omp.lb) #3
  store i64 0, ptr %.omp.lb, align 8
  call void @llvm.lifetime.start.p0(i64 8, ptr nonnull %.omp.ub) #3
  store i64 %sub7, ptr %.omp.ub, align 8
  call void @llvm.lifetime.start.p0(i64 8, ptr nonnull %.omp.stride) #3
  store i64 1, ptr %.omp.stride, align 8
  call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %.omp.is_last) #3
  store i32 0, ptr %.omp.is_last, align 4
  %2 = load i32, ptr %.global_tid., align 4
  call void @__kmpc_for_static_init_8(ptr nonnull @1, i32 %2, i32 33, ptr nonnull %.omp.is_last, ptr nonnull %.omp.lb, ptr nonnull %.omp.ub, ptr nonnull %.omp.stride, i64 1, i64 512)
  %3 = load i64, ptr %.omp.ub, align 8
  %cond60 = call i64 @llvm.smin.i64(i64 %3, i64 %sub7)
  store i64 %cond60, ptr %.omp.ub, align 8
  %4 = load i64, ptr %.omp.lb, align 8
  %cmp12.not61 = icmp sgt i64 %4, %cond60
  br i1 %cmp12.not61, label %omp.dispatch.end, label %omp.inner.for.cond.preheader.lr.ph

omp.inner.for.cond.preheader.lr.ph:               ; preds = %omp.precond.then
  br label %omp.inner.for.cond.preheader

omp.inner.for.cond.preheader:                     ; preds = %omp.inner.for.cond.preheader.lr.ph, %omp.dispatch.inc
  %5 = phi i64 [ %4, %omp.inner.for.cond.preheader.lr.ph ], [ %add42, %omp.dispatch.inc ]
  %cond62 = phi i64 [ %cond60, %omp.inner.for.cond.preheader.lr.ph ], [ %cond, %omp.dispatch.inc ]
  %smax = call i64 @llvm.smax.i64(i64 %cond62, i64 %5)
  %6 = add i64 %smax, 1
  %7 = load ptr, ptr %rspace, align 8
  %8 = load ptr, ptr %out, align 8
  br label %omp.inner.for.body

omp.inner.for.body:                               ; preds = %omp.inner.for.cond.preheader, %omp.inner.for.body
  %.omp.iv.059 = phi i64 [ %5, %omp.inner.for.cond.preheader ], [ %add41, %omp.inner.for.body ]
  %div18 = sdiv i64 %.omp.iv.059, %conv6
  %conv20 = trunc i64 %div18 to i32
  %mul30 = mul nsw i64 %div18, %conv6
  %sub31 = sub nsw i64 %.omp.iv.059, %mul30
  %conv34 = trunc i64 %sub31 to i32
  %mul35 = mul nsw i32 %1, %conv20
  %add36 = add nsw i32 %mul35, %conv34
  %idxprom = sext i32 %add36 to i64
  %arrayidx = getelementptr inbounds double, ptr %7, i64 %idxprom
  %9 = load double, ptr %arrayidx, align 8
  %arrayidx40 = getelementptr inbounds double, ptr %8, i64 %idxprom
  store double %9, ptr %arrayidx40, align 8
  %add41 = add i64 %.omp.iv.059, 1
  %exitcond = icmp ne i64 %add41, %6
  br i1 %exitcond, label %omp.inner.for.body, label %omp.dispatch.inc

omp.dispatch.inc:                                 ; preds = %omp.inner.for.body
  %10 = load i64, ptr %.omp.stride, align 8
  %add42 = add nsw i64 %10, %5
  store i64 %add42, ptr %.omp.lb, align 8
  %add43 = add nsw i64 %10, %cond62
  %cond = call i64 @llvm.smin.i64(i64 %add43, i64 %sub7)
  store i64 %cond, ptr %.omp.ub, align 8
  %cmp12.not = icmp sgt i64 %add42, %cond
  br i1 %cmp12.not, label %omp.dispatch.cond.omp.dispatch.end_crit_edge, label %omp.inner.for.cond.preheader

omp.dispatch.cond.omp.dispatch.end_crit_edge:     ; preds = %omp.dispatch.inc
  br label %omp.dispatch.end

omp.dispatch.end:                                 ; preds = %omp.dispatch.cond.omp.dispatch.end_crit_edge, %omp.precond.then
  call void @__kmpc_for_static_fini(ptr nonnull @1, i32 %2)
  call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %.omp.is_last) #3
  call void @llvm.lifetime.end.p0(i64 8, ptr nonnull %.omp.stride) #3
  call void @llvm.lifetime.end.p0(i64 8, ptr nonnull %.omp.ub) #3
  call void @llvm.lifetime.end.p0(i64 8, ptr nonnull %.omp.lb) #3
  br label %omp.precond.end

omp.precond.end:                                  ; preds = %omp.dispatch.end, %entry
  ret void
}

; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #2

; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #2

; Function Attrs: nounwind
declare void @__kmpc_for_static_init_8(ptr, i32, i32, ptr, ptr, ptr, ptr, i64, i64) local_unnamed_addr #3

; Function Attrs: nounwind
declare void @__kmpc_for_static_fini(ptr, i32) local_unnamed_addr #3

; Function Attrs: nounwind
declare void @__kmpc_fork_call(ptr, i32, ptr, ...) local_unnamed_addr #3

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i64 @llvm.smin.i64(i64, i64) #4

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i64 @llvm.smax.i64(i64, i64) #4

attributes #0 = { mustprogress nounwind uwtable vscale_range(1,16) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+fp-armv8,+fullfp16,+neon,+sve,+v8a,-fmv" }
attributes #1 = { alwaysinline norecurse nounwind uwtable vscale_range(1,16) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+fp-armv8,+fullfp16,+neon,+sve,+v8a,-fmv" }
attributes #2 = { mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
attributes #3 = { nounwind }
attributes #4 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }

```

Comments: author: eastB233
body: Simpler test case is
```c
extern const int npy;
extern const int nx;
double* rspace;

void recip2real(double* out, const double factor)
{
#ifdef _OPENMP
#pragma omp parallel for collapse(2)
#endif
        for (int ix = 0; ix < nx; ++ix)
        {
            for (int ipy = 0; ipy < npy; ++ipy) {
                out[ix * npy + ipy] += factor * rspace[ix * npy + ipy];
            }
        }
}
```

Command is `clang -O3 -march=armv9-a -fopenmp -mllvm -prefer-predicate-over-epilogue=predicate-else-scalar-epilogue -S`

It can be seen at   https://godbolt.org/z/6MGsecEr5
author: eastB233
body: I don't know much about VPlan, and as far as I understand by tracing the code,

### first, it fails at the following VPlan
```
VPlan 'Initial VPlan for VF={vscale x 1,vscale x 2},UF>=1' {
vp<%2> = original trip-count

ph:
  EMIT vp<%2> = EXPAND SCEV (1 + (-1 * %5) + ((-1 + ((zext i32 %0 to i64) * (sext i32 %1 to i64)))<nsw> smin %4))
No successors

vector.ph:
  EMIT vp<%3> = TC > VF ? TC - VF : 0 vp<%2>
  EMIT vp<%4> = VF * Part + ir<0>
  EMIT vp<%5> = active lane mask vp<%4>, vp<%2>
Successor(s): vector loop

<x1> vector loop: {
  vector.body:
    EMIT vp<%6> = CANONICAL-INDUCTION
    ACTIVE-LANE-MASK-PHI vp<%7> = phi vp<%5>, vp<%27>
    vp<%8>    = DERIVED-IV ir<%5> + vp<%6> * ir<1>
    vp<%9>    = SCALAR-STEPS vp<%8>, ir<1>
  Successor(s): pred.sdiv

  <xVFxUF> pred.sdiv: {
    pred.sdiv.entry:
      BRANCH-ON-MASK vp<%7>
    Successor(s): pred.sdiv.if, pred.sdiv.continue

    pred.sdiv.if:
      CLONE ir<%div24> = sdiv vp<%9>, ir<%conv6>
    Successor(s): pred.sdiv.continue

    pred.sdiv.continue:
      PHI-PREDICATED-INSTRUCTION vp<%11> = ir<%div24>
    No successors
  }
  Successor(s): omp.inner.for.body.0

  omp.inner.for.body.0:
    CLONE ir<%conv26> = trunc vp<%11>
    CLONE ir<%mul36> = mul nsw vp<%11>, ir<%conv6>
    CLONE ir<%sub37> = sub nsw vp<%9>, ir<%mul36>
    CLONE ir<%conv40> = trunc ir<%sub37>
    CLONE ir<%mul41> = mul nsw ir<%1>, ir<%conv26>
    CLONE ir<%add42> = add nsw ir<%mul41>, ir<%conv40>
    CLONE ir<%idxprom> = sext ir<%add42>
    CLONE ir<%arrayidx> = getelementptr inbounds ir<%6>, ir<%idxprom>
    WIDEN ir<%8> = load ir<%arrayidx>, vp<%7>
    WIDEN ir<%mul43> = fmul contract ir<%2>, ir<%8>
    CLONE ir<%arrayidx47> = getelementptr inbounds ir<%7>, ir<%idxprom>
    WIDEN ir<%9> = load ir<%arrayidx47>, vp<%7>
    WIDEN ir<%add48> = fadd contract ir<%mul43>, ir<%9>
    WIDEN store ir<%arrayidx47>, ir<%add48>, vp<%7>
    EMIT vp<%25> = VF * UF + vp<%6>
    EMIT vp<%26> = VF * Part + vp<%6>
    EMIT vp<%27> = active lane mask vp<%26>, vp<%3>
    EMIT vp<%28> = not vp<%27>
    EMIT branch-on-cond vp<%28>
  No successors
}
Successor(s): middle.block
```

VPRegion `pred.sdiv` fails at assertion
```c++
void VPRegionBlock::execute(VPTransformState *State) {
...
  if (!isReplicator()) {
...
    return;
  }
...
  for (...) {
    assert(!State->VF.isScalable() && "VF is assumed to be non scalable.");
  }
}
```
I think VPRegion `pred.sdiv` should have `isReplicator() == false` or `pred.sdiv` just should not exist.

### second, I find VPRegion `pred.sdiv` is splitted from `WorkList`
```c++
static void addReplicateRegions(VPlan &Plan) {
  SmallVector<VPReplicateRecipe *> WorkList;
  for (VPBasicBlock *VPBB : VPBlockUtils::blocksOnly<VPBasicBlock>(
           vp_depth_first_deep(Plan.getEntry()))) {
    for (VPRecipeBase &R : *VPBB)
      if (auto *RepR = dyn_cast<VPReplicateRecipe>(&R)) {
        if (RepR->isPredicated())
          WorkList.push_back(RepR);
      }
  }
...
}
```
by VPRecipe `CLONE ir<%div24> = sdiv ir<%.omp.iv.065>, ir<%conv6>, vp<%7>`, where the instruction is `%div24 = sdiv i64 %.omp.iv.065, %conv6`
I think this VPRecipe should have `isPredicated() == false` here, so it will not be splitted.

### third, I find this VPRecipe is created here
```c++
VPRecipeOrVPValueTy VPRecipeBuilder::handleReplication(...) {
  bool IsUniform = LoopVectorizationPlanner::getDecisionAndClampRange(
      [&](ElementCount VF) { return CM.isUniformAfterVectorization(I, VF); },
      Range);

  bool IsPredicated = CM.isPredicatedInst(I);
...
  VPValue *BlockInMask = nullptr;
  if (!IsPredicated) {
    // Finalize the recipe for Instr, first if it is not predicated.
    LLVM_DEBUG(dbgs() << "LV: Scalarizing:" << *I << "\n");
  } else {
    LLVM_DEBUG(dbgs() << "LV: Scalarizing and predicating:" << *I << "\n");
    // Instructions marked for predication are replicated and a mask operand is
    // added initially. Masked replicate recipes will later be placed under an
    // if-then construct to prevent side-effects. Generate recipes to compute
    // the block mask for this region.
    BlockInMask = createBlockInMask(I->getParent(), Plan);
  }

  auto *Recipe = new VPReplicateRecipe(I, Plan.mapToVPValues(I->operands()),
                                       IsUniform, BlockInMask);
  return toVPRecipeResult(Recipe);
}
```
I notice that instruction `I` (`%div24 = sdiv i64 %.omp.iv.065, %conv6`) do not need to vectorize, because function `isScalarAfterVectorization` returns true and `I` is just used to calculate the index.
It seems reasonable that a `scalar` instruction does not need `Predicated`.

### So I try the following modification,
```diff
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index 907b8ce002e8..76a5704a61c5 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -9819,7 +9819,9 @@ VPRecipeOrVPValueTy VPRecipeBuilder::handleReplication(Instruction *I,
       [&](ElementCount VF) { return CM.isUniformAfterVectorization(I, VF); },
       Range);

-  bool IsPredicated = CM.isPredicatedInst(I);
+  bool IsPredicated = LoopVectorizationPlanner::getDecisionAndClampRange(
+      [&](ElementCount VF) { return CM.isPredicatedInst(I) && !CM.isScalarAfterVectorization(I, VF); },
+      Range);

   // Even if the instruction is not marked as uniform, there are certain
   // intrinsic calls that can be effectively treated as such, so we check for
```

Just my guess, I'm not sure if it is correct direction.
author: eastB233
body: Ping @fhahn 
author: eastB233
body: I think I misunderstand something, and the changes above may be wrong.

And I have another way. In instruction `%div24 = sdiv i64 %.omp.iv.065, %conv6`, `%conv6` is invariant in loop, so it seems we do not need `Predicated`.

I try the following patch,
```diff
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index c7c19ef456c7..f294703e1529 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -3856,21 +3856,21 @@ bool LoopVectorizationCostModel::isPredicatedInst(Instruction *I) const {
         !Legal->blockNeedsPredication(I->getParent()))
       return false;
     return true;
   }
   case Instruction::UDiv:
   case Instruction::SDiv:
   case Instruction::SRem:
   case Instruction::URem:
     // TODO: We can use the loop-preheader as context point here and get
     // context sensitive reasoning
-    return !isSafeToSpeculativelyExecute(I);
+    return !isSafeToSpeculativelyExecute(I) && !Legal->isInvariant(I->getOperand(1));
   case Instruction::Call:
     return Legal->isMaskRequired(I);
   }
 }

 std::pair<InstructionCost, InstructionCost>
 LoopVectorizationCostModel::getDivRemSpeculationCost(Instruction *I,
                                                     ElementCount VF) const {
   assert(I->getOpcode() == Instruction::UDiv ||
          I->getOpcode() == Instruction::SDiv ||

```
author: eastB233
body: ping @sdesmalen-arm @davemgreen @paulwalker-arm 
author: fhahn
body: @eastB233 unfortunately I don't think this change is correct, e.g. consider https://github.com/llvm/llvm-project/blob/967eba07549d64f15e7a91e798aa46214704f62b/llvm/test/Transforms/LoopVectorize/X86/divs-with-tail-folding.ll#L251 when the sdiv/udiv is executed conditionally in the loop

Fix patch:
commit 008df3cf85e9bb1532c079bfd7a7a00e90e0a3c6
Author: Florian Hahn <flo@fhahn.com>
Date:   Fri Jul 19 12:02:25 2024 +0100

    [LV] Check isPredInst instead of isScalarWithPred in uniform analysis. (#98892)
    
    Any instruction marked as uniform will result in a uniform
    VPReplicateRecipe. If it requires predication, it will be placed in a
    replicate region, even if isScalarWithPredication returns false.
    
    Check isPredicatedInst instead of isScalarWithPredication to avoid
    generating uniform VPReplicateRecipes placed inside a replicate region.
    This fixes an assertion when using scalable VFs.
    
    Fixes https://github.com/llvm/llvm-project/issues/80416.
    Fixes https://github.com/llvm/llvm-project/issues/94328.
    Fixes https://github.com/llvm/llvm-project/issues/99625.
    
    PR: https://github.com/llvm/llvm-project/pull/98892

diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
index fbca4cdcbcfc..cceed75aa50b 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
@@ -3914,19 +3914,19 @@ void LoopVectorizationCostModel::collectLoopUniforms(ElementCount VF) {
   SetVector<Instruction *> Worklist;
 
   // Add uniform instructions demanding lane 0 to the worklist. Instructions
-  // that are scalar with predication must not be considered uniform after
+  // that require predication must not be considered uniform after
   // vectorization, because that would create an erroneous replicating region
   // where only a single instance out of VF should be formed.
-  // TODO: optimize such seldom cases if found important, see PR40816.
   auto addToWorklistIfAllowed = [&](Instruction *I) -> void {
     if (isOutOfScope(I)) {
       LLVM_DEBUG(dbgs() << "LV: Found not uniform due to scope: "
                         << *I << "\n");
       return;
     }
-    if (isScalarWithPredication(I, VF)) {
-      LLVM_DEBUG(dbgs() << "LV: Found not uniform being ScalarWithPredication: "
-                        << *I << "\n");
+    if (isPredicatedInst(I)) {
+      LLVM_DEBUG(
+          dbgs() << "LV: Found not uniform due to requiring predication: " << *I
+                 << "\n");
       return;
     }
     LLVM_DEBUG(dbgs() << "LV: Found uniform instruction: " << *I << "\n");
@@ -9516,6 +9516,8 @@ void VPInterleaveRecipe::execute(VPTransformState &State) {
 void VPReplicateRecipe::execute(VPTransformState &State) {
   Instruction *UI = getUnderlyingInstr();
   if (State.Instance) { // Generate a single instance.
+    assert((State.VF.isScalar() || !isUniform()) &&
+           "uniform recipe shouldn't be predicated");
     assert(!State.VF.isScalable() && "Can't scalarize a scalable vector");
     State.ILV->scalarizeInstruction(UI, this, *State.Instance, State);
     // Insert scalar instance packing it into a vector.


Regression tests:
file: llvm/test/Transforms/LoopVectorize/AArch64/divs-with-scalable-vfs.ll
commands: opt -p loop-vectorize -mtriple aarch64 -mcpu=neoverse-v1 -S %s
tests: test_name: udiv_urem_feeding_gep
test_body: define void @udiv_urem_feeding_gep(i64 %x, ptr %dst, i64 %N) {
entry:
  %mul.1.i = mul i64 %x, %x
  %mul.2.i = mul i64 %mul.1.i, %x
  br label %loop

loop:                                             ; preds = %loop, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
  %div.i = udiv i64 %iv, %mul.2.i
  %rem.i = urem i64 %iv, %mul.2.i
  %div.1.i = udiv i64 %rem.i, %mul.1.i
  %rem.1.i = urem i64 %rem.i, %mul.1.i
  %div.2.i = udiv i64 %rem.1.i, %x
  %rem.2.i = urem i64 %rem.1.i, %x
  %mul.i = mul i64 %x, %div.i
  %add.i = add i64 %mul.i, %div.1.i
  %mul.1.i9 = mul i64 %add.i, %x
  %add.1.i = add i64 %mul.1.i9, %div.2.i
  %mul.2.i11 = mul i64 %add.1.i, %x
  %add.2.i = add i64 %mul.2.i11, %rem.2.i
  %sext.i = shl i64 %add.2.i, 32
  %conv6.i = ashr i64 %sext.i, 32
  %gep = getelementptr i64, ptr %dst, i64 %conv6.i
  store i64 %div.i, ptr %gep, align 4
  %iv.next = add i64 %iv, 1
  %exitcond.not = icmp eq i64 %iv, %N
  br i1 %exitcond.not, label %exit, label %loop

exit:                                             ; preds = %loop
  ret void
}

test_name: sdiv_feeding_gep_predicated
test_body: define void @sdiv_feeding_gep_predicated(ptr %dst, i32 %x, i64 %M, i64 %conv6, i64 %N) {
entry:
  %conv61 = zext i32 %x to i64
  br label %loop

loop:                                             ; preds = %loop.latch, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
  %c = icmp ule i64 %iv, %M
  br i1 %c, label %then, label %loop.latch

then:                                             ; preds = %loop
  %div18 = sdiv i64 %M, %conv6
  %conv20 = trunc i64 %div18 to i32
  %mul30 = mul i64 %div18, %conv61
  %sub31 = sub i64 %iv, %mul30
  %conv34 = trunc i64 %sub31 to i32
  %mul35 = mul i32 %x, %conv20
  %add36 = add i32 %mul35, %conv34
  %idxprom = sext i32 %add36 to i64
  %gep = getelementptr double, ptr %dst, i64 %idxprom
  store double 0.000000e+00, ptr %gep, align 8
  br label %loop.latch

loop.latch:                                       ; preds = %then, %loop
  %iv.next = add i64 %iv, 1
  %ec = icmp eq i64 %iv.next, %N
  br i1 %ec, label %exit, label %loop

exit:                                             ; preds = %loop.latch
  ret void
}

test_name: sdiv_feeding_gep
test_body: define void @sdiv_feeding_gep(ptr %dst, i32 %x, i64 %M, i64 %conv6, i64 %N) {
entry:
  %conv61 = zext i32 %x to i64
  br label %loop

loop:                                             ; preds = %loop, %entry
  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
  %div18 = sdiv i64 %M, %conv6
  %conv20 = trunc i64 %div18 to i32
  %mul30 = mul i64 %div18, %conv61
  %sub31 = sub i64 %iv, %mul30
  %conv34 = trunc i64 %sub31 to i32
  %mul35 = mul i32 %x, %conv20
  %add36 = add i32 %mul35, %conv34
  %idxprom = sext i32 %add36 to i64
  %gep = getelementptr double, ptr %dst, i64 %idxprom
  store double 0.000000e+00, ptr %gep, align 8
  %iv.next = add i64 %iv, 1
  %ec = icmp eq i64 %iv.next, %N
  br i1 %ec, label %exit, label %loop

exit:                                             ; preds = %loop
  ret void
}