• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1; RUN: llc -mtriple=thumbv7m -arm-disable-cgp=false %s -o - | FileCheck %s --check-prefix=CHECK-COMMON --check-prefix=CHECK-NODSP
2; RUN: llc -mtriple=thumbv8m.main -arm-disable-cgp=false %s -o - | FileCheck %s --check-prefix=CHECK-COMMON --check-prefix=CHECK-NODSP
3; RUN: llc -mtriple=thumbv8m.main -arm-disable-cgp=false -arm-enable-scalar-dsp=true -mcpu=cortex-m33 %s -o - | FileCheck %s --check-prefix=CHECK-COMMON --check-prefix=CHECK-DSP
4; RUN: llc -mtriple=thumbv7em %s -arm-disable-cgp=false -arm-enable-scalar-dsp=true -arm-enable-scalar-dsp-imms=true -o - | FileCheck %s --check-prefix=CHECK-COMMON --check-prefix=CHECK-DSP-IMM
5
6; Test that ARMCodeGenPrepare can handle:
7; - loops
8; - call operands
9; - call return values
10; - ret instructions
11; We use nuw on the arithmetic instructions to avoid complications.
12
13; Check that the arguments are extended but then nothing else is.
14; This also ensures that the pass can handle loops.
15; CHECK-COMMON-LABEL: phi_feeding_phi_args
16; CHECK-COMMON: uxtb
17; CHECK-COMMON: uxtb
18; CHECK-NOT: uxtb
19define void @phi_feeding_phi_args(i8 %a, i8 %b) {
20entry:
21  %0 = icmp ugt i8 %a, %b
22  br i1 %0, label %preheader, label %empty
23
24empty:
25  br label %preheader
26
27preheader:
28  %1 = phi i8 [ %a, %entry ], [ %b, %empty ]
29  br label %loop
30
31loop:
32  %val = phi i8 [ %1, %preheader ], [ %inc2, %if.end ]
33  %cmp = icmp ult i8 %val, 254
34  br i1 %cmp, label %if.then, label %if.else
35
36if.then:
37  %inc = sub nuw i8 %val, 2
38  br label %if.end
39
40if.else:
41  %inc1 = shl nuw i8 %val, 1
42  br label %if.end
43
44if.end:
45  %inc2 = phi i8 [ %inc, %if.then], [ %inc1, %if.else ]
46  %cmp1 = icmp eq i8 %inc2, 255
47  br i1 %cmp1, label %exit, label %loop
48
49exit:
50  ret void
51}
52
53; Same as above, but as the args are zeroext, we shouldn't see any uxts.
54; CHECK-COMMON-LABEL: phi_feeding_phi_zeroext_args
55; CHECK-COMMON-NOT: uxt
56define void @phi_feeding_phi_zeroext_args(i8 zeroext %a, i8 zeroext %b) {
57entry:
58  %0 = icmp ugt i8 %a, %b
59  br i1 %0, label %preheader, label %empty
60
61empty:
62  br label %preheader
63
64preheader:
65  %1 = phi i8 [ %a, %entry ], [ %b, %empty ]
66  br label %loop
67
68loop:
69  %val = phi i8 [ %1, %preheader ], [ %inc2, %if.end ]
70  %cmp = icmp ult i8 %val, 254
71  br i1 %cmp, label %if.then, label %if.else
72
73if.then:
74  %inc = sub nuw i8 %val, 2
75  br label %if.end
76
77if.else:
78  %inc1 = shl nuw i8 %val, 1
79  br label %if.end
80
81if.end:
82  %inc2 = phi i8 [ %inc, %if.then], [ %inc1, %if.else ]
83  %cmp1 = icmp eq i8 %inc2, 255
84  br i1 %cmp1, label %exit, label %loop
85
86exit:
87  ret void
88}
89
90; Just check that phis also work with i16s.
91; CHECK-COMMON-LABEL: phi_i16:
92; CHECK-COMMON-NOT:   uxt
93define void @phi_i16() {
94entry:
95  br label %loop
96
97loop:
98  %val = phi i16 [ 0, %entry ], [ %inc2, %if.end ]
99  %cmp = icmp ult i16 %val, 128
100  br i1 %cmp, label %if.then, label %if.else
101
102if.then:
103  %inc = add nuw i16 %val, 2
104  br label %if.end
105
106if.else:
107  %inc1 = add nuw i16 %val, 1
108  br label %if.end
109
110if.end:
111  %inc2 = phi i16 [ %inc, %if.then], [ %inc1, %if.else ]
112  %cmp1 = icmp ult i16 %inc2, 253
113  br i1 %cmp1, label %loop, label %exit
114
115exit:
116  ret void
117}
118
119; CHECK-COMMON-LABEL: phi_feeding_switch
120; CHECK-COMMON: ldrb
121; CHECK-COMMON: uxtb
122; CHECK-COMMON-NOT: uxt
123define void @phi_feeding_switch(i8* %memblock, i8* %store, i16 %arg) {
124entry:
125  %pre = load i8, i8* %memblock, align 1
126  %conv = trunc i16 %arg to i8
127  br label %header
128
129header:
130  %phi.0 = phi i8 [ %pre, %entry ], [ %count, %latch ]
131  %phi.1 = phi i8 [ %conv, %entry ], [ %phi.3, %latch ]
132  %phi.2 = phi i8 [ 0, %entry], [ %count, %latch ]
133  switch i8 %phi.0, label %default [
134    i8 43, label %for.inc.i
135    i8 45, label %for.inc.i.i
136  ]
137
138for.inc.i:
139  %xor = xor i8 %phi.1, 1
140  br label %latch
141
142for.inc.i.i:
143  %and = and i8 %phi.1, 3
144  br label %latch
145
146default:
147  %sub = sub i8 %phi.0, 1
148  %cmp2 = icmp ugt i8 %sub, 4
149  br i1 %cmp2, label %latch, label %exit
150
151latch:
152  %phi.3 = phi i8 [ %xor, %for.inc.i ], [ %and, %for.inc.i.i ], [ %phi.2, %default ]
153  %count = add nuw i8 %phi.2, 1
154  store i8 %count, i8* %store, align 1
155  br label %header
156
157exit:
158  ret void
159}
160
161; CHECK-COMMON-LABEL: ret_i8
162; CHECK-COMMON-NOT:   uxt
163define i8 @ret_i8() {
164entry:
165  br label %loop
166
167loop:
168  %val = phi i8 [ 0, %entry ], [ %inc2, %if.end ]
169  %cmp = icmp ult i8 %val, 128
170  br i1 %cmp, label %if.then, label %if.else
171
172if.then:
173  %inc = add nuw i8 %val, 2
174  br label %if.end
175
176if.else:
177  %inc1 = add nuw i8 %val, 1
178  br label %if.end
179
180if.end:
181  %inc2 = phi i8 [ %inc, %if.then], [ %inc1, %if.else ]
182  %cmp1 = icmp ult i8 %inc2, 253
183  br i1 %cmp1, label %exit, label %loop
184
185exit:
186  ret i8 %inc2
187}
188
189; Check that %exp requires uxth in all cases, and will also be required to
190; promote %1 for the call - unless we can generate a uadd16.
191; CHECK-COMMON-LABEL: zext_load_sink_call:
192; CHECK-COMMON:       uxt
193; CHECK-DSP-IMM:      uadd16
194; CHECK-COMMON:       cmp
195; CHECK-DSP:          uxt
196; CHECK-DSP-IMM-NOT:  uxt
197define i32 @zext_load_sink_call(i16* %ptr, i16 %exp) {
198entry:
199  %0 = load i16, i16* %ptr, align 4
200  %1 = add i16 %exp, 3
201  %cmp = icmp eq i16 %0, %exp
202  br i1 %cmp, label %exit, label %if.then
203
204if.then:
205  %conv0 = zext i16 %0 to i32
206  %conv1 = zext i16 %1 to i32
207  %call = tail call arm_aapcs_vfpcc i32 @dummy(i32 %conv0, i32 %conv1)
208  br label %exit
209
210exit:
211  %exitval = phi i32 [ %call, %if.then ], [ 0, %entry  ]
212  ret i32 %exitval
213}
214
215
216; Check that the pass doesn't try to promote the immediate parameters.
217; CHECK-COMMON-LABEL: call_with_imms
218; CHECK-COMMON-NOT:   uxt
219define i8 @call_with_imms(i8* %arg) {
220  %call = tail call arm_aapcs_vfpcc zeroext i8 @dummy2(i8* nonnull %arg, i8 zeroext 0, i8 zeroext 0)
221  %cmp = icmp eq i8 %call, 0
222  %res = select i1 %cmp, i8 %call, i8 1
223  ret i8 %res
224}
225
226; Test that the call result is still extended.
227; CHECK-COMMON-LABEL: test_call:
228; CHECK-COMMON: bl
229; CHECK-COMMONNEXT: sxtb r1, r0
230define i16 @test_call(i8 zeroext %arg) {
231  %call = call i8 @dummy_i8(i8 %arg)
232  %cmp = icmp ult i8 %call, 128
233  %conv = zext i1 %cmp to i16
234  ret i16 %conv
235}
236
237; Test that the transformation bails when it finds that i16 is larger than i8.
238; TODO: We should be able to remove the uxtb in these cases.
239; CHECK-LABEL: promote_i8_sink_i16_1
240; CHECK-COMMON: bl dummy_i8
241; CHECK-COMMON: adds r0, #1
242; CHECK-COMMON: uxtb r0, r0
243; CHECK-COMMON: cmp r0
244define i16 @promote_i8_sink_i16_1(i8 zeroext %arg0, i16 zeroext %arg1, i16 zeroext %arg2) {
245  %call = tail call zeroext i8 @dummy_i8(i8 %arg0)
246  %add = add nuw i8 %call, 1
247  %conv = zext i8 %add to i16
248  %cmp = icmp ne i16 %conv, %arg1
249  %sel = select i1 %cmp, i16 %arg1, i16 %arg2
250  %res = tail call zeroext i16 @dummy3(i16 %sel)
251  ret i16 %res
252}
253
254; CHECK-COMMON-LABEL: promote_i8_sink_i16_2
255; CHECK-COMMON: bl dummy_i8
256; CHECK-COMMON: adds r0, #1
257; CHECK-COMMON: uxtb r0, r0
258; CHECK-COMMON: cmp r0
259define i16 @promote_i8_sink_i16_2(i8 zeroext %arg0, i8 zeroext %arg1, i16 zeroext %arg2) {
260  %call = tail call zeroext i8 @dummy_i8(i8 %arg0)
261  %add = add nuw i8 %call, 1
262  %cmp = icmp ne i8 %add, %arg1
263  %conv = zext i8 %arg1 to i16
264  %sel = select i1 %cmp, i16 %conv, i16 %arg2
265  %res = tail call zeroext i16 @dummy3(i16 %sel)
266  ret i16 %res
267}
268
269@uc = global i8 42, align 1
270@LL = global i64 0, align 8
271
272; CHECK-COMMON-LABEL: zext_i64
273; CHECK-COMMON: ldrb
274; CHECK-COMMON: strd
275define void @zext_i64() {
276entry:
277  %0 = load i8, i8* @uc, align 1
278  %conv = zext i8 %0 to i64
279  store i64 %conv, i64* @LL, align 8
280  %cmp = icmp eq i8 %0, 42
281  %conv1 = zext i1 %cmp to i32
282  %call = tail call i32 bitcast (i32 (...)* @assert to i32 (i32)*)(i32 %conv1)
283  ret void
284}
285
286@a = global i16* null, align 4
287@b = global i32 0, align 4
288
289; CHECK-COMMON-LABEL: constexpr
290; CHECK-COMMON: uxth
291define i32 @constexpr() {
292entry:
293  store i32 ptrtoint (i32* @b to i32), i32* @b, align 4
294  %0 = load i16*, i16** @a, align 4
295  %1 = load i16, i16* %0, align 2
296  %or = or i16 %1, ptrtoint (i32* @b to i16)
297  store i16 %or, i16* %0, align 2
298  %cmp = icmp ne i16 %or, 4
299  %conv3 = zext i1 %cmp to i32
300  %call = tail call i32 bitcast (i32 (...)* @e to i32 (i32)*)(i32 %conv3) #2
301  ret i32 undef
302}
303
304; Check that d.sroa.0.0.be is promoted passed directly into the tail call.
305; CHECK-COMMON-LABEL: check_zext_phi_call_arg
306; CHECK-COMMON-NOT: uxt
307define i32 @check_zext_phi_call_arg() {
308entry:
309  br label %for.cond
310
311for.cond:                                         ; preds = %for.cond.backedge, %entry
312  %d.sroa.0.0 = phi i16 [ 30, %entry ], [ %d.sroa.0.0.be, %for.cond.backedge ]
313  %tobool = icmp eq i16 %d.sroa.0.0, 0
314  br i1 %tobool, label %for.cond.backedge, label %if.then
315
316for.cond.backedge:                                ; preds = %for.cond, %if.then
317  %d.sroa.0.0.be = phi i16 [ %call, %if.then ], [ 0, %for.cond ]
318  br label %for.cond
319
320if.then:                                          ; preds = %for.cond
321  %d.sroa.0.0.insert.ext = zext i16 %d.sroa.0.0 to i32
322  %call = tail call zeroext i16 bitcast (i16 (...)* @f to i16 (i32)*)(i32 %d.sroa.0.0.insert.ext) #2
323  br label %for.cond.backedge
324}
325
326
327; The call to safe_lshift_func takes two parameters, but they're the same value just one is zext.
328; CHECK-COMMON-LABEL: call_zext_i8_i32
329define fastcc i32 @call_zext_i8_i32(i32 %p_45, i8 zeroext %p_46) {
330for.cond8.preheader:
331  %call217 = call fastcc zeroext i8 @safe_mul_func_uint8_t_u_u(i8 zeroext undef)
332  %tobool219 = icmp eq i8 %call217, 0
333  br i1 %tobool219, label %for.end411, label %for.cond273.preheader
334
335for.cond273.preheader:                            ; preds = %for.cond8.preheader
336  %call217.lcssa = phi i8 [ %call217, %for.cond8.preheader ]
337  %conv218.le = zext i8 %call217.lcssa to i32
338  %call346 = call fastcc zeroext i8 @safe_lshift_func(i8 zeroext %call217.lcssa, i32 %conv218.le)
339  unreachable
340
341for.end411:                                       ; preds = %for.cond8.preheader
342  %call452 = call fastcc i64 @safe_sub_func_int64_t_s_s(i64 undef, i64 4)
343  unreachable
344}
345
346%struct.anon = type { i32 }
347
348@g_57 = hidden local_unnamed_addr global %struct.anon zeroinitializer, align 4
349@g_893 = hidden local_unnamed_addr global %struct.anon zeroinitializer, align 4
350@g_82 = hidden local_unnamed_addr global i32 0, align 4
351
352; Test that the transform bails on finding a call which returns a i16**
353; CHECK-COMMON-LABEL: call_return_pointer
354; CHECK-COMMON: sxth
355; CHECK-COMMON-NOT: uxt
356define hidden i32 @call_return_pointer(i8 zeroext %p_13) local_unnamed_addr #0 {
357entry:
358  %conv1 = zext i8 %p_13 to i16
359  %call = tail call i16** @func_62(i8 zeroext undef, i32 undef, i16 signext %conv1, i32* undef)
360  %0 = load i32, i32* getelementptr inbounds (%struct.anon, %struct.anon* @g_893, i32 0, i32 0), align 4
361  %conv2 = trunc i32 %0 to i16
362  br label %for.cond
363
364for.cond:                                         ; preds = %for.cond.backedge, %entry
365  %p_13.addr.0 = phi i8 [ %p_13, %entry ], [ %p_13.addr.0.be, %for.cond.backedge ]
366  %tobool = icmp eq i8 %p_13.addr.0, 0
367  br i1 %tobool, label %for.cond.backedge, label %if.then
368
369for.cond.backedge:                                ; preds = %for.cond, %if.then
370  %p_13.addr.0.be = phi i8 [ %conv4, %if.then ], [ 0, %for.cond ]
371  br label %for.cond
372
373if.then:                                          ; preds = %for.cond
374  %call3 = tail call fastcc signext i16 @safe_sub_func_int16_t_s_s(i16 signext %conv2)
375  %conv4 = trunc i16 %call3 to i8
376  br label %for.cond.backedge
377}
378
379declare noalias i16** @func_62(i8 zeroext %p_63, i32 %p_64, i16 signext %p_65, i32* nocapture readnone %p_66)
380declare fastcc signext i16 @safe_sub_func_int16_t_s_s(i16 signext %si2)
381declare dso_local fastcc i64 @safe_sub_func_int64_t_s_s(i64, i64)
382declare dso_local fastcc zeroext i8 @safe_lshift_func(i8 zeroext, i32)
383declare dso_local fastcc zeroext i8 @safe_mul_func_uint8_t_u_u(i8 returned zeroext)
384
385declare dso_local i32 @e(...) local_unnamed_addr #1
386declare dso_local zeroext i16 @f(...) local_unnamed_addr #1
387
388declare i32 @dummy(i32, i32)
389declare i8 @dummy_i8(i8)
390declare i8 @dummy2(i8*, i8, i8)
391declare i16 @dummy3(i16)
392declare i32 @assert(...)
393