Skip to content

Commit dfa8741

Browse files
committedSep 13, 2017
[GVNHoist] Factor out reachability to search for anticipable instructions quickly
Factor out the reachability such that multiple queries to find reachability of values are fast. This is based on finding the ANTIC points in the CFG which do not change during hoisting. The ANTIC points are basically the dominance-frontiers in the inverse graph. So we introduce a data structure (CHI nodes) to keep track of values flowing out of a basic block. We only do this for values with multiple occurrences in the function as they are the potential hoistable candidates. This patch allows us to hoist instructions to a basic block with >2 successors, as well as deal with infinite loops in a trivial way. Relevant test cases are added to show the functionality as well as regression fixes from PR32821. Regression from previous GVNHoist: We do not hoist fully redundant expressions because fully redundant expressions are already handled by NewGVN Differential Revision: https://reviews.llvm.org/D35918 Reviewers: dberlin, sebpop, gberry, llvm-svn: 313116
1 parent d9d2a89 commit dfa8741

10 files changed

+952
-400
lines changed
 

‎llvm/lib/Transforms/Scalar/GVNHoist.cpp

+418-288
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
; RUN: opt -gvn-hoist -S < %s | FileCheck %s
2+
3+
; CHECK: store
4+
; CHECK-NOT: store
5+
6+
; Check that an instruction can be hoisted to a basic block
7+
; with more than two successors.
8+
9+
@G = external global i32, align 4
10+
11+
define void @foo(i32 %c1) {
12+
entry:
13+
switch i32 %c1, label %exit1 [
14+
i32 0, label %sw0
15+
i32 1, label %sw1
16+
]
17+
18+
sw0:
19+
store i32 1, i32* @G
20+
br label %exit
21+
22+
sw1:
23+
store i32 1, i32* @G
24+
br label %exit
25+
26+
exit1:
27+
store i32 1, i32* @G
28+
ret void
29+
exit:
30+
ret void
31+
}

‎llvm/test/Transforms/GVNHoist/hoist-mssa.ll

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
; RUN: opt -S -gvn-hoist < %s | FileCheck %s
1+
; RUN: opt -S -gvn-hoist -newgvn < %s | FileCheck %s
22

