[WebAssembly] Use the new offset syntax for memory operands in inline asm.
[oota-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: cmp [[IV]], #0
143 ; CHECK-NEXT: bne [[LOOP]]
144 ;
145 ; Next BB.
146 ; SUM << 3.
147 ; CHECK: lsls [[SUM]], [[SUM]], #3
148 ;
149 ; Duplicated epilogue.
150 ; DISABLE-V5T: pop {r4, pc}
151 ; DISABLE-V4T: b [[END_LABEL:LBB[0-9_]+]]
152 ;
153 ; CHECK: [[ELSE_LABEL]]: @ %if.else
154 ; Shift second argument by one and store into returned register.
155 ; CHECK: lsls r0, r1, #1
156 ; DISABLE-V5T-NEXT: pop {r4, pc}
157 ; DISABLE-V4T-NEXT: [[END_LABEL]]: @ %if.end
158 ; DISABLE-V4T-NEXT: pop {r4}
159 ; DISABLE-V4T-NEXT: pop {r1}
160 ; DISABLE-V4T-NEXT: bx r1
161 ;
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: cmp [[IV]], #0
212 ; CHECK-NEXT: bne [[LOOP_LABEL]]
213 ; Next BB.
214 ; CHECK: @ %for.exit
215 ; This is the nop.
216 ; CHECK: mov r8, r8
217 ; CHECK: pop {r4
218 define i32 @freqSaveAndRestoreOutsideLoop2(i32 %cond) {
219 entry:
220   br label %for.preheader
221
222 for.preheader:
223   tail call void asm "nop", ""()
224   br label %for.body
225
226 for.body:                                         ; preds = %for.body, %entry
227   %i.04 = phi i32 [ 0, %for.preheader ], [ %inc, %for.body ]
228   %sum.03 = phi i32 [ 0, %for.preheader ], [ %add, %for.body ]
229   %call = tail call i32 asm sideeffect "movs $0, #1", "=r,~{r4}"()
230   %add = add nsw i32 %call, %sum.03
231   %inc = add nuw nsw i32 %i.04, 1
232   %exitcond = icmp eq i32 %inc, 10
233   br i1 %exitcond, label %for.exit, label %for.body
234
235 for.exit:
236   tail call void asm "nop", ""()
237   br label %for.end
238
239 for.end:                                          ; preds = %for.body
240   ret i32 %add
241 }
242
243 ; Check with a more complex case that we do not have save within the loop and
244 ; restore outside.
245 ; CHECK-LABEL: loopInfoSaveOutsideLoop:
246 ;
247 ; ENABLE: cmp r0, #0
248 ; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
249 ;
250 ; Prologue code.
251 ; Make sure we save the CSR used in the inline asm: r4.
252 ; CHECK: push {r4, lr}
253 ;
254 ; DISABLE: cmp r0, #0
255 ; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
256 ;
257 ; SUM is in r0 because it is coalesced with the second
258 ; argument on the else path.
259 ; CHECK: movs [[SUM:r0]], #0
260 ; CHECK-NEXT: movs [[IV:r[0-9]+]], #10
261 ;
262 ; Next BB.
263 ; CHECK: [[LOOP:LBB[0-9_]+]]: @ %for.body
264 ; CHECK: movs [[TMP:r[0-9]+]], #1
265 ; CHECK: adds [[SUM]], [[TMP]], [[SUM]]
266 ; CHECK-NEXT: subs [[IV]], [[IV]], #1
267 ; CHECK-NEXT: cmp [[IV]], #0
268 ; CHECK-NEXT: bne [[LOOP]]
269 ;
270 ; Next BB.
271 ; SUM << 3.
272 ; CHECK: lsls [[SUM]], [[SUM]], #3
273 ; ENABLE-NEXT: pop {r4, lr}
274 ;
275 ; Duplicated epilogue.
276 ; DISABLE-V5T: pop {r4, pc}
277 ; DISABLE-V4T: b [[END_LABEL:LBB[0-9_]+]]
278 ;
279 ; CHECK: [[ELSE_LABEL]]: @ %if.else
280 ; Shift second argument by one and store into returned register.
281 ; CHECK: lsls r0, r1, #1
282 ; DISABLE-V5T-NEXT: pop {r4, pc}
283 ; DISABLE-V4T-NEXT: [[END_LABEL]]: @ %if.end
284 ; DISABLE-V4T-NEXT: pop {r4}
285 ; DISABLE-V4T-NEXT: pop {r1}
286 ; DISABLE-V4T-NEXT: bx r1
287 ;
288 ; ENABLE-NEXT: bx lr
289 define i32 @loopInfoSaveOutsideLoop(i32 %cond, i32 %N) {
290 entry:
291   %tobool = icmp eq i32 %cond, 0
292   br i1 %tobool, label %if.else, label %for.preheader
293
294 for.preheader:
295   tail call void asm "nop", ""()
296   br label %for.body
297
298 for.body:                                         ; preds = %entry, %for.body
299   %i.05 = phi i32 [ %inc, %for.body ], [ 0, %for.preheader ]
300   %sum.04 = phi i32 [ %add, %for.body ], [ 0, %for.preheader ]
301   %call = tail call i32 asm sideeffect "movs $0, #1", "=r,~{r4}"()
302   %add = add nsw i32 %call, %sum.04
303   %inc = add nuw nsw i32 %i.05, 1
304   %exitcond = icmp eq i32 %inc, 10
305   br i1 %exitcond, label %for.end, label %for.body
306
307 for.end:                                          ; preds = %for.body
308   tail call void asm "nop", "~{r4}"()
309   %shl = shl i32 %add, 3
310   br label %if.end
311
312 if.else:                                          ; preds = %entry
313   %mul = shl nsw i32 %N, 1
314   br label %if.end
315
316 if.end:                                           ; preds = %if.else, %for.end
317   %sum.1 = phi i32 [ %shl, %for.end ], [ %mul, %if.else ]
318   ret i32 %sum.1
319 }
320
321 declare void @somethingElse(...)
322
323 ; Check with a more complex case that we do not have restore within the loop and
324 ; save outside.
325 ; CHECK-LABEL: loopInfoRestoreOutsideLoop:
326 ;
327 ; ENABLE: cmp r0, #0
328 ; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
329 ;
330 ; Prologue code.
331 ; Make sure we save the CSR used in the inline asm: r4.
332 ; CHECK: push {r4, lr}
333 ;
334 ; DISABLE-NEXT: cmp r0, #0
335 ; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
336 ;
337 ; SUM is in r0 because it is coalesced with the second
338 ; argument on the else path.
339 ; CHECK: movs [[SUM:r0]], #0
340 ; CHECK-NEXT: movs [[IV:r[0-9]+]], #10
341 ;
342 ; Next BB.
343 ; CHECK: [[LOOP:LBB[0-9_]+]]: @ %for.body
344 ; CHECK: movs [[TMP:r[0-9]+]], #1
345 ; CHECK: adds [[SUM]], [[TMP]], [[SUM]]
346 ; CHECK-NEXT: subs [[IV]], [[IV]], #1
347 ; CHECK-NEXT: cmp [[IV]], #0
348 ; CHECK-NEXT: bne [[LOOP]]
349 ;
350 ; Next BB.
351 ; SUM << 3.
352 ; CHECK: lsls [[SUM]], [[SUM]], #3
353 ; ENABLE: pop {r4, lr}
354 ;
355 ; Duplicated epilogue.
356 ; DISABLE-V5T: pop {r4, pc}
357 ; DISABLE-V4T: b [[END_LABEL:LBB[0-9_]+]]
358 ;
359 ; CHECK: [[ELSE_LABEL]]: @ %if.else
360 ; Shift second argument by one and store into returned register.
361 ; CHECK: lsls r0, r1, #1
362 ; DISABLE-V5T-NEXT: pop {r4, pc}
363 ; DISABLE-V4T-NEXT: [[END_LABEL]]: @ %if.end
364 ; DISABLE-V4T-NEXT: pop {r4}
365 ; DISABLE-V4T-NEXT: pop {r1}
366 ; DISABLE-V4T-NEXT: bx r1
367 ;
368 ; ENABLE-NEXT: bx lr
369 define i32 @loopInfoRestoreOutsideLoop(i32 %cond, i32 %N) #0 {
370 entry:
371   %tobool = icmp eq i32 %cond, 0
372   br i1 %tobool, label %if.else, label %if.then
373
374 if.then:                                          ; preds = %entry
375   tail call void asm "nop", "~{r4}"()
376   br label %for.body
377
378 for.body:                                         ; preds = %for.body, %if.then
379   %i.05 = phi i32 [ 0, %if.then ], [ %inc, %for.body ]
380   %sum.04 = phi i32 [ 0, %if.then ], [ %add, %for.body ]
381   %call = tail call i32 asm sideeffect "movs $0, #1", "=r,~{r4}"()
382   %add = add nsw i32 %call, %sum.04
383   %inc = add nuw nsw i32 %i.05, 1
384   %exitcond = icmp eq i32 %inc, 10
385   br i1 %exitcond, label %for.end, label %for.body
386
387 for.end:                                          ; preds = %for.body
388   %shl = shl i32 %add, 3
389   br label %if.end
390
391 if.else:                                          ; preds = %entry
392   %mul = shl nsw i32 %N, 1
393   br label %if.end
394
395 if.end:                                           ; preds = %if.else, %for.end
396   %sum.1 = phi i32 [ %shl, %for.end ], [ %mul, %if.else ]
397   ret i32 %sum.1
398 }
399
400 ; Check that we handle function with no frame information correctly.
401 ; CHECK-LABEL: emptyFrame:
402 ; CHECK: @ %entry
403 ; CHECK-NEXT: movs r0, #0
404 ; CHECK-NEXT: bx lr
405 define i32 @emptyFrame() {
406 entry:
407   ret i32 0
408 }
409
410 ; Check that we handle inline asm correctly.
411 ; CHECK-LABEL: inlineAsm:
412 ;
413 ; ENABLE: cmp r0, #0
414 ; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
415 ;
416 ; Prologue code.
417 ; Make sure we save the CSR used in the inline asm: r4.
418 ; CHECK: push {r4, lr}
419 ;
420 ; DISABLE: cmp r0, #0
421 ; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
422 ;
423 ; CHECK: movs [[IV:r[0-9]+]], #10
424 ;
425 ; Next BB.
426 ; CHECK: [[LOOP:LBB[0-9_]+]]: @ %for.body
427 ; CHECK: movs r4, #1
428 ; CHECK: subs [[IV]], [[IV]], #1
429 ; CHECK-NEXT: cmp [[IV]], #0
430 ; CHECK-NEXT: bne [[LOOP]]
431 ;
432 ; Next BB.
433 ; CHECK: movs r0, #0
434 ; ENABLE-NEXT: pop {r4, lr}
435 ;
436 ; Duplicated epilogue.
437 ; DISABLE-V5T-NEXT: pop {r4, pc}
438 ; DISABLE-V4T-NEXT: b [[END_LABEL:LBB[0-9_]+]]
439 ;
440 ; CHECK: [[ELSE_LABEL]]: @ %if.else
441 ; Shift second argument by one and store into returned register.
442 ; CHECK: lsls r0, r1, #1
443 ; DISABLE-V5T-NEXT: pop {r4, pc}
444 ; DISABLE-V4T-NEXT: [[END_LABEL]]: @ %if.end
445 ; DISABLE-V4T-NEXT: pop {r4}
446 ; DISABLE-V4T-NEXT: pop {r1}
447 ; DISABLE-V4T-NEXT: bx r1
448 ;
449 ; ENABLE-NEXT: bx lr
450 define i32 @inlineAsm(i32 %cond, i32 %N) {
451 entry:
452   %tobool = icmp eq i32 %cond, 0
453   br i1 %tobool, label %if.else, label %for.preheader
454
455 for.preheader:
456   tail call void asm "nop", ""()
457   br label %for.body
458
459 for.body:                                         ; preds = %entry, %for.body
460   %i.03 = phi i32 [ %inc, %for.body ], [ 0, %for.preheader ]
461   tail call void asm sideeffect "movs r4, #1", "~{r4}"()
462   %inc = add nuw nsw i32 %i.03, 1
463   %exitcond = icmp eq i32 %inc, 10
464   br i1 %exitcond, label %for.exit, label %for.body
465
466 for.exit:
467   tail call void asm "nop", ""()
468   br label %if.end
469
470 if.else:                                          ; preds = %entry
471   %mul = shl nsw i32 %N, 1
472   br label %if.end
473
474 if.end:                                           ; preds = %for.body, %if.else
475   %sum.0 = phi i32 [ %mul, %if.else ], [ 0, %for.exit ]
476   ret i32 %sum.0
477 }
478
479 ; Check that we handle calls to variadic functions correctly.
480 ; CHECK-LABEL: callVariadicFunc:
481 ;
482 ; ENABLE: cmp r0, #0
483 ; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
484 ;
485 ; Prologue code.
486 ; CHECK: push {[[TMP:r[0-9]+]], lr}
487 ; CHECK: sub sp, #16
488 ;
489 ; DISABLE: cmp r0, #0
490 ; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
491 ;
492 ; Setup of the varags.
493 ; CHECK: mov [[TMP_SP:r[0-9]+]], sp
494 ; CHECK-NEXT: str r1, {{\[}}[[TMP_SP]]]
495 ; CHECK-NEXT: str r1, {{\[}}[[TMP_SP]], #4]
496 ; CHECK-NEXT: str r1, {{\[}}[[TMP_SP]], #8]
497 ; Thumb has quite a strange way for moving stuff
498 ; in around. Oh well, match the current sequence.
499 ; CHECK: push {r1}
500 ; CHECK-NEXT: pop {r0}
501 ; CHECK: push {r1}
502 ; CHECK-NEXT: pop {r2}
503 ; CHECK: push {r1}
504 ; CHECK-NEXT: pop {r3}
505 ; CHECK-NEXT: bl
506 ; CHECK-NEXT: lsls r0, r0, #3
507 ;
508 ; ENABLE-NEXT: add sp, #16
509 ; ENABLE-NEXT: pop {[[TMP]], lr}
510 ;
511 ; Duplicated epilogue.
512 ; DISABLE-V5T-NEXT: add sp, #16
513 ; DISABLE-V5T-NEXT: pop {[[TMP]], pc}
514 ; DISABLE-V4T-NEXT: b [[END_LABEL:LBB[0-9_]+]]
515 ;
516 ; CHECK: [[ELSE_LABEL]]: @ %if.else
517 ; Shift second argument by one and store into returned register.
518 ; CHECK: lsls r0, r1, #1
519 ;
520 ; Epilogue code.
521 ; ENABLE-NEXT: bx lr
522 ;
523 ; DISABLE-V4T-NEXT: [[END_LABEL]]: @ %if.end
524 ; DISABLE-NEXT: add sp, #16
525 ; DISABLE-V5T-NEXT: pop {[[TMP]], pc}
526 ; DISABLE-V4T-NEXT: pop {[[TMP]]}
527 ; DISABLE-V4T-NEXT: pop {r1}
528 ; DISABLE-V4T-NEXT: bx r1
529 define i32 @callVariadicFunc(i32 %cond, i32 %N) {
530 entry:
531   %tobool = icmp eq i32 %cond, 0
532   br i1 %tobool, label %if.else, label %if.then
533
534 if.then:                                          ; preds = %entry
535   %call = tail call i32 (i32, ...) @someVariadicFunc(i32 %N, i32 %N, i32 %N, i32 %N, i32 %N, i32 %N, i32 %N)
536   %shl = shl i32 %call, 3
537   br label %if.end
538
539 if.else:                                          ; preds = %entry
540   %mul = shl nsw i32 %N, 1
541   br label %if.end
542
543 if.end:                                           ; preds = %if.else, %if.then
544   %sum.0 = phi i32 [ %shl, %if.then ], [ %mul, %if.else ]
545   ret i32 %sum.0
546 }
547
548 declare i32 @someVariadicFunc(i32, ...)
549
550 ; Make sure we do not insert unreachable code after noreturn function.
551 ; Although this is not incorrect to insert such code, it is useless
552 ; and it hurts the binary size.
553 ;
554 ; CHECK-LABEL: noreturn:
555 ; DISABLE: push
556 ;
557 ; CHECK: movs [[TMP:r[0-9]+]], #255
558 ; CHECK-NEXT: tst  r0, [[TMP]]
559 ; CHECK-NEXT: bne      [[ABORT:LBB[0-9_]+]]
560 ;
561 ; CHECK: movs r0, #42
562 ;
563 ; ENABLE-NEXT: bx lr
564 ;
565 ; DISABLE-NEXT: pop
566 ;;
567 ; CHECK: [[ABORT]]: @ %if.abort
568 ;
569 ; ENABLE: push
570 ;
571 ; CHECK: bl
572 ; ENABLE-NOT: pop
573 define i32 @noreturn(i8 signext %bad_thing) {
574 entry:
575   %tobool = icmp eq i8 %bad_thing, 0
576   br i1 %tobool, label %if.end, label %if.abort
577
578 if.abort:
579   %call = tail call i32 asm sideeffect "movs $0, #1", "=r,~{r4}"()
580   tail call void @abort() #0
581   unreachable
582
583 if.end:
584   ret i32 42
585 }
586
587 declare void @abort() #0
588
589 attributes #0 = { noreturn nounwind }