• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1; RUN: opt -S -callsite-splitting < %s | FileCheck --check-prefix=CHECK %s
2; RUN: opt -S -callsite-splitting -callsite-splitting-duplication-threshold=0 < %s | FileCheck --check-prefix=NODUP %s
3
4; Instructions before a call that will be pushed to its predecessors
5; with uses after the callsite, must be patched up as PHI nodes in
6; the join block.
7define i32* @test_split_branch_phi(i32* %ptrarg, i32 %i) {
8Header:
9  %tobool = icmp ne i32* %ptrarg, null
10  br i1 %tobool, label %TBB, label %CallSite
11
12TBB:                                    ; preds = %Header
13  %arrayidx = getelementptr inbounds i32, i32* %ptrarg, i64 42
14  %0 = load i32, i32* %arrayidx, align 4
15  %tobool1 = icmp ne i32 %0, 0
16  br i1 %tobool1, label %CallSite, label %End
17
18CallSite:                                          ; preds = %TBB, %Header
19  %somepointer = getelementptr i32, i32* %ptrarg, i64 18
20  call void @bar(i32* %ptrarg, i32 %i)
21  br label %End
22
23End:                                           ; preds = %CallSite, %TBB
24  %somepointerphi = phi i32* [ %somepointer, %CallSite ], [ null, %TBB ]
25  ret i32* %somepointerphi
26}
27; NODUP-LABEL: test_split_branch_phi
28; NODUP-NOT: split
29; CHECK-LABEL: Header.split
30; CHECK: %[[V1:somepointer[0-9]+]] = getelementptr i32, i32* %ptrarg, i64 18
31; CHECK: call void @bar(i32* null, i32 %i)
32; CHECK: br label %CallSite
33; CHECK-LABEL: TBB.split:
34; CHECK: %[[V2:somepointer[0-9]+]] = getelementptr i32, i32* %ptrarg, i64 18
35; CHECK: call void @bar(i32* nonnull %ptrarg, i32 %i)
36; CHECK: br label %CallSite
37; CHECK: CallSite:
38; CHECK: phi i32* [ %[[V1]], %Header.split ], [ %[[V2]], %TBB.split ]
39
40
41define void @split_branch_no_extra_phi(i32* %ptrarg, i32 %i) {
42Header:
43  %tobool = icmp ne i32* %ptrarg, null
44  br i1 %tobool, label %TBB, label %CallSite
45
46TBB:                                    ; preds = %Header
47  %arrayidx = getelementptr inbounds i32, i32* %ptrarg, i64 42
48  %0 = load i32, i32* %arrayidx, align 4
49  %tobool1 = icmp ne i32 %0, 0
50  br i1 %tobool1, label %CallSite, label %End
51
52CallSite:                                          ; preds = %TBB, %Header
53  %i.add = add i32 %i, 99
54  call void @bar(i32* %ptrarg, i32 %i.add)
55  br label %End
56
57End:                                           ; preds = %CallSite, %TBB
58  ret void
59}
60; NODUP-LABEL: split_branch_no_extra_phi
61; NODUP-NOT: split
62; CHECK-LABEL: split_branch_no_extra_phi
63; CHECK-LABEL: Header.split
64; CHECK: %[[V1:.+]] = add i32 %i, 99
65; CHECK: call void @bar(i32* null, i32 %[[V1]])
66; CHECK: br label %CallSite
67; CHECK-LABEL: TBB.split:
68; CHECK: %[[V2:.+]] = add i32 %i, 99
69; CHECK: call void @bar(i32* nonnull %ptrarg, i32 %[[V2]])
70; CHECK: br label %CallSite
71; CHECK: CallSite:
72; CHECK-NOT: phi
73
74
75; In this test case, the codesize cost of the instructions before the call to
76; bar() is equal to the default DuplicationThreshold of 5, because calls are
77; more expensive.
78define void @test_no_split_threshold(i32* %ptrarg, i32 %i) {
79Header:
80  %tobool = icmp ne i32* %ptrarg, null
81  br i1 %tobool, label %TBB, label %CallSite
82
83TBB:                                    ; preds = %Header
84  %arrayidx = getelementptr inbounds i32, i32* %ptrarg, i64 42
85  %0 = load i32, i32* %arrayidx, align 4
86  %tobool1 = icmp ne i32 %0, 0
87  br i1 %tobool1, label %CallSite, label %End
88
89CallSite:                                          ; preds = %TBB, %Header
90  %i2 = add i32 %i, 10
91  call void @bari(i32 %i2)
92  call void @bari(i32 %i2)
93  call void @bar(i32* %ptrarg, i32 %i2)
94  br label %End
95
96End:                                           ; preds = %CallSite, %TBB
97  ret void
98}
99; NODUP-LABEL: test_no_split_threshold
100; NODUP-NOT: split
101; CHECK-LABEL: test_no_split_threshold
102; CHECK-NOT: split
103; CHECK-LABEL: CallSite:
104; CHECK: call void @bar(i32* %ptrarg, i32 %i2)
105
106; In this test case, the phi node %l in CallSite should be removed, as after
107; moving the call to the split blocks we can use the values directly.
108define void @test_remove_unused_phi(i32* %ptrarg, i32 %i) {
109Header:
110  %l1 = load i32, i32* undef, align 16
111  %tobool = icmp ne i32* %ptrarg, null
112  br i1 %tobool, label %TBB, label %CallSite
113
114TBB:                                    ; preds = %Header
115  %arrayidx = getelementptr inbounds i32, i32* %ptrarg, i64 42
116  %0 = load i32, i32* %arrayidx, align 4
117  %l2 = load i32, i32* undef, align 16
118  %tobool1 = icmp ne i32 %0, 0
119  br i1 %tobool1, label %CallSite, label %End
120
121CallSite:                                          ; preds = %TBB, %Header
122  %l = phi i32 [ %l1, %Header ], [ %l2, %TBB ]
123  call void @bar(i32* %ptrarg, i32 %l)
124  br label %End
125
126End:                                           ; preds = %CallSite, %TBB
127  ret void
128}
129; NODUP-LABEL: test_remove_unused_phi
130; NODUP-NOT: split
131; CHECK-LABEL: test_remove_unused_phi
132; CHECK-LABEL: Header.split
133; CHECK: call void @bar(i32* null, i32 %l1)
134; CHECK: br label %CallSite
135; CHECK-LABEL: TBB.split:
136; CHECK: call void @bar(i32* nonnull %ptrarg, i32 %l2)
137; CHECK: br label %CallSite
138; CHECK-LABEL: CallSite:
139; CHECK-NOT: phi
140
141; In this test case, we need to insert a new PHI node in TailBB to combine
142; the loads we moved to the predecessors.
143define void @test_add_new_phi(i32* %ptrarg, i32 %i) {
144Header:
145  %tobool = icmp ne i32* %ptrarg, null
146  br i1 %tobool, label %TBB, label %CallSite
147
148TBB:
149  br i1 undef, label %CallSite, label %End
150
151CallSite:
152  %arrayidx112 = getelementptr inbounds i32, i32* undef, i64 1
153  %0 = load i32, i32* %arrayidx112, align 4
154  call void @bar(i32* %ptrarg, i32 %i)
155  %sub = sub nsw i32 %0, undef
156  br label %End
157
158End:                                           ; preds = %CallSite, %TBB
159  ret void
160}
161; NODUP-LABEL: test_add_new_phi
162; NODUP-NOT: split
163; CHECK-LABEL: test_add_new_phi
164; CHECK-LABEL: Header.split
165; CHECK: %[[V1:.+]] = load i32, i32*
166; CHECK: call void @bar(i32* null, i32 %i)
167; CHECK: br label %CallSite
168; CHECK-LABEL: TBB.split:
169; CHECK: %[[V2:.+]] = load i32, i32*
170; CHECK: call void @bar(i32* nonnull %ptrarg, i32 %i)
171; CHECK: br label %CallSite
172; CHECK-LABEL: CallSite:
173; CHECK-NEXT: %[[V3:.+]] = phi i32 [ %[[V1]], %Header.split ], [ %[[V2]], %TBB.split ]
174; CHECK: %sub = sub nsw i32 %[[V3]], undef
175
176define i32 @test_firstnophi(i32* %a, i32 %v) {
177Header:
178  %tobool1 = icmp eq i32* %a, null
179  br i1 %tobool1, label %Tail, label %TBB
180
181TBB:
182  %cmp = icmp eq i32 %v, 1
183  br i1 %cmp, label %Tail, label %End
184
185Tail:
186  %p = phi i32[1,%Header], [2, %TBB]
187  store i32 %v, i32* %a
188  %r = call i32 @callee(i32* %a, i32 %v, i32 %p)
189  ret i32 %r
190
191End:
192  ret i32 %v
193}
194; NODUP-LABEL: @test_firstnophi
195; NODUP-NOT: split:
196; CHECK-LABEL: @test_firstnophi
197; CHECK-LABEL: Header.split:
198; CHECK-NEXT: store i32 %v, i32* %a
199; CHECK-NEXT: %[[CALL1:.*]] = call i32 @callee(i32* null, i32 %v, i32 1)
200; CHECK-NEXT: br label %Tail
201; CHECK-LABEL: TBB.split:
202; CHECK-NEXT: store i32 %v, i32* %a
203; CHECK-NEXT: %[[CALL2:.*]] = call i32 @callee(i32* nonnull %a, i32 1, i32 2)
204; CHECK-NEXT: br label %Tail
205; CHECK-LABEL: Tail:
206; CHECK: %[[MERGED:.*]] = phi i32 [ %[[CALL1]], %Header.split ], [ %[[CALL2]], %TBB.split ]
207; CHECK: ret i32 %[[MERGED]]
208define i32 @callee(i32* %a, i32 %v, i32 %p) {
209    ret i32 0
210}
211
212define void @test_no_remove_used_phi(i32* %ptrarg, i32 %i) {
213Header:
214  %l1 = load i32, i32* undef, align 16
215  %tobool = icmp ne i32* %ptrarg, null
216  br i1 %tobool, label %TBB, label %CallSite
217
218TBB:                                    ; preds = %Header
219  %arrayidx = getelementptr inbounds i32, i32* %ptrarg, i64 42
220  %0 = load i32, i32* %arrayidx, align 4
221  %l2 = load i32, i32* undef, align 16
222  %tobool1 = icmp ne i32 %0, 0
223  br i1 %tobool1, label %CallSite, label %End
224
225CallSite:                                          ; preds = %TBB, %Header
226  %l = phi i32 [ %l1, %Header ], [ %l2, %TBB ]
227  call void @bar(i32* %ptrarg, i32 %l)
228  call void @bari(i32 %l)
229  br label %End
230
231End:                                           ; preds = %CallSite, %TBB
232  ret void
233}
234; NODUP-LABEL: @test_no_remove_used_phi
235; NODUP-NOT: split
236; CHECK-LABEL: @test_no_remove_used_phi
237; CHECK-LABEL: Header.split:
238; CHECK: call void @bar(i32* null, i32 %l1)
239; CHECK-NEXT: br label %CallSite
240; CHECK-LABEL: TBB.split:
241; CHECK: call void @bar(i32* nonnull %ptrarg, i32 %l2)
242; CHECK-NEXT: br label %CallSite
243; CHECK-LABEL: CallSite:
244; CHECK-NEXT:  %l = phi i32 [ %l1, %Header.split ], [ %l2, %TBB.split ]
245; CHECK: call void @bari(i32 %l)
246
247define void @bar(i32*, i32) {
248    ret void
249}
250
251define  void @bari(i32) {
252    ret void
253}
254