Skip to content

Commit

Permalink
[LoopVectorize] Enable more early exit vectorisation tests (#117008)
Browse files Browse the repository at this point in the history
PR #112138 introduced initial support for dispatching to
multiple exit blocks via split middle blocks. This patch
fixes a few issues so that we can enable more tests to use
the new enable-early-exit-vectorization flag. Fixes are:

1. The code to bail out for any loop live-out values happens
too late. This is because collectUsersInExitBlocks ignores
induction variables, which get dealt with in fixupIVUsers.
I've moved the check much earlier in processLoop by looking
for outside users of loop-defined values.
2. We shouldn't yet be interleaving when vectorising loops
with uncountable early exits, since we've not added support
for this yet.
3. Similarly, we also shouldn't be creating vector epilogues.
4. Similarly, we shouldn't enable tail-folding.
5. The existing implementation doesn't yet support loops
that require scalar epilogues, although I plan to add that
as part of PR #88385.
6. The new split middle blocks weren't being added to the
parent loop.
  • Loading branch information
david-arm authored Dec 18, 2024
1 parent 96bb281 commit 13107cb
Show file tree
Hide file tree
Showing 8 changed files with 306 additions and 18 deletions.
9 changes: 9 additions & 0 deletions llvm/include/llvm/Transforms/Vectorize/LoopVectorize.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,15 @@ void reportVectorizationFailure(const StringRef DebugMsg,
const StringRef OREMsg, const StringRef ORETag,
OptimizationRemarkEmitter *ORE, Loop *TheLoop, Instruction *I = nullptr);

/// Same as above, but the debug message and optimization remark are identical
inline void reportVectorizationFailure(const StringRef DebugMsg,
const StringRef ORETag,
OptimizationRemarkEmitter *ORE,
Loop *TheLoop,
Instruction *I = nullptr) {
reportVectorizationFailure(DebugMsg, DebugMsg, ORETag, ORE, TheLoop, I);
}

/// A marker analysis to determine if extra passes should be run after loop
/// vectorization.
struct ShouldRunExtraVectorPasses
Expand Down
75 changes: 67 additions & 8 deletions llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3039,6 +3039,22 @@ void InnerLoopVectorizer::fixVectorizedLoop(VPTransformState &State) {
PSE.getSE()->forgetLoop(OrigLoop);
PSE.getSE()->forgetBlockAndLoopDispositions();

// When dealing with uncountable early exits we create middle.split blocks
// between the vector loop region and the exit block. These blocks need
// adding to any outer loop.
VPRegionBlock *VectorRegion = State.Plan->getVectorLoopRegion();
Loop *OuterLoop = OrigLoop->getParentLoop();
if (Legal->hasUncountableEarlyExit() && OuterLoop) {
VPBasicBlock *MiddleVPBB = State.Plan->getMiddleBlock();
VPBlockBase *PredVPBB = MiddleVPBB->getSinglePredecessor();
while (PredVPBB && PredVPBB != VectorRegion) {
BasicBlock *MiddleSplitBB =
State.CFG.VPBB2IRBB[cast<VPBasicBlock>(PredVPBB)];
OuterLoop->addBasicBlockToLoop(MiddleSplitBB, *LI);
PredVPBB = PredVPBB->getSinglePredecessor();
}
}

// After vectorization, the exit blocks of the original loop will have
// additional predecessors. Invalidate SCEVs for the exit phis in case SE
// looked through single-entry phis.
Expand Down Expand Up @@ -3069,7 +3085,6 @@ void InnerLoopVectorizer::fixVectorizedLoop(VPTransformState &State) {
for (Instruction *PI : PredicatedInstructions)
sinkScalarOperands(&*PI);

VPRegionBlock *VectorRegion = State.Plan->getVectorLoopRegion();
VPBasicBlock *HeaderVPBB = VectorRegion->getEntryBasicBlock();
BasicBlock *HeaderBB = State.CFG.VPBB2IRBB[HeaderVPBB];

Expand Down Expand Up @@ -4776,6 +4791,7 @@ bool LoopVectorizationPlanner::isCandidateForEpilogueVectorization(
// Epilogue vectorization code has not been auditted to ensure it handles
// non-latch exits properly. It may be fine, but it needs auditted and
// tested.
// TODO: Add support for loops with an early exit.
if (OrigLoop->getExitingBlock() != OrigLoop->getLoopLatch())
return false;

Expand Down Expand Up @@ -5024,6 +5040,12 @@ LoopVectorizationCostModel::selectInterleaveCount(ElementCount VF,
if (!Legal->isSafeForAnyVectorWidth())
return 1;

// We don't attempt to perform interleaving for loops with uncountable early
// exits because the VPInstruction::AnyOf code cannot currently handle
// multiple parts.
if (Legal->hasUncountableEarlyExit())
return 1;

auto BestKnownTC = getSmallBestKnownTC(PSE, TheLoop);
const bool HasReductions = !Legal->getReductionVars().empty();

Expand Down Expand Up @@ -7837,6 +7859,8 @@ DenseMap<const SCEV *, Value *> LoopVectorizationPlanner::executePlan(
// 2.5 When vectorizing the epilogue, fix reduction and induction resume
// values from the additional bypass block.
if (VectorizingEpilogue) {
assert(!ILV.Legal->hasUncountableEarlyExit() &&
"Epilogue vectorisation not yet supported with early exits");
BasicBlock *BypassBlock = ILV.getAdditionalBypassBlock();
for (VPRecipeBase &R : *ExitVPBB) {
fixReductionScalarResumeWhenVectorizingEpilog(
Expand Down Expand Up @@ -10202,13 +10226,36 @@ bool LoopVectorizePass::processLoop(Loop *L) {
return false;
}

if (LVL.hasUncountableEarlyExit() && !EnableEarlyExitVectorization) {
reportVectorizationFailure("Auto-vectorization of loops with uncountable "
"early exit is not enabled",
"Auto-vectorization of loops with uncountable "
"early exit is not enabled",
"UncountableEarlyExitLoopsDisabled", ORE, L);
return false;
if (LVL.hasUncountableEarlyExit()) {
if (!EnableEarlyExitVectorization) {
reportVectorizationFailure("Auto-vectorization of loops with uncountable "
"early exit is not enabled",
"UncountableEarlyExitLoopsDisabled", ORE, L);
return false;
}

// In addUsersInExitBlocks we already bail out if there is an outside use
// of a loop-defined variable, but it ignores induction variables which are
// handled by InnerLoopVectorizer::fixupIVUsers. We need to bail out if we
// encounter induction variables too otherwise fixupIVUsers will crash.
BasicBlock *LoopLatch = L->getLoopLatch();
for (const auto &Induction : LVL.getInductionVars()) {
PHINode *Ind = Induction.first;
Instruction *IndUpdate =
cast<Instruction>(Ind->getIncomingValueForBlock(LoopLatch));
for (Instruction *I : {cast<Instruction>(Ind), IndUpdate}) {
for (User *U : I->users()) {
Instruction *UI = cast<Instruction>(U);
if (!L->contains(UI)) {
reportVectorizationFailure(
"Auto-vectorization of loops with uncountable early exits and "
"outside uses of induction variables unsupported",
"UncountableEarlyExitLoopIndLiveOutsUnsupported", ORE, L);
return false;
}
}
}
}
}

// Entrance to the VPlan-native vectorization path. Outer loops are processed
Expand All @@ -10233,6 +10280,18 @@ bool LoopVectorizePass::processLoop(Loop *L) {
if (UseInterleaved)
IAI.analyzeInterleaving(useMaskedInterleavedAccesses(*TTI));

if (LVL.hasUncountableEarlyExit()) {
BasicBlock *LoopLatch = L->getLoopLatch();
if (IAI.requiresScalarEpilogue() ||
any_of(LVL.getCountableExitingBlocks(),
[LoopLatch](BasicBlock *BB) { return BB != LoopLatch; })) {
reportVectorizationFailure("Auto-vectorization of early exit loops "
"requiring a scalar epilogue is unsupported",
"UncountableEarlyExitUnsupported", ORE, L);
return false;
}
}

// Check the function attributes and profiles to find out if this function
// should be optimized for size.
ScalarEpilogueLowering SEL =
Expand Down
103 changes: 98 additions & 5 deletions llvm/test/Transforms/LoopVectorize/AArch64/simple_early_exit.ll
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
; RUN: opt -S < %s -p loop-vectorize | FileCheck %s --check-prefixes=CHECK
; RUN: opt -S < %s -p loop-vectorize -enable-early-exit-vectorization | FileCheck %s --check-prefixes=CHECK

target triple = "aarch64-unknown-linux-gnu"

Expand Down Expand Up @@ -272,22 +272,66 @@ define i32 @diff_exit_block_needs_scev_check(i32 %end) {
; CHECK-NEXT: call void @init_mem(ptr [[P1]], i64 1024)
; CHECK-NEXT: call void @init_mem(ptr [[P2]], i64 1024)
; CHECK-NEXT: [[END_CLAMPED:%.*]] = and i32 [[END]], 1023
; CHECK-NEXT: [[TMP19:%.*]] = trunc i32 [[END]] to i10
; CHECK-NEXT: [[TMP20:%.*]] = zext i10 [[TMP19]] to i64
; CHECK-NEXT: [[UMAX1:%.*]] = call i64 @llvm.umax.i64(i64 [[TMP20]], i64 1)
; CHECK-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[UMAX1]], 12
; CHECK-NEXT: br i1 [[MIN_ITERS_CHECK]], label [[SCALAR_PH:%.*]], label [[VECTOR_SCEVCHECK:%.*]]
; CHECK: vector.scevcheck:
; CHECK-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[END_CLAMPED]], i32 1)
; CHECK-NEXT: [[TMP2:%.*]] = add nsw i32 [[UMAX]], -1
; CHECK-NEXT: [[TMP3:%.*]] = trunc i32 [[TMP2]] to i8
; CHECK-NEXT: [[TMP4:%.*]] = add i8 1, [[TMP3]]
; CHECK-NEXT: [[TMP5:%.*]] = icmp ult i8 [[TMP4]], 1
; CHECK-NEXT: [[TMP6:%.*]] = icmp ugt i32 [[TMP2]], 255
; CHECK-NEXT: [[TMP7:%.*]] = or i1 [[TMP5]], [[TMP6]]
; CHECK-NEXT: br i1 [[TMP7]], label [[SCALAR_PH]], label [[VECTOR_PH:%.*]]
; CHECK: vector.ph:
; CHECK-NEXT: [[N_MOD_VF:%.*]] = urem i64 [[UMAX1]], 4
; CHECK-NEXT: [[N_VEC:%.*]] = sub i64 [[UMAX1]], [[N_MOD_VF]]
; CHECK-NEXT: [[IND_END:%.*]] = trunc i64 [[N_VEC]] to i8
; CHECK-NEXT: br label [[FOR_BODY1:%.*]]
; CHECK: vector.body:
; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, [[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], [[FOR_BODY1]] ]
; CHECK-NEXT: [[TMP8:%.*]] = add i64 [[INDEX]], 0
; CHECK-NEXT: [[TMP9:%.*]] = getelementptr inbounds i32, ptr [[P1]], i64 [[TMP8]]
; CHECK-NEXT: [[TMP10:%.*]] = getelementptr inbounds i32, ptr [[TMP9]], i32 0
; CHECK-NEXT: [[WIDE_LOAD:%.*]] = load <4 x i32>, ptr [[TMP10]], align 4
; CHECK-NEXT: [[TMP11:%.*]] = getelementptr inbounds i32, ptr [[P2]], i64 [[TMP8]]
; CHECK-NEXT: [[TMP12:%.*]] = getelementptr inbounds i32, ptr [[TMP11]], i32 0
; CHECK-NEXT: [[WIDE_LOAD3:%.*]] = load <4 x i32>, ptr [[TMP12]], align 4
; CHECK-NEXT: [[TMP13:%.*]] = icmp eq <4 x i32> [[WIDE_LOAD]], [[WIDE_LOAD3]]
; CHECK-NEXT: [[TMP14:%.*]] = xor <4 x i1> [[TMP13]], splat (i1 true)
; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 4
; CHECK-NEXT: [[TMP15:%.*]] = xor <4 x i1> [[TMP14]], splat (i1 true)
; CHECK-NEXT: [[TMP16:%.*]] = call i1 @llvm.vector.reduce.or.v4i1(<4 x i1> [[TMP15]])
; CHECK-NEXT: [[TMP17:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
; CHECK-NEXT: [[TMP18:%.*]] = or i1 [[TMP16]], [[TMP17]]
; CHECK-NEXT: br i1 [[TMP18]], label [[MIDDLE_SPLIT:%.*]], label [[FOR_BODY1]], !llvm.loop [[LOOP0:![0-9]+]]
; CHECK: middle.split:
; CHECK-NEXT: br i1 [[TMP16]], label [[FOUND:%.*]], label [[MIDDLE_BLOCK:%.*]]
; CHECK: middle.block:
; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[UMAX1]], [[N_VEC]]
; CHECK-NEXT: br i1 [[CMP_N]], label [[EXIT:%.*]], label [[SCALAR_PH]]
; CHECK: scalar.ph:
; CHECK-NEXT: [[BC_RESUME_VAL:%.*]] = phi i8 [ [[IND_END]], [[MIDDLE_BLOCK]] ], [ 0, [[ENTRY:%.*]] ], [ 0, [[VECTOR_SCEVCHECK]] ]
; CHECK-NEXT: [[BC_RESUME_VAL2:%.*]] = phi i64 [ [[N_VEC]], [[MIDDLE_BLOCK]] ], [ 0, [[ENTRY]] ], [ 0, [[VECTOR_SCEVCHECK]] ]
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.body:
; CHECK-NEXT: [[IND:%.*]] = phi i8 [ [[IND_NEXT:%.*]], [[FOR_INC:%.*]] ], [ 0, [[ENTRY:%.*]] ]
; CHECK-NEXT: [[GEP_IND:%.*]] = phi i64 [ [[GEP_IND_NEXT:%.*]], [[FOR_INC]] ], [ 0, [[ENTRY]] ]
; CHECK-NEXT: [[IND:%.*]] = phi i8 [ [[IND_NEXT:%.*]], [[FOR_INC:%.*]] ], [ [[BC_RESUME_VAL]], [[SCALAR_PH]] ]
; CHECK-NEXT: [[GEP_IND:%.*]] = phi i64 [ [[GEP_IND_NEXT:%.*]], [[FOR_INC]] ], [ [[BC_RESUME_VAL2]], [[SCALAR_PH]] ]
; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds i32, ptr [[P1]], i64 [[GEP_IND]]
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX1]], align 4
; CHECK-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds i32, ptr [[P2]], i64 [[GEP_IND]]
; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[ARRAYIDX2]], align 4
; CHECK-NEXT: [[CMP_EARLY:%.*]] = icmp eq i32 [[TMP0]], [[TMP1]]
; CHECK-NEXT: br i1 [[CMP_EARLY]], label [[FOUND:%.*]], label [[FOR_INC]]
; CHECK-NEXT: br i1 [[CMP_EARLY]], label [[FOUND]], label [[FOR_INC]]
; CHECK: for.inc:
; CHECK-NEXT: [[IND_NEXT]] = add i8 [[IND]], 1
; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[IND_NEXT]] to i32
; CHECK-NEXT: [[GEP_IND_NEXT]] = add i64 [[GEP_IND]], 1
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[CONV]], [[END_CLAMPED]]
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY1]], label [[EXIT:%.*]]
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[EXIT]], !llvm.loop [[LOOP3:![0-9]+]]
; CHECK: found:
; CHECK-NEXT: ret i32 1
; CHECK: exit:
Expand Down Expand Up @@ -325,9 +369,58 @@ exit:
ret i32 0
}

%my.struct = type { i8, i8 }

define i64 @same_exit_block_requires_interleaving() {
; CHECK-LABEL: define i64 @same_exit_block_requires_interleaving() {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[P1:%.*]] = alloca [128 x %my.struct], align 8
; CHECK-NEXT: call void @init_mem(ptr [[P1]], i64 256)
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ [[INDEX_NEXT:%.*]], [[LOOP_LATCH:%.*]] ], [ 3, [[ENTRY:%.*]] ]
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [128 x %my.struct], ptr [[P1]], i64 0, i64 [[INDEX]]
; CHECK-NEXT: [[LD1:%.*]] = load i8, ptr [[ARRAYIDX]], align 1
; CHECK-NEXT: [[CMP3:%.*]] = icmp eq i8 [[LD1]], 3
; CHECK-NEXT: br i1 [[CMP3]], label [[LOOP_LATCH]], label [[LOOP_END:%.*]]
; CHECK: loop.latch:
; CHECK-NEXT: [[INDEX_NEXT]] = add i64 [[INDEX]], 1
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[INDEX_NEXT]], 69
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[LOOP_END]]
; CHECK: loop.end:
; CHECK-NEXT: [[RETVAL:%.*]] = phi i64 [ 0, [[LOOP_LATCH]] ], [ 1, [[LOOP]] ]
; CHECK-NEXT: ret i64 [[RETVAL]]
;
entry:
%p1 = alloca [128 x %my.struct]
call void @init_mem(ptr %p1, i64 256)
br label %loop

