LV does not preserve LCSSA, it constructs it just before processing a loop to vectorize. Runtime check expressions are invariant to that loop, so expanding them should not break LCSSA form for the loop we are about to vectorize. This fixes a crash when discarding instructions generated when expanding runtime checks, if the expansion introduces LCSSA phis for values from other loops which are not in LCSSA form: we would introduce new LCSSA phis and update all outside users, some of which are not created by the expander and cannot be cleaned up. Fixes https://github.com/llvm/llvm-project/issues/158259. PR: https://github.com/llvm/llvm-project/pull/159556
80 lines
2.7 KiB
LLVM
80 lines
2.7 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
|
|
; RUN: opt -p loop-vectorize -S %s | FileCheck %s
|
|
|
|
target triple = "x86_64-unknown-linux-gnu"
|
|
|
|
declare ptr @get()
|
|
declare i1 @cond()
|
|
|
|
; Make sure we can clean up the created runtime checks, if vectorization isn't
|
|
; profitable.
|
|
define void @widget(i32 %arg, i64 %arg1, ptr %src) #0 {
|
|
; CHECK-LABEL: define void @widget(
|
|
; CHECK-SAME: i32 [[ARG:%.*]], i64 [[ARG1:%.*]], ptr [[SRC:%.*]]) #[[ATTR0:[0-9]+]] {
|
|
; CHECK-NEXT: [[ENTRY:.*:]]
|
|
; CHECK-NEXT: br label %[[LOOP_1_HEADER:.*]]
|
|
; CHECK: [[LOOP_1_HEADER]]:
|
|
; CHECK-NEXT: br label %[[INNER_1:.*]]
|
|
; CHECK: [[INNER_1]]:
|
|
; CHECK-NEXT: [[C_1:%.*]] = call i1 @cond()
|
|
; CHECK-NEXT: br i1 [[C_1]], label %[[INNER_2:.*]], label %[[INNER_1]]
|
|
; CHECK: [[INNER_2]]:
|
|
; CHECK-NEXT: [[LOAD:%.*]] = call ptr @get()
|
|
; CHECK-NEXT: [[C_2:%.*]] = call i1 @cond()
|
|
; CHECK-NEXT: br i1 [[C_2]], label %[[LOOP_2_PREHEADER:.*]], label %[[LOOP_1_LATCH:.*]]
|
|
; CHECK: [[LOOP_2_PREHEADER]]:
|
|
; CHECK-NEXT: br label %[[LOOP_2:.*]]
|
|
; CHECK: [[LOOP_1_LATCH]]:
|
|
; CHECK-NEXT: br label %[[LOOP_1_HEADER]]
|
|
; CHECK: [[LOOP_2]]:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[IV_NEXT:%.*]], %[[LOOP_2]] ], [ [[ARG]], %[[LOOP_2_PREHEADER]] ]
|
|
; CHECK-NEXT: [[PHI8:%.*]] = phi i32 [ [[OR:%.*]], %[[LOOP_2]] ], [ 99, %[[LOOP_2_PREHEADER]] ]
|
|
; CHECK-NEXT: [[GEP_SRC:%.*]] = getelementptr i32, ptr [[SRC]], i32 [[IV]]
|
|
; CHECK-NEXT: [[L:%.*]] = load i32, ptr [[GEP_SRC]], align 4
|
|
; CHECK-NEXT: [[OR]] = or i32 [[PHI8]], [[L]]
|
|
; CHECK-NEXT: store i32 [[OR]], ptr [[LOAD]], align 4
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
|
|
; CHECK-NEXT: [[EC:%.*]] = icmp eq i32 [[IV]], 100
|
|
; CHECK-NEXT: br i1 [[EC]], label %[[EXIT:.*]], label %[[LOOP_2]], !prof [[PROF0:![0-9]+]]
|
|
; CHECK: [[EXIT]]:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop.1.header
|
|
|
|
loop.1.header:
|
|
br label %inner.1
|
|
|
|
inner.1:
|
|
%c.1 = call i1 @cond()
|
|
br i1 %c.1, label %inner.2, label %inner.1
|
|
|
|
inner.2:
|
|
%load = call ptr @get()
|
|
%c.2 = call i1 @cond()
|
|
br i1 %c.2, label %loop.2, label %loop.1.latch
|
|
|
|
loop.1.latch:
|
|
br label %loop.1.header
|
|
|
|
loop.2:
|
|
%iv = phi i32 [ %arg, %inner.2 ], [ %iv.next, %loop.2 ]
|
|
%phi8 = phi i32 [ 99, %inner.2 ], [ %or, %loop.2 ]
|
|
%gep.src = getelementptr i32, ptr %src, i32 %iv
|
|
%l = load i32, ptr %gep.src, align 4
|
|
%or = or i32 %phi8, %l
|
|
store i32 %or, ptr %load, align 4
|
|
%iv.next = add i32 %iv, 1
|
|
%ec = icmp eq i32 %iv, 100
|
|
br i1 %ec, label %exit, label %loop.2, !prof !0
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
attributes #0 = { "target-features"="+avx2" }
|
|
!0 = !{!"branch_weights", i32 89478484, i32 1879048192}
|
|
;.
|
|
; CHECK: [[PROF0]] = !{!"branch_weights", i32 89478484, i32 1879048192}
|
|
;.
|