@@ -86,8 +86,8 @@ define i32 @test3(ptr nocapture readonly %P, i32 %i) {
8686; CHECK-LABEL: @test3(
8787; CHECK-NEXT: entry:
8888; 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]]
9191; CHECK-NEXT: ]
9292; CHECK: sw.bb:
9393; CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[I]] to i64
@@ -190,8 +190,8 @@ define i32 @test6(ptr nocapture readonly %P, i32 %i, i1 %cond) {
190190; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 [[IDXPROM]]
191191; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
192192; 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]]
195195; CHECK-NEXT: ]
196196; CHECK: sw.bb:
197197; CHECK-NEXT: br label [[SW_EPILOG]]
@@ -272,3 +272,114 @@ abort:
272272 call void @abort ()
273273 unreachable
274274}
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