@@ -118,14 +118,16 @@ exit:
118118
119119declare void @store (i32 %val , ptr %p ) argmemonly writeonly nounwind
120120
121+ ; loop invariant calls to writeonly functions such as the above
122+ ; should be hoisted
121123define void @test (ptr %loc ) {
122124; CHECK-LABEL: define void @test(
123125; CHECK-SAME: ptr [[LOC:%.*]]) {
124126; CHECK-NEXT: [[ENTRY:.*]]:
127+ ; CHECK-NEXT: call void @store(i32 0, ptr [[LOC]])
125128; CHECK-NEXT: br label %[[LOOP:.*]]
126129; CHECK: [[LOOP]]:
127130; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
128- ; CHECK-NEXT: call void @store(i32 0, ptr [[LOC]])
129131; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
130132; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[IV]], 200
131133; CHECK-NEXT: br i1 [[CMP]], label %[[LOOP]], label %[[EXIT:.*]]
@@ -150,10 +152,10 @@ define void @test_multiexit(ptr %loc, i1 %earlycnd) {
150152; CHECK-LABEL: define void @test_multiexit(
151153; CHECK-SAME: ptr [[LOC:%.*]], i1 [[EARLYCND:%.*]]) {
152154; CHECK-NEXT: [[ENTRY:.*]]:
155+ ; CHECK-NEXT: call void @store(i32 0, ptr [[LOC]])
153156; CHECK-NEXT: br label %[[LOOP:.*]]
154157; CHECK: [[LOOP]]:
155158; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[BACKEDGE:.*]] ]
156- ; CHECK-NEXT: call void @store(i32 0, ptr [[LOC]])
157159; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
158160; CHECK-NEXT: br i1 [[EARLYCND]], label %[[EXIT1:.*]], label %[[BACKEDGE]]
159161; CHECK: [[BACKEDGE]]:
@@ -183,6 +185,97 @@ exit2:
183185 ret void
184186}
185187
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+
186279define void @neg_lv_value (ptr %loc ) {
187280; CHECK-LABEL: define void @neg_lv_value(
188281; CHECK-SAME: ptr [[LOC:%.*]]) {
@@ -406,14 +499,47 @@ exit:
406499 ret void
407500}
408501
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 ) {
410505; CHECK-LABEL: define void @neg_not_argmemonly(
411- ; CHECK-SAME: ptr [[LOC:%.*]]) {
506+ ; CHECK-SAME: ptr [[LOC:%.*]], ptr [[LOC2:%.*]] ) {
412507; CHECK-NEXT: [[ENTRY:.*]]:
413508; CHECK-NEXT: br label %[[LOOP:.*]]
414509; CHECK: [[LOOP]]:
415510; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
416511; 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]] ]
417543; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
418544; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[IV]], 200
419545; CHECK-NEXT: br i1 [[CMP]], label %[[LOOP]], label %[[EXIT:.*]]
0 commit comments