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
3 ; RUN: llc %s -o - -enable-shrink-wrap=false -ifcvt-fn-start=1 -ifcvt-fn-stop=0 -mtriple=thumb-macho \
4 ; RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=DISABLE
6 ; Note: Lots of tests use inline asm instead of regular calls.
7 ; This allows to have a better control on what the allocation will do.
8 ; Otherwise, we may have spill right in the entry block, defeating
9 ; shrink-wrapping. Moreover, some of the inline asm statements (nop)
10 ; are here to ensure that the related paths do not end up as critical
12 ; Also disable the late if-converter as it makes harder to reason on
15 ; Initial motivating example: Simple diamond with a call just on one side.
18 ; Compare the arguments and jump to exit.
21 ; ENABLE-NEXT: bge [[EXIT_LABEL:LBB[0-9_]+]]
24 ; CHECK: push {r7, lr}
27 ; Compare the arguments and jump to exit.
28 ; After the prologue is set.
30 ; DISABLE-NEXT: bge [[EXIT_LABEL:LBB[0-9_]+]]
32 ; Store %a in the alloca.
33 ; CHECK: str r0, [sp, #4]
34 ; Set the alloca address in the second argument.
35 ; Set the first argument to zero.
37 ; CHECK-NEXT: add r1, sp, #4
40 ; With shrink-wrapping, epilogue is just after the call.
41 ; ENABLE-NEXT: add sp, #8
42 ; ENABLE-NEXT: pop {r7, lr}
44 ; CHECK: [[EXIT_LABEL]]:
46 ; Without shrink-wrapping, epilogue is in the exit block.
47 ; Epilogue code. (What we pop does not matter.)
49 ; DISABLE-NEXT: pop {r7, pc}
52 define i32 @foo(i32 %a, i32 %b) {
53 %tmp = alloca i32, align 4
54 %tmp2 = icmp slt i32 %a, %b
55 br i1 %tmp2, label %true, label %false
58 store i32 %a, i32* %tmp, align 4
59 %tmp4 = call i32 @doSomething(i32 0, i32* %tmp)
63 %tmp.0 = phi i32 [ %tmp4, %true ], [ %a, %0 ]
67 ; Function Attrs: optsize
68 declare i32 @doSomething(i32, i32*)
71 ; Check that we do not perform the restore inside the loop whereas the save
73 ; CHECK-LABEL: freqSaveAndRestoreOutsideLoop:
75 ; Shrink-wrapping allows to skip the prologue in the else case.
77 ; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
80 ; Make sure we save the CSR used in the inline asm: r4.
81 ; CHECK: push {r4, lr}
84 ; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
86 ; SUM is in r0 because it is coalesced with the second
87 ; argument on the else path.
88 ; CHECK: movs [[SUM:r0]], #0
89 ; CHECK-NEXT: movs [[IV:r[0-9]+]], #10
92 ; CHECK: [[LOOP:LBB[0-9_]+]]: @ %for.body
93 ; CHECK: movs [[TMP:r[0-9]+]], #1
94 ; CHECK: adds [[SUM]], [[TMP]], [[SUM]]
95 ; CHECK-NEXT: subs [[IV]], [[IV]], #1
96 ; CHECK-NEXT: cmp [[IV]], #0
97 ; CHECK-NEXT: bne [[LOOP]]
101 ; CHECK: lsls [[SUM]], [[SUM]], #3
103 ; Duplicated epilogue.
104 ; DISABLE: pop {r4, pc}
106 ; CHECK: [[ELSE_LABEL]]: @ %if.else
107 ; Shift second argument by one and store into returned register.
108 ; CHECK: lsls r0, r1, #1
109 ; DISABLE-NEXT: pop {r4, pc}
112 define i32 @freqSaveAndRestoreOutsideLoop(i32 %cond, i32 %N) {
114 %tobool = icmp eq i32 %cond, 0
115 br i1 %tobool, label %if.else, label %for.preheader
118 tail call void asm "nop", ""()
121 for.body: ; preds = %entry, %for.body
122 %i.05 = phi i32 [ %inc, %for.body ], [ 0, %for.preheader ]
123 %sum.04 = phi i32 [ %add, %for.body ], [ 0, %for.preheader ]
124 %call = tail call i32 asm sideeffect "movs $0, #1", "=r,~{r4}"()
125 %add = add nsw i32 %call, %sum.04
126 %inc = add nuw nsw i32 %i.05, 1
127 %exitcond = icmp eq i32 %inc, 10
128 br i1 %exitcond, label %for.end, label %for.body
130 for.end: ; preds = %for.body
131 %shl = shl i32 %add, 3
134 if.else: ; preds = %entry
135 %mul = shl nsw i32 %N, 1
138 if.end: ; preds = %if.else, %for.end
139 %sum.1 = phi i32 [ %shl, %for.end ], [ %mul, %if.else ]
143 declare i32 @something(...)
145 ; Check that we do not perform the shrink-wrapping inside the loop even
146 ; though that would be legal. The cost model must prevent that.
147 ; CHECK-LABEL: freqSaveAndRestoreOutsideLoop2:
149 ; Make sure we save the CSR used in the inline asm: r4.
153 ; CHECK: movs [[SUM:r0]], #0
154 ; CHECK-NEXT: movs [[IV:r[0-9]+]], #10
156 ; CHECK: [[LOOP_LABEL:LBB[0-9_]+]]: @ %for.body
157 ; CHECK: movs [[TMP:r[0-9]+]], #1
158 ; CHECK: adds [[SUM]], [[TMP]], [[SUM]]
159 ; CHECK-NEXT: subs [[IV]], [[IV]], #1
160 ; CHECK-NEXT: cmp [[IV]], #0
161 ; CHECK-NEXT: bne [[LOOP_LABEL]]
167 define i32 @freqSaveAndRestoreOutsideLoop2(i32 %cond) {
169 br label %for.preheader
172 tail call void asm "nop", ""()
175 for.body: ; preds = %for.body, %entry
176 %i.04 = phi i32 [ 0, %for.preheader ], [ %inc, %for.body ]
177 %sum.03 = phi i32 [ 0, %for.preheader ], [ %add, %for.body ]
178 %call = tail call i32 asm sideeffect "movs $0, #1", "=r,~{r4}"()
179 %add = add nsw i32 %call, %sum.03
180 %inc = add nuw nsw i32 %i.04, 1
181 %exitcond = icmp eq i32 %inc, 10
182 br i1 %exitcond, label %for.exit, label %for.body
185 tail call void asm "nop", ""()
188 for.end: ; preds = %for.body
192 ; Check with a more complex case that we do not have save within the loop and
194 ; CHECK-LABEL: loopInfoSaveOutsideLoop:
197 ; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
200 ; Make sure we save the CSR used in the inline asm: r4.
201 ; CHECK: push {r4, lr}
203 ; DISABLE: cmp r0, #0
204 ; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
206 ; SUM is in r0 because it is coalesced with the second
207 ; argument on the else path.
208 ; CHECK: movs [[SUM:r0]], #0
209 ; CHECK-NEXT: movs [[IV:r[0-9]+]], #10
212 ; CHECK: [[LOOP:LBB[0-9_]+]]: @ %for.body
213 ; CHECK: movs [[TMP:r[0-9]+]], #1
214 ; CHECK: adds [[SUM]], [[TMP]], [[SUM]]
215 ; CHECK-NEXT: subs [[IV]], [[IV]], #1
216 ; CHECK-NEXT: cmp [[IV]], #0
217 ; CHECK-NEXT: bne [[LOOP]]
221 ; CHECK: lsls [[SUM]], [[SUM]], #3
222 ; ENABLE-NEXT: pop {r4, lr}
224 ; Duplicated epilogue.
225 ; DISABLE: pop {r4, pc}
227 ; CHECK: [[ELSE_LABEL]]: @ %if.else
228 ; Shift second argument by one and store into returned register.
229 ; CHECK: lsls r0, r1, #1
230 ; DISABLE-NEXT: pop {r4, pc}
233 define i32 @loopInfoSaveOutsideLoop(i32 %cond, i32 %N) {
235 %tobool = icmp eq i32 %cond, 0
236 br i1 %tobool, label %if.else, label %for.preheader
239 tail call void asm "nop", ""()
242 for.body: ; preds = %entry, %for.body
243 %i.05 = phi i32 [ %inc, %for.body ], [ 0, %for.preheader ]
244 %sum.04 = phi i32 [ %add, %for.body ], [ 0, %for.preheader ]
245 %call = tail call i32 asm sideeffect "movs $0, #1", "=r,~{r4}"()
246 %add = add nsw i32 %call, %sum.04
247 %inc = add nuw nsw i32 %i.05, 1
248 %exitcond = icmp eq i32 %inc, 10
249 br i1 %exitcond, label %for.end, label %for.body
251 for.end: ; preds = %for.body
252 tail call void asm "nop", "~{r4}"()
253 %shl = shl i32 %add, 3
256 if.else: ; preds = %entry
257 %mul = shl nsw i32 %N, 1
260 if.end: ; preds = %if.else, %for.end
261 %sum.1 = phi i32 [ %shl, %for.end ], [ %mul, %if.else ]
265 declare void @somethingElse(...)
267 ; Check with a more complex case that we do not have restore within the loop and
269 ; CHECK-LABEL: loopInfoRestoreOutsideLoop:
272 ; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
275 ; Make sure we save the CSR used in the inline asm: r4.
276 ; CHECK: push {r4, lr}
278 ; DISABLE-NEXT: cmp r0, #0
279 ; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
281 ; SUM is in r0 because it is coalesced with the second
282 ; argument on the else path.
283 ; CHECK: movs [[SUM:r0]], #0
284 ; CHECK-NEXT: movs [[IV:r[0-9]+]], #10
287 ; CHECK: [[LOOP:LBB[0-9_]+]]: @ %for.body
288 ; CHECK: movs [[TMP:r[0-9]+]], #1
289 ; CHECK: adds [[SUM]], [[TMP]], [[SUM]]
290 ; CHECK-NEXT: subs [[IV]], [[IV]], #1
291 ; CHECK-NEXT: cmp [[IV]], #0
292 ; CHECK-NEXT: bne [[LOOP]]
296 ; CHECK: lsls [[SUM]], [[SUM]], #3
297 ; ENABLE: pop {r4, lr}
299 ; Duplicated epilogue.
300 ; DISABLE: pop {r4, pc}
302 ; CHECK: [[ELSE_LABEL]]: @ %if.else
303 ; Shift second argument by one and store into returned register.
304 ; CHECK: lsls r0, r1, #1
305 ; DISABLE-NEXT: pop {r4, pc}
308 define i32 @loopInfoRestoreOutsideLoop(i32 %cond, i32 %N) #0 {
310 %tobool = icmp eq i32 %cond, 0
311 br i1 %tobool, label %if.else, label %if.then
313 if.then: ; preds = %entry
314 tail call void asm "nop", "~{r4}"()
317 for.body: ; preds = %for.body, %if.then
318 %i.05 = phi i32 [ 0, %if.then ], [ %inc, %for.body ]
319 %sum.04 = phi i32 [ 0, %if.then ], [ %add, %for.body ]
320 %call = tail call i32 asm sideeffect "movs $0, #1", "=r,~{r4}"()
321 %add = add nsw i32 %call, %sum.04
322 %inc = add nuw nsw i32 %i.05, 1
323 %exitcond = icmp eq i32 %inc, 10
324 br i1 %exitcond, label %for.end, label %for.body
326 for.end: ; preds = %for.body
327 %shl = shl i32 %add, 3
330 if.else: ; preds = %entry
331 %mul = shl nsw i32 %N, 1
334 if.end: ; preds = %if.else, %for.end
335 %sum.1 = phi i32 [ %shl, %for.end ], [ %mul, %if.else ]
339 ; Check that we handle function with no frame information correctly.
340 ; CHECK-LABEL: emptyFrame:
342 ; CHECK-NEXT: movs r0, #0
344 define i32 @emptyFrame() {
349 ; Check that we handle inline asm correctly.
350 ; CHECK-LABEL: inlineAsm:
353 ; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
356 ; Make sure we save the CSR used in the inline asm: r4.
357 ; CHECK: push {r4, lr}
359 ; DISABLE: cmp r0, #0
360 ; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
362 ; CHECK: movs [[IV:r[0-9]+]], #10
365 ; CHECK: [[LOOP:LBB[0-9_]+]]: @ %for.body
367 ; CHECK: subs [[IV]], [[IV]], #1
368 ; CHECK-NEXT: cmp [[IV]], #0
369 ; CHECK-NEXT: bne [[LOOP]]
373 ; ENABLE-NEXT: pop {r4, lr}
375 ; Duplicated epilogue.
376 ; DISABLE-NEXT: pop {r4, pc}
378 ; CHECK: [[ELSE_LABEL]]: @ %if.else
379 ; Shift second argument by one and store into returned register.
380 ; CHECK: lsls r0, r1, #1
381 ; DISABLE-NEXT: pop {r4, pc}
384 define i32 @inlineAsm(i32 %cond, i32 %N) {
386 %tobool = icmp eq i32 %cond, 0
387 br i1 %tobool, label %if.else, label %for.preheader
390 tail call void asm "nop", ""()
393 for.body: ; preds = %entry, %for.body
394 %i.03 = phi i32 [ %inc, %for.body ], [ 0, %for.preheader ]
395 tail call void asm sideeffect "movs r4, #1", "~{r4}"()
396 %inc = add nuw nsw i32 %i.03, 1
397 %exitcond = icmp eq i32 %inc, 10
398 br i1 %exitcond, label %for.exit, label %for.body
401 tail call void asm "nop", ""()
404 if.else: ; preds = %entry
405 %mul = shl nsw i32 %N, 1
408 if.end: ; preds = %for.body, %if.else
409 %sum.0 = phi i32 [ %mul, %if.else ], [ 0, %for.exit ]
413 ; Check that we handle calls to variadic functions correctly.
414 ; CHECK-LABEL: callVariadicFunc:
417 ; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
420 ; CHECK: push {[[TMP:r[0-9]+]], lr}
423 ; DISABLE: cmp r0, #0
424 ; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
426 ; Setup of the varags.
427 ; CHECK: mov [[TMP_SP:r[0-9]+]], sp
428 ; CHECK-NEXT: str r1, {{\[}}[[TMP_SP]]]
429 ; CHECK-NEXT: str r1, {{\[}}[[TMP_SP]], #4]
430 ; CHECK-NEXT: str r1, {{\[}}[[TMP_SP]], #8]
431 ; Thumb has quite a strange way for moving stuff
432 ; in around. Oh well, match the current sequence.
434 ; CHECK-NEXT: pop {r0}
436 ; CHECK-NEXT: pop {r2}
438 ; CHECK-NEXT: pop {r3}
440 ; CHECK-NEXT: lsls r0, r0, #3
441 ; CHECK-NEXT: add sp, #16
443 ; ENABLE-NEXT: pop {[[TMP]], lr}
445 ; Duplicated epilogue.
446 ; DISABLE-NEXT: pop {[[TMP]], pc}
448 ; CHECK: [[ELSE_LABEL]]: @ %if.else
449 ; Shift second argument by one and store into returned register.
450 ; CHECK: lsls r0, r1, #1
455 ; DISABLE-NEXT: add sp, #16
456 ; DISABLE-NEXT: pop {[[TMP]], pc}
457 define i32 @callVariadicFunc(i32 %cond, i32 %N) {
459 %tobool = icmp eq i32 %cond, 0
460 br i1 %tobool, label %if.else, label %if.then
462 if.then: ; preds = %entry
463 %call = tail call i32 (i32, ...) @someVariadicFunc(i32 %N, i32 %N, i32 %N, i32 %N, i32 %N, i32 %N, i32 %N)
464 %shl = shl i32 %call, 3
467 if.else: ; preds = %entry
468 %mul = shl nsw i32 %N, 1
471 if.end: ; preds = %if.else, %if.then
472 %sum.0 = phi i32 [ %shl, %if.then ], [ %mul, %if.else ]
476 declare i32 @someVariadicFunc(i32, ...)
478 ; Make sure we do not insert unreachable code after noreturn function.
479 ; Although this is not incorrect to insert such code, it is useless
480 ; and it hurts the binary size.
482 ; CHECK-LABEL: noreturn:
485 ; CHECK: movs [[TMP:r[0-9]+]], #255
486 ; CHECK-NEXT: tst r0, [[TMP]]
487 ; CHECK-NEXT: bne [[ABORT:LBB[0-9_]+]]
489 ; CHECK: movs r0, #42
495 ; CHECK: [[ABORT]]: @ %if.abort
501 define i32 @noreturn(i8 signext %bad_thing) {
503 %tobool = icmp eq i8 %bad_thing, 0
504 br i1 %tobool, label %if.end, label %if.abort
507 %call = tail call i32 asm sideeffect "movs $0, #1", "=r,~{r4}"()
508 tail call void @abort() #0
515 declare void @abort() #0
517 attributes #0 = { noreturn nounwind }