This removes the restriction requiring a single predicated early exit. Using MaskedCond, we only combine early-exit conditions with block masks from non-exiting control flow. This means we have to ensure that we check the early exit conditions in program order, to make sure we take the first exit in program order that exits at the first lane for the combined exit condition. To do so, sort the exits by their reverse post-order numbers. Depends on https://github.com/llvm/llvm-project/pull/182395 PR: https://github.com/llvm/llvm-project/pull/182396
637 lines
20 KiB
LLVM
637 lines
20 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
|
|
; REQUIRES: asserts
|
|
; RUN: opt -S < %s -p loop-vectorize -debug-only=loop-vectorize -force-vector-width=4 -disable-output 2>&1 | FileCheck %s
|
|
|
|
declare void @init_mem(ptr, i64);
|
|
|
|
; == SOME LEGAL EXAMPLES ==
|
|
|
|
; The form of the induction variables requires SCEV predicates.
|
|
define i32 @diff_exit_block_needs_scev_check(i32 %end) {
|
|
; CHECK-LABEL: LV: Checking a loop in 'diff_exit_block_needs_scev_check'
|
|
; CHECK: Found an early exit loop with symbolic max backedge taken count: (-1 + (1 umax (zext i10 (trunc i32 %end to i10) to i32)))<nsw>
|
|
; CHECK-NEXT: LV: We can vectorize this loop!
|
|
; CHECK-NOT: LV: Not vectorizing:
|
|
entry:
|
|
%p1 = alloca [1024 x i32]
|
|
%p2 = alloca [1024 x i32]
|
|
call void @init_mem(ptr %p1, i64 1024)
|
|
call void @init_mem(ptr %p2, i64 1024)
|
|
%end.clamped = and i32 %end, 1023
|
|
br label %for.body
|
|
|
|
for.body:
|
|
%ind = phi i8 [ %ind.next, %for.inc ], [ 0, %entry ]
|
|
%gep.ind = phi i64 [ %gep.ind.next, %for.inc ], [ 0, %entry ]
|
|
%arrayidx1 = getelementptr inbounds i32, ptr %p1, i64 %gep.ind
|
|
%0 = load i32, ptr %arrayidx1, align 4
|
|
%arrayidx2 = getelementptr inbounds i32, ptr %p2, i64 %gep.ind
|
|
%1 = load i32, ptr %arrayidx2, align 4
|
|
%cmp.early = icmp eq i32 %0, %1
|
|
br i1 %cmp.early, label %found, label %for.inc
|
|
|
|
for.inc:
|
|
%ind.next = add i8 %ind, 1
|
|
%conv = zext i8 %ind.next to i32
|
|
%gep.ind.next = add i64 %gep.ind, 1
|
|
%cmp = icmp ult i32 %conv, %end.clamped
|
|
br i1 %cmp, label %for.body, label %exit
|
|
|
|
found:
|
|
ret i32 1
|
|
|
|
exit:
|
|
ret i32 0
|
|
}
|
|
|
|
|
|
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
|
|
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 ]
|
|
%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.inc, label %loop.end
|
|
|
|
loop.inc:
|
|
%index.next = add i64 %index, 1
|
|
%exitcond = icmp ne i64 %index.next, 67
|
|
br i1 %exitcond, label %loop, label %loop.end
|
|
|
|
loop.end:
|
|
%retval = phi i64 [ %index, %loop ], [ 67, %loop.inc ]
|
|
ret i64 %retval
|
|
}
|
|
|
|
|
|
define i64 @loop_contains_safe_call() {
|
|
; CHECK-LABEL: LV: Checking a loop in 'loop_contains_safe_call'
|
|
; CHECK: LV: Found an early exit loop with symbolic max backedge taken count: 63
|
|
; CHECK-NEXT: LV: We can vectorize this loop!
|
|
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 ]
|
|
%arrayidx = getelementptr inbounds float, ptr %p1, i64 %index
|
|
%ld1 = load float, ptr %arrayidx, align 1
|
|
%sqrt = tail call fast float @llvm.sqrt.f32(float %ld1)
|
|
%cmp = fcmp fast ult float %sqrt, 3.0e+00
|
|
br i1 %cmp, label %loop.inc, label %loop.end
|
|
|
|
loop.inc:
|
|
%index.next = add i64 %index, 1
|
|
%exitcond = icmp ne i64 %index.next, 67
|
|
br i1 %exitcond, label %loop, label %loop.end
|
|
|
|
loop.end:
|
|
%retval = phi i64 [ %index, %loop ], [ 67, %loop.inc ]
|
|
ret i64 %retval
|
|
}
|
|
|
|
|
|
define i64 @loop_contains_safe_div() {
|
|
; CHECK-LABEL: LV: Checking a loop in 'loop_contains_safe_div'
|
|
; CHECK: LV: Found an early exit loop with symbolic max backedge taken count: 63
|
|
; CHECK-NEXT: LV: We can vectorize this loop!
|
|
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 ]
|
|
%arrayidx = getelementptr inbounds i32, ptr %p1, i64 %index
|
|
%ld1 = load i32, ptr %arrayidx, align 1
|
|
%div = udiv i32 %ld1, 20000
|
|
%cmp = icmp eq i32 %div, 1
|
|
br i1 %cmp, label %loop.inc, label %loop.end
|
|
|
|
loop.inc:
|
|
%index.next = add i64 %index, 1
|
|
%exitcond = icmp ne i64 %index.next, 67
|
|
br i1 %exitcond, label %loop, label %loop.end
|
|
|
|
loop.end:
|
|
%retval = phi i64 [ %index, %loop ], [ 67, %loop.inc ]
|
|
ret i64 %retval
|
|
}
|
|
|
|
|
|
define i64 @loop_contains_load_after_early_exit(ptr dereferenceable(1024) align(8) %p2) {
|
|
; 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-NOT: LV: Not vectorizing
|
|
entry:
|
|
%p1 = alloca [1024 x i8]
|
|
call void @init_mem(ptr %p1, i64 1024)
|
|
br label %loop
|
|
|
|
loop:
|
|
%index = phi i64 [ %index.next, %loop.inc ], [ 3, %entry ]
|
|
%arrayidx = getelementptr inbounds i32, ptr %p1, i64 %index
|
|
%ld1 = load i32, ptr %arrayidx, align 1
|
|
%cmp = icmp eq i32 %ld1, 1
|
|
br i1 %cmp, label %loop.inc, label %loop.end
|
|
|
|
loop.inc:
|
|
%arrayidx2 = getelementptr inbounds i64, ptr %p2, i64 %index
|
|
%ld2 = load i64, ptr %arrayidx2, align 8
|
|
%index.next = add i64 %index, 1
|
|
%exitcond = icmp ne i64 %index.next, 67
|
|
br i1 %exitcond, label %loop, label %loop.end
|
|
|
|
loop.end:
|
|
%retval = phi i64 [ %index, %loop ], [ %ld2, %loop.inc ]
|
|
ret i64 %retval
|
|
}
|
|
|
|
|
|
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 ==
|
|
|
|
|
|
define i64 @same_exit_block_pre_inc_use1_too_small_allocas() {
|
|
; CHECK-LABEL: LV: Checking a loop in 'same_exit_block_pre_inc_use1_too_small_allocas'
|
|
; CHECK: LV: Not vectorizing: Auto-vectorization of loops with potentially faulting load is not supported.
|
|
entry:
|
|
%p1 = alloca [42 x i8]
|
|
%p2 = alloca [42 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 ]
|
|
%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.inc, label %loop.end
|
|
|
|
loop.inc:
|
|
%index.next = add i64 %index, 1
|
|
%exitcond = icmp ne i64 %index.next, 67
|
|
br i1 %exitcond, label %loop, label %loop.end
|
|
|
|
loop.end:
|
|
%retval = phi i64 [ %index, %loop ], [ 67, %loop.inc ]
|
|
ret i64 %retval
|
|
}
|
|
|
|
|
|
define i64 @same_exit_block_pre_inc_use1_too_small_deref_ptrs(ptr dereferenceable(42) %p1, ptr dereferenceable(42) %p2) {
|
|
; CHECK-LABEL: LV: Checking a loop in 'same_exit_block_pre_inc_use1_too_small_deref_ptrs'
|
|
; CHECK: LV: Not vectorizing: Auto-vectorization of loops with potentially faulting load is not supported.
|
|
entry:
|
|
br label %loop
|
|
|
|
loop:
|
|
%index = phi i64 [ %index.next, %loop.inc ], [ 3, %entry ]
|
|
%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.inc, label %loop.end
|
|
|
|
loop.inc:
|
|
%index.next = add i64 %index, 1
|
|
%exitcond = icmp ne i64 %index.next, 67
|
|
br i1 %exitcond, label %loop, label %loop.end
|
|
|
|
loop.end:
|
|
%retval = phi i64 [ %index, %loop ], [ 67, %loop.inc ]
|
|
ret i64 %retval
|
|
}
|
|
|
|
|
|
define i64 @same_exit_block_pre_inc_use1_unknown_ptrs(ptr %p1, ptr %p2) {
|
|
; CHECK-LABEL: LV: Checking a loop in 'same_exit_block_pre_inc_use1_unknown_ptrs'
|
|
; CHECK: LV: Not vectorizing: Auto-vectorization of loops with potentially faulting load is not supported.
|
|
entry:
|
|
br label %loop
|
|
|
|
loop:
|
|
%index = phi i64 [ %index.next, %loop.inc ], [ 3, %entry ]
|
|
%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.inc, label %loop.end
|
|
|
|
loop.inc:
|
|
%index.next = add i64 %index, 1
|
|
%exitcond = icmp ne i64 %index.next, 67
|
|
br i1 %exitcond, label %loop, label %loop.end
|
|
|
|
loop.end:
|
|
%retval = phi i64 [ %index, %loop ], [ 67, %loop.inc ]
|
|
ret i64 %retval
|
|
}
|
|
|
|
define ptr @same_exit_block_strided_unknown_ptr(ptr %first, ptr %last, i32 %value) {
|
|
; CHECK-LABEL: LV: Checking a loop in 'same_exit_block_strided_unknown_ptr'
|
|
; CHECK: LV: Not vectorizing: Loop contains potentially faulting strided load.
|
|
entry:
|
|
%cond = icmp eq ptr %first, %last
|
|
br i1 %cond, label %return, label %for.body
|
|
|
|
for.body:
|
|
%first.addr = phi ptr [ %first, %entry ], [ %first.next, %for.inc ]
|
|
%1 = load i32, ptr %first.addr, align 4
|
|
%cond2 = icmp eq i32 %1, %value
|
|
br i1 %cond2, label %for.end, label %for.inc
|
|
|
|
for.inc:
|
|
%first.next = getelementptr inbounds i32, ptr %first.addr, i64 2
|
|
%cond3 = icmp eq ptr %first.next, %last
|
|
br i1 %cond3, label %for.end, label %for.body
|
|
|
|
for.end:
|
|
%retval.ph = phi ptr [ %first.addr, %for.body ], [ %last, %for.inc ]
|
|
br label %return
|
|
|
|
return:
|
|
%retval = phi ptr [ %first, %entry ], [ %retval.ph, %for.end ]
|
|
ret ptr %retval
|
|
}
|
|
|
|
; The early exit (i.e. unknown exit-not-taken count) is the latch - we don't
|
|
; support this yet.
|
|
define i64 @uncountable_exit_on_last_block() {
|
|
; CHECK-LABEL: LV: Checking a loop in 'uncountable_exit_on_last_block'
|
|
; CHECK: LV: Not vectorizing: Cannot determine exact exit count for latch block.
|
|
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, %search ], [ 3, %entry ]
|
|
%index.next = add i64 %index, 1
|
|
%exitcond = icmp ne i64 %index.next, 67
|
|
br i1 %exitcond, 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
|
|
|
|
loop.end:
|
|
%retval = phi i64 [ 64, %loop ], [ %index, %search ]
|
|
ret i64 %retval
|
|
}
|
|
|
|
|
|
; Multiple uncountable early exits are now supported.
|
|
define i64 @multiple_uncountable_exits() {
|
|
; CHECK-LABEL: LV: Checking a loop in 'multiple_uncountable_exits'
|
|
; CHECK: LV: We can vectorize this loop!
|
|
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 %search1
|
|
|
|
search1:
|
|
%index = phi i64 [ %index.next, %loop.inc ], [ 3, %entry ]
|
|
%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
|
|
%cmp1 = icmp eq i8 %ld1, %ld2
|
|
br i1 %cmp1, label %loop.end, label %search2
|
|
|
|
search2:
|
|
%cmp2 = icmp ult i8 %ld1, 34
|
|
br i1 %cmp2, label %loop.end, label %loop.inc
|
|
|
|
loop.inc:
|
|
%index.next = add i64 %index, 1
|
|
%exitcond = icmp ne i64 %index.next, 67
|
|
br i1 %exitcond, label %search1, label %loop.end
|
|
|
|
loop.end:
|
|
%retval = phi i64 [ %index, %search1 ], [ 100, %search2 ], [ 43, %loop.inc ]
|
|
ret i64 %retval
|
|
}
|
|
|
|
|
|
define i64 @uncountable_exit_infinite_loop() {
|
|
; CHECK-LABEL: LV: Checking a loop in 'uncountable_exit_infinite_loop'
|
|
; CHECK: LV: Not vectorizing: Cannot vectorize uncountable loop.
|
|
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 ]
|
|
%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.inc, label %loop.end
|
|
|
|
loop.inc:
|
|
%index.next = add i64 %index, 1
|
|
%exitcond = icmp ne i64 %index.next, 67
|
|
br label %loop
|
|
|
|
loop.end:
|
|
%retval = phi i64 [ %index, %loop ]
|
|
ret i64 %retval
|
|
}
|
|
|
|
|
|
define i64 @loop_contains_unsafe_call() {
|
|
; CHECK-LABEL: LV: Checking a loop in 'loop_contains_unsafe_call'
|
|
; CHECK: LV: Not vectorizing: Early exit loop contains operations that cannot be speculatively executed.
|
|
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 ]
|
|
%arrayidx = getelementptr inbounds i32, ptr %p1, i64 %index
|
|
%ld1 = load i32, ptr %arrayidx, align 1
|
|
%bad_call = call i32 @foo(i32 %ld1) #0
|
|
%cmp = icmp eq i32 %bad_call, 34
|
|
br i1 %cmp, label %loop.inc, label %loop.end
|
|
|
|
loop.inc:
|
|
%index.next = add i64 %index, 1
|
|
%exitcond = icmp ne i64 %index.next, 67
|
|
br i1 %exitcond, label %loop, label %loop.end
|
|
|
|
loop.end:
|
|
%retval = phi i64 [ %index, %loop ], [ 67, %loop.inc ]
|
|
ret i64 %retval
|
|
}
|
|
|
|
|
|
define i64 @loop_contains_unsafe_div() {
|
|
; CHECK-LABEL: LV: Checking a loop in 'loop_contains_unsafe_div'
|
|
; CHECK: LV: Not vectorizing: Early exit loop contains operations that cannot be speculatively executed.
|
|
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 ]
|
|
%arrayidx = getelementptr inbounds i8, ptr %p1, i64 %index
|
|
%ld1 = load i32, ptr %arrayidx, align 1
|
|
%div = udiv i32 20000, %ld1
|
|
%cmp = icmp eq i32 %div, 1
|
|
br i1 %cmp, label %loop.inc, label %loop.end
|
|
|
|
loop.inc:
|
|
%index.next = add i64 %index, 1
|
|
%exitcond = icmp ne i64 %index.next, 67
|
|
br i1 %exitcond, label %loop, label %loop.end
|
|
|
|
loop.end:
|
|
%retval = phi i64 [ %index, %loop ], [ 67, %loop.inc ]
|
|
ret i64 %retval
|
|
}
|
|
|
|
define void @exit_conditions_combined_in_single_branch(ptr noalias dereferenceable(40) %array, ptr readonly align 2 dereferenceable(40) %pred) {
|
|
; CHECK-LABEL: LV: Checking a loop in 'exit_conditions_combined_in_single_branch'
|
|
; CHECK: LV: Not vectorizing: Cannot vectorize uncountable loop.
|
|
entry:
|
|
br label %for.body
|
|
|
|
for.body: ; preds = %for.body, %entry
|
|
%iv = phi i64 [ 0, %entry ], [ %iv.next, %for.body ]
|
|
%st.addr = getelementptr inbounds nuw i16, ptr %array, i64 %iv
|
|
%data = load i16, ptr %st.addr, align 2
|
|
%inc = add nsw i16 %data, 1
|
|
store i16 %inc, ptr %st.addr, align 2
|
|
%ee.addr = getelementptr inbounds nuw i16, ptr %pred, i64 %iv
|
|
%ee.val = load i16, ptr %ee.addr, align 2
|
|
%ee.cond = icmp sgt i16 %ee.val, 500
|
|
%iv.next = add nuw nsw i64 %iv, 1
|
|
%counted.cond = icmp eq i64 %iv.next, 20
|
|
%or.cond = select i1 %ee.cond, i1 true, i1 %counted.cond
|
|
br i1 %or.cond, label %exit, label %for.body
|
|
|
|
exit: ; preds = %for.body
|
|
ret void
|
|
}
|
|
|
|
define i64 @same_exit_block_pre_inc_use1_with_reduction() {
|
|
; CHECK-LABEL: LV: Checking a loop in 'same_exit_block_pre_inc_use1_with_reduction'
|
|
; CHECK: LV: Not vectorizing: Found reductions or recurrences in early-exit loop.
|
|
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 ]
|
|
%red = phi i64 [ %red.next, %loop.inc ], [ 0, %entry ]
|
|
%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
|
|
%ld2.zext = zext i8 %ld2 to i64
|
|
%red.next = add i64 %red, %ld2.zext
|
|
%cmp3 = icmp eq i8 %ld1, %ld2
|
|
br i1 %cmp3, label %loop.inc, label %loop.end
|
|
|
|
loop.inc:
|
|
%index.next = add i64 %index, 1
|
|
%exitcond = icmp ne i64 %index.next, 67
|
|
br i1 %exitcond, label %loop, label %loop.end
|
|
|
|
loop.end:
|
|
%final.ind = phi i64 [ %index, %loop ], [ 67, %loop.inc ]
|
|
%retval = add i64 %red.next, %final.ind
|
|
ret i64 %retval
|
|
}
|
|
|
|
|
|
define i64 @uncountable_exit_has_multiple_outside_successors() {
|
|
; CHECK-LABEL: LV: Checking a loop in 'uncountable_exit_has_multiple_outside_successors'
|
|
; CHECK: LV: Not vectorizing: Loop contains an unsupported switch
|
|
entry:
|
|
%p1 = alloca [1024 x i8]
|
|
call void @init_mem(ptr %p1, i64 1024)
|
|
br label %loop
|
|
|
|
loop:
|
|
%index = phi i64 [ %index.next, %loop.inc ], [ 3, %entry ]
|
|
%arrayidx = getelementptr inbounds i8, ptr %p1, i64 %index
|
|
%ld1 = load i8, ptr %arrayidx, align 1
|
|
switch i8 %ld1, label %loop.inc [
|
|
i8 2, label %loop.end
|
|
i8 3, label %loop.surprise
|
|
]
|
|
|
|
loop.inc:
|
|
%index.next = add i64 %index, 1
|
|
%exitcond = icmp ne i64 %index.next, 67
|
|
br i1 %exitcond, label %loop, label %loop.end
|
|
|
|
loop.surprise:
|
|
ret i64 3
|
|
|
|
loop.end:
|
|
%retval = phi i64 [ %index, %loop ], [ 67, %loop.inc ]
|
|
ret i64 %retval
|
|
}
|
|
|
|
|
|
; Two early exits on parallel branches (neither dominates the other).
|
|
; This is now supported with predicated early exits.
|
|
define i64 @uncountable_exits_on_parallel_branches() {
|
|
; CHECK-LABEL: LV: Checking a loop in 'uncountable_exits_on_parallel_branches'
|
|
; CHECK: LV: We can vectorize this loop!
|
|
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 %header
|
|
|
|
header:
|
|
%index = phi i64 [ %index.next, %latch ], [ 3, %entry ]
|
|
%arrayidx = getelementptr inbounds i8, ptr %p1, i64 %index
|
|
%ld1 = load i8, ptr %arrayidx, align 1
|
|
%branch.cond = icmp sgt i8 %ld1, 0
|
|
br i1 %branch.cond, label %left, label %right
|
|
|
|
left:
|
|
%arrayidx.left = getelementptr inbounds i8, ptr %p2, i64 %index
|
|
%ld.left = load i8, ptr %arrayidx.left, align 1
|
|
%cmp.left = icmp eq i8 %ld1, %ld.left
|
|
br i1 %cmp.left, label %loop.end, label %latch
|
|
|
|
right:
|
|
%cmp.right = icmp ult i8 %ld1, 34
|
|
br i1 %cmp.right, label %loop.end, label %latch
|
|
|
|
latch:
|
|
%index.next = add i64 %index, 1
|
|
%exitcond = icmp ne i64 %index.next, 67
|
|
br i1 %exitcond, label %header, label %loop.end
|
|
|
|
loop.end:
|
|
%retval = phi i64 [ %index, %left ], [ 100, %right ], [ 43, %latch ]
|
|
ret i64 %retval
|
|
}
|
|
|
|
|
|
; Parallel uncountable exits with loop-invariant conditions.
|
|
; Note: This loop cannot be vectorized because the latch has no determinate
|
|
; exit count (loop is infinite without early exits).
|
|
define void @uncountable_exits_invariant_conditions(ptr %p, i1 %cond1, i1 %cond2, i1 %cond3) {
|
|
; CHECK-LABEL: LV: Checking a loop in 'uncountable_exits_invariant_conditions'
|
|
; CHECK: LV: Not vectorizing: Cannot determine exact exit count for latch block.
|
|
entry:
|
|
br label %loop.header
|
|
|
|
loop.header:
|
|
%iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
br i1 %cond1, label %then.1, label %else.1
|
|
|
|
else.1:
|
|
br i1 %cond2, label %then.2, label %exit
|
|
|
|
then.2:
|
|
%getelementptr.i = getelementptr i16, ptr %p, i64 %iv
|
|
%l = load i16, ptr %getelementptr.i, align 2
|
|
%ec = icmp ugt i16 %l, -25
|
|
br i1 %ec, label %exit, label %loop.latch
|
|
|
|
then.1:
|
|
br i1 %cond3, label %exit, label %loop.latch
|
|
|
|
loop.latch:
|
|
%iv.next = add i64 %iv, 1
|
|
br label %loop.header
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
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)" }
|