loop:
%index = phi i64 [ %index.next, %loop.latch ], [ 3, %entry ]
%arrayidx = getelementptr inbounds [128 x %my.struct], ptr %p1, i64 0, i64 %index
%ld1 = load i8, ptr %arrayidx, align 1
%cmp3 = icmp eq i8 %ld1, 3
br i1 %cmp3, label %loop.latch, label %loop.end

loop.latch:
%index.next = add i64 %index, 1
%exitcond = icmp ne i64 %index.next, 69
br i1 %exitcond, label %loop, label %loop.end

loop.end:
%retval = phi i64 [ 0, %loop.latch ], [ 1, %loop ]
ret i64 %retval
}

declare i32 @foo(i32) readonly
declare <vscale x 4 x i32> @foo_vec(<vscale x 4 x i32>)

attributes #0 = { "vector-function-abi-variant"="_ZGVsNxv_foo(foo_vec)" }
attributes #1 = { "target-features"="+sve" vscale_range(1,16) }
;.
; CHECK: [[LOOP0]] = distinct !{[[LOOP0]], [[META1:![0-9]+]], [[META2:![0-9]+]]}
; CHECK: [[META1]] = !{!"llvm.loop.isvectorized", i32 1}
; CHECK: [[META2]] = !{!"llvm.loop.unroll.runtime.disable"}
; CHECK: [[LOOP3]] = distinct !{[[LOOP3]], [[META1]]}
;.
40 changes: 38 additions & 2 deletions llvm/test/Transforms/LoopVectorize/early_exit_legality.ll
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ define i64 @same_exit_block_pre_inc_use1() {
; CHECK-LABEL: LV: Checking a loop in 'same_exit_block_pre_inc_use1'
; CHECK: LV: Found an early exit loop with symbolic max backedge taken count: 63
; CHECK-NEXT: LV: We can vectorize this loop!
; CHECK-NOT: LV: Not vectorizing
; CHECK-NEXT: LV: Not vectorizing: Auto-vectorization of loops with uncountable early exits and outside uses of induction variables unsupported
entry:
%p1 = alloca [1024 x i8]
%p2 = alloca [1024 x i8]
Expand Down Expand Up @@ -141,7 +141,7 @@ define i64 @loop_contains_load_after_early_exit(ptr dereferenceable(1024) align(
; CHECK-LABEL: LV: Checking a loop in 'loop_contains_load_after_early_exit'
; CHECK: LV: Found an early exit loop with symbolic max backedge taken count: 63
; CHECK-NEXT: LV: We can vectorize this loop!
; CHECK: LV: Not vectorizing: Some exit values in loop with uncountable exit not supported yet.
; CHECK: LV: Not vectorizing: Auto-vectorization of loops with uncountable early exits and outside uses of induction variables unsupported
entry:
%p1 = alloca [1024 x i8]
call void @init_mem(ptr %p1, i64 1024)
Expand All @@ -167,6 +167,42 @@ loop.end:
}


define i64 @one_uncountable_two_countable_same_exit_phi_of_consts() {
; CHECK-LABEL: LV: Checking a loop in 'one_uncountable_two_countable_same_exit_phi_of_consts'
; CHECK: LV: Found an early exit loop with symbolic max backedge taken count: 61
; CHECK-NEXT: LV: We can vectorize this loop!
; CHECK-NEXT: LV: Not vectorizing: Auto-vectorization of early exit loops requiring a scalar epilogue is unsupported.
entry:
%p1 = alloca [1024 x i8]
%p2 = alloca [1024 x i8]
call void @init_mem(ptr %p1, i64 1024)
call void @init_mem(ptr %p2, i64 1024)
br label %loop

loop:
%index = phi i64 [ %index.next, %loop.inc ], [ 3, %entry ]
%cmp1 = icmp ne i64 %index, 64
br i1 %cmp1, label %search, label %loop.end

search:
%arrayidx = getelementptr inbounds i8, ptr %p1, i64 %index
%ld1 = load i8, ptr %arrayidx, align 1
%arrayidx1 = getelementptr inbounds i8, ptr %p2, i64 %index
%ld2 = load i8, ptr %arrayidx1, align 1
%cmp3 = icmp eq i8 %ld1, %ld2
br i1 %cmp3, label %loop.end, label %loop.inc

loop.inc:
%index.next = add i64 %index, 1
%exitcond = icmp ne i64 %index.next, 128
br i1 %exitcond, label %loop, label %loop.end

loop.end:
%retval = phi i64 [ 0, %loop ], [ 1, %search ], [ 0, %loop.inc ]
ret i64 %retval
}


; == SOME ILLEGAL EXAMPLES ==


Expand Down
2 changes: 1 addition & 1 deletion llvm/test/Transforms/LoopVectorize/multi_early_exit.ll
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
; RUN: opt -S < %s -p loop-vectorize | FileCheck %s
; RUN: opt -S < %s -p loop-vectorize -enable-early-exit-vectorization | FileCheck %s

declare void @init_mem(ptr, i64);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
; RUN: opt -S < %s -p loop-vectorize | FileCheck %s
; RUN: opt -S < %s -p loop-vectorize -enable-early-exit-vectorization | FileCheck %s

declare void @init_mem(ptr, i64);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
; RUN: opt -S < %s -p loop-vectorize | FileCheck %s
; RUN: opt -S < %s -p loop-vectorize -enable-early-exit-vectorization | FileCheck %s

declare void @init_mem(ptr, i64);

Expand Down
Loading

0 comments on commit 13107cb

Please sign in to comment.