1 ; RUN: opt -S -passes='require<profile-summary>,function(codegenprepare)' -mtriple=thumbv7m -disable-complex-addr-modes=false -addr-sink-new-select=true -addr-sink-new-phis=true < %s | FileCheck %s
3 target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
5 @gv1 = common global i32 0, align 4
6 @gv2 = common global i32 0, align 4
8 ; Phi selects between ptr and gep with ptr as base and constant offset
9 define void @test_phi_onegep_offset(ptr %ptr, i32 %value) {
10 ; CHECK-LABEL: @test_phi_onegep_offset
11 ; CHECK-NOT: phi ptr [ %ptr, %entry ], [ %gep, %if.then ]
12 ; CHECK: phi i32 [ 4, %if.then ], [ 0, %entry ]
14 %cmp = icmp sgt i32 %value, 0
15 br i1 %cmp, label %if.then, label %if.end
18 %gep = getelementptr inbounds i32, ptr %ptr, i32 1
22 %phi = phi ptr [ %ptr, %entry ], [ %gep, %if.then ]
23 store i32 %value, ptr %phi, align 4
27 ; Phi selects between two geps with same base, different constant offsets
28 define void @test_phi_twogep_offset(ptr %ptr, i32 %value) {
29 ; CHECK-LABEL: @test_phi_twogep_offset
30 ; CHECK-NOT: phi ptr [ %gep1, %if.then ], [ %gep2, %if.else ]
31 ; CHECK: phi i32 [ 8, %if.else ], [ 4, %if.then ]
33 %cmp = icmp sgt i32 %value, 0
34 br i1 %cmp, label %if.then, label %if.else
37 %gep1 = getelementptr inbounds i32, ptr %ptr, i32 1
41 %gep2 = getelementptr inbounds i32, ptr %ptr, i32 2
45 %phi = phi ptr [ %gep1, %if.then ], [ %gep2, %if.else ]
46 store i32 %value, ptr %phi, align 4
50 ; Phi selects between ptr and gep with ptr as base and nonconstant offset
51 define void @test_phi_onegep_nonconst_offset(ptr %ptr, i32 %value, i32 %off) {
52 ; CHECK-LABEL: @test_phi_onegep_nonconst_offset
53 ; CHECK-NOT: phi ptr [ %ptr, %entry ], [ %gep, %if.then ]
54 ; CHECK: phi i32 [ %off, %if.then ], [ 0, %entry ]
56 %cmp = icmp sgt i32 %value, 0
57 br i1 %cmp, label %if.then, label %if.end
60 %gep = getelementptr inbounds i32, ptr %ptr, i32 %off
64 %phi = phi ptr [ %ptr, %entry ], [ %gep, %if.then ]
65 store i32 %value, ptr %phi, align 4
69 ; Phi selects between two geps with same base, different nonconstant offsets
70 define void @test_phi_twogep_nonconst_offset(ptr %ptr, i32 %value, i32 %off1, i32 %off2) {
71 ; CHECK-LABEL: @test_phi_twogep_nonconst_offset
72 ; CHECK-NOT: phi ptr [ %gep1, %if.then ], [ %gep2, %if.else ]
73 ; CHECK: phi i32 [ %off2, %if.else ], [ %off1, %if.then ]
75 %cmp = icmp sgt i32 %value, 0
76 br i1 %cmp, label %if.then, label %if.else
79 %gep1 = getelementptr inbounds i32, ptr %ptr, i32 %off1
83 %gep2 = getelementptr inbounds i32, ptr %ptr, i32 %off2
87 %phi = phi ptr [ %gep1, %if.then ], [ %gep2, %if.else ]
88 store i32 %value, ptr %phi, align 4
92 ; Phi selects between two geps with different base, same constant offset
93 define void @test_phi_twogep_base(ptr %ptr1, ptr %ptr2, i32 %value) {
94 ; CHECK-LABEL: @test_phi_twogep_base
95 ; CHECK-NOT: phi ptr [ %gep1, %if.then ], [ %gep2, %if.else ]
96 ; CHECK: phi ptr [ %ptr2, %if.else ], [ %ptr1, %if.then ]
98 %cmp = icmp sgt i32 %value, 0
99 br i1 %cmp, label %if.then, label %if.else
102 %gep1 = getelementptr inbounds i32, ptr %ptr1, i32 1
106 %gep2 = getelementptr inbounds i32, ptr %ptr2, i32 1
110 %phi = phi ptr [ %gep1, %if.then ], [ %gep2, %if.else ]
111 store i32 %value, ptr %phi, align 4
115 ; Phi selects between two geps with different base global variables, same constant offset
116 define void @test_phi_twogep_base_gv(i32 %value) {
117 ; CHECK-LABEL: @test_phi_twogep_base_gv
118 ; CHECK-NOT: phi ptr [ %gep1, %if.then ], [ %gep2, %if.else ]
119 ; CHECK: phi ptr [ @gv2, %if.else ], [ @gv1, %if.then ]
121 %cmp = icmp sgt i32 %value, 0
122 br i1 %cmp, label %if.then, label %if.else
125 %gep1 = getelementptr inbounds i32, ptr @gv1, i32 1
129 %gep2 = getelementptr inbounds i32, ptr @gv2, i32 1
133 %phi = phi ptr [ %gep1, %if.then ], [ %gep2, %if.else ]
134 store i32 %value, ptr %phi, align 4
138 ; Phi selects between ptr and gep with ptr as base and constant offset
139 define void @test_select_onegep_offset(ptr %ptr, i32 %value) {
140 ; CHECK-LABEL: @test_select_onegep_offset
141 ; CHECK-NOT: select i1 %cmp, ptr %ptr, ptr %gep
142 ; CHECK: select i1 %cmp, i32 0, i32 4
144 %cmp = icmp sgt i32 %value, 0
145 %gep = getelementptr inbounds i32, ptr %ptr, i32 1
146 %select = select i1 %cmp, ptr %ptr, ptr %gep
147 store i32 %value, ptr %select, align 4
151 ; Select between two geps with same base, different constant offsets
152 define void @test_select_twogep_offset(ptr %ptr, i32 %value) {
153 ; CHECK-LABEL: @test_select_twogep_offset
154 ; CHECK-NOT: select i1 %cmp, ptr %gep1, ptr %gep2
155 ; CHECK: select i1 %cmp, i32 4, i32 8
157 %cmp = icmp sgt i32 %value, 0
158 %gep1 = getelementptr inbounds i32, ptr %ptr, i32 1
159 %gep2 = getelementptr inbounds i32, ptr %ptr, i32 2
160 %select = select i1 %cmp, ptr %gep1, ptr %gep2
161 store i32 %value, ptr %select, align 4
165 ; Select between ptr and gep with ptr as base and nonconstant offset
166 define void @test_select_onegep_nonconst_offset(ptr %ptr, i32 %value, i32 %off) {
167 ; CHECK-LABEL: @test_select_onegep_nonconst_offset
168 ; CHECK-NOT: select i1 %cmp, ptr %ptr, ptr %gep
169 ; CHECK: select i1 %cmp, i32 0, i32 %off
171 %cmp = icmp sgt i32 %value, 0
172 %gep = getelementptr inbounds i32, ptr %ptr, i32 %off
173 %select = select i1 %cmp, ptr %ptr, ptr %gep
174 store i32 %value, ptr %select, align 4
178 ; Select between two geps with same base, different nonconstant offsets
179 define void @test_select_twogep_nonconst_offset(ptr %ptr, i32 %value, i32 %off1, i32 %off2) {
180 ; CHECK-LABEL: @test_select_twogep_nonconst_offset
181 ; CHECK-NOT: select i1 %cmp, ptr %gep1, ptr %gep2
182 ; CHECK: select i1 %cmp, i32 %off1, i32 %off2
184 %cmp = icmp sgt i32 %value, 0
185 %gep1 = getelementptr inbounds i32, ptr %ptr, i32 %off1
186 %gep2 = getelementptr inbounds i32, ptr %ptr, i32 %off2
187 %select = select i1 %cmp, ptr %gep1, ptr %gep2
188 store i32 %value, ptr %select, align 4
192 ; Select between two geps with different base, same constant offset
193 define void @test_select_twogep_base(ptr %ptr1, ptr %ptr2, i32 %value) {
194 ; CHECK-LABEL: @test_select_twogep_base
195 ; CHECK-NOT: select i1 %cmp, ptr %gep1, ptr %gep2
196 ; CHECK: select i1 %cmp, ptr %ptr1, ptr %ptr2
198 %cmp = icmp sgt i32 %value, 0
199 %gep1 = getelementptr inbounds i32, ptr %ptr1, i32 1
200 %gep2 = getelementptr inbounds i32, ptr %ptr2, i32 1
201 %select = select i1 %cmp, ptr %gep1, ptr %gep2
202 store i32 %value, ptr %select, align 4
206 ; Select between two geps with different base global variables, same constant offset
207 define void @test_select_twogep_base_gv(i32 %value) {
208 ; CHECK-LABEL: @test_select_twogep_base_gv
209 ; CHECK-NOT: select i1 %cmp, ptr %gep1, ptr %gep2
210 ; CHECK: select i1 %cmp, ptr @gv1, ptr @gv2
212 %cmp = icmp sgt i32 %value, 0
213 %gep1 = getelementptr inbounds i32, ptr @gv1, i32 1
214 %gep2 = getelementptr inbounds i32, ptr @gv2, i32 1
215 %select = select i1 %cmp, ptr %gep1, ptr %gep2
216 store i32 %value, ptr %select, align 4
220 ; If the phi is in a different block to where the gep will be, the phi goes where
221 ; the original phi was not where the gep is.
222 ; CHECK-LABEL: @test_phi_different_block
223 ; CHECK-LABEL: if1.end
224 ; CHECK-NOT: phi ptr [ %ptr, %entry ], [ %gep, %if1.then ]
225 ; CHECK: phi i32 [ 4, %if1.then ], [ 0, %entry ]
226 define void @test_phi_different_block(ptr %ptr, i32 %value1, i32 %value2) {
228 %cmp1 = icmp sgt i32 %value1, 0
229 br i1 %cmp1, label %if1.then, label %if1.end
232 %gep = getelementptr inbounds i32, ptr %ptr, i32 1
236 %phi = phi ptr [ %ptr, %entry ], [ %gep, %if1.then ]
237 %cmp2 = icmp sgt i32 %value2, 0
238 br i1 %cmp2, label %if2.then, label %if2.end
241 store i32 %value1, ptr %ptr, align 4
245 store i32 %value2, ptr %phi, align 4
249 ; A phi with three incoming values should be optimised
250 ; CHECK-LABEL: @test_phi_threegep
251 ; CHECK-NOT: phi ptr [ %gep1, %if.then ], [ %gep2, %if.else.then ], [ %gep3, %if.else.else ]
252 ; CHECK: phi i32 [ 12, %if.else.else ], [ 8, %if.else.then ], [ 4, %if.then ]
253 define void @test_phi_threegep(ptr %ptr, i32 %value1, i32 %value2) {
255 %cmp1 = icmp sgt i32 %value1, 0
256 br i1 %cmp1, label %if.then, label %if.else
259 %gep1 = getelementptr inbounds i32, ptr %ptr, i32 1
263 %cmp2 = icmp sgt i32 %value2, 0
264 br i1 %cmp2, label %if.else.then, label %if.else.else
267 %gep2 = getelementptr inbounds i32, ptr %ptr, i32 2
271 %gep3 = getelementptr inbounds i32, ptr %ptr, i32 3
275 %phi = phi ptr [ %gep1, %if.then ], [ %gep2, %if.else.then ], [ %gep3, %if.else.else ]
276 store i32 %value1, ptr %phi, align 4
280 ; A phi with two incoming values but three geps due to nesting should be
282 ; CHECK-LABEL: @test_phi_threegep_nested
283 ; CHECK: %[[PHI:[a-z0-9_]+]] = phi i32 [ 12, %if.else.else ], [ 8, %if.else.then ]
284 ; CHECK: phi i32 [ %[[PHI]], %if.else.end ], [ 4, %if.then ]
285 define void @test_phi_threegep_nested(ptr %ptr, i32 %value1, i32 %value2) {
287 %cmp1 = icmp sgt i32 %value1, 0
288 br i1 %cmp1, label %if.then, label %if.else
291 %gep1 = getelementptr inbounds i32, ptr %ptr, i32 1
295 %cmp2 = icmp sgt i32 %value2, 0
296 br i1 %cmp2, label %if.else.then, label %if.else.else
299 %gep2 = getelementptr inbounds i32, ptr %ptr, i32 2
300 br label %if.else.end
303 %gep3 = getelementptr inbounds i32, ptr %ptr, i32 3
304 br label %if.else.end
307 %gep4 = phi ptr [ %gep2, %if.else.then ], [ %gep3, %if.else.else ]
308 store i32 %value2, ptr %ptr, align 4
312 %phi = phi ptr [ %gep1, %if.then ], [ %gep4, %if.else.end ]
313 store i32 %value1, ptr %phi, align 4
317 ; A nested select is expected to be optimised
318 ; CHECK-LABEL: @test_nested_select
319 ; CHECK: %[[SELECT:[a-z0-9_]+]] = select i1 %cmp2, i32 4, i32 8
320 ; CHECK: select i1 %cmp1, i32 4, i32 %[[SELECT]]
321 define void @test_nested_select(ptr %ptr, i32 %value1, i32 %value2) {
323 %gep1 = getelementptr inbounds i32, ptr %ptr, i32 1
324 %gep2 = getelementptr inbounds i32, ptr %ptr, i32 2
325 %cmp1 = icmp sgt i32 %value1, 0
326 %cmp2 = icmp sgt i32 %value2, 0
327 %select1 = select i1 %cmp2, ptr %gep1, ptr %gep2
328 %select2 = select i1 %cmp1, ptr %gep1, ptr %select1
329 store i32 %value1, ptr %select2, align 4
333 ; Scaling the offset by a different amount is expected not to be optimised
334 ; CHECK-LABEL: @test_select_different_scale
335 ; CHECK: select i1 %cmp, ptr %gep1, ptr %gep2
336 define void @test_select_different_scale(ptr %ptr, i32 %value, i32 %off) {
338 %cmp = icmp sgt i32 %value, 0
339 %gep1 = getelementptr inbounds i32, ptr %ptr, i32 %off
340 %gep2 = getelementptr inbounds i16, ptr %ptr, i32 %off
341 %select = select i1 %cmp, ptr %gep1, ptr %gep2
342 store i32 %value, ptr %select, align 4
346 ; A select between two values is already the best we can do
347 ; CHECK-LABEL: @test_select_trivial
348 ; CHECK: select i1 %cmp, ptr %ptr1, ptr %ptr2
349 define void @test_select_trivial(ptr %ptr1, ptr %ptr2, i32 %value) {
351 %cmp = icmp sgt i32 %value, 0
352 %select = select i1 %cmp, ptr %ptr1, ptr %ptr2
353 store i32 %value, ptr %select, align 4
357 ; A select between two global variables is already the best we can do
358 ; CHECK-LABEL: @test_select_trivial_gv
359 ; CHECK: select i1 %cmp, ptr @gv1, ptr @gv2
360 define void @test_select_trivial_gv(i32 %value) {
362 %cmp = icmp sgt i32 %value, 0
363 %select = select i1 %cmp, ptr @gv1, ptr @gv2
364 store i32 %value, ptr %select, align 4
368 ; Same for a select between a value and global variable
369 ; CHECK-LABEL: @test_select_trivial_ptr_gv
370 ; CHECK: select i1 %cmp, ptr %ptr, ptr @gv2
371 define void @test_select_trivial_ptr_gv(ptr %ptr, i32 %value) {
373 %cmp = icmp sgt i32 %value, 0
374 %select = select i1 %cmp, ptr %ptr, ptr @gv2
375 store i32 %value, ptr %select, align 4
379 ; Same for a select between a global variable and null, though the test needs to
380 ; be a little more complicated to avoid dereferencing a potential null pointer
381 ; CHECK-LABEL: @test_select_trivial_gv_null
382 ; CHECK: select i1 %cmp.i, ptr @gv1, ptr null
383 define void @test_select_trivial_gv_null(){
385 %gv1_val = load i32, ptr @gv1, align 4
386 %cmp.i = icmp eq i32 %gv1_val, 0
387 %spec.select.i = select i1 %cmp.i, ptr @gv1, ptr null
388 br i1 %cmp.i, label %if.then, label %if.end
391 %val = load i32, ptr %spec.select.i, align 4
392 %inc = add nsw i32 %val, 1
393 store i32 %inc, ptr %spec.select.i, align 4
400 ; Same for a select between a value and null
401 ; CHECK-LABEL: @test_select_trivial_ptr_null
402 ; CHECK: select i1 %cmp.i, ptr %ptr, ptr null
403 define void @test_select_trivial_ptr_null(ptr %ptr){
405 %gv1_val = load i32, ptr %ptr, align 4
406 %cmp.i = icmp eq i32 %gv1_val, 0
407 %spec.select.i = select i1 %cmp.i, ptr %ptr, ptr null
408 br i1 %cmp.i, label %if.then, label %if.end
411 %val = load i32, ptr %spec.select.i, align 4
412 %inc = add nsw i32 %val, 1
413 store i32 %inc, ptr %spec.select.i, align 4