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
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
16 ; Also disable the late if-converter as it makes harder to reason on
19 ; Initial motivating example: Simple diamond with a call just on one side.
22 ; Compare the arguments and jump to exit.
25 ; ENABLE-NEXT: bge [[EXIT_LABEL:LBB[0-9_]+]]
28 ; CHECK: push {r7, lr}
31 ; Compare the arguments and jump to exit.
32 ; After the prologue is set.
34 ; DISABLE-NEXT: bge [[EXIT_LABEL:LBB[0-9_]+]]
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.
41 ; CHECK-NEXT: add r1, sp, #4
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
51 ; CHECK: [[EXIT_LABEL]]:
53 ; Without shrink-wrapping, epilogue is in the exit block.
54 ; Epilogue code. (What we pop does not matter.)
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
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
68 store i32 %a, i32* %tmp, align 4
69 %tmp4 = call i32 @doSomething(i32 0, i32* %tmp)
73 %tmp.0 = phi i32 [ %tmp4, %true ], [ %a, %0 ]
78 ; Same, but the final BB is non-trivial, so we don't duplicate the return inst.
81 ; With shrink-wrapping, epilogue is just after the call.
83 ; ENABLE-NEXT: add sp, #8
84 ; ENABLE-NEXT: pop {r7}
85 ; ENABLE-NEXT: pop {r0}
86 ; ENABLE-NEXT: mov lr, r0
90 ; Without shrink-wrapping, epilogue is in the exit block.
91 ; Epilogue code. (What we pop does not matter.)
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
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
105 store i32 %a, i32* %tmp, align 4
106 %tmp4 = call i32 @doSomething(i32 0, i32* %tmp)
113 ; Function Attrs: optsize
114 declare i32 @doSomething(i32, i32*)
117 ; Check that we do not perform the restore inside the loop whereas the save
119 ; CHECK-LABEL: freqSaveAndRestoreOutsideLoop:
121 ; Shrink-wrapping allows to skip the prologue in the else case.
123 ; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
126 ; Make sure we save the CSR used in the inline asm: r4.
127 ; CHECK: push {r4, lr}
129 ; DISABLE: cmp r0, #0
130 ; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
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
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]]
147 ; CHECK: lsls [[SUM]], [[SUM]], #3
149 ; Duplicated epilogue.
150 ; DISABLE-V5T: pop {r4, pc}
151 ; DISABLE-V4T: b [[END_LABEL:LBB[0-9_]+]]
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
163 define i32 @freqSaveAndRestoreOutsideLoop(i32 %cond, i32 %N) {
165 %tobool = icmp eq i32 %cond, 0
166 br i1 %tobool, label %if.else, label %for.preheader
169 tail call void asm "nop", ""()
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
181 for.end: ; preds = %for.body
182 %shl = shl i32 %add, 3
185 if.else: ; preds = %entry
186 %mul = shl nsw i32 %N, 1
189 if.end: ; preds = %if.else, %for.end
190 %sum.1 = phi i32 [ %shl, %for.end ], [ %mul, %if.else ]
194 declare i32 @something(...)
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:
200 ; Make sure we save the CSR used in the inline asm: r4.
204 ; CHECK: movs [[SUM:r0]], #0
205 ; CHECK-NEXT: movs [[IV:r[0-9]+]], #10
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]]
218 define i32 @freqSaveAndRestoreOutsideLoop2(i32 %cond) {
220 br label %for.preheader
223 tail call void asm "nop", ""()
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
236 tail call void asm "nop", ""()
239 for.end: ; preds = %for.body
243 ; Check with a more complex case that we do not have save within the loop and
245 ; CHECK-LABEL: loopInfoSaveOutsideLoop:
248 ; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
251 ; Make sure we save the CSR used in the inline asm: r4.
252 ; CHECK: push {r4, lr}
254 ; DISABLE: cmp r0, #0
255 ; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
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
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]]
272 ; CHECK: lsls [[SUM]], [[SUM]], #3
273 ; ENABLE-NEXT: pop {r4, lr}
275 ; Duplicated epilogue.
276 ; DISABLE-V5T: pop {r4, pc}
277 ; DISABLE-V4T: b [[END_LABEL:LBB[0-9_]+]]
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
289 define i32 @loopInfoSaveOutsideLoop(i32 %cond, i32 %N) {
291 %tobool = icmp eq i32 %cond, 0
292 br i1 %tobool, label %if.else, label %for.preheader
295 tail call void asm "nop", ""()
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
307 for.end: ; preds = %for.body
308 tail call void asm "nop", "~{r4}"()
309 %shl = shl i32 %add, 3
312 if.else: ; preds = %entry
313 %mul = shl nsw i32 %N, 1
316 if.end: ; preds = %if.else, %for.end
317 %sum.1 = phi i32 [ %shl, %for.end ], [ %mul, %if.else ]
321 declare void @somethingElse(...)
323 ; Check with a more complex case that we do not have restore within the loop and
325 ; CHECK-LABEL: loopInfoRestoreOutsideLoop:
328 ; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
331 ; Make sure we save the CSR used in the inline asm: r4.
332 ; CHECK: push {r4, lr}
334 ; DISABLE-NEXT: cmp r0, #0
335 ; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
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
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]]
352 ; CHECK: lsls [[SUM]], [[SUM]], #3
353 ; ENABLE: pop {r4, lr}
355 ; Duplicated epilogue.
356 ; DISABLE-V5T: pop {r4, pc}
357 ; DISABLE-V4T: b [[END_LABEL:LBB[0-9_]+]]
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
369 define i32 @loopInfoRestoreOutsideLoop(i32 %cond, i32 %N) #0 {
371 %tobool = icmp eq i32 %cond, 0
372 br i1 %tobool, label %if.else, label %if.then
374 if.then: ; preds = %entry
375 tail call void asm "nop", "~{r4}"()
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
387 for.end: ; preds = %for.body
388 %shl = shl i32 %add, 3
391 if.else: ; preds = %entry
392 %mul = shl nsw i32 %N, 1
395 if.end: ; preds = %if.else, %for.end
396 %sum.1 = phi i32 [ %shl, %for.end ], [ %mul, %if.else ]
400 ; Check that we handle function with no frame information correctly.
401 ; CHECK-LABEL: emptyFrame:
403 ; CHECK-NEXT: movs r0, #0
405 define i32 @emptyFrame() {
410 ; Check that we handle inline asm correctly.
411 ; CHECK-LABEL: inlineAsm:
414 ; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
417 ; Make sure we save the CSR used in the inline asm: r4.
418 ; CHECK: push {r4, lr}
420 ; DISABLE: cmp r0, #0
421 ; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
423 ; CHECK: movs [[IV:r[0-9]+]], #10
426 ; CHECK: [[LOOP:LBB[0-9_]+]]: @ %for.body
428 ; CHECK: subs [[IV]], [[IV]], #1
429 ; CHECK-NEXT: cmp [[IV]], #0
430 ; CHECK-NEXT: bne [[LOOP]]
434 ; ENABLE-NEXT: pop {r4, lr}
436 ; Duplicated epilogue.
437 ; DISABLE-V5T-NEXT: pop {r4, pc}
438 ; DISABLE-V4T-NEXT: b [[END_LABEL:LBB[0-9_]+]]
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
450 define i32 @inlineAsm(i32 %cond, i32 %N) {
452 %tobool = icmp eq i32 %cond, 0
453 br i1 %tobool, label %if.else, label %for.preheader
456 tail call void asm "nop", ""()
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
467 tail call void asm "nop", ""()
470 if.else: ; preds = %entry
471 %mul = shl nsw i32 %N, 1
474 if.end: ; preds = %for.body, %if.else
475 %sum.0 = phi i32 [ %mul, %if.else ], [ 0, %for.exit ]
479 ; Check that we handle calls to variadic functions correctly.
480 ; CHECK-LABEL: callVariadicFunc:
483 ; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
486 ; CHECK: push {[[TMP:r[0-9]+]], lr}
489 ; DISABLE: cmp r0, #0
490 ; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
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.
500 ; CHECK-NEXT: pop {r0}
502 ; CHECK-NEXT: pop {r2}
504 ; CHECK-NEXT: pop {r3}
506 ; CHECK-NEXT: lsls r0, r0, #3
508 ; ENABLE-NEXT: add sp, #16
509 ; ENABLE-NEXT: pop {[[TMP]], lr}
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_]+]]
516 ; CHECK: [[ELSE_LABEL]]: @ %if.else
517 ; Shift second argument by one and store into returned register.
518 ; CHECK: lsls r0, r1, #1
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) {
531 %tobool = icmp eq i32 %cond, 0
532 br i1 %tobool, label %if.else, label %if.then
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
539 if.else: ; preds = %entry
540 %mul = shl nsw i32 %N, 1
543 if.end: ; preds = %if.else, %if.then
544 %sum.0 = phi i32 [ %shl, %if.then ], [ %mul, %if.else ]
548 declare i32 @someVariadicFunc(i32, ...)
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.
554 ; CHECK-LABEL: noreturn:
557 ; CHECK: movs [[TMP:r[0-9]+]], #255
558 ; CHECK-NEXT: tst r0, [[TMP]]
559 ; CHECK-NEXT: bne [[ABORT:LBB[0-9_]+]]
561 ; CHECK: movs r0, #42
567 ; CHECK: [[ABORT]]: @ %if.abort
573 define i32 @noreturn(i8 signext %bad_thing) {
575 %tobool = icmp eq i8 %bad_thing, 0
576 br i1 %tobool, label %if.end, label %if.abort
579 %call = tail call i32 asm sideeffect "movs $0, #1", "=r,~{r4}"()
580 tail call void @abort() #0
587 declare void @abort() #0
589 attributes #0 = { noreturn nounwind }