@@ -118,14 +118,16 @@ exit:
118
118
119
119
declare void @store (i32 %val , ptr %p ) argmemonly writeonly nounwind
120
120
121
+ ; loop invariant calls to writeonly functions such as the above
122
+ ; should be hoisted
121
123
define void @test (ptr %loc ) {
122
124
; CHECK-LABEL: define void @test(
123
125
; CHECK-SAME: ptr [[LOC:%.*]]) {
124
126
; CHECK-NEXT: [[ENTRY:.*]]:
127
+ ; CHECK-NEXT: call void @store(i32 0, ptr [[LOC]])
125
128
; CHECK-NEXT: br label %[[LOOP:.*]]
126
129
; CHECK: [[LOOP]]:
127
130
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
128
- ; CHECK-NEXT: call void @store(i32 0, ptr [[LOC]])
129
131
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
130
132
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[IV]], 200
131
133
; CHECK-NEXT: br i1 [[CMP]], label %[[LOOP]], label %[[EXIT:.*]]
@@ -150,10 +152,10 @@ define void @test_multiexit(ptr %loc, i1 %earlycnd) {
150
152
; CHECK-LABEL: define void @test_multiexit(
151
153
; CHECK-SAME: ptr [[LOC:%.*]], i1 [[EARLYCND:%.*]]) {
152
154
; CHECK-NEXT: [[ENTRY:.*]]:
155
+ ; CHECK-NEXT: call void @store(i32 0, ptr [[LOC]])
153
156
; CHECK-NEXT: br label %[[LOOP:.*]]
154
157
; CHECK: [[LOOP]]:
155
158
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[BACKEDGE:.*]] ]
156
- ; CHECK-NEXT: call void @store(i32 0, ptr [[LOC]])
157
159
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
158
160
; CHECK-NEXT: br i1 [[EARLYCND]], label %[[EXIT1:.*]], label %[[BACKEDGE]]
159
161
; CHECK: [[BACKEDGE]]:
@@ -183,6 +185,97 @@ exit2:
183
185
ret void
184
186
}
185
187
188
+ ; cannot be hoisted because the two pointers can alias one another
189
+ define void @neg_two_pointer (ptr %loc , ptr %otherloc ) {
190
+ ; CHECK-LABEL: define void @neg_two_pointer(
191
+ ; CHECK-SAME: ptr [[LOC:%.*]], ptr [[OTHERLOC:%.*]]) {
192
+ ; CHECK-NEXT: [[ENTRY:.*]]:
193
+ ; CHECK-NEXT: br label %[[LOOP:.*]]
194
+ ; CHECK: [[LOOP]]:
195
+ ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
196
+ ; CHECK-NEXT: call void @store(i32 0, ptr [[LOC]])
197
+ ; CHECK-NEXT: call void @store(i32 1, ptr [[OTHERLOC]])
198
+ ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
199
+ ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[IV]], 200
200
+ ; CHECK-NEXT: br i1 [[CMP]], label %[[LOOP]], label %[[EXIT:.*]]
201
+ ; CHECK: [[EXIT]]:
202
+ ; CHECK-NEXT: ret void
203
+ ;
204
+ entry:
205
+ br label %loop
206
+
207
+ loop:
208
+ %iv = phi i32 [0 , %entry ], [%iv.next , %loop ]
209
+ call void @store (i32 0 , ptr %loc )
210
+ call void @store (i32 1 , ptr %otherloc )
211
+ %iv.next = add i32 %iv , 1
212
+ %cmp = icmp slt i32 %iv , 200
213
+ br i1 %cmp , label %loop , label %exit
214
+ exit:
215
+ ret void
216
+ }
217
+
218
+ ; hoisted due to pointers not aliasing
219
+ define void @two_pointer_noalias (ptr noalias %loc , ptr noalias %otherloc ) {
220
+ ; CHECK-LABEL: define void @two_pointer_noalias(
221
+ ; CHECK-SAME: ptr noalias [[LOC:%.*]], ptr noalias [[OTHERLOC:%.*]]) {
222
+ ; CHECK-NEXT: [[ENTRY:.*]]:
223
+ ; CHECK-NEXT: call void @store(i32 0, ptr [[LOC]])
224
+ ; CHECK-NEXT: call void @store(i32 1, ptr [[OTHERLOC]])
225
+ ; CHECK-NEXT: br label %[[LOOP:.*]]
226
+ ; CHECK: [[LOOP]]:
227
+ ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
228
+ ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
229
+ ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[IV]], 200
230
+ ; CHECK-NEXT: br i1 [[CMP]], label %[[LOOP]], label %[[EXIT:.*]]
231
+ ; CHECK: [[EXIT]]:
232
+ ; CHECK-NEXT: ret void
233
+ ;
234
+ entry:
235
+ br label %loop
236
+
237
+ loop:
238
+ %iv = phi i32 [0 , %entry ], [%iv.next , %loop ]
239
+ call void @store (i32 0 , ptr %loc )
240
+ call void @store (i32 1 , ptr %otherloc )
241
+ %iv.next = add i32 %iv , 1
242
+ %cmp = icmp slt i32 %iv , 200
243
+ br i1 %cmp , label %loop , label %exit
244
+ exit:
245
+ ret void
246
+ }
247
+
248
+ ; when there's a conflicting read, store call should not be hoisted
249
+ define void @neg_conflicting_read (ptr noalias %loc , ptr noalias %otherloc ) {
250
+ ; CHECK-LABEL: define void @neg_conflicting_read(
251
+ ; CHECK-SAME: ptr noalias [[LOC:%.*]], ptr noalias [[OTHERLOC:%.*]]) {
252
+ ; CHECK-NEXT: [[ENTRY:.*]]:
253
+ ; CHECK-NEXT: call void @store(i32 0, ptr [[LOC]])
254
+ ; CHECK-NEXT: br label %[[LOOP:.*]]
255
+ ; CHECK: [[LOOP]]:
256
+ ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
257
+ ; CHECK-NEXT: call void @load(i32 0, ptr [[LOC]])
258
+ ; CHECK-NEXT: call void @store(i32 0, ptr [[LOC]])
259
+ ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
260
+ ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[IV]], 200
261
+ ; CHECK-NEXT: br i1 [[CMP]], label %[[LOOP]], label %[[EXIT:.*]]
262
+ ; CHECK: [[EXIT]]:
263
+ ; CHECK-NEXT: ret void
264
+ ;
265
+ entry:
266
+ call void @store (i32 0 , ptr %loc )
267
+ br label %loop
268
+ loop:
269
+ %iv = phi i32 [0 , %entry ], [%iv.next , %loop ]
270
+ call void @load (i32 0 , ptr %loc )
271
+ call void @store (i32 0 , ptr %loc )
272
+ %iv.next = add i32 %iv , 1
273
+ %cmp = icmp slt i32 %iv , 200
274
+ br i1 %cmp , label %loop , label %exit
275
+ exit:
276
+ ret void
277
+ }
278
+
186
279
define void @neg_lv_value (ptr %loc ) {
187
280
; CHECK-LABEL: define void @neg_lv_value(
188
281
; CHECK-SAME: ptr [[LOC:%.*]]) {
@@ -406,14 +499,47 @@ exit:
406
499
ret void
407
500
}
408
501
409
- define void @neg_not_argmemonly (ptr %loc ) {
502
+ ; when the call is not argmemonly and is not the only memory access we
503
+ ; do not hoist
504
+ define void @neg_not_argmemonly (ptr %loc , ptr %loc2 ) {
410
505
; CHECK-LABEL: define void @neg_not_argmemonly(
411
- ; CHECK-SAME: ptr [[LOC:%.*]]) {
506
+ ; CHECK-SAME: ptr [[LOC:%.*]], ptr [[LOC2:%.*]] ) {
412
507
; CHECK-NEXT: [[ENTRY:.*]]:
413
508
; CHECK-NEXT: br label %[[LOOP:.*]]
414
509
; CHECK: [[LOOP]]:
415
510
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
416
511
; CHECK-NEXT: call void @not_argmemonly(i32 0, ptr [[LOC]])
512
+ ; CHECK-NEXT: call void @load(i32 0, ptr [[LOC2]])
513
+ ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
514
+ ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[IV]], 200
515
+ ; CHECK-NEXT: br i1 [[CMP]], label %[[LOOP]], label %[[EXIT:.*]]
516
+ ; CHECK: [[EXIT]]:
517
+ ; CHECK-NEXT: ret void
518
+ ;
519
+ entry:
520
+ br label %loop
521
+
522
+ loop:
523
+ %iv = phi i32 [0 , %entry ], [%iv.next , %loop ]
524
+ call void @not_argmemonly (i32 0 , ptr %loc )
525
+ call void @load (i32 0 , ptr %loc2 )
526
+ %iv.next = add i32 %iv , 1
527
+ %cmp = icmp slt i32 %iv , 200
528
+ br i1 %cmp , label %loop , label %exit
529
+
530
+ exit:
531
+ ret void
532
+ }
533
+
534
+ ; when the call is not argmemonly and is only memory access we hoist it
535
+ define void @not_argmemonly_hoisted (ptr %loc , ptr %loc2 ) {
536
+ ; CHECK-LABEL: define void @not_argmemonly_hoisted(
537
+ ; CHECK-SAME: ptr [[LOC:%.*]], ptr [[LOC2:%.*]]) {
538
+ ; CHECK-NEXT: [[ENTRY:.*]]:
539
+ ; CHECK-NEXT: call void @not_argmemonly(i32 0, ptr [[LOC]])
540
+ ; CHECK-NEXT: br label %[[LOOP:.*]]
541
+ ; CHECK: [[LOOP]]:
542
+ ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
417
543
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
418
544
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[IV]], 200
419
545
; CHECK-NEXT: br i1 [[CMP]], label %[[LOOP]], label %[[EXIT:.*]]
0 commit comments