33
; Check that store hoisting works: there should be only one store left.
44
; CHECK-LABEL: @getopt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
; RUN: opt -gvn-hoist -newgvn -S < %s | FileCheck %s
2+
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
3+
target triple = "x86_64-unknown-linux-gnu"
4+
5+
@GlobalVar = internal global float 1.000000e+00
6+
7+
; Check that we hoist load and scalar expressions in dominator.
8+
; CHECK-LABEL: @dominatorHoisting
9+
; CHECK: load
10+
; CHECK: load
11+
; CHECK: fsub
12+
; CHECK: fmul
13+
; CHECK: load
14+
; CHECK: fsub
15+
; CHECK: fmul
16+
; CHECK-NOT: load
17+
; CHECK-NOT: fmul
18+
; CHECK-NOT: fsub
19+
define float @dominatorHoisting(float %d, float* %min, float* %max, float* %a) {
20+
entry:
21+
%div = fdiv float 1.000000e+00, %d
22+
%0 = load float, float* %min, align 4
23+
%1 = load float, float* %a, align 4
24+
%sub = fsub float %0, %1
25+
%mul = fmul float %sub, %div
26+
%2 = load float, float* %max, align 4
27+
%sub1 = fsub float %2, %1
28+
%mul2 = fmul float %sub1, %div
29+
%cmp = fcmp oge float %div, 0.000000e+00
30+
br i1 %cmp, label %if.then, label %if.end
31+
32+
if.then: ; preds = %entry
33+
%3 = load float, float* %max, align 4
34+
%4 = load float, float* %a, align 4
35+
%sub3 = fsub float %3, %4
36+
%mul4 = fmul float %sub3, %div
37+
%5 = load float, float* %min, align 4
38+
%sub5 = fsub float %5, %4
39+
%mul6 = fmul float %sub5, %div
40+
br label %if.end
41+
42+
if.end: ; preds = %entry
43+
%p1 = phi float [ %mul4, %if.then ], [ 0.000000e+00, %entry ]
44+
%p2 = phi float [ %mul6, %if.then ], [ 0.000000e+00, %entry ]
45+
46+
%x = fadd float %p1, %mul2
47+
%y = fadd float %p2, %mul
48+
%z = fadd float %x, %y
49+
ret float %z
50+
}
51+
52+
; Check that we hoist load and scalar expressions in dominator.
53+
; CHECK-LABEL: @domHoisting
54+
; CHECK: load
55+
; CHECK: load
56+
; CHECK: fsub
57+
; CHECK: fmul
58+
; CHECK: load
59+
; CHECK: fsub
60+
; CHECK: fmul
61+
; CHECK-NOT: load
62+
; CHECK-NOT: fmul
63+
; CHECK-NOT: fsub
64+
define float @domHoisting(float %d, float* %min, float* %max, float* %a) {
65+
entry:
66+
%div = fdiv float 1.000000e+00, %d
67+
%0 = load float, float* %min, align 4
68+
%1 = load float, float* %a, align 4
69+
%sub = fsub float %0, %1
70+
%mul = fmul float %sub, %div
71+
%2 = load float, float* %max, align 4
72+
%sub1 = fsub float %2, %1
73+
%mul2 = fmul float %sub1, %div
74+
%cmp = fcmp oge float %div, 0.000000e+00
75+
br i1 %cmp, label %if.then, label %if.else
76+
77+
if.then:
78+
%3 = load float, float* %max, align 4
79+
%4 = load float, float* %a, align 4
80+
%sub3 = fsub float %3, %4
81+
%mul4 = fmul float %sub3, %div
82+
%5 = load float, float* %min, align 4
83+
%sub5 = fsub float %5, %4
84+
%mul6 = fmul float %sub5, %div
85+
br label %if.end
86+
87+
if.else:
88+
%6 = load float, float* %max, align 4
89+
%7 = load float, float* %a, align 4
90+
%sub9 = fsub float %6, %7
91+
%mul10 = fmul float %sub9, %div
92+
%8 = load float, float* %min, align 4
93+
%sub12 = fsub float %8, %7
94+
%mul13 = fmul float %sub12, %div
95+
br label %if.end
96+
97+
if.end:
98+
%p1 = phi float [ %mul4, %if.then ], [ %mul10, %if.else ]
99+
%p2 = phi float [ %mul6, %if.then ], [ %mul13, %if.else ]
100+
101+
%x = fadd float %p1, %mul2
102+
%y = fadd float %p2, %mul
103+
%z = fadd float %x, %y
104+
ret float %z
105+
}

‎llvm/test/Transforms/GVNHoist/hoist-pr20242.ll

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
; RUN: opt -gvn-hoist -S < %s | FileCheck %s
1+
; RUN: opt -gvn-hoist -newgvn -gvn-hoist -S < %s | FileCheck %s
2+
; Test to demonstrate that newgvn creates opportunities for
3+
; more gvn-hoist when sibling branches contain identical expressions.
4+
25
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
36
target triple = "x86_64-unknown-linux-gnu"
47

‎llvm/test/Transforms/GVNHoist/hoist-pr28933.ll

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
; RUN: opt -S -gvn-hoist -verify-memoryssa < %s | FileCheck %s
1+
; RUN: opt -S -gvn-hoist -verify-memoryssa -newgvn < %s | FileCheck %s
22

