OSDN Git Service

Revert "CodeGen: Allow small copyable blocks to "break" the CFG."
[android-x86/external-llvm.git] / test / CodeGen / Thumb / thumb-shrink-wrapping.ll
1 ; RUN: llc %s -o - -enable-shrink-wrap=true -ifcvt-fn-start=1 -ifcvt-fn-stop=0 -mtriple=thumb-macho \
2 ; RUN:      | FileCheck %s --check-prefix=CHECK --check-prefix=ENABLE --check-prefix=ENABLE-V4T
3 ; RUN: llc %s -o - -enable-shrink-wrap=true -ifcvt-fn-start=1 -ifcvt-fn-stop=0 -mtriple=thumbv5-macho \
4 ; RUN:      | FileCheck %s --check-prefix=CHECK --check-prefix=ENABLE --check-prefix=ENABLE-V5T
5 ; RUN: llc %s -o - -enable-shrink-wrap=false -ifcvt-fn-start=1 -ifcvt-fn-stop=0 -mtriple=thumb-macho \
6 ; RUN:      | FileCheck %s --check-prefix=CHECK --check-prefix=DISABLE --check-prefix=DISABLE-V4T
7 ; RUN: llc %s -o - -enable-shrink-wrap=false -ifcvt-fn-start=1 -ifcvt-fn-stop=0 -mtriple=thumbv5-macho \
8 ; RUN:      | FileCheck %s --check-prefix=CHECK --check-prefix=DISABLE --check-prefix=DISABLE-V5T
9 ;
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}
29 ; CHECK: sub sp, #8
30 ;
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
46 ; 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
50 ;
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
56 ; DISABLE-V5T-NEXT: pop {r7, pc}
57 ; DISABLE-V4T-NEXT: pop {r7}
58 ; DISABLE-V4T-NEXT: pop {r1}
59 ; DISABLE-V4T-NEXT: bx r1
60 ;
61 ; ENABLE-NEXT: bx lr
62 define 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
67 true:
68   store i32 %a, i32* %tmp, align 4
69   %tmp4 = call i32 @doSomething(i32 0, i32* %tmp)
70   br label %false
71
72 false:
73   %tmp.0 = phi i32 [ %tmp4, %true ], [ %a, %0 ]
74   ret i32 %tmp.0
75 }
76
77
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
99 define 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
104 true:
105   store i32 %a, i32* %tmp, align 4
106   %tmp4 = call i32 @doSomething(i32 0, i32* %tmp)
107   br label %false
108
109 false:
110   ret i32 42
111 }
112
113 ; Function Attrs: optsize
114 declare 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
142 ; CHECK-NEXT: bne [[LOOP]]
143 ;
144 ; Next BB.
145 ; SUM << 3.
146 ; CHECK: lsls [[SUM]], [[SUM]], #3
147 ;
148 ; Duplicated epilogue.
149 ; DISABLE-V5T: pop {r4, pc}
150 ; DISABLE-V4T: b [[END_LABEL:LBB[0-9_]+]]
151 ;
152 ; CHECK: [[ELSE_LABEL]]: @ %if.else
153 ; Shift second argument by one and store into returned register.
154 ; CHECK: lsls r0, r1, #1
155 ; 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
160 ;
161 ; ENABLE-V5T-NEXT: {{LBB[0-9_]+}}: @ %if.end
162 ; ENABLE-NEXT: bx lr
163 define i32 @freqSaveAndRestoreOutsideLoop(i32 %cond, i32 %N) {
164 entry:
165   %tobool = icmp eq i32 %cond, 0
166   br i1 %tobool, label %if.else, label %for.preheader
167
168 for.preheader:
169   tail call void asm "nop", ""()
170   br label %for.body
171
172 for.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
181 for.end:                                          ; preds = %for.body
182   %shl = shl i32 %add, 3
183   br label %if.end
184
185 if.else:                                          ; preds = %entry
186   %mul = shl nsw i32 %N, 1
187   br label %if.end
188
189 if.end:                                           ; preds = %if.else, %for.end
190   %sum.1 = phi i32 [ %shl, %for.end ], [ %mul, %if.else ]
191   ret i32 %sum.1
192 }
193
194 declare 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
211 ; 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
217 define i32 @freqSaveAndRestoreOutsideLoop2(i32 %cond) {
218 entry:
219   br label %for.preheader
220
221 for.preheader:
222   tail call void asm "nop", ""()
223   br label %for.body
224
225 for.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
234 for.exit:
235   tail call void asm "nop", ""()
236   br label %for.end
237
238 for.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
266 ; CHECK-NEXT: bne [[LOOP]]
267 ;
268 ; Next BB.
269 ; SUM << 3.
270 ; CHECK: lsls [[SUM]], [[SUM]], #3
271 ; ENABLE-V5T-NEXT: pop {r4, pc}
272 ; ENABLE-V4T-NEXT: pop {r4}
273 ; ENABLE-V4T-NEXT: pop {r1}
274 ; ENABLE-V4T-NEXT: bx r1
275 ;
276 ; Duplicated epilogue.
277 ; DISABLE-V5T: pop {r4, pc}
278 ; DISABLE-V4T: b [[END_LABEL:LBB[0-9_]+]]
279 ;
280 ; CHECK: [[ELSE_LABEL]]: @ %if.else
281 ; Shift second argument by one and store into returned register.
282 ; CHECK: lsls r0, r1, #1
283 ; 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
288 ;
289 ; ENABLE-V5T-NEXT: {{LBB[0-9_]+}}: @ %if.end
290 ; ENABLE-NEXT: bx lr
291 define i32 @loopInfoSaveOutsideLoop(i32 %cond, i32 %N) {
292 entry:
293   %tobool = icmp eq i32 %cond, 0
294   br i1 %tobool, label %if.else, label %for.preheader
295
296 for.preheader:
297   tail call void asm "nop", ""()
298   br label %for.body
299
300 for.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
309 for.end:                                          ; preds = %for.body
310   tail call void asm "nop", "~{r4}"()
311   %shl = shl i32 %add, 3
312   br label %if.end
313
314 if.else:                                          ; preds = %entry
315   %mul = shl nsw i32 %N, 1
316   br label %if.end
317
318 if.end:                                           ; preds = %if.else, %for.end
319   %sum.1 = phi i32 [ %shl, %for.end ], [ %mul, %if.else ]
320   ret i32 %sum.1
321 }
322
323 declare 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
349 ; CHECK-NEXT: bne [[LOOP]]
350 ;
351 ; Next BB.
352 ; SUM << 3.
353 ; CHECK: lsls [[SUM]], [[SUM]], #3
354 ; ENABLE-V5T-NEXT: pop {r4, pc}
355 ; ENABLE-V4T-NEXT: pop {r4}
356 ; ENABLE-V4T-NEXT: pop {r1}
357 ; ENABLE-V4T-NEXT: bx r1
358 ;
359 ; Duplicated epilogue.
360 ; DISABLE-V5T: pop {r4, pc}
361 ; DISABLE-V4T: b [[END_LABEL:LBB[0-9_]+]]
362 ;
363 ; CHECK: [[ELSE_LABEL]]: @ %if.else
364 ; Shift second argument by one and store into returned register.
365 ; CHECK: lsls r0, r1, #1
366 ; 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
371 ;
372 ; ENABLE-V5T-NEXT: {{LBB[0-9_]+}}: @ %if.end
373 ; ENABLE-NEXT: bx lr
374 define i32 @loopInfoRestoreOutsideLoop(i32 %cond, i32 %N) #0 {
375 entry:
376   %tobool = icmp eq i32 %cond, 0
377   br i1 %tobool, label %if.else, label %if.then
378
379 if.then:                                          ; preds = %entry
380   tail call void asm "nop", "~{r4}"()
381   br label %for.body
382
383 for.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
392 for.end:                                          ; preds = %for.body
393   %shl = shl i32 %add, 3
394   br label %if.end
395
396 if.else:                                          ; preds = %entry
397   %mul = shl nsw i32 %N, 1
398   br label %if.end
399
400 if.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
410 define i32 @emptyFrame() {
411 entry:
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
434 ; CHECK-NEXT: bne [[LOOP]]
435 ;
436 ; Next BB.
437 ; CHECK: movs r0, #0
438 ; ENABLE-V5T-NEXT: pop {r4, pc}
439 ; ENABLE-V4T-NEXT: pop {r4}
440 ; ENABLE-V4T-NEXT: pop {r1}
441 ; ENABLE-V4T-NEXT: bx r1
442 ;
443 ; Duplicated epilogue.
444 ; DISABLE-V5T-NEXT: pop {r4, pc}
445 ; DISABLE-V4T-NEXT: b [[END_LABEL:LBB[0-9_]+]]
446 ;
447 ; CHECK: [[ELSE_LABEL]]: @ %if.else
448 ; Shift second argument by one and store into returned register.
449 ; CHECK: lsls r0, r1, #1
450 ; 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
455 ;
456 ; ENABLE-V5T-NEXT: {{LBB[0-9_]+}}: @ %if.end
457 ; ENABLE-NEXT: bx lr
458 define i32 @inlineAsm(i32 %cond, i32 %N) {
459 entry:
460   %tobool = icmp eq i32 %cond, 0
461   br i1 %tobool, label %if.else, label %for.preheader
462
463 for.preheader:
464   tail call void asm "nop", ""()
465   br label %for.body
466
467 for.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
474 for.exit:
475   tail call void asm "nop", ""()
476   br label %if.end
477
478 if.else:                                          ; preds = %entry
479   %mul = shl nsw i32 %N, 1
480   br label %if.end
481
482 if.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}
495 ; CHECK: sub sp, #16
496 ;
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
515 ;
516 ; ENABLE-NEXT: add sp, #16
517 ; ENABLE-V5T-NEXT: pop {[[TMP]], pc}
518 ; ENABLE-V4T-NEXT: pop {[[TMP]]}
519 ; ENABLE-V4T-NEXT: pop {r1}
520 ; ENABLE-V4T-NEXT: bx r1
521 ;
522 ; Duplicated epilogue.
523 ; DISABLE-V5T-NEXT: add sp, #16
524 ; DISABLE-V5T-NEXT: pop {[[TMP]], pc}
525 ; DISABLE-V4T-NEXT: b [[END_LABEL:LBB[0-9_]+]]
526 ;
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.
532 ; ENABLE-V5T-NEXT: {{LBB[0-9_]+}}: @ %if.end
533 ; ENABLE-NEXT: bx lr
534 ;
535 ; DISABLE-V4T-NEXT: [[END_LABEL]]: @ %if.end
536 ; DISABLE-NEXT: add sp, #16
537 ; DISABLE-V5T-NEXT: pop {[[TMP]], pc}
538 ; DISABLE-V4T-NEXT: pop {[[TMP]]}
539 ; DISABLE-V4T-NEXT: pop {r1}
540 ; DISABLE-V4T-NEXT: bx r1
541 define i32 @callVariadicFunc(i32 %cond, i32 %N) {
542 entry:
543   %tobool = icmp eq i32 %cond, 0
544   br i1 %tobool, label %if.else, label %if.then
545
546 if.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
551 if.else:                                          ; preds = %entry
552   %mul = shl nsw i32 %N, 1
553   br label %if.end
554
555 if.end:                                           ; preds = %if.else, %if.then
556   %sum.0 = phi i32 [ %shl, %if.then ], [ %mul, %if.else ]
557   ret i32 %sum.0
558 }
559
560 declare 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 ;
569 ; CHECK: cmp r0, #0
570 ; 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
584 define i32 @noreturn(i8 signext %bad_thing) {
585 entry:
586   %tobool = icmp eq i8 %bad_thing, 0
587   br i1 %tobool, label %if.end, label %if.abort
588
589 if.abort:
590   %call = tail call i32 asm sideeffect "movs $0, #1", "=r,~{r4}"()
591   tail call void @abort() #0
592   unreachable
593
594 if.end:
595   ret i32 42
596 }
597
598 declare void @abort() #0
599
600 define 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
627 entry:
628   %cmp = icmp slt i32 %value, 50
629   br i1 %cmp, label %if.then, label %if.else
630
631 if.then:
632   %div = sdiv i32 5000, %value
633   br label %if.end
634
635 if.else:
636   %mul = shl nsw i32 %value, 1
637   br label %if.end
638
639 if.end:
640   %value.addr.0 = phi i32 [ %div, %if.then ], [ %mul, %if.else ]
641   ret i32 %value.addr.0
642 }
643
644 define 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}
653 ; ENABLE-NEXT: mov r12, r{{.*}}
654 ; ENABLE-NEXT: pop {r0}
655 ; ENABLE-NEXT: mov lr, r0
656 ; ENABLE-NEXT: mov r0, r12
657 ; CHECK-NEXT: beq [[EXIT_LABEL]]
658
659 ; CHECK: str r1, [r2]
660 ; CHECK: str r3, [r2]
661 ; 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
669 entry:
670   %cmp = icmp eq i32* %y, null
671   br i1 %cmp, label %cleanup, label %if.end
672
673 if.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
679 if.end4:
680   store i32 %head, i32* %y, align 4
681   store volatile i32 %z, i32* %y, align 4
682   br label %cleanup
683
684 cleanup:
685   %retval.0 = phi i1 [ 0, %if.end4 ], [ 1, %entry ], [ 1, %if.end ]
686   ret i1 %retval.0
687 }
688
689 attributes #0 = { noreturn nounwind }