Skip to content

Commit 76f3776

Browse files
authored
[NFC][LoopVectorize] Restructure simple early exit tests (#112721)
The previous simple_early_exit.ll was growing too large and difficult to manage. Instead I've decided to refactor the tests by splitting out into notional groups: 1. single_early_exit.ll: loops with a single uncountable exit that do not have live-outs from the loop. 2. single_early_exit_live_outs.ll: loops with a single uncountable exit with live-outs. 3. multi_early_exit.ll: loops with multiple early exits, i.e. a mixture of countable and uncountable exits, but with no live-outs from the loop. 4. multi_early_exit_live_outs.ll: as above, but with live-outs. 5. single_early_exit_unsafe_ptrs.ll: loops with a single uncountable exit, but with pointers that are not unconditionally dereferenceable. 6. unsupported_early_exit.ll: loops with uncountable exits that we cannot yet vectorise. 7. early_exit_legality.ll: tests the debug output from LoopVectorizationLegality to make sure we handle different scenarios correctly. Only the last test now requires asserts. Over time some of these tests should start vectorising as more support is added. I also tried to rename the multi early exit tests to make it clear there what mixture of countable and uncountable exits are present.
1 parent c85611e commit 76f3776

File tree

8 files changed

+2646
-2118
lines changed

8 files changed

+2646
-2118
lines changed

llvm/test/Transforms/LoopVectorize/early_exit_legality.ll

Lines changed: 542 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
2+
; RUN: opt -S < %s -p loop-vectorize | FileCheck %s
3+
4+
declare void @init_mem(ptr, i64);
5+
6+
define i64 @one_uncountable_two_countable_same_exit_phi_of_consts() {
7+
; CHECK-LABEL: define i64 @one_uncountable_two_countable_same_exit_phi_of_consts() {
8+
; CHECK-NEXT: entry:
9+
; CHECK-NEXT: [[P1:%.*]] = alloca [1024 x i8], align 1
10+
; CHECK-NEXT: [[P2:%.*]] = alloca [1024 x i8], align 1
11+
; CHECK-NEXT: call void @init_mem(ptr [[P1]], i64 1024)
12+
; CHECK-NEXT: call void @init_mem(ptr [[P2]], i64 1024)
13+
; CHECK-NEXT: br label [[LOOP:%.*]]
14+
; CHECK: loop:
15+
; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ [[INDEX_NEXT:%.*]], [[LOOP_INC:%.*]] ], [ 3, [[ENTRY:%.*]] ]
16+
; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i64 [[INDEX]], 64
17+
; CHECK-NEXT: br i1 [[CMP1]], label [[SEARCH:%.*]], label [[LOOP_END:%.*]]
18+
; CHECK: search:
19+
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[P1]], i64 [[INDEX]]
20+
; CHECK-NEXT: [[LD1:%.*]] = load i8, ptr [[ARRAYIDX]], align 1
21+
; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds i8, ptr [[P2]], i64 [[INDEX]]
22+
; CHECK-NEXT: [[LD2:%.*]] = load i8, ptr [[ARRAYIDX1]], align 1
23+
; CHECK-NEXT: [[CMP3:%.*]] = icmp eq i8 [[LD1]], [[LD2]]
24+
; CHECK-NEXT: br i1 [[CMP3]], label [[LOOP_END]], label [[LOOP_INC]]
25+
; CHECK: loop.inc:
26+
; CHECK-NEXT: [[INDEX_NEXT]] = add i64 [[INDEX]], 1
27+
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[INDEX_NEXT]], 128
28+
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[LOOP_END]]
29+
; CHECK: loop.end:
30+
; CHECK-NEXT: [[RETVAL:%.*]] = phi i64 [ 0, [[LOOP]] ], [ 1, [[SEARCH]] ], [ 0, [[LOOP_INC]] ]
31+
; CHECK-NEXT: ret i64 [[RETVAL]]
32+
;
33+
entry:
34+
%p1 = alloca [1024 x i8]
35+
%p2 = alloca [1024 x i8]
36+
call void @init_mem(ptr %p1, i64 1024)
37+
call void @init_mem(ptr %p2, i64 1024)
38+
br label %loop
39+
40+
loop:
41+
%index = phi i64 [ %index.next, %loop.inc ], [ 3, %entry ]
42+
%cmp1 = icmp ne i64 %index, 64
43+
br i1 %cmp1, label %search, label %loop.end
44+
45+
search:
46+
%arrayidx = getelementptr inbounds i8, ptr %p1, i64 %index
47+
%ld1 = load i8, ptr %arrayidx, align 1
48+
%arrayidx1 = getelementptr inbounds i8, ptr %p2, i64 %index
49+
%ld2 = load i8, ptr %arrayidx1, align 1
50+
%cmp3 = icmp eq i8 %ld1, %ld2
51+
br i1 %cmp3, label %loop.end, label %loop.inc
52+
53+
loop.inc:
54+
%index.next = add i64 %index, 1
55+
%exitcond = icmp ne i64 %index.next, 128
56+
br i1 %exitcond, label %loop, label %loop.end
57+
58+
loop.end:
59+
%retval = phi i64 [ 0, %loop ], [ 1, %search ], [ 0, %loop.inc ]
60+
ret i64 %retval
61+
}
62+
63+
64+
define i64 @one_uncountable_two_countable_diff_exit_no_phis() {
65+
; CHECK-LABEL: define i64 @one_uncountable_two_countable_diff_exit_no_phis() {
66+
; CHECK-NEXT: entry:
67+
; CHECK-NEXT: [[P1:%.*]] = alloca [1024 x i8], align 1
68+
; CHECK-NEXT: [[P2:%.*]] = alloca [1024 x i8], align 1
69+
; CHECK-NEXT: call void @init_mem(ptr [[P1]], i64 1024)
70+
; CHECK-NEXT: call void @init_mem(ptr [[P2]], i64 1024)
71+
; CHECK-NEXT: br label [[LOOP:%.*]]
72+
; CHECK: loop:
73+
; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ [[INDEX_NEXT:%.*]], [[LOOP_INC:%.*]] ], [ 3, [[ENTRY:%.*]] ]
74+
; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i64 [[INDEX]], 64
75+
; CHECK-NEXT: br i1 [[CMP1]], label [[SEARCH:%.*]], label [[LOOP_END:%.*]]
76+
; CHECK: search:
77+
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[P1]], i64 [[INDEX]]
78+
; CHECK-NEXT: [[LD1:%.*]] = load i8, ptr [[ARRAYIDX]], align 1
79+
; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds i8, ptr [[P2]], i64 [[INDEX]]
80+
; CHECK-NEXT: [[LD2:%.*]] = load i8, ptr [[ARRAYIDX1]], align 1
81+
; CHECK-NEXT: [[CMP3:%.*]] = icmp eq i8 [[LD1]], [[LD2]]
82+
; CHECK-NEXT: br i1 [[CMP3]], label [[LOOP_END_EARLY:%.*]], label [[LOOP_INC]]
83+
; CHECK: loop.inc:
84+
; CHECK-NEXT: [[INDEX_NEXT]] = add i64 [[INDEX]], 1
85+
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[INDEX_NEXT]], 128
86+
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[LOOP_END]]
87+
; CHECK: loop.end.early:
88+
; CHECK-NEXT: ret i64 1
89+
; CHECK: loop.end:
90+
; CHECK-NEXT: ret i64 0
91+
;
92+
entry:
93+
%p1 = alloca [1024 x i8]
94+
%p2 = alloca [1024 x i8]
95+
call void @init_mem(ptr %p1, i64 1024)
96+
call void @init_mem(ptr %p2, i64 1024)
97+
br label %loop
98+
99+
loop:
100+
%index = phi i64 [ %index.next, %loop.inc ], [ 3, %entry ]
101+
%cmp1 = icmp ne i64 %index, 64
102+
br i1 %cmp1, label %search, label %loop.end
103+
104+
search:
105+
%arrayidx = getelementptr inbounds i8, ptr %p1, i64 %index
106+
%ld1 = load i8, ptr %arrayidx, align 1
107+
%arrayidx1 = getelementptr inbounds i8, ptr %p2, i64 %index
108+
%ld2 = load i8, ptr %arrayidx1, align 1
109+
%cmp3 = icmp eq i8 %ld1, %ld2
110+
br i1 %cmp3, label %loop.end.early, label %loop.inc
111+
112+
loop.inc:
113+
%index.next = add i64 %index, 1
114+
%exitcond = icmp ne i64 %index.next, 128
115+
br i1 %exitcond, label %loop, label %loop.end
116+
117+
loop.end.early:
118+
ret i64 1
119+
120+
loop.end:
121+
ret i64 0
122+
}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
2+
; RUN: opt -S < %s -p loop-vectorize | FileCheck %s
3+
4+
declare void @init_mem(ptr, i64);
5+
6+
; There are multiple exit blocks - two of them have an exact representation for the
7+
; exit-not-taken counts and the other is unknown, i.e. the "early exit".
8+
define i64 @one_uncountable_two_countable_same_exit() {
9+
; CHECK-LABEL: define i64 @one_uncountable_two_countable_same_exit() {
10+
; CHECK-NEXT: entry:
11+
; CHECK-NEXT: [[P1:%.*]] = alloca [1024 x i8], align 1
12+
; CHECK-NEXT: [[P2:%.*]] = alloca [1024 x i8], align 1
13+
; CHECK-NEXT: call void @init_mem(ptr [[P1]], i64 1024)
14+
; CHECK-NEXT: call void @init_mem(ptr [[P2]], i64 1024)
15+
; CHECK-NEXT: br label [[LOOP:%.*]]
16+
; CHECK: loop:
17+
; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ [[INDEX_NEXT:%.*]], [[LOOP_INC:%.*]] ], [ 3, [[ENTRY:%.*]] ]
18+
; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i64 [[INDEX]], 64
19+
; CHECK-NEXT: br i1 [[CMP1]], label [[SEARCH:%.*]], label [[LOOP_END:%.*]]
20+
; CHECK: search:
21+
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[P1]], i64 [[INDEX]]
22+
; CHECK-NEXT: [[LD1:%.*]] = load i8, ptr [[ARRAYIDX]], align 1
23+
; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds i8, ptr [[P2]], i64 [[INDEX]]
24+
; CHECK-NEXT: [[LD2:%.*]] = load i8, ptr [[ARRAYIDX1]], align 1
25+
; CHECK-NEXT: [[CMP3:%.*]] = icmp eq i8 [[LD1]], [[LD2]]
26+
; CHECK-NEXT: br i1 [[CMP3]], label [[LOOP_END]], label [[LOOP_INC]]
27+
; CHECK: loop.inc:
28+
; CHECK-NEXT: [[INDEX_NEXT]] = add i64 [[INDEX]], 1
29+
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[INDEX_NEXT]], 128
30+
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[LOOP_END]]
31+
; CHECK: loop.end:
32+
; CHECK-NEXT: [[RETVAL:%.*]] = phi i64 [ 64, [[LOOP]] ], [ [[INDEX]], [[SEARCH]] ], [ 128, [[LOOP_INC]] ]
33+
; CHECK-NEXT: ret i64 [[RETVAL]]
34+
;
35+
entry:
36+
%p1 = alloca [1024 x i8]
37+
%p2 = alloca [1024 x i8]
38+
call void @init_mem(ptr %p1, i64 1024)
39+
call void @init_mem(ptr %p2, i64 1024)
40+
br label %loop
41+
42+
loop:
43+
%index = phi i64 [ %index.next, %loop.inc ], [ 3, %entry ]
44+
%cmp1 = icmp ne i64 %index, 64
45+
br i1 %cmp1, label %search, label %loop.end
46+
47+
search:
48+
%arrayidx = getelementptr inbounds i8, ptr %p1, i64 %index
49+
%ld1 = load i8, ptr %arrayidx, align 1
50+
%arrayidx1 = getelementptr inbounds i8, ptr %p2, i64 %index
51+
%ld2 = load i8, ptr %arrayidx1, align 1
52+
%cmp3 = icmp eq i8 %ld1, %ld2
53+
br i1 %cmp3, label %loop.end, label %loop.inc
54+
55+
loop.inc:
56+
%index.next = add i64 %index, 1
57+
%exitcond = icmp ne i64 %index.next, 128
58+
br i1 %exitcond, label %loop, label %loop.end
59+
60+
loop.end:
61+
%retval = phi i64 [ 64, %loop ], [ %index, %search ], [ 128, %loop.inc ]
62+
ret i64 %retval
63+
}
64+
65+
66+
define i64 @one_uncountable_two_countable_diff_exit() {
67+
; CHECK-LABEL: define i64 @one_uncountable_two_countable_diff_exit() {
68+
; CHECK-NEXT: entry:
69+
; CHECK-NEXT: [[P1:%.*]] = alloca [1024 x i8], align 1
70+
; CHECK-NEXT: [[P2:%.*]] = alloca [1024 x i8], align 1
71+
; CHECK-NEXT: call void @init_mem(ptr [[P1]], i64 1024)
72+
; CHECK-NEXT: call void @init_mem(ptr [[P2]], i64 1024)
73+
; CHECK-NEXT: br label [[LOOP:%.*]]
74+
; CHECK: loop:
75+
; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ [[INDEX_NEXT:%.*]], [[LOOP_INC:%.*]] ], [ 3, [[ENTRY:%.*]] ]
76+
; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i64 [[INDEX]], 64
77+
; CHECK-NEXT: br i1 [[CMP1]], label [[SEARCH:%.*]], label [[LOOP_END:%.*]]
78+
; CHECK: search:
79+
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[P1]], i64 [[INDEX]]
80+
; CHECK-NEXT: [[LD1:%.*]] = load i8, ptr [[ARRAYIDX]], align 1
81+
; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds i8, ptr [[P2]], i64 [[INDEX]]
82+
; CHECK-NEXT: [[LD2:%.*]] = load i8, ptr [[ARRAYIDX1]], align 1
83+
; CHECK-NEXT: [[CMP3:%.*]] = icmp eq i8 [[LD1]], [[LD2]]
84+
; CHECK-NEXT: br i1 [[CMP3]], label [[LOOP_END_EARLY:%.*]], label [[LOOP_INC]]
85+
; CHECK: loop.inc:
86+
; CHECK-NEXT: [[INDEX_NEXT]] = add i64 [[INDEX]], 1
87+
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[INDEX_NEXT]], 128
88+
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[LOOP_END]]
89+
; CHECK: loop.end.early:
90+
; CHECK-NEXT: [[RET_EARLY:%.*]] = phi i64 [ [[INDEX]], [[SEARCH]] ]
91+
; CHECK-NEXT: ret i64 [[RET_EARLY]]
92+
; CHECK: loop.end:
93+
; CHECK-NEXT: [[RETVAL:%.*]] = phi i64 [ 64, [[LOOP]] ], [ 128, [[LOOP_INC]] ]
94+
; CHECK-NEXT: ret i64 [[RETVAL]]
95+
;
96+
entry:
97+
%p1 = alloca [1024 x i8]
98+
%p2 = alloca [1024 x i8]
99+
call void @init_mem(ptr %p1, i64 1024)
100+
call void @init_mem(ptr %p2, i64 1024)
101+
br label %loop
102+
103+
loop:
104+
%index = phi i64 [ %index.next, %loop.inc ], [ 3, %entry ]
105+
%cmp1 = icmp ne i64 %index, 64
106+
br i1 %cmp1, label %search, label %loop.end
107+
108+
search:
109+
%arrayidx = getelementptr inbounds i8, ptr %p1, i64 %index
110+
%ld1 = load i8, ptr %arrayidx, align 1
111+
%arrayidx1 = getelementptr inbounds i8, ptr %p2, i64 %index
112+
%ld2 = load i8, ptr %arrayidx1, align 1
113+
%cmp3 = icmp eq i8 %ld1, %ld2
114+
br i1 %cmp3, label %loop.end.early, label %loop.inc
115+
116+
loop.inc:
117+
%index.next = add i64 %index, 1
118+
%exitcond = icmp ne i64 %index.next, 128
119+
br i1 %exitcond, label %loop, label %loop.end
120+
121+
loop.end.early:
122+
%ret.early = phi i64 [ %index, %search ]
123+
ret i64 %ret.early
124+
125+
loop.end:
126+
%retval = phi i64 [ 64, %loop ], [ 128, %loop.inc ]
127+
ret i64 %retval
128+
}

0 commit comments

Comments
 (0)