33
; Check that we end up with one load and one store, in the right order
44
; CHECK-LABEL: define void @test_it(
55
; CHECK: store
6-
; CHECK-NEXT: load
76
; CHECK-NOT: store
87
; CHECK-NOT: load
98

‎llvm/test/Transforms/GVNHoist/hoist-recursive-geps.ll

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1-
; RUN: opt -gvn-hoist -S < %s | FileCheck %s
1+
; RUN: opt -gvn-hoist -newgvn -gvn-hoist -S < %s | FileCheck %s
2+
3+
; Check that recursive GEPs are hoisted. Since hoisting creates
4+
; fully redundant instructions, newgvn is run to remove them which then
5+
; creates more opportunites for hoisting.
26

3-
; Check that recursive GEPs are hoisted.
47
; CHECK-LABEL: @fun
5-
; CHECK: fdiv
68
; CHECK: load
9+
; CHECK: fdiv
710
; CHECK: load
811
; CHECK: load
912
; CHECK: load
1013
; CHECK: fsub
11-
; CHECK: fsub
1214
; CHECK: fmul
15+
; CHECK: fsub
1316
; CHECK: fmul
1417
; CHECK-NOT: fsub
1518
; CHECK-NOT: fmul

‎llvm/test/Transforms/GVNHoist/hoist.ll

+4-104
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ target triple = "x86_64-unknown-linux-gnu"
88
;
99
; CHECK-LABEL: @scalarsHoisting
1010
; CHECK: fsub
11-
; CHECK: fsub
1211
; CHECK: fmul
12+
; CHECK: fsub
1313
; CHECK: fmul
1414
; CHECK-NOT: fmul
1515
; CHECK-NOT: fsub
@@ -48,8 +48,8 @@ if.end: ; preds = %if.else, %if.then
4848
; CHECK: load
4949
; CHECK: load
5050
; CHECK: fsub
51-
; CHECK: fsub
5251
; CHECK: fmul
52+
; CHECK: fsub
5353
; CHECK: fmul
5454
; CHECK-NOT: load
5555
; CHECK-NOT: fmul
@@ -148,8 +148,8 @@ if.end: ; preds = %if.else, %if.then
148148
; CHECK: load
149149
; CHECK: load
150150
; CHECK: fsub
151-
; CHECK: fsub
152151
; CHECK: fmul
152+
; CHECK: fsub
153153
; CHECK: fmul
154154
; CHECK-NOT: load
155155
; CHECK-NOT: fmul
@@ -265,8 +265,8 @@ if.end:
265265
; CHECK: load
266266
; CHECK: load
267267
; CHECK: fsub
268-
; CHECK: fsub
269268
; CHECK: fmul
269+
; CHECK: fsub
270270
; CHECK: fmul
271271
; CHECK-NOT: load
272272
; CHECK-NOT: fmul
@@ -304,106 +304,6 @@ if.end: ; preds = %entry
304304
ret float %z
305305
}
306306

