llvm.org GIT mirror llvm / cef4495
[Tests] Add tests for a possible loop predication transform variant As highlighted by tests, if one of the operands is loop variant, but guaranteed to have the same value on all iterations, we have a missed oppurtunity. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@357403 91177308-0d34-0410-b5e6-96231b3b80d8 Philip Reames 5 months ago
1 changed file(s) with 247 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
1 ; RUN: opt -S -basicaa -loop-predication < %s 2>&1 | FileCheck %s
2 ; RUN: opt -S -aa-pipeline=basic-aa -passes='require,require,loop(loop-predication)' < %s 2>&1 | FileCheck %s
3
4 declare void @llvm.experimental.guard(i1, ...)
5
6 @UNKNOWN = external global i1
7
8 define i32 @neg_length_variant(i32* %array, i32* %length, i32 %n) {
9 ; CHECK-LABEL: @neg_length_variant(
10 ; CHECK-NEXT: entry:
11 ; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i32 [[N:%.*]], 0
12 ; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
13 ; CHECK: loop.preheader:
14 ; CHECK-NEXT: br label [[LOOP:%.*]]
15 ; CHECK: loop:
16 ; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
17 ; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
18 ; CHECK-NEXT: [[UNKNOWN:%.*]] = load volatile i1, i1* @UNKNOWN
19 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[UNKNOWN]]) [ "deopt"() ]
20 ; CHECK-NEXT: [[LEN:%.*]] = load i32, i32* [[LENGTH:%.*]], align 4
21 ; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LEN]]
22 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WITHIN_BOUNDS]], i32 9) [ "deopt"() ]
23 ; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
24 ; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY:%.*]], i64 [[I_I64]]
25 ; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, i32* [[ARRAY_I_PTR]], align 4
26 ; CHECK-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
27 ; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
28 ; CHECK-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
29 ; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
30 ; CHECK: exit.loopexit:
31 ; CHECK-NEXT: [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
32 ; CHECK-NEXT: br label [[EXIT]]
33 ; CHECK: exit:
34 ; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
35 ; CHECK-NEXT: ret i32 [[RESULT]]
36 ;
37 entry:
38 %tmp5 = icmp eq i32 %n, 0
39 br i1 %tmp5, label %exit, label %loop.preheader
40
41 loop.preheader:
42 br label %loop
43
44 loop:
45 %loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
46 %i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
47 %unknown = load volatile i1, i1* @UNKNOWN
48 call void (i1, ...) @llvm.experimental.guard(i1 %unknown) [ "deopt"() ]
49 %len = load i32, i32* %length, align 4
50 %within.bounds = icmp ult i32 %i, %len
51 call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
52
53 %i.i64 = zext i32 %i to i64
54 %array.i.ptr = getelementptr inbounds i32, i32* %array, i64 %i.i64
55 %array.i = load i32, i32* %array.i.ptr, align 4
56 %loop.acc.next = add i32 %loop.acc, %array.i
57
58 %i.next = add nuw i32 %i, 1
59 %continue = icmp ult i32 %i.next, %n
60 br i1 %continue, label %loop, label %exit
61
62 exit:
63 %result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
64 ret i32 %result
65 }
66
67 define i32 @invariant_load(i32* %array, i32* %length, i32 %n) {
68 ; CHECK-LABEL: @invariant_load(
69 ; CHECK-NEXT: entry:
70 ; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i32 [[N:%.*]], 0
71 ; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
72 ; CHECK: loop.preheader:
73 ; CHECK-NEXT: br label [[LOOP:%.*]]
74 ; CHECK: loop:
75 ; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
76 ; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
77 ; CHECK-NEXT: [[UNKNOWN:%.*]] = load volatile i1, i1* @UNKNOWN
78 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[UNKNOWN]]) [ "deopt"() ]
79 ; CHECK-NEXT: [[LEN:%.*]] = load i32, i32* [[LENGTH:%.*]], align 4, !invariant.load !0
80 ; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LEN]]
81 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WITHIN_BOUNDS]], i32 9) [ "deopt"() ]
82 ; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
83 ; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY:%.*]], i64 [[I_I64]]
84 ; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, i32* [[ARRAY_I_PTR]], align 4
85 ; CHECK-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
86 ; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
87 ; CHECK-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
88 ; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
89 ; CHECK: exit.loopexit:
90 ; CHECK-NEXT: [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
91 ; CHECK-NEXT: br label [[EXIT]]
92 ; CHECK: exit:
93 ; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
94 ; CHECK-NEXT: ret i32 [[RESULT]]
95 ;
96 entry:
97 %tmp5 = icmp eq i32 %n, 0
98 br i1 %tmp5, label %exit, label %loop.preheader
99
100 loop.preheader:
101 br label %loop
102
103 loop:
104 %loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
105 %i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
106 %unknown = load volatile i1, i1* @UNKNOWN
107 call void (i1, ...) @llvm.experimental.guard(i1 %unknown) [ "deopt"() ]
108 %len = load i32, i32* %length, align 4, !invariant.load !{}
109 %within.bounds = icmp ult i32 %i, %len
110 call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
111
112 %i.i64 = zext i32 %i to i64
113 %array.i.ptr = getelementptr inbounds i32, i32* %array, i64 %i.i64
114 %array.i = load i32, i32* %array.i.ptr, align 4
115 %loop.acc.next = add i32 %loop.acc, %array.i
116
117 %i.next = add nuw i32 %i, 1
118 %continue = icmp ult i32 %i.next, %n
119 br i1 %continue, label %loop, label %exit
120
121 exit:
122 %result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
123 ret i32 %result
124 }
125
126 @Length = external constant i32
127
128 define i32 @constant_memory(i32* %array, i32 %n) {
129 ; CHECK-LABEL: @constant_memory(
130 ; CHECK-NEXT: entry:
131 ; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i32 [[N:%.*]], 0
132 ; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
133 ; CHECK: loop.preheader:
134 ; CHECK-NEXT: br label [[LOOP:%.*]]
135 ; CHECK: loop:
136 ; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
137 ; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
138 ; CHECK-NEXT: [[UNKNOWN:%.*]] = load volatile i1, i1* @UNKNOWN
139 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[UNKNOWN]]) [ "deopt"() ]
140 ; CHECK-NEXT: [[LEN:%.*]] = load i32, i32* @Length, align 4
141 ; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], [[LEN]]
142 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WITHIN_BOUNDS]], i32 9) [ "deopt"() ]
143 ; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
144 ; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY:%.*]], i64 [[I_I64]]
145 ; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, i32* [[ARRAY_I_PTR]], align 4
146 ; CHECK-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
147 ; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
148 ; CHECK-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
149 ; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
150 ; CHECK: exit.loopexit:
151 ; CHECK-NEXT: [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
152 ; CHECK-NEXT: br label [[EXIT]]
153 ; CHECK: exit:
154 ; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
155 ; CHECK-NEXT: ret i32 [[RESULT]]
156 ;
157 entry:
158 %tmp5 = icmp eq i32 %n, 0
159 br i1 %tmp5, label %exit, label %loop.preheader
160
161 loop.preheader:
162 br label %loop
163
164 loop:
165 %loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
166 %i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
167 %unknown = load volatile i1, i1* @UNKNOWN
168 call void (i1, ...) @llvm.experimental.guard(i1 %unknown) [ "deopt"() ]
169 %len = load i32, i32* @Length, align 4
170 %within.bounds = icmp ult i32 %i, %len
171 call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
172
173 %i.i64 = zext i32 %i to i64
174 %array.i.ptr = getelementptr inbounds i32, i32* %array, i64 %i.i64
175 %array.i = load i32, i32* %array.i.ptr, align 4
176 %loop.acc.next = add i32 %loop.acc, %array.i
177
178 %i.next = add nuw i32 %i, 1
179 %continue = icmp ult i32 %i.next, %n
180 br i1 %continue, label %loop, label %exit
181
182 exit:
183 %result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
184 ret i32 %result
185 }
186
187 define i32 @constant_length(i32* %array, i32 %n) {
188 ; CHECK-LABEL: @constant_length(
189 ; CHECK-NEXT: entry:
190 ; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i32 [[N:%.*]], 0
191 ; CHECK-NEXT: br i1 [[TMP5]], label [[EXIT:%.*]], label [[LOOP_PREHEADER:%.*]]
192 ; CHECK: loop.preheader:
193 ; CHECK-NEXT: [[TMP0:%.*]] = icmp ule i32 [[N]], 20
194 ; CHECK-NEXT: [[TMP1:%.*]] = and i1 true, [[TMP0]]
195 ; CHECK-NEXT: br label [[LOOP:%.*]]
196 ; CHECK: loop:
197 ; CHECK-NEXT: [[LOOP_ACC:%.*]] = phi i32 [ [[LOOP_ACC_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
198 ; CHECK-NEXT: [[I:%.*]] = phi i32 [ [[I_NEXT:%.*]], [[LOOP]] ], [ 0, [[LOOP_PREHEADER]] ]
199 ; CHECK-NEXT: [[UNKNOWN:%.*]] = load volatile i1, i1* @UNKNOWN
200 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[UNKNOWN]]) [ "deopt"() ]
201 ; CHECK-NEXT: [[WITHIN_BOUNDS:%.*]] = icmp ult i32 [[I]], 20
202 ; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[TMP1]], i32 9) [ "deopt"() ]
203 ; CHECK-NEXT: [[I_I64:%.*]] = zext i32 [[I]] to i64
204 ; CHECK-NEXT: [[ARRAY_I_PTR:%.*]] = getelementptr inbounds i32, i32* [[ARRAY:%.*]], i64 [[I_I64]]
205 ; CHECK-NEXT: [[ARRAY_I:%.*]] = load i32, i32* [[ARRAY_I_PTR]], align 4
206 ; CHECK-NEXT: [[LOOP_ACC_NEXT]] = add i32 [[LOOP_ACC]], [[ARRAY_I]]
207 ; CHECK-NEXT: [[I_NEXT]] = add nuw i32 [[I]], 1
208 ; CHECK-NEXT: [[CONTINUE:%.*]] = icmp ult i32 [[I_NEXT]], [[N]]
209 ; CHECK-NEXT: br i1 [[CONTINUE]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
210 ; CHECK: exit.loopexit:
211 ; CHECK-NEXT: [[LOOP_ACC_NEXT_LCSSA:%.*]] = phi i32 [ [[LOOP_ACC_NEXT]], [[LOOP]] ]
212 ; CHECK-NEXT: br label [[EXIT]]
213 ; CHECK: exit:
214 ; CHECK-NEXT: [[RESULT:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[LOOP_ACC_NEXT_LCSSA]], [[EXIT_LOOPEXIT]] ]
215 ; CHECK-NEXT: ret i32 [[RESULT]]
216 ;
217 entry:
218 %tmp5 = icmp eq i32 %n, 0
219 br i1 %tmp5, label %exit, label %loop.preheader
220
221 loop.preheader:
222 br label %loop
223
224 loop:
225 %loop.acc = phi i32 [ %loop.acc.next, %loop ], [ 0, %loop.preheader ]
226 %i = phi i32 [ %i.next, %loop ], [ 0, %loop.preheader ]
227 %unknown = load volatile i1, i1* @UNKNOWN
228 call void (i1, ...) @llvm.experimental.guard(i1 %unknown) [ "deopt"() ]
229 %within.bounds = icmp ult i32 %i, 20
230 call void (i1, ...) @llvm.experimental.guard(i1 %within.bounds, i32 9) [ "deopt"() ]
231
232 %i.i64 = zext i32 %i to i64
233 %array.i.ptr = getelementptr inbounds i32, i32* %array, i64 %i.i64
234 %array.i = load i32, i32* %array.i.ptr, align 4
235 %loop.acc.next = add i32 %loop.acc, %array.i
236
237 %i.next = add nuw i32 %i, 1
238 %continue = icmp ult i32 %i.next, %n
239 br i1 %continue, label %loop, label %exit
240
241 exit:
242 %result = phi i32 [ 0, %entry ], [ %loop.acc.next, %loop ]
243 ret i32 %result
244 }
245
246