@@ -86,8 +86,8 @@ define i32 @test3(ptr nocapture readonly %P, i32 %i) {
86
86
; CHECK-LABEL: @test3(
87
87
; CHECK-NEXT: entry:
88
88
; CHECK-NEXT: switch i32 [[I:%.*]], label [[SW_EPILOG:%.*]] [
89
- ; CHECK-NEXT: i32 5, label [[SW_BB:%.*]]
90
- ; CHECK-NEXT: i32 2, label [[SW_BB]]
89
+ ; CHECK-NEXT: i32 5, label [[SW_BB:%.*]]
90
+ ; CHECK-NEXT: i32 2, label [[SW_BB]]
91
91
; CHECK-NEXT: ]
92
92
; CHECK: sw.bb:
93
93
; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I]] to i64
@@ -190,8 +190,8 @@ define i32 @test6(ptr nocapture readonly %P, i32 %i, i1 %cond) {
190
190
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 [[IDXPROM]]
191
191
; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
192
192
; CHECK-NEXT: switch i32 [[I]], label [[SW_BB:%.*]] [
193
- ; CHECK-NEXT: i32 5, label [[SW_EPILOG:%.*]]
194
- ; CHECK-NEXT: i32 2, label [[SW_EPILOG]]
193
+ ; CHECK-NEXT: i32 5, label [[SW_EPILOG:%.*]]
194
+ ; CHECK-NEXT: i32 2, label [[SW_EPILOG]]
195
195
; CHECK-NEXT: ]
196
196
; CHECK: sw.bb:
197
197
; CHECK-NEXT: br label [[SW_EPILOG]]
@@ -272,3 +272,114 @@ abort:
272
272
call void @abort ()
273
273
unreachable
274
274
}
275
+
276
+ ; Loads marked invariant can be sunk past potential memory writes.
277
+
278
+ define i32 @invariant_load_metadata (ptr %p , i1 %cond ) {
279
+ ; CHECK-LABEL: @invariant_load_metadata(
280
+ ; CHECK-NEXT: entry:
281
+ ; CHECK-NEXT: br i1 [[COND:%.*]], label [[BLOCK:%.*]], label [[END:%.*]]
282
+ ; CHECK: block:
283
+ ; CHECK-NEXT: call void @fn()
284
+ ; CHECK-NEXT: br label [[END]]
285
+ ; CHECK: end:
286
+ ; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[P:%.*]], align 4, !invariant.load [[META0:![0-9]+]]
287
+ ; CHECK-NEXT: ret i32 [[V]]
288
+ ;
289
+ entry:
290
+ %v = load i32 , ptr %p , !invariant.load !0
291
+ br i1 %cond , label %block , label %end
292
+ block:
293
+ call void @fn ()
294
+ br label %end
295
+ end:
296
+ ret i32 %v
297
+ }
298
+
299
+ ; Loads not marked invariant cannot be sunk past potential memory writes.
300
+
301
+ define i32 @invariant_load_neg (ptr %p , i1 %cond ) {
302
+ ; CHECK-LABEL: @invariant_load_neg(
303
+ ; CHECK-NEXT: entry:
304
+ ; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[P:%.*]], align 4
305
+ ; CHECK-NEXT: br i1 [[COND:%.*]], label [[BLOCK:%.*]], label [[END:%.*]]
306
+ ; CHECK: block:
307
+ ; CHECK-NEXT: call void @fn()
308
+ ; CHECK-NEXT: br label [[END]]
309
+ ; CHECK: end:
310
+ ; CHECK-NEXT: ret i32 [[V]]
311
+ ;
312
+ entry:
313
+ %v = load i32 , ptr %p
314
+ br i1 %cond , label %block , label %end
315
+ block:
316
+ call void @fn ()
317
+ br label %end
318
+ end:
319
+ ret i32 %v
320
+ }
321
+
322
+ ; Loads that aren't marked invariant but used in one branch
323
+ ; can be sunk to that branch.
324
+
325
+ define void @invariant_load_use_in_br (ptr %p , i1 %cond ) {
326
+ ; CHECK-LABEL: @invariant_load_use_in_br(
327
+ ; CHECK-NEXT: entry:
328
+ ; CHECK-NEXT: br i1 [[COND:%.*]], label [[TRUE_BR:%.*]], label [[FALSE_BR:%.*]]
329
+ ; CHECK: true.br:
330
+ ; CHECK-NEXT: call void @fn()
331
+ ; CHECK-NEXT: br label [[EXIT:%.*]]
332
+ ; CHECK: false.br:
333
+ ; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[P:%.*]], align 4
334
+ ; CHECK-NEXT: call void @fn(i32 [[VAL]])
335
+ ; CHECK-NEXT: br label [[EXIT]]
336
+ ; CHECK: exit:
337
+ ; CHECK-NEXT: ret void
338
+ ;
339
+ entry:
340
+ %val = load i32 , ptr %p
341
+ br i1 %cond , label %true.br , label %false.br
342
+ true .br:
343
+ call void @fn ()
344
+ br label %exit
345
+ false .br:
346
+ call void @fn (i32 %val )
347
+ br label %exit
348
+ exit:
349
+ ret void
350
+ }
351
+
352
+ ; Invariant loads marked with metadata can be sunk past calls.
353
+
354
+ define void @invariant_load_metadata_call (ptr %p , i1 %cond ) {
355
+ ; CHECK-LABEL: @invariant_load_metadata_call(
356
+ ; CHECK-NEXT: entry:
357
+ ; CHECK-NEXT: call void @fn()
358
+ ; CHECK-NEXT: br i1 [[COND:%.*]], label [[TRUE_BR:%.*]], label [[FALSE_BR:%.*]]
359
+ ; CHECK: true.br:
360
+ ; CHECK-NEXT: call void @fn()
361
+ ; CHECK-NEXT: br label [[EXIT:%.*]]
362
+ ; CHECK: false.br:
363
+ ; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[P:%.*]], align 4, !invariant.load [[META0]]
364
+ ; CHECK-NEXT: call void @fn(i32 [[VAL]])
365
+ ; CHECK-NEXT: br label [[EXIT]]
366
+ ; CHECK: exit:
367
+ ; CHECK-NEXT: ret void
368
+ ;
369
+ entry:
370
+ %val = load i32 , ptr %p , !invariant.load !0
371
+ call void @fn ()
372
+ br i1 %cond , label %true.br , label %false.br
373
+ true .br:
374
+ call void @fn ()
375
+ br label %exit
376
+ false .br:
377
+ call void @fn (i32 %val )
378
+ br label %exit
379
+ exit:
380
+ ret void
381
+ }
382
+
383
+ declare void @fn ()
384
+
385
+ !0 = !{}
0 commit comments