307-
; Check that we hoist load and scalar expressions in dominator.
308-
; CHECK-LABEL: @dominatorHoisting
309-
; CHECK: load
310-
; CHECK: load
311-
; CHECK: fsub
312-
; CHECK: fmul
313-
; CHECK: load
314-
; CHECK: fsub
315-
; CHECK: fmul
316-
; CHECK-NOT: load
317-
; CHECK-NOT: fmul
318-
; CHECK-NOT: fsub
319-
define float @dominatorHoisting(float %d, float* %min, float* %max, float* %a) {
320-
entry:
321-
%div = fdiv float 1.000000e+00, %d
322-
%0 = load float, float* %min, align 4
323-
%1 = load float, float* %a, align 4
324-
%sub = fsub float %0, %1
325-
%mul = fmul float %sub, %div
326-
%2 = load float, float* %max, align 4
327-
%sub1 = fsub float %2, %1
328-
%mul2 = fmul float %sub1, %div
329-
%cmp = fcmp oge float %div, 0.000000e+00
330-
br i1 %cmp, label %if.then, label %if.end
331-
332-
if.then: ; preds = %entry
333-
%3 = load float, float* %max, align 4
334-
%4 = load float, float* %a, align 4
335-
%sub3 = fsub float %3, %4
336-
%mul4 = fmul float %sub3, %div
337-
%5 = load float, float* %min, align 4
338-
%sub5 = fsub float %5, %4
339-
%mul6 = fmul float %sub5, %div
340-
br label %if.end
341-
342-
if.end: ; preds = %entry
343-
%p1 = phi float [ %mul4, %if.then ], [ 0.000000e+00, %entry ]
344-
%p2 = phi float [ %mul6, %if.then ], [ 0.000000e+00, %entry ]
345-
346-
%x = fadd float %p1, %mul2
347-
%y = fadd float %p2, %mul
348-
%z = fadd float %x, %y
349-
ret float %z
350-
}
351-
352-
; Check that we hoist load and scalar expressions in dominator.
353-
; CHECK-LABEL: @domHoisting
354-
; CHECK: load
355-
; CHECK: load
356-
; CHECK: fsub
357-
; CHECK: fmul
358-
; CHECK: load
359-
; CHECK: fsub
360-
; CHECK: fmul
361-
; CHECK-NOT: load
362-
; CHECK-NOT: fmul
363-
; CHECK-NOT: fsub
364-
define float @domHoisting(float %d, float* %min, float* %max, float* %a) {
365-
entry:
366-
%div = fdiv float 1.000000e+00, %d
367-
%0 = load float, float* %min, align 4
368-
%1 = load float, float* %a, align 4
369-
%sub = fsub float %0, %1
370-
%mul = fmul float %sub, %div
371-
%2 = load float, float* %max, align 4
372-
%sub1 = fsub float %2, %1
373-
%mul2 = fmul float %sub1, %div
374-
%cmp = fcmp oge float %div, 0.000000e+00
375-
br i1 %cmp, label %if.then, label %if.else
376-
377-
if.then:
378-
%3 = load float, float* %max, align 4
379-
%4 = load float, float* %a, align 4
380-
%sub3 = fsub float %3, %4
381-
%mul4 = fmul float %sub3, %div
382-
%5 = load float, float* %min, align 4
383-
%sub5 = fsub float %5, %4
384-
%mul6 = fmul float %sub5, %div
385-
br label %if.end
386-
387-
if.else:
388-
%6 = load float, float* %max, align 4
389-
%7 = load float, float* %a, align 4
390-
%sub9 = fsub float %6, %7
391-
%mul10 = fmul float %sub9, %div
392-
%8 = load float, float* %min, align 4
393-
%sub12 = fsub float %8, %7
394-
%mul13 = fmul float %sub12, %div
395-
br label %if.end
396-
397-
if.end:
398-
%p1 = phi float [ %mul4, %if.then ], [ %mul10, %if.else ]
399-
%p2 = phi float [ %mul6, %if.then ], [ %mul13, %if.else ]
400-
401-
%x = fadd float %p1, %mul2
402-
%y = fadd float %p2, %mul
403-
%z = fadd float %x, %y
404-
ret float %z
405-
}
406-
407307
; Check that we do not hoist loads past stores within a same basic block.
408308
; CHECK-LABEL: @noHoistInSingleBBWithStore
409309
; CHECK: load
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
; RUN: opt -S -gvn-hoist < %s | FileCheck %s
2+
3+
; Checking gvn-hoist in case of infinite loops and irreducible control flow.
4+
5+
; Check that bitcast is not hoisted beacuse down safety is not guaranteed.
6+
; CHECK-LABEL: @bazv1
7+
; CHECK: if.then.i:
8+
; CHECK: bitcast
9+
; CHECK-NEXT: load
10+
; CHECK: if.then4.i:
11+
; CHECK: bitcast
12+
; CHECK-NEXT: load
13+
14+
%class.bar = type { i8*, %class.base* }
15+
%class.base = type { i32 (...)** }
16+
17+
; Function Attrs: noreturn nounwind uwtable
18+
define void @bazv1() local_unnamed_addr {
19+
entry:
20+
%agg.tmp = alloca %class.bar, align 8
21+
%x.sroa.2.0..sroa_idx2 = getelementptr inbounds %class.bar, %class.bar* %agg.tmp, i64 0, i32 1
22+
store %class.base* null, %class.base** %x.sroa.2.0..sroa_idx2, align 8
23+
call void @_Z3foo3bar(%class.bar* nonnull %agg.tmp)
24+
%0 = load %class.base*, %class.base** %x.sroa.2.0..sroa_idx2, align 8
25+
%1 = bitcast %class.bar* %agg.tmp to %class.base*
26+
%cmp.i = icmp eq %class.base* %0, %1
27+
br i1 %cmp.i, label %if.then.i, label %if.else.i
28+
29+
if.then.i: ; preds = %entry
30+
%2 = bitcast %class.base* %0 to void (%class.base*)***
31+
%vtable.i = load void (%class.base*)**, void (%class.base*)*** %2, align 8
32+
%vfn.i = getelementptr inbounds void (%class.base*)*, void (%class.base*)** %vtable.i, i64 2
33+
%3 = load void (%class.base*)*, void (%class.base*)** %vfn.i, align 8
34+
call void %3(%class.base* %0)
35+
br label %while.cond.preheader
36+
37+
if.else.i: ; preds = %entry
38+
%tobool.i = icmp eq %class.base* %0, null
39+
br i1 %tobool.i, label %while.cond.preheader, label %if.then4.i
40+
41+
if.then4.i: ; preds = %if.else.i
42+
%4 = bitcast %class.base* %0 to void (%class.base*)***
43+
%vtable6.i = load void (%class.base*)**, void (%class.base*)*** %4, align 8
44+
%vfn7.i = getelementptr inbounds void (%class.base*)*, void (%class.base*)** %vtable6.i, i64 3
45+
%5 = load void (%class.base*)*, void (%class.base*)** %vfn7.i, align 8
46+
call void %5(%class.base* nonnull %0)
47+
br label %while.cond.preheader
48+
49+
while.cond.preheader: ; preds = %if.then.i, %if.else.i, %if.then4.i
50+
br label %while.cond
51+
52+
while.cond: ; preds = %while.cond.preheader, %while.cond
53+
%call = call i32 @sleep(i32 10)
54+
br label %while.cond
55+
}
56+
57+
declare void @_Z3foo3bar(%class.bar*) local_unnamed_addr
58+
59+
declare i32 @sleep(i32) local_unnamed_addr
60+
61+
; Check that the load is hoisted even if it is inside an irreducible control flow
62+
; because the load is anticipable on all paths.
63+
64+
; CHECK-LABEL: @bazv
65+
; CHECK: bb2:
66+
; CHECK-NOT: load
67+
; CHECK-NOT: bitcast
68+
69+
define void @bazv() {
70+
entry:
71+
%agg.tmp = alloca %class.bar, align 8
72+
%x= getelementptr inbounds %class.bar, %class.bar* %agg.tmp, i64 0, i32 1
73+
%0 = load %class.base*, %class.base** %x, align 8
74+
%1 = bitcast %class.bar* %agg.tmp to %class.base*
75+
%cmp.i = icmp eq %class.base* %0, %1
76+
br i1 %cmp.i, label %bb1, label %bb4
77+
78+
bb1:
79+
%b1 = bitcast %class.base* %0 to void (%class.base*)***
80+
%i = load void (%class.base*)**, void (%class.base*)*** %b1, align 8
81+
%vfn.i = getelementptr inbounds void (%class.base*)*, void (%class.base*)** %i, i64 2
82+
%cmp.j = icmp eq %class.base* %0, %1
83+
br i1 %cmp.j, label %bb2, label %bb3
84+
85+
bb2:
86+
%l1 = load void (%class.base*)*, void (%class.base*)** %vfn.i, align 8
87+
br label %bb3
88+
89+
bb3:
90+
%l2 = load void (%class.base*)*, void (%class.base*)** %vfn.i, align 8
91+
br label %bb2
92+
93+
bb4:
94+
%b2 = bitcast %class.base* %0 to void (%class.base*)***
95+
ret void
96+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
; RUN: opt -S -gvn-hoist < %s | FileCheck %s
2+
3+
; Checking gvn-hoist in case of indirect branches.
4+
5+
; Check that the bitcast is is not hoisted because it is after an indirect call
6+
; CHECK-LABEL: @foo
7+
; CHECK-LABEL: l1.preheader:
8+
; CHECK-NEXT: bitcast
9+
; CHECK-LABEL: l1
10+
; CHECK: bitcast
11+
12+
%class.bar = type { i8*, %class.base* }
13+
%class.base = type { i32 (...)** }
14+
15+
@bar = local_unnamed_addr global i32 ()* null, align 8
16+
@bar1 = local_unnamed_addr global i32 ()* null, align 8
17+
18+
define i32 @foo(i32* nocapture readonly %i) {
19+
entry:
20+
%agg.tmp = alloca %class.bar, align 8
21+
%x= getelementptr inbounds %class.bar, %class.bar* %agg.tmp, i64 0, i32 1
22+
%y = load %class.base*, %class.base** %x, align 8
23+
%0 = load i32, i32* %i, align 4
24+
%.off = add i32 %0, -1
25+
%switch = icmp ult i32 %.off, 2
26+
br i1 %switch, label %l1.preheader, label %sw.default
27+
28+
l1.preheader: ; preds = %sw.default, %entry
29+
%b1 = bitcast %class.base* %y to void (%class.base*)***
30+
br label %l1
31+
32+
l1: ; preds = %l1.preheader, %l1
33+
%1 = load i32 ()*, i32 ()** @bar, align 8
34+
%call = tail call i32 %1()
35+
%b2 = bitcast %class.base* %y to void (%class.base*)***
36+
br label %l1
37+
38+
sw.default: ; preds = %entry
39+
%2 = load i32 ()*, i32 ()** @bar1, align 8
40+
%call2 = tail call i32 %2()
41+
br label %l1.preheader
42+
}
43+
44+
45+
; Any instruction inside an infinite loop will not be hoisted because
46+
; there is no path to exit of the function.
47+
48+
; CHECK-LABEL: @foo1
49+
; CHECK-LABEL: l1.preheader:
50+
; CHECK-NEXT: bitcast
51+
; CHECK-LABEL: l1:
52+
; CHECK: bitcast
53+
54+
define i32 @foo1(i32* nocapture readonly %i) {
55+
entry:
56+
%agg.tmp = alloca %class.bar, align 8
57+
%x= getelementptr inbounds %class.bar, %class.bar* %agg.tmp, i64 0, i32 1
58+
%y = load %class.base*, %class.base** %x, align 8
59+
%0 = load i32, i32* %i, align 4
60+
%.off = add i32 %0, -1
61+
%switch = icmp ult i32 %.off, 2
62+
br i1 %switch, label %l1.preheader, label %sw.default
63+
64+
l1.preheader: ; preds = %sw.default, %entry
65+
%b1 = bitcast %class.base* %y to void (%class.base*)***
66+
%y1 = load %class.base*, %class.base** %x, align 8
67+
br label %l1
68+
69+
l1: ; preds = %l1.preheader, %l1
70+
%b2 = bitcast %class.base* %y to void (%class.base*)***
71+
%1 = load i32 ()*, i32 ()** @bar, align 8
72+
%y2 = load %class.base*, %class.base** %x, align 8
73+
%call = tail call i32 %1()
74+
br label %l1
75+
76+
sw.default: ; preds = %entry
77+
%2 = load i32 ()*, i32 ()** @bar1, align 8
78+
%call2 = tail call i32 %2()
79+
br label %l1.preheader
80+
}
81+
82+
; Check that bitcast is hoisted even when one of them is partially redundant.
83+
; CHECK-LABEL: @test13
84+
; CHECK: bitcast
85+
; CHECK-NOT: bitcast
86+
87+
define i32 @test13(i32* %P, i8* %Ptr, i32* nocapture readonly %i) {
88+
entry:
89+
%agg.tmp = alloca %class.bar, align 8
90+
%x= getelementptr inbounds %class.bar, %class.bar* %agg.tmp, i64 0, i32 1
91+
%y = load %class.base*, %class.base** %x, align 8
92+
indirectbr i8* %Ptr, [label %BrBlock, label %B2]
93+
94+
B2:
95+
%b1 = bitcast %class.base* %y to void (%class.base*)***
96+
store i32 4, i32 *%P
97+
br label %BrBlock
98+
99+
BrBlock:
100+
%b2 = bitcast %class.base* %y to void (%class.base*)***
101+
%L = load i32, i32* %P
102+
%C = icmp eq i32 %L, 42
103+
br i1 %C, label %T, label %F
104+
105+
T:
106+
ret i32 123
107+
F:
108+
ret i32 1422
109+
}
110+
111+
; Check that the bitcast is not hoisted because anticipability
112+
; cannot be guaranteed here as one of the indirect branch targets
113+
; do not have the bitcast instruction.
114+
115+
; CHECK-LABEL: @test14
116+
; CHECK-LABEL: B2:
117+
; CHECK-NEXT: bitcast
118+
; CHECK-LABEL: BrBlock:
119+
; CHECK-NEXT: bitcast
120+
121+
define i32 @test14(i32* %P, i8* %Ptr, i32* nocapture readonly %i) {
122+
entry:
123+
%agg.tmp = alloca %class.bar, align 8
124+
%x= getelementptr inbounds %class.bar, %class.bar* %agg.tmp, i64 0, i32 1
125+
%y = load %class.base*, %class.base** %x, align 8
126+
indirectbr i8* %Ptr, [label %BrBlock, label %B2, label %T]
127+
128+
B2:
129+
%b1 = bitcast %class.base* %y to void (%class.base*)***
130+
store i32 4, i32 *%P
131+
br label %BrBlock
132+
133+
BrBlock:
134+
%b2 = bitcast %class.base* %y to void (%class.base*)***
135+
%L = load i32, i32* %P
136+
%C = icmp eq i32 %L, 42
137+
br i1 %C, label %T, label %F
138+
139+
T:
140+
%pi = load i32, i32* %i, align 4
141+
ret i32 %pi
142+
F:
143+
%pl = load i32, i32* %P
144+
ret i32 %pl
145+
}
146+
147+
148+
; Check that the bitcast is not hoisted because of a cycle
149+
; due to indirect branches
150+
; CHECK-LABEL: @test16
151+
; CHECK-LABEL: B2:
152+
; CHECK-NEXT: bitcast
153+
; CHECK-LABEL: BrBlock:
154+
; CHECK-NEXT: bitcast
155+
156+
define i32 @test16(i32* %P, i8* %Ptr, i32* nocapture readonly %i) {
157+
entry:
158+
%agg.tmp = alloca %class.bar, align 8
159+
%x= getelementptr inbounds %class.bar, %class.bar* %agg.tmp, i64 0, i32 1
160+
%y = load %class.base*, %class.base** %x, align 8
161+
indirectbr i8* %Ptr, [label %BrBlock, label %B2]
162+
163+
B2:
164+
%b1 = bitcast %class.base* %y to void (%class.base*)***
165+
%0 = load i32, i32* %i, align 4
166+
store i32 %0, i32 *%P
167+
br label %BrBlock
168+
169+
BrBlock:
170+
%b2 = bitcast %class.base* %y to void (%class.base*)***
171+
%L = load i32, i32* %P
172+
%C = icmp eq i32 %L, 42
173+
br i1 %C, label %T, label %F
174+
175+
T:
176+
indirectbr i32* %P, [label %BrBlock, label %B2]
177+
178+
F:
179+
indirectbr i8* %Ptr, [label %BrBlock, label %B2]
180+
}
181+
182+
183+
@_ZTIi = external constant i8*
184+
185+
; Check that an instruction is not hoisted out of landing pad (%lpad4)
186+
; Also within a landing pad no redundancies are removed by gvn-hoist,
187+
; however an instruction may be hoisted into a landing pad if
188+
; landing pad has direct branches (e.g., %lpad to %catch1, %catch)
189+
; This CFG has a cycle (%lpad -> %catch1 -> %lpad4 -> %lpad)
190+
191+
; CHECK-LABEL: @foo2
192+
; Check that nothing gets hoisted out of %lpad
193+
; CHECK-LABEL: lpad:
194+
; CHECK: %bc1 = add i32 %0, 10
195+
; CHECK: %bc7 = add i32 %0, 10
196+
197+
; Check that the add is hoisted
198+
; CHECK-LABEL: catch1:
199+
; CHECK-NEXT: invoke
200+
201+
; Check that the add is hoisted
202+
; CHECK-LABEL: catch:
203+
; CHECK-NEXT: load
204+
205+
; Check that other adds are not hoisted
206+
; CHECK-LABEL: lpad4:
207+
; CHECK: %bc5 = add i32 %0, 10
208+
; CHECK-LABEL: unreachable:
209+
; CHECK: %bc2 = add i32 %0, 10
210+
211+
; Function Attrs: noinline uwtable
212+
define i32 @foo2(i32* nocapture readonly %i) local_unnamed_addr personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
213+
entry:
214+
%0 = load i32, i32* %i, align 4
215+
%cmp = icmp eq i32 %0, 0
216+
br i1 %cmp, label %try.cont, label %if.then
217+
218+
if.then:
219+
%exception = tail call i8* @__cxa_allocate_exception(i64 4) #2
220+
%1 = bitcast i8* %exception to i32*
221+
store i32 %0, i32* %1, align 16
222+
invoke void @__cxa_throw(i8* %exception, i8* bitcast (i8** @_ZTIi to i8*), i8* null) #3
223+
to label %unreachable unwind label %lpad
224+
225+
lpad:
226+
%2 = landingpad { i8*, i32 }
227+
catch i8* bitcast (i8** @_ZTIi to i8*)
228+
catch i8* null
229+
%bc1 = add i32 %0, 10
230+
%3 = extractvalue { i8*, i32 } %2, 0
231+
%4 = extractvalue { i8*, i32 } %2, 1
232+
%5 = tail call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*)) #2
233+
%matches = icmp eq i32 %4, %5
234+
%bc7 = add i32 %0, 10
235+
%6 = tail call i8* @__cxa_begin_catch(i8* %3) #2
236+
br i1 %matches, label %catch1, label %catch
237+
238+
catch1:
239+
%bc3 = add i32 %0, 10
240+
invoke void @__cxa_rethrow() #3
241+
to label %unreachable unwind label %lpad4
242+
243+
catch:
244+
%bc4 = add i32 %0, 10
245+
%7 = load i32, i32* %i, align 4
246+
%add = add nsw i32 %7, 1
247+
tail call void @__cxa_end_catch()
248+
br label %try.cont
249+
250+
lpad4:
251+
%8 = landingpad { i8*, i32 }
252+
cleanup
253+
%bc5 = add i32 %0, 10
254+
tail call void @__cxa_end_catch() #2
255+
invoke void @__cxa_throw(i8* %exception, i8* bitcast (i8** @_ZTIi to i8*), i8* null) #3
256+
to label %unreachable unwind label %lpad
257+
258+
try.cont:
259+
%k.0 = phi i32 [ %add, %catch ], [ 0, %entry ]
260+
%bc6 = add i32 %0, 10
261+
ret i32 %k.0
262+
263+
unreachable:
264+
%bc2 = add i32 %0, 10
265+
ret i32 %bc2
266+
}
267+
268+
declare i8* @__cxa_allocate_exception(i64) local_unnamed_addr
269+
270+
declare void @__cxa_throw(i8*, i8*, i8*) local_unnamed_addr
271+
272+
declare i32 @__gxx_personality_v0(...)
273+
274+
; Function Attrs: nounwind readnone
275+
declare i32 @llvm.eh.typeid.for(i8*) #1
276+
277+
declare i8* @__cxa_begin_catch(i8*) local_unnamed_addr
278+
279+
declare void @__cxa_end_catch() local_unnamed_addr
280+
281+
declare void @__cxa_rethrow() local_unnamed_addr
282+
283+
attributes #1 = { nounwind readnone }
284+
attributes #2 = { nounwind }
285+
attributes #3 = { noreturn }

0 commit comments

Comments
 (0)
Please sign in to comment.