09c2ae3b4f7201f30fc56cb1f6a00f4cb585591f
[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 
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
5 ;
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
11 ; edges.
12 ; Also disable the late if-converter as it makes harder to reason on
13 ; the diffs.
14
15 ; Initial motivating example: Simple diamond with a call just on one side.
16 ; CHECK-LABEL: foo:
17 ;
18 ; Compare the arguments and jump to exit.
19 ; No prologue needed.
20 ; ENABLE: cmp r0, r1
21 ; ENABLE-NEXT: bge [[EXIT_LABEL:LBB[0-9_]+]]
22 ;
23 ; Prologue code.
24 ; CHECK: push {r7, lr}
25 ; CHECK: sub sp, #8
26 ;
27 ; Compare the arguments and jump to exit.
28 ; After the prologue is set.
29 ; DISABLE: cmp r0, r1
30 ; DISABLE-NEXT: bge [[EXIT_LABEL:LBB[0-9_]+]]
31 ;
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.
36 ; CHECK: movs r0, #0
37 ; CHECK-NEXT: add r1, sp, #4
38 ; CHECK-NEXT: bl
39 ;
40 ; With shrink-wrapping, epilogue is just after the call.
41 ; ENABLE-NEXT: add sp, #8
42 ; ENABLE-NEXT: pop {r7, lr}
43 ;
44 ; CHECK: [[EXIT_LABEL]]:
45 ;
46 ; Without shrink-wrapping, epilogue is in the exit block.
47 ; Epilogue code. (What we pop does not matter.)
48 ; DISABLE: add sp, #8
49 ; DISABLE-NEXT: pop {r7, pc}
50 ;
51 ; ENABLE-NEXT: bx lr
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
56
57 true:
58   store i32 %a, i32* %tmp, align 4
59   %tmp4 = call i32 @doSomething(i32 0, i32* %tmp)
60   br label %false
61
62 false:
63   %tmp.0 = phi i32 [ %tmp4, %true ], [ %a, %0 ]
64   ret i32 %tmp.0
65 }
66
67 ; Function Attrs: optsize
68 declare i32 @doSomething(i32, i32*)
69
70
71 ; Check that we do not perform the restore inside the loop whereas the save
72 ; is outside.
73 ; CHECK-LABEL: freqSaveAndRestoreOutsideLoop:
74 ;
75 ; Shrink-wrapping allows to skip the prologue in the else case.
76 ; ENABLE: cmp r0, #0
77 ; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
78 ;
79 ; Prologue code.
80 ; Make sure we save the CSR used in the inline asm: r4.
81 ; CHECK: push {r4, lr}
82 ;
83 ; DISABLE: cmp r0, #0
84 ; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
85 ;
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
90 ;
91 ; Next BB.
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]]
98 ;
99 ; Next BB.
100 ; SUM << 3.
101 ; CHECK: lsls [[SUM]], [[SUM]], #3
102 ;
103 ; Duplicated epilogue.
104 ; DISABLE: pop {r4, pc}
105 ;
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}
110 ;
111 ; ENABLE-NEXT: bx lr
112 define i32 @freqSaveAndRestoreOutsideLoop(i32 %cond, i32 %N) {
113 entry:
114   %tobool = icmp eq i32 %cond, 0
115   br i1 %tobool, label %if.else, label %for.preheader
116
117 for.preheader:
118   tail call void asm "nop", ""()
119   br label %for.body
120
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
129
130 for.end:                                          ; preds = %for.body
131   %shl = shl i32 %add, 3
132   br label %if.end
133
134 if.else:                                          ; preds = %entry
135   %mul = shl nsw i32 %N, 1
136   br label %if.end
137
138 if.end:                                           ; preds = %if.else, %for.end
139   %sum.1 = phi i32 [ %shl, %for.end ], [ %mul, %if.else ]
140   ret i32 %sum.1
141 }
142
143 declare i32 @something(...)
144
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:
148 ; Prologue code.
149 ; Make sure we save the CSR used in the inline asm: r4.
150 ; CHECK: push {r4
151 ; This is the nop.
152 ; CHECK: mov r8, r8
153 ; CHECK: movs [[SUM:r0]], #0
154 ; CHECK-NEXT: movs [[IV:r[0-9]+]], #10
155 ; Next BB.
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]]
162 ; Next BB.
163 ; CHECK: @ %for.exit
164 ; This is the nop.
165 ; CHECK: mov r8, r8
166 ; CHECK: pop {r4
167 define i32 @freqSaveAndRestoreOutsideLoop2(i32 %cond) {
168 entry:
169   br label %for.preheader
170
171 for.preheader:
172   tail call void asm "nop", ""()
173   br label %for.body
174
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
183
184 for.exit:
185   tail call void asm "nop", ""()
186   br label %for.end
187
188 for.end:                                          ; preds = %for.body
189   ret i32 %add
190 }
191
192 ; Check with a more complex case that we do not have save within the loop and
193 ; restore outside.
194 ; CHECK-LABEL: loopInfoSaveOutsideLoop:
195 ;
196 ; ENABLE: cmp r0, #0
197 ; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
198 ;
199 ; Prologue code.
200 ; Make sure we save the CSR used in the inline asm: r4.
201 ; CHECK: push {r4, lr}
202 ;
203 ; DISABLE: cmp r0, #0
204 ; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
205 ;
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
210 ;
211 ; Next BB.
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]]
218 ;
219 ; Next BB.
220 ; SUM << 3.
221 ; CHECK: lsls [[SUM]], [[SUM]], #3
222 ; ENABLE-NEXT: pop {r4, lr}
223 ;
224 ; Duplicated epilogue.
225 ; DISABLE: pop {r4, pc}
226 ;
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}
231 ;
232 ; ENABLE-NEXT: bx lr
233 define i32 @loopInfoSaveOutsideLoop(i32 %cond, i32 %N) {
234 entry:
235   %tobool = icmp eq i32 %cond, 0
236   br i1 %tobool, label %if.else, label %for.preheader
237
238 for.preheader:
239   tail call void asm "nop", ""()
240   br label %for.body
241
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
250
251 for.end:                                          ; preds = %for.body
252   tail call void asm "nop", "~{r4}"()
253   %shl = shl i32 %add, 3
254   br label %if.end
255
256 if.else:                                          ; preds = %entry
257   %mul = shl nsw i32 %N, 1
258   br label %if.end
259
260 if.end:                                           ; preds = %if.else, %for.end
261   %sum.1 = phi i32 [ %shl, %for.end ], [ %mul, %if.else ]
262   ret i32 %sum.1
263 }
264
265 declare void @somethingElse(...)
266
267 ; Check with a more complex case that we do not have restore within the loop and
268 ; save outside.
269 ; CHECK-LABEL: loopInfoRestoreOutsideLoop:
270 ;
271 ; ENABLE: cmp r0, #0
272 ; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
273 ;
274 ; Prologue code.
275 ; Make sure we save the CSR used in the inline asm: r4.
276 ; CHECK: push {r4, lr}
277 ;
278 ; DISABLE-NEXT: cmp r0, #0
279 ; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
280 ;
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
285 ;
286 ; Next BB.
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]]
293 ;
294 ; Next BB.
295 ; SUM << 3.
296 ; CHECK: lsls [[SUM]], [[SUM]], #3
297 ; ENABLE: pop {r4, lr}
298 ;
299 ; Duplicated epilogue.
300 ; DISABLE: pop {r4, pc}
301 ;
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}
306 ;
307 ; ENABLE-NEXT: bx lr
308 define i32 @loopInfoRestoreOutsideLoop(i32 %cond, i32 %N) #0 {
309 entry:
310   %tobool = icmp eq i32 %cond, 0
311   br i1 %tobool, label %if.else, label %if.then
312
313 if.then:                                          ; preds = %entry
314   tail call void asm "nop", "~{r4}"()
315   br label %for.body
316
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
325
326 for.end:                                          ; preds = %for.body
327   %shl = shl i32 %add, 3
328   br label %if.end
329
330 if.else:                                          ; preds = %entry
331   %mul = shl nsw i32 %N, 1
332   br label %if.end
333
334 if.end:                                           ; preds = %if.else, %for.end
335   %sum.1 = phi i32 [ %shl, %for.end ], [ %mul, %if.else ]
336   ret i32 %sum.1
337 }
338
339 ; Check that we handle function with no frame information correctly.
340 ; CHECK-LABEL: emptyFrame:
341 ; CHECK: @ %entry
342 ; CHECK-NEXT: movs r0, #0
343 ; CHECK-NEXT: bx lr
344 define i32 @emptyFrame() {
345 entry:
346   ret i32 0
347 }
348
349 ; Check that we handle inline asm correctly.
350 ; CHECK-LABEL: inlineAsm:
351 ;
352 ; ENABLE: cmp r0, #0
353 ; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
354 ;
355 ; Prologue code.
356 ; Make sure we save the CSR used in the inline asm: r4.
357 ; CHECK: push {r4, lr}
358 ;
359 ; DISABLE: cmp r0, #0
360 ; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
361 ;
362 ; CHECK: movs [[IV:r[0-9]+]], #10
363 ;
364 ; Next BB.
365 ; CHECK: [[LOOP:LBB[0-9_]+]]: @ %for.body
366 ; CHECK: movs r4, #1
367 ; CHECK: subs [[IV]], [[IV]], #1
368 ; CHECK-NEXT: cmp [[IV]], #0
369 ; CHECK-NEXT: bne [[LOOP]]
370 ;
371 ; Next BB.
372 ; CHECK: movs r0, #0
373 ; ENABLE-NEXT: pop {r4, lr}
374 ;
375 ; Duplicated epilogue.
376 ; DISABLE-NEXT: pop {r4, pc}
377 ;
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}
382 ;
383 ; ENABLE-NEXT: bx lr
384 define i32 @inlineAsm(i32 %cond, i32 %N) {
385 entry:
386   %tobool = icmp eq i32 %cond, 0
387   br i1 %tobool, label %if.else, label %for.preheader
388
389 for.preheader:
390   tail call void asm "nop", ""()
391   br label %for.body
392
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
399
400 for.exit:
401   tail call void asm "nop", ""()
402   br label %if.end
403
404 if.else:                                          ; preds = %entry
405   %mul = shl nsw i32 %N, 1
406   br label %if.end
407
408 if.end:                                           ; preds = %for.body, %if.else
409   %sum.0 = phi i32 [ %mul, %if.else ], [ 0, %for.exit ]
410   ret i32 %sum.0
411 }
412
413 ; Check that we handle calls to variadic functions correctly.
414 ; CHECK-LABEL: callVariadicFunc:
415 ;
416 ; ENABLE: cmp r0, #0
417 ; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
418 ;
419 ; Prologue code.
420 ; CHECK: push {[[TMP:r[0-9]+]], lr}
421 ; CHECK: sub sp, #16
422 ;
423 ; DISABLE: cmp r0, #0
424 ; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
425 ;
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.
433 ; CHECK: push {r1}
434 ; CHECK-NEXT: pop {r0}
435 ; CHECK: push {r1}
436 ; CHECK-NEXT: pop {r2}
437 ; CHECK: push {r1}
438 ; CHECK-NEXT: pop {r3}
439 ; CHECK-NEXT: bl
440 ; CHECK-NEXT: lsls r0, r0, #3
441 ; CHECK-NEXT: add sp, #16
442 ;
443 ; ENABLE-NEXT: pop {[[TMP]], lr}
444 ;
445 ; Duplicated epilogue.
446 ; DISABLE-NEXT: pop {[[TMP]], pc}
447 ;
448 ; CHECK: [[ELSE_LABEL]]: @ %if.else
449 ; Shift second argument by one and store into returned register.
450 ; CHECK: lsls r0, r1, #1
451 ;
452 ; Epilogue code.
453 ; ENABLE-NEXT: bx lr
454 ;
455 ; DISABLE-NEXT: add sp, #16
456 ; DISABLE-NEXT: pop {[[TMP]], pc}
457 define i32 @callVariadicFunc(i32 %cond, i32 %N) {
458 entry:
459   %tobool = icmp eq i32 %cond, 0
460   br i1 %tobool, label %if.else, label %if.then
461
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
465   br label %if.end
466
467 if.else:                                          ; preds = %entry
468   %mul = shl nsw i32 %N, 1
469   br label %if.end
470
471 if.end:                                           ; preds = %if.else, %if.then
472   %sum.0 = phi i32 [ %shl, %if.then ], [ %mul, %if.else ]
473   ret i32 %sum.0
474 }
475
476 declare i32 @someVariadicFunc(i32, ...)
477
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.
481 ;
482 ; CHECK-LABEL: noreturn:
483 ; DISABLE: push
484 ;
485 ; CHECK: movs [[TMP:r[0-9]+]], #255
486 ; CHECK-NEXT: tst  r0, [[TMP]]
487 ; CHECK-NEXT: bne      [[ABORT:LBB[0-9_]+]]
488 ;
489 ; CHECK: movs r0, #42
490 ;
491 ; ENABLE-NEXT: bx lr
492 ;
493 ; DISABLE-NEXT: pop
494 ;;
495 ; CHECK: [[ABORT]]: @ %if.abort
496 ;
497 ; ENABLE: push
498 ;
499 ; CHECK: bl
500 ; ENABLE-NOT: pop
501 define i32 @noreturn(i8 signext %bad_thing) {
502 entry:
503   %tobool = icmp eq i8 %bad_thing, 0
504   br i1 %tobool, label %if.end, label %if.abort
505
506 if.abort:
507   %call = tail call i32 asm sideeffect "movs $0, #1", "=r,~{r4}"()
508   tail call void @abort() #0
509   unreachable
510
511 if.end:
512   ret i32 42
513 }
514
515 declare void @abort() #0
516
517 attributes #0 = { noreturn nounwind }