blob: 6114b72569e7fcd954c64736dde93e68d8eb2bd8 [file] [log] [blame]
Kyle Buttefe56fe2017-01-11 19:55:19 +00001; RUN: llc %s -o - -enable-shrink-wrap=true -ifcvt-fn-start=1 -ifcvt-fn-stop=0 -mtriple=thumb-macho \
Artyom Skrobov0a37b802015-12-08 19:59:01 +00002; RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=ENABLE --check-prefix=ENABLE-V4T
Kyle Buttefe56fe2017-01-11 19:55:19 +00003; RUN: llc %s -o - -enable-shrink-wrap=true -ifcvt-fn-start=1 -ifcvt-fn-stop=0 -mtriple=thumbv5-macho \
Artyom Skrobov0a37b802015-12-08 19:59:01 +00004; RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=ENABLE --check-prefix=ENABLE-V5T
Kyle Buttefe56fe2017-01-11 19:55:19 +00005; RUN: llc %s -o - -enable-shrink-wrap=false -ifcvt-fn-start=1 -ifcvt-fn-stop=0 -mtriple=thumb-macho \
Artyom Skrobov0a37b802015-12-08 19:59:01 +00006; RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=DISABLE --check-prefix=DISABLE-V4T
Kyle Buttefe56fe2017-01-11 19:55:19 +00007; RUN: llc %s -o - -enable-shrink-wrap=false -ifcvt-fn-start=1 -ifcvt-fn-stop=0 -mtriple=thumbv5-macho \
Artyom Skrobov0a37b802015-12-08 19:59:01 +00008; RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=DISABLE --check-prefix=DISABLE-V5T
Quentin Colombet48b77202015-07-22 16:34:37 +00009;
10; Note: Lots of tests use inline asm instead of regular calls.
11; This allows to have a better control on what the allocation will do.
12; Otherwise, we may have spill right in the entry block, defeating
13; shrink-wrapping. Moreover, some of the inline asm statements (nop)
14; are here to ensure that the related paths do not end up as critical
15; edges.
16; Also disable the late if-converter as it makes harder to reason on
17; the diffs.
18
19; Initial motivating example: Simple diamond with a call just on one side.
20; CHECK-LABEL: foo:
21;
22; Compare the arguments and jump to exit.
23; No prologue needed.
24; ENABLE: cmp r0, r1
25; ENABLE-NEXT: bge [[EXIT_LABEL:LBB[0-9_]+]]
26;
27; Prologue code.
28; CHECK: push {r7, lr}
Tim Northover747ae9a2015-11-18 21:10:39 +000029; CHECK: sub sp, #8
Quentin Colombet48b77202015-07-22 16:34:37 +000030;
31; Compare the arguments and jump to exit.
32; After the prologue is set.
33; DISABLE: cmp r0, r1
34; DISABLE-NEXT: bge [[EXIT_LABEL:LBB[0-9_]+]]
35;
36; Store %a in the alloca.
37; CHECK: str r0, [sp, #4]
38; Set the alloca address in the second argument.
39; Set the first argument to zero.
40; CHECK: movs r0, #0
41; CHECK-NEXT: add r1, sp, #4
42; CHECK-NEXT: bl
43;
44; With shrink-wrapping, epilogue is just after the call.
45; ENABLE-NEXT: add sp, #8
Artyom Skrobov0a37b802015-12-08 19:59:01 +000046; ENABLE-V5T-NEXT: pop {r7, pc}
47; ENABLE-V4T-NEXT: pop {r7}
48; ENABLE-V4T-NEXT: pop {r1}
49; ENABLE-V4T-NEXT: mov lr, r1
Quentin Colombet48b77202015-07-22 16:34:37 +000050;
51; CHECK: [[EXIT_LABEL]]:
52;
53; Without shrink-wrapping, epilogue is in the exit block.
54; Epilogue code. (What we pop does not matter.)
55; DISABLE: add sp, #8
Artyom Skrobov0a37b802015-12-08 19:59:01 +000056; DISABLE-V5T-NEXT: pop {r7, pc}
57; DISABLE-V4T-NEXT: pop {r7}
58; DISABLE-V4T-NEXT: pop {r1}
59; DISABLE-V4T-NEXT: bx r1
Quentin Colombet48b77202015-07-22 16:34:37 +000060;
61; ENABLE-NEXT: bx lr
62define i32 @foo(i32 %a, i32 %b) {
63 %tmp = alloca i32, align 4
64 %tmp2 = icmp slt i32 %a, %b
65 br i1 %tmp2, label %true, label %false
66
67true:
68 store i32 %a, i32* %tmp, align 4
69 %tmp4 = call i32 @doSomething(i32 0, i32* %tmp)
70 br label %false
71
72false:
73 %tmp.0 = phi i32 [ %tmp4, %true ], [ %a, %0 ]
74 ret i32 %tmp.0
75}
76
Artyom Skrobov0a37b802015-12-08 19:59:01 +000077
78; Same, but the final BB is non-trivial, so we don't duplicate the return inst.
79; CHECK-LABEL: bar:
80;
81; With shrink-wrapping, epilogue is just after the call.
82; CHECK: bl
83; ENABLE-NEXT: add sp, #8
84; ENABLE-NEXT: pop {r7}
85; ENABLE-NEXT: pop {r0}
86; ENABLE-NEXT: mov lr, r0
87;
88; CHECK: movs r0, #42
89;
90; Without shrink-wrapping, epilogue is in the exit block.
91; Epilogue code. (What we pop does not matter.)
92; DISABLE: add sp, #8
93; DISABLE-V5T-NEXT: pop {r7, pc}
94; DISABLE-V4T-NEXT: pop {r7}
95; DISABLE-V4T-NEXT: pop {r1}
96; DISABLE-V4T-NEXT: bx r1
97;
98; ENABLE-NEXT: bx lr
99define i32 @bar(i32 %a, i32 %b) {
100 %tmp = alloca i32, align 4
101 %tmp2 = icmp slt i32 %a, %b
102 br i1 %tmp2, label %true, label %false
103
104true:
105 store i32 %a, i32* %tmp, align 4
106 %tmp4 = call i32 @doSomething(i32 0, i32* %tmp)
107 br label %false
108
109false:
110 ret i32 42
111}
112
Quentin Colombet48b77202015-07-22 16:34:37 +0000113; Function Attrs: optsize
114declare i32 @doSomething(i32, i32*)
115
116
117; Check that we do not perform the restore inside the loop whereas the save
118; is outside.
119; CHECK-LABEL: freqSaveAndRestoreOutsideLoop:
120;
121; Shrink-wrapping allows to skip the prologue in the else case.
122; ENABLE: cmp r0, #0
123; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
124;
125; Prologue code.
126; Make sure we save the CSR used in the inline asm: r4.
127; CHECK: push {r4, lr}
128;
129; DISABLE: cmp r0, #0
130; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
131;
132; SUM is in r0 because it is coalesced with the second
133; argument on the else path.
134; CHECK: movs [[SUM:r0]], #0
135; CHECK-NEXT: movs [[IV:r[0-9]+]], #10
136;
137; Next BB.
138; CHECK: [[LOOP:LBB[0-9_]+]]: @ %for.body
139; CHECK: movs [[TMP:r[0-9]+]], #1
140; CHECK: adds [[SUM]], [[TMP]], [[SUM]]
141; CHECK-NEXT: subs [[IV]], [[IV]], #1
Quentin Colombet48b77202015-07-22 16:34:37 +0000142; CHECK-NEXT: bne [[LOOP]]
143;
144; Next BB.
145; SUM << 3.
146; CHECK: lsls [[SUM]], [[SUM]], #3
147;
148; Duplicated epilogue.
Artyom Skrobov0a37b802015-12-08 19:59:01 +0000149; DISABLE-V5T: pop {r4, pc}
150; DISABLE-V4T: b [[END_LABEL:LBB[0-9_]+]]
Quentin Colombet48b77202015-07-22 16:34:37 +0000151;
152; CHECK: [[ELSE_LABEL]]: @ %if.else
153; Shift second argument by one and store into returned register.
154; CHECK: lsls r0, r1, #1
Artyom Skrobov0a37b802015-12-08 19:59:01 +0000155; DISABLE-V5T-NEXT: pop {r4, pc}
156; DISABLE-V4T-NEXT: [[END_LABEL]]: @ %if.end
157; DISABLE-V4T-NEXT: pop {r4}
158; DISABLE-V4T-NEXT: pop {r1}
159; DISABLE-V4T-NEXT: bx r1
Quentin Colombet48b77202015-07-22 16:34:37 +0000160;
Artyom Skrobov2aca0c62015-12-28 21:40:45 +0000161; ENABLE-V5T-NEXT: {{LBB[0-9_]+}}: @ %if.end
Quentin Colombet48b77202015-07-22 16:34:37 +0000162; ENABLE-NEXT: bx lr
163define i32 @freqSaveAndRestoreOutsideLoop(i32 %cond, i32 %N) {
164entry:
165 %tobool = icmp eq i32 %cond, 0
166 br i1 %tobool, label %if.else, label %for.preheader
167
168for.preheader:
169 tail call void asm "nop", ""()
170 br label %for.body
171
172for.body: ; preds = %entry, %for.body
173 %i.05 = phi i32 [ %inc, %for.body ], [ 0, %for.preheader ]
174 %sum.04 = phi i32 [ %add, %for.body ], [ 0, %for.preheader ]
175 %call = tail call i32 asm sideeffect "movs $0, #1", "=r,~{r4}"()
176 %add = add nsw i32 %call, %sum.04
177 %inc = add nuw nsw i32 %i.05, 1
178 %exitcond = icmp eq i32 %inc, 10
179 br i1 %exitcond, label %for.end, label %for.body
180
181for.end: ; preds = %for.body
182 %shl = shl i32 %add, 3
183 br label %if.end
184
185if.else: ; preds = %entry
186 %mul = shl nsw i32 %N, 1
187 br label %if.end
188
189if.end: ; preds = %if.else, %for.end
190 %sum.1 = phi i32 [ %shl, %for.end ], [ %mul, %if.else ]
191 ret i32 %sum.1
192}
193
194declare i32 @something(...)
195
196; Check that we do not perform the shrink-wrapping inside the loop even
197; though that would be legal. The cost model must prevent that.
198; CHECK-LABEL: freqSaveAndRestoreOutsideLoop2:
199; Prologue code.
200; Make sure we save the CSR used in the inline asm: r4.
201; CHECK: push {r4
202; This is the nop.
203; CHECK: mov r8, r8
204; CHECK: movs [[SUM:r0]], #0
205; CHECK-NEXT: movs [[IV:r[0-9]+]], #10
206; Next BB.
207; CHECK: [[LOOP_LABEL:LBB[0-9_]+]]: @ %for.body
208; CHECK: movs [[TMP:r[0-9]+]], #1
209; CHECK: adds [[SUM]], [[TMP]], [[SUM]]
210; CHECK-NEXT: subs [[IV]], [[IV]], #1
Quentin Colombet48b77202015-07-22 16:34:37 +0000211; CHECK-NEXT: bne [[LOOP_LABEL]]
212; Next BB.
213; CHECK: @ %for.exit
214; This is the nop.
215; CHECK: mov r8, r8
216; CHECK: pop {r4
217define i32 @freqSaveAndRestoreOutsideLoop2(i32 %cond) {
218entry:
219 br label %for.preheader
220
221for.preheader:
222 tail call void asm "nop", ""()
223 br label %for.body
224
225for.body: ; preds = %for.body, %entry
226 %i.04 = phi i32 [ 0, %for.preheader ], [ %inc, %for.body ]
227 %sum.03 = phi i32 [ 0, %for.preheader ], [ %add, %for.body ]
228 %call = tail call i32 asm sideeffect "movs $0, #1", "=r,~{r4}"()
229 %add = add nsw i32 %call, %sum.03
230 %inc = add nuw nsw i32 %i.04, 1
231 %exitcond = icmp eq i32 %inc, 10
232 br i1 %exitcond, label %for.exit, label %for.body
233
234for.exit:
235 tail call void asm "nop", ""()
236 br label %for.end
237
238for.end: ; preds = %for.body
239 ret i32 %add
240}
241
242; Check with a more complex case that we do not have save within the loop and
243; restore outside.
244; CHECK-LABEL: loopInfoSaveOutsideLoop:
245;
246; ENABLE: cmp r0, #0
247; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
248;
249; Prologue code.
250; Make sure we save the CSR used in the inline asm: r4.
251; CHECK: push {r4, lr}
252;
253; DISABLE: cmp r0, #0
254; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
255;
256; SUM is in r0 because it is coalesced with the second
257; argument on the else path.
258; CHECK: movs [[SUM:r0]], #0
259; CHECK-NEXT: movs [[IV:r[0-9]+]], #10
260;
261; Next BB.
262; CHECK: [[LOOP:LBB[0-9_]+]]: @ %for.body
263; CHECK: movs [[TMP:r[0-9]+]], #1
264; CHECK: adds [[SUM]], [[TMP]], [[SUM]]
265; CHECK-NEXT: subs [[IV]], [[IV]], #1
Quentin Colombet48b77202015-07-22 16:34:37 +0000266; CHECK-NEXT: bne [[LOOP]]
267;
268; Next BB.
269; SUM << 3.
270; CHECK: lsls [[SUM]], [[SUM]], #3
Artyom Skrobov2aca0c62015-12-28 21:40:45 +0000271; ENABLE-V5T-NEXT: pop {r4, pc}
272; ENABLE-V4T-NEXT: pop {r4}
273; ENABLE-V4T-NEXT: pop {r1}
274; ENABLE-V4T-NEXT: bx r1
Quentin Colombet48b77202015-07-22 16:34:37 +0000275;
276; Duplicated epilogue.
Artyom Skrobov0a37b802015-12-08 19:59:01 +0000277; DISABLE-V5T: pop {r4, pc}
278; DISABLE-V4T: b [[END_LABEL:LBB[0-9_]+]]
Quentin Colombet48b77202015-07-22 16:34:37 +0000279;
280; CHECK: [[ELSE_LABEL]]: @ %if.else
281; Shift second argument by one and store into returned register.
282; CHECK: lsls r0, r1, #1
Artyom Skrobov0a37b802015-12-08 19:59:01 +0000283; DISABLE-V5T-NEXT: pop {r4, pc}
284; DISABLE-V4T-NEXT: [[END_LABEL]]: @ %if.end
285; DISABLE-V4T-NEXT: pop {r4}
286; DISABLE-V4T-NEXT: pop {r1}
287; DISABLE-V4T-NEXT: bx r1
Quentin Colombet48b77202015-07-22 16:34:37 +0000288;
Artyom Skrobov2aca0c62015-12-28 21:40:45 +0000289; ENABLE-V5T-NEXT: {{LBB[0-9_]+}}: @ %if.end
Quentin Colombet48b77202015-07-22 16:34:37 +0000290; ENABLE-NEXT: bx lr
291define i32 @loopInfoSaveOutsideLoop(i32 %cond, i32 %N) {
292entry:
293 %tobool = icmp eq i32 %cond, 0
294 br i1 %tobool, label %if.else, label %for.preheader
295
296for.preheader:
297 tail call void asm "nop", ""()
298 br label %for.body
299
300for.body: ; preds = %entry, %for.body
301 %i.05 = phi i32 [ %inc, %for.body ], [ 0, %for.preheader ]
302 %sum.04 = phi i32 [ %add, %for.body ], [ 0, %for.preheader ]
303 %call = tail call i32 asm sideeffect "movs $0, #1", "=r,~{r4}"()
304 %add = add nsw i32 %call, %sum.04
305 %inc = add nuw nsw i32 %i.05, 1
306 %exitcond = icmp eq i32 %inc, 10
307 br i1 %exitcond, label %for.end, label %for.body
308
309for.end: ; preds = %for.body
310 tail call void asm "nop", "~{r4}"()
311 %shl = shl i32 %add, 3
312 br label %if.end
313
314if.else: ; preds = %entry
315 %mul = shl nsw i32 %N, 1
316 br label %if.end
317
318if.end: ; preds = %if.else, %for.end
319 %sum.1 = phi i32 [ %shl, %for.end ], [ %mul, %if.else ]
320 ret i32 %sum.1
321}
322
323declare void @somethingElse(...)
324
325; Check with a more complex case that we do not have restore within the loop and
326; save outside.
327; CHECK-LABEL: loopInfoRestoreOutsideLoop:
328;
329; ENABLE: cmp r0, #0
330; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
331;
332; Prologue code.
333; Make sure we save the CSR used in the inline asm: r4.
334; CHECK: push {r4, lr}
335;
336; DISABLE-NEXT: cmp r0, #0
337; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
338;
339; SUM is in r0 because it is coalesced with the second
340; argument on the else path.
341; CHECK: movs [[SUM:r0]], #0
342; CHECK-NEXT: movs [[IV:r[0-9]+]], #10
343;
344; Next BB.
345; CHECK: [[LOOP:LBB[0-9_]+]]: @ %for.body
346; CHECK: movs [[TMP:r[0-9]+]], #1
347; CHECK: adds [[SUM]], [[TMP]], [[SUM]]
348; CHECK-NEXT: subs [[IV]], [[IV]], #1
Quentin Colombet48b77202015-07-22 16:34:37 +0000349; CHECK-NEXT: bne [[LOOP]]
350;
351; Next BB.
352; SUM << 3.
353; CHECK: lsls [[SUM]], [[SUM]], #3
Artyom Skrobov2aca0c62015-12-28 21:40:45 +0000354; ENABLE-V5T-NEXT: pop {r4, pc}
355; ENABLE-V4T-NEXT: pop {r4}
356; ENABLE-V4T-NEXT: pop {r1}
357; ENABLE-V4T-NEXT: bx r1
Quentin Colombet48b77202015-07-22 16:34:37 +0000358;
359; Duplicated epilogue.
Artyom Skrobov0a37b802015-12-08 19:59:01 +0000360; DISABLE-V5T: pop {r4, pc}
361; DISABLE-V4T: b [[END_LABEL:LBB[0-9_]+]]
Quentin Colombet48b77202015-07-22 16:34:37 +0000362;
363; CHECK: [[ELSE_LABEL]]: @ %if.else
364; Shift second argument by one and store into returned register.
365; CHECK: lsls r0, r1, #1
Artyom Skrobov0a37b802015-12-08 19:59:01 +0000366; DISABLE-V5T-NEXT: pop {r4, pc}
367; DISABLE-V4T-NEXT: [[END_LABEL]]: @ %if.end
368; DISABLE-V4T-NEXT: pop {r4}
369; DISABLE-V4T-NEXT: pop {r1}
370; DISABLE-V4T-NEXT: bx r1
Quentin Colombet48b77202015-07-22 16:34:37 +0000371;
Artyom Skrobov2aca0c62015-12-28 21:40:45 +0000372; ENABLE-V5T-NEXT: {{LBB[0-9_]+}}: @ %if.end
Quentin Colombet48b77202015-07-22 16:34:37 +0000373; ENABLE-NEXT: bx lr
374define i32 @loopInfoRestoreOutsideLoop(i32 %cond, i32 %N) #0 {
375entry:
376 %tobool = icmp eq i32 %cond, 0
377 br i1 %tobool, label %if.else, label %if.then
378
379if.then: ; preds = %entry
380 tail call void asm "nop", "~{r4}"()
381 br label %for.body
382
383for.body: ; preds = %for.body, %if.then
384 %i.05 = phi i32 [ 0, %if.then ], [ %inc, %for.body ]
385 %sum.04 = phi i32 [ 0, %if.then ], [ %add, %for.body ]
386 %call = tail call i32 asm sideeffect "movs $0, #1", "=r,~{r4}"()
387 %add = add nsw i32 %call, %sum.04
388 %inc = add nuw nsw i32 %i.05, 1
389 %exitcond = icmp eq i32 %inc, 10
390 br i1 %exitcond, label %for.end, label %for.body
391
392for.end: ; preds = %for.body
393 %shl = shl i32 %add, 3
394 br label %if.end
395
396if.else: ; preds = %entry
397 %mul = shl nsw i32 %N, 1
398 br label %if.end
399
400if.end: ; preds = %if.else, %for.end
401 %sum.1 = phi i32 [ %shl, %for.end ], [ %mul, %if.else ]
402 ret i32 %sum.1
403}
404
405; Check that we handle function with no frame information correctly.
406; CHECK-LABEL: emptyFrame:
407; CHECK: @ %entry
408; CHECK-NEXT: movs r0, #0
409; CHECK-NEXT: bx lr
410define i32 @emptyFrame() {
411entry:
412 ret i32 0
413}
414
415; Check that we handle inline asm correctly.
416; CHECK-LABEL: inlineAsm:
417;
418; ENABLE: cmp r0, #0
419; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
420;
421; Prologue code.
422; Make sure we save the CSR used in the inline asm: r4.
423; CHECK: push {r4, lr}
424;
425; DISABLE: cmp r0, #0
426; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
427;
428; CHECK: movs [[IV:r[0-9]+]], #10
429;
430; Next BB.
431; CHECK: [[LOOP:LBB[0-9_]+]]: @ %for.body
432; CHECK: movs r4, #1
433; CHECK: subs [[IV]], [[IV]], #1
Quentin Colombet48b77202015-07-22 16:34:37 +0000434; CHECK-NEXT: bne [[LOOP]]
435;
436; Next BB.
437; CHECK: movs r0, #0
Artyom Skrobov2aca0c62015-12-28 21:40:45 +0000438; ENABLE-V5T-NEXT: pop {r4, pc}
439; ENABLE-V4T-NEXT: pop {r4}
440; ENABLE-V4T-NEXT: pop {r1}
441; ENABLE-V4T-NEXT: bx r1
Quentin Colombet48b77202015-07-22 16:34:37 +0000442;
443; Duplicated epilogue.
Artyom Skrobov0a37b802015-12-08 19:59:01 +0000444; DISABLE-V5T-NEXT: pop {r4, pc}
445; DISABLE-V4T-NEXT: b [[END_LABEL:LBB[0-9_]+]]
Quentin Colombet48b77202015-07-22 16:34:37 +0000446;
447; CHECK: [[ELSE_LABEL]]: @ %if.else
448; Shift second argument by one and store into returned register.
449; CHECK: lsls r0, r1, #1
Artyom Skrobov0a37b802015-12-08 19:59:01 +0000450; DISABLE-V5T-NEXT: pop {r4, pc}
451; DISABLE-V4T-NEXT: [[END_LABEL]]: @ %if.end
452; DISABLE-V4T-NEXT: pop {r4}
453; DISABLE-V4T-NEXT: pop {r1}
454; DISABLE-V4T-NEXT: bx r1
Quentin Colombet48b77202015-07-22 16:34:37 +0000455;
Artyom Skrobov2aca0c62015-12-28 21:40:45 +0000456; ENABLE-V5T-NEXT: {{LBB[0-9_]+}}: @ %if.end
Quentin Colombet48b77202015-07-22 16:34:37 +0000457; ENABLE-NEXT: bx lr
458define i32 @inlineAsm(i32 %cond, i32 %N) {
459entry:
460 %tobool = icmp eq i32 %cond, 0
461 br i1 %tobool, label %if.else, label %for.preheader
462
463for.preheader:
464 tail call void asm "nop", ""()
465 br label %for.body
466
467for.body: ; preds = %entry, %for.body
468 %i.03 = phi i32 [ %inc, %for.body ], [ 0, %for.preheader ]
469 tail call void asm sideeffect "movs r4, #1", "~{r4}"()
470 %inc = add nuw nsw i32 %i.03, 1
471 %exitcond = icmp eq i32 %inc, 10
472 br i1 %exitcond, label %for.exit, label %for.body
473
474for.exit:
475 tail call void asm "nop", ""()
476 br label %if.end
477
478if.else: ; preds = %entry
479 %mul = shl nsw i32 %N, 1
480 br label %if.end
481
482if.end: ; preds = %for.body, %if.else
483 %sum.0 = phi i32 [ %mul, %if.else ], [ 0, %for.exit ]
484 ret i32 %sum.0
485}
486
487; Check that we handle calls to variadic functions correctly.
488; CHECK-LABEL: callVariadicFunc:
489;
490; ENABLE: cmp r0, #0
491; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
492;
493; Prologue code.
494; CHECK: push {[[TMP:r[0-9]+]], lr}
Tim Northover747ae9a2015-11-18 21:10:39 +0000495; CHECK: sub sp, #16
Quentin Colombet48b77202015-07-22 16:34:37 +0000496;
497; DISABLE: cmp r0, #0
498; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
499;
500; Setup of the varags.
501; CHECK: mov [[TMP_SP:r[0-9]+]], sp
502; CHECK-NEXT: str r1, {{\[}}[[TMP_SP]]]
503; CHECK-NEXT: str r1, {{\[}}[[TMP_SP]], #4]
504; CHECK-NEXT: str r1, {{\[}}[[TMP_SP]], #8]
505; Thumb has quite a strange way for moving stuff
506; in around. Oh well, match the current sequence.
507; CHECK: push {r1}
508; CHECK-NEXT: pop {r0}
509; CHECK: push {r1}
510; CHECK-NEXT: pop {r2}
511; CHECK: push {r1}
512; CHECK-NEXT: pop {r3}
513; CHECK-NEXT: bl
514; CHECK-NEXT: lsls r0, r0, #3
Quentin Colombet48b77202015-07-22 16:34:37 +0000515;
Artyom Skrobov0a37b802015-12-08 19:59:01 +0000516; ENABLE-NEXT: add sp, #16
Artyom Skrobov2aca0c62015-12-28 21:40:45 +0000517; ENABLE-V5T-NEXT: pop {[[TMP]], pc}
518; ENABLE-V4T-NEXT: pop {[[TMP]]}
519; ENABLE-V4T-NEXT: pop {r1}
520; ENABLE-V4T-NEXT: bx r1
Quentin Colombet48b77202015-07-22 16:34:37 +0000521;
522; Duplicated epilogue.
Artyom Skrobov0a37b802015-12-08 19:59:01 +0000523; DISABLE-V5T-NEXT: add sp, #16
524; DISABLE-V5T-NEXT: pop {[[TMP]], pc}
525; DISABLE-V4T-NEXT: b [[END_LABEL:LBB[0-9_]+]]
Quentin Colombet48b77202015-07-22 16:34:37 +0000526;
527; CHECK: [[ELSE_LABEL]]: @ %if.else
528; Shift second argument by one and store into returned register.
529; CHECK: lsls r0, r1, #1
530;
531; Epilogue code.
Artyom Skrobov2aca0c62015-12-28 21:40:45 +0000532; ENABLE-V5T-NEXT: {{LBB[0-9_]+}}: @ %if.end
Quentin Colombet48b77202015-07-22 16:34:37 +0000533; ENABLE-NEXT: bx lr
534;
Artyom Skrobov0a37b802015-12-08 19:59:01 +0000535; DISABLE-V4T-NEXT: [[END_LABEL]]: @ %if.end
Quentin Colombet48b77202015-07-22 16:34:37 +0000536; DISABLE-NEXT: add sp, #16
Artyom Skrobov0a37b802015-12-08 19:59:01 +0000537; DISABLE-V5T-NEXT: pop {[[TMP]], pc}
538; DISABLE-V4T-NEXT: pop {[[TMP]]}
539; DISABLE-V4T-NEXT: pop {r1}
540; DISABLE-V4T-NEXT: bx r1
Quentin Colombet48b77202015-07-22 16:34:37 +0000541define i32 @callVariadicFunc(i32 %cond, i32 %N) {
542entry:
543 %tobool = icmp eq i32 %cond, 0
544 br i1 %tobool, label %if.else, label %if.then
545
546if.then: ; preds = %entry
547 %call = tail call i32 (i32, ...) @someVariadicFunc(i32 %N, i32 %N, i32 %N, i32 %N, i32 %N, i32 %N, i32 %N)
548 %shl = shl i32 %call, 3
549 br label %if.end
550
551if.else: ; preds = %entry
552 %mul = shl nsw i32 %N, 1
553 br label %if.end
554
555if.end: ; preds = %if.else, %if.then
556 %sum.0 = phi i32 [ %shl, %if.then ], [ %mul, %if.else ]
557 ret i32 %sum.0
558}
559
560declare i32 @someVariadicFunc(i32, ...)
561
562; Make sure we do not insert unreachable code after noreturn function.
563; Although this is not incorrect to insert such code, it is useless
564; and it hurts the binary size.
565;
566; CHECK-LABEL: noreturn:
567; DISABLE: push
568;
Weiming Zhao812fde32016-07-29 23:33:48 +0000569; CHECK: cmp r0, #0
Quentin Colombet48b77202015-07-22 16:34:37 +0000570; CHECK-NEXT: bne [[ABORT:LBB[0-9_]+]]
571;
572; CHECK: movs r0, #42
573;
574; ENABLE-NEXT: bx lr
575;
576; DISABLE-NEXT: pop
577;;
578; CHECK: [[ABORT]]: @ %if.abort
579;
580; ENABLE: push
581;
582; CHECK: bl
583; ENABLE-NOT: pop
584define i32 @noreturn(i8 signext %bad_thing) {
585entry:
586 %tobool = icmp eq i8 %bad_thing, 0
587 br i1 %tobool, label %if.end, label %if.abort
588
589if.abort:
590 %call = tail call i32 asm sideeffect "movs $0, #1", "=r,~{r4}"()
591 tail call void @abort() #0
592 unreachable
593
594if.end:
595 ret i32 42
596}
597
598declare void @abort() #0
599
Artyom Skrobov2aca0c62015-12-28 21:40:45 +0000600define i32 @b_to_bx(i32 %value) {
601; CHECK-LABEL: b_to_bx:
602; DISABLE: push {r7, lr}
603; CHECK: cmp r1, #49
604; CHECK-NEXT: bgt [[ELSE_LABEL:LBB[0-9_]+]]
605; ENABLE: push {r7, lr}
606
607; CHECK: bl
608; DISABLE-V5-NEXT: pop {r7, pc}
609; DISABLE-V4T-NEXT: b [[END_LABEL:LBB[0-9_]+]]
610
611; ENABLE-V5-NEXT: pop {r7, pc}
612; ENABLE-V4-NEXT: pop {r7}
613; ENABLE-V4-NEXT: pop {r1}
614; ENABLE-V4-NEXT: bx r1
615
616; CHECK: [[ELSE_LABEL]]: @ %if.else
617; CHECK-NEXT: lsls r0, r1, #1
618; DISABLE-V5-NEXT: pop {r7, pc}
619; DISABLE-V4T-NEXT: [[END_LABEL]]: @ %if.end
620; DISABLE-V4T-NEXT: pop {r7}
621; DISABLE-V4T-NEXT: pop {r1}
622; DISABLE-V4T-NEXT: bx r1
623
624; ENABLE-V5T-NEXT: {{LBB[0-9_]+}}: @ %if.end
625; ENABLE-NEXT: bx lr
626
627entry:
628 %cmp = icmp slt i32 %value, 50
629 br i1 %cmp, label %if.then, label %if.else
630
631if.then:
632 %div = sdiv i32 5000, %value
633 br label %if.end
634
635if.else:
636 %mul = shl nsw i32 %value, 1
637 br label %if.end
638
639if.end:
640 %value.addr.0 = phi i32 [ %div, %if.then ], [ %mul, %if.else ]
641 ret i32 %value.addr.0
642}
643
644define i1 @beq_to_bx(i32* %y, i32 %head) {
645; CHECK-LABEL: beq_to_bx:
646; DISABLE: push {r4, lr}
647; CHECK: cmp r2, #0
648; CHECK-NEXT: beq [[EXIT_LABEL:LBB[0-9_]+]]
649; ENABLE: push {r4, lr}
650
651; CHECK: tst r3, r4
652; ENABLE-NEXT: pop {r4}
Sjoerd Meijer96e10b52016-12-15 09:38:59 +0000653; ENABLE-NEXT: mov r12, r{{.*}}
654; ENABLE-NEXT: pop {r0}
655; ENABLE-NEXT: mov lr, r0
656; ENABLE-NEXT: mov r0, r12
Artyom Skrobov2aca0c62015-12-28 21:40:45 +0000657; CHECK-NEXT: beq [[EXIT_LABEL]]
658
659; CHECK: str r1, [r2]
Sjoerd Meijer96e10b52016-12-15 09:38:59 +0000660; CHECK: str r3, [r2]
Artyom Skrobov2aca0c62015-12-28 21:40:45 +0000661; CHECK-NEXT: movs r0, #0
662; CHECK-NEXT: [[EXIT_LABEL]]: @ %cleanup
663; ENABLE-NEXT: bx lr
664; DISABLE-V5-NEXT: pop {r4, pc}
665; DISABLE-V4T-NEXT: pop {r4}
666; DISABLE-V4T-NEXT: pop {r1}
667; DISABLE-V4T-NEXT: bx r1
668
669entry:
670 %cmp = icmp eq i32* %y, null
671 br i1 %cmp, label %cleanup, label %if.end
672
673if.end:
674 %z = load i32, i32* %y, align 4
675 %and = and i32 %z, 2
676 %cmp2 = icmp eq i32 %and, 0
677 br i1 %cmp2, label %cleanup, label %if.end4
678
679if.end4:
680 store i32 %head, i32* %y, align 4
Sjoerd Meijer96e10b52016-12-15 09:38:59 +0000681 store volatile i32 %z, i32* %y, align 4
Artyom Skrobov2aca0c62015-12-28 21:40:45 +0000682 br label %cleanup
683
684cleanup:
685 %retval.0 = phi i1 [ 0, %if.end4 ], [ 1, %entry ], [ 1, %if.end ]
686 ret i1 %retval.0
687}
688
Quentin Colombet48b77202015-07-22 16:34:37 +0000689attributes #0 = { noreturn nounwind }