llvm.org GIT mirror llvm / c59ca90
[ARM] Make the frame lowering code ready for shrink-wrapping. Shrink-wrapping can now be tested on ARM with -enable-shrink-wrap. Related to <rdar://problem/20821730> git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@242908 91177308-0d34-0410-b5e6-96231b3b80d8 Quentin Colombet 5 years ago
5 changed file(s) with 1234 addition(s) and 127 deletion(s). Raw diff Collapse all Expand all
287287
288288 void ARMFrameLowering::emitPrologue(MachineFunction &MF,
289289 MachineBasicBlock &MBB) const {
290 assert(&MBB == &MF.front() && "Shrink-wrapping not yet implemented");
291290 MachineBasicBlock::iterator MBBI = MBB.begin();
292291 MachineFrameInfo *MFI = MF.getFrameInfo();
293292 ARMFunctionInfo *AFI = MF.getInfo();
18411840 if (!ST->isTargetAndroid() && !ST->isTargetLinux())
18421841 report_fatal_error("Segmented stacks not supported on this platform.");
18431842
1844 assert(&PrologueMBB == &MF.front() && "Shrink-wrapping not yet implemented");
18451843 MachineFrameInfo *MFI = MF.getFrameInfo();
18461844 MachineModuleInfo &MMI = MF.getMMI();
18471845 MCContext &Context = MMI.getContext();
8484
8585 void Thumb1FrameLowering::emitPrologue(MachineFunction &MF,
8686 MachineBasicBlock &MBB) const {
87 assert(&MBB == &MF.front() && "Shrink-wrapping not yet implemented");
8887 MachineBasicBlock::iterator MBBI = MBB.begin();
8988 MachineFrameInfo *MFI = MF.getFrameInfo();
9089 ARMFunctionInfo *AFI = MF.getInfo();
384383 }
385384 }
386385
386 if (needPopSpecialFixUp(MF)) {
387 bool Done = emitPopSpecialFixUp(MBB, /* DoIt */ true);
388 (void)Done;
389 assert(Done && "Emission of the special fixup failed!?");
390 }
391 }
392
393 bool Thumb1FrameLowering::canUseAsEpilogue(const MachineBasicBlock &MBB) const {
394 if (!needPopSpecialFixUp(*MBB.getParent()))
395 return true;
396
397 MachineBasicBlock *TmpMBB = const_cast(&MBB);
398 return emitPopSpecialFixUp(*TmpMBB, /* DoIt */ false);
399 }
400
401 bool Thumb1FrameLowering::needPopSpecialFixUp(const MachineFunction &MF) const {
402 ARMFunctionInfo *AFI =
403 const_cast(&MF)->getInfo();
404 if (AFI->getArgRegsSaveSize())
405 return true;
406
387407 bool IsV4PopReturn = false;
388 for (const CalleeSavedInfo &CSI : MFI->getCalleeSavedInfo())
408 for (const CalleeSavedInfo &CSI : MF.getFrameInfo()->getCalleeSavedInfo())
389409 if (CSI.getReg() == ARM::LR)
390410 IsV4PopReturn = true;
391 IsV4PopReturn &= STI.hasV4TOps() && !STI.hasV5TOps();
392
393 // Unlike T2 and ARM mode, the T1 pop instruction cannot restore
394 // to LR, and we can't pop the value directly to the PC since
395 // we need to update the SP after popping the value. So instead
396 // we have to emit:
397 // POP {r3}
398 // ADD sp, #offset
399 // BX r3
400 // If this would clobber a return value, then generate this sequence instead:
401 // MOV ip, r3
402 // POP {r3}
403 // ADD sp, #offset
404 // MOV lr, r3
405 // MOV r3, ip
406 // BX lr
407 if (ArgRegsSaveSize || IsV4PopReturn) {
408 // If MBBI is a return instruction, we may be able to directly restore
409 // LR in the PC.
410 // This is possible if we do not need to emit any SP update.
411 // Otherwise, we need a temporary register to pop the value
412 // and copy that value into LR.
413 MBBI = MBB.getFirstTerminator();
414 if (!ArgRegsSaveSize && MBBI != MBB.end() &&
415 MBBI->getOpcode() == ARM::tBX_RET) {
416 MachineInstrBuilder MIB =
417 AddDefaultPred(
418 BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII.get(ARM::tPOP_RET)))
419 .addReg(ARM::PC, RegState::Define);
420 MIB.copyImplicitOps(&*MBBI);
421 // erase the old tBX_RET instruction
422 MBB.erase(MBBI);
423 return;
424 }
425
426 // Look for a temporary register to use.
427 // First, compute the liveness information.
428 LivePhysRegs UsedRegs(STI.getRegisterInfo());
429 UsedRegs.addLiveOuts(&MBB, /*AddPristines*/ true);
430 // The semantic of pristines changed recently and now,
431 // the callee-saved registers that are touched in the function
432 // are not part of the pristines set anymore.
433 // Add those callee-saved now.
434 const TargetRegisterInfo *TRI = STI.getRegisterInfo();
435 const MCPhysReg *CSRegs = TRI->getCalleeSavedRegs(&MF);
436 for (unsigned i = 0; CSRegs[i]; ++i)
437 UsedRegs.addReg(CSRegs[i]);
438
439 DebugLoc dl = DebugLoc();
440 if (MBBI != MBB.end()) {
441 dl = MBBI->getDebugLoc();
442 auto InstUpToMBBI = MBB.end();
443 // The post-decrement is on purpose here.
444 // We want to have the liveness right before MBBI.
445 while (InstUpToMBBI-- != MBBI)
446 UsedRegs.stepBackward(*InstUpToMBBI);
447 }
448
449 // Look for a register that can be directly use in the POP.
450 unsigned PopReg = 0;
451 // And some temporary register, just in case.
452 unsigned TemporaryReg = 0;
453 BitVector PopFriendly =
454 TRI->getAllocatableSet(MF, TRI->getRegClass(ARM::tGPRRegClassID));
455 assert(PopFriendly.any() && "No allocatable pop-friendly register?!");
456 // Rebuild the GPRs from the high registers because they are removed
457 // form the GPR reg class for thumb1.
458 BitVector GPRsNoLRSP =
459 TRI->getAllocatableSet(MF, TRI->getRegClass(ARM::hGPRRegClassID));
460 GPRsNoLRSP |= PopFriendly;
461 GPRsNoLRSP.reset(ARM::LR);
462 GPRsNoLRSP.reset(ARM::SP);
463 GPRsNoLRSP.reset(ARM::PC);
464 for (int Register = GPRsNoLRSP.find_first(); Register != -1;
465 Register = GPRsNoLRSP.find_next(Register)) {
466 if (!UsedRegs.contains(Register)) {
467 // Remember the first pop-friendly register and exit.
468 if (PopFriendly.test(Register)) {
469 PopReg = Register;
470 TemporaryReg = 0;
471 break;
472 }
473 // Otherwise, remember that the register will be available to
474 // save a pop-friendly register.
475 TemporaryReg = Register;
411 return IsV4PopReturn && STI.hasV4TOps() && !STI.hasV5TOps();
412 }
413
414 bool Thumb1FrameLowering::emitPopSpecialFixUp(MachineBasicBlock &MBB,
415 bool DoIt) const {
416 MachineFunction &MF = *MBB.getParent();
417 ARMFunctionInfo *AFI = MF.getInfo();
418 unsigned ArgRegsSaveSize = AFI->getArgRegsSaveSize();
419 const TargetInstrInfo &TII = *STI.getInstrInfo();
420 const ThumbRegisterInfo *RegInfo =
421 static_cast(STI.getRegisterInfo());
422
423 // If MBBI is a return instruction, we may be able to directly restore
424 // LR in the PC.
425 // This is possible if we do not need to emit any SP update.
426 // Otherwise, we need a temporary register to pop the value
427 // and copy that value into LR.
428 auto MBBI = MBB.getFirstTerminator();
429 if (!ArgRegsSaveSize && MBBI != MBB.end() &&
430 MBBI->getOpcode() == ARM::tBX_RET) {
431 if (!DoIt)
432 return true;
433 MachineInstrBuilder MIB =
434 AddDefaultPred(
435 BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII.get(ARM::tPOP_RET)))
436 .addReg(ARM::PC, RegState::Define);
437 MIB.copyImplicitOps(&*MBBI);
438 // erase the old tBX_RET instruction
439 MBB.erase(MBBI);
440 return true;
441 }
442
443 // Look for a temporary register to use.
444 // First, compute the liveness information.
445 LivePhysRegs UsedRegs(STI.getRegisterInfo());
446 UsedRegs.addLiveOuts(&MBB, /*AddPristines*/ true);
447 // The semantic of pristines changed recently and now,
448 // the callee-saved registers that are touched in the function
449 // are not part of the pristines set anymore.
450 // Add those callee-saved now.
451 const TargetRegisterInfo *TRI = STI.getRegisterInfo();
452 const MCPhysReg *CSRegs = TRI->getCalleeSavedRegs(&MF);
453 for (unsigned i = 0; CSRegs[i]; ++i)
454 UsedRegs.addReg(CSRegs[i]);
455
456 DebugLoc dl = DebugLoc();
457 if (MBBI != MBB.end()) {
458 dl = MBBI->getDebugLoc();
459 auto InstUpToMBBI = MBB.end();
460 // The post-decrement is on purpose here.
461 // We want to have the liveness right before MBBI.
462 while (InstUpToMBBI-- != MBBI)
463 UsedRegs.stepBackward(*InstUpToMBBI);
464 }
465
466 // Look for a register that can be directly use in the POP.
467 unsigned PopReg = 0;
468 // And some temporary register, just in case.
469 unsigned TemporaryReg = 0;
470 BitVector PopFriendly =
471 TRI->getAllocatableSet(MF, TRI->getRegClass(ARM::tGPRRegClassID));
472 assert(PopFriendly.any() && "No allocatable pop-friendly register?!");
473 // Rebuild the GPRs from the high registers because they are removed
474 // form the GPR reg class for thumb1.
475 BitVector GPRsNoLRSP =
476 TRI->getAllocatableSet(MF, TRI->getRegClass(ARM::hGPRRegClassID));
477 GPRsNoLRSP |= PopFriendly;
478 GPRsNoLRSP.reset(ARM::LR);
479 GPRsNoLRSP.reset(ARM::SP);
480 GPRsNoLRSP.reset(ARM::PC);
481 for (int Register = GPRsNoLRSP.find_first(); Register != -1;
482 Register = GPRsNoLRSP.find_next(Register)) {
483 if (!UsedRegs.contains(Register)) {
484 // Remember the first pop-friendly register and exit.
485 if (PopFriendly.test(Register)) {
486 PopReg = Register;
487 TemporaryReg = 0;
488 break;
476489 }
477 }
478
479 assert((PopReg || TemporaryReg) && "Cannot get LR");
480
481 if (TemporaryReg) {
482 assert(!PopReg && "Unnecessary MOV is about to be inserted");
483 PopReg = PopFriendly.find_first();
484 AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVr))
485 .addReg(TemporaryReg, RegState::Define)
486 .addReg(PopReg, RegState::Kill));
487 }
488
489 assert(PopReg && "Do not know how to get LR");
490 AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tPOP)))
491 .addReg(PopReg, RegState::Define);
492
493 emitSPUpdate(MBB, MBBI, TII, dl, *RegInfo, ArgRegsSaveSize);
494
495 if (!TemporaryReg && MBBI != MBB.end() &&
496 MBBI->getOpcode() == ARM::tBX_RET) {
497 MachineInstrBuilder MIB = BuildMI(MBB, MBBI, dl, TII.get(ARM::tBX))
498 .addReg(PopReg, RegState::Kill);
499 AddDefaultPred(MIB);
500 MIB.copyImplicitOps(&*MBBI);
501 // erase the old tBX_RET instruction
502 MBB.erase(MBBI);
503 return;
504 }
505
490 // Otherwise, remember that the register will be available to
491 // save a pop-friendly register.
492 TemporaryReg = Register;
493 }
494 }
495
496 if (!DoIt && !PopReg && !TemporaryReg)
497 return false;
498
499 assert((PopReg || TemporaryReg) && "Cannot get LR");
500
501 if (TemporaryReg) {
502 assert(!PopReg && "Unnecessary MOV is about to be inserted");
503 PopReg = PopFriendly.find_first();
506504 AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVr))
507 .addReg(ARM::LR, RegState::Define)
505 .addReg(TemporaryReg, RegState::Define)
508506 .addReg(PopReg, RegState::Kill));
509
510 if (TemporaryReg) {
511 AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVr))
512 .addReg(PopReg, RegState::Define)
513 .addReg(TemporaryReg, RegState::Kill));
514 }
515 }
507 }
508
509 assert(PopReg && "Do not know how to get LR");
510 AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tPOP)))
511 .addReg(PopReg, RegState::Define);
512
513 emitSPUpdate(MBB, MBBI, TII, dl, *RegInfo, ArgRegsSaveSize);
514
515 if (!TemporaryReg && MBBI != MBB.end() && MBBI->getOpcode() == ARM::tBX_RET) {
516 MachineInstrBuilder MIB = BuildMI(MBB, MBBI, dl, TII.get(ARM::tBX))
517 .addReg(PopReg, RegState::Kill);
518 AddDefaultPred(MIB);
519 MIB.copyImplicitOps(&*MBBI);
520 // erase the old tBX_RET instruction
521 MBB.erase(MBBI);
522 return true;
523 }
524
525 AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVr))
526 .addReg(ARM::LR, RegState::Define)
527 .addReg(PopReg, RegState::Kill));
528
529 if (TemporaryReg) {
530 AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVr))
531 .addReg(PopReg, RegState::Define)
532 .addReg(TemporaryReg, RegState::Kill));
533 }
534
535 return true;
516536 }
517537
518538 bool Thumb1FrameLowering::
566586 const TargetInstrInfo &TII = *STI.getInstrInfo();
567587
568588 bool isVarArg = AFI->getArgRegsSaveSize() > 0;
569 DebugLoc DL = MI->getDebugLoc();
589 DebugLoc DL = MI != MBB.end() ? MI->getDebugLoc() : DebugLoc();
570590 MachineInstrBuilder MIB = BuildMI(MF, DL, TII.get(ARM::tPOP));
571591 AddDefaultPred(MIB);
572592
4444 eliminateCallFramePseudoInstr(MachineFunction &MF,
4545 MachineBasicBlock &MBB,
4646 MachineBasicBlock::iterator MI) const override;
47
48 /// Check whether or not the given \p MBB can be used as a epilogue
49 /// for the target.
50 /// The epilogue will be inserted before the first terminator of that block.
51 /// This method is used by the shrink-wrapping pass to decide if
52 /// \p MBB will be correctly handled by the target.
53 bool canUseAsEpilogue(const MachineBasicBlock &MBB) const override;
54
55 private:
56 /// Check if the frame lowering of \p MF needs a special fixup
57 /// code sequence for the epilogue.
58 /// Unlike T2 and ARM mode, the T1 pop instruction cannot restore
59 /// to LR, and we can't pop the value directly to the PC when
60 /// we need to update the SP after popping the value. So instead
61 /// we have to emit:
62 /// POP {r3}
63 /// ADD sp, #offset
64 /// BX r3
65 /// If this would clobber a return value, then generate this sequence instead:
66 /// MOV ip, r3
67 /// POP {r3}
68 /// ADD sp, #offset
69 /// MOV lr, r3
70 /// MOV r3, ip
71 /// BX lr
72 bool needPopSpecialFixUp(const MachineFunction &MF) const;
73
74 /// Emit the special fixup code sequence for the epilogue.
75 /// \see needPopSpecialFixUp for more details.
76 /// \p DoIt, tells this method whether or not to actually insert
77 /// the code sequence in \p MBB. I.e., when \p DoIt is false,
78 /// \p MBB is left untouched.
79 /// \returns For \p DoIt == true: True when the emission succeeded
80 /// false otherwise. For \p DoIt == false: True when the emission
81 /// would have been possible, false otherwise.
82 bool emitPopSpecialFixUp(MachineBasicBlock &MBB, bool DoIt) const;
4783 };
4884
4985 } // End llvm namespace
0 ; RUN: llc %s -o - -enable-shrink-wrap=true -ifcvt-fn-start=1 -ifcvt-fn-stop=0 -mtriple=armv7-apple-ios \
1 ; RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=ARM --check-prefix=ENABLE --check-prefix=ARM-ENABLE
2 ; RUN: llc %s -o - -enable-shrink-wrap=false -ifcvt-fn-start=1 -ifcvt-fn-stop=0 -mtriple=armv7-apple-ios \
3 ; RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=ARM --check-prefix=DISABLE --check-prefix=ARM-DISABLE
4 ; RUN: llc %s -o - -enable-shrink-wrap=true -ifcvt-fn-start=1 -ifcvt-fn-stop=0 -mtriple=thumbv7-apple-ios \
5 ; RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=THUMB --check-prefix=ENABLE --check-prefix=THUMB-ENABLE
6 ; RUN: llc %s -o - -enable-shrink-wrap=false -ifcvt-fn-start=1 -ifcvt-fn-stop=0 -mtriple=thumbv7-apple-ios \
7 ; RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=THUMB --check-prefix=DISABLE --check-prefix=THUMB-DISABLE
8
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-NEXT: mov r7, sp
30 ;;
31 ; Compare the arguments and jump to exit.
32 ; After the prologue is set.
33 ; DISABLE: sub sp
34 ; DISABLE: cmp r0, r1
35 ; DISABLE-NEXT: bge [[EXIT_LABEL:LBB[0-9_]+]]
36 ;
37 ; Store %a in the alloca.
38 ; ARM-ENABLE: push {r0}
39 ; THUMB-ENABLE: str r0, [sp, #-4]
40 ; DISABLE: str r0, [sp]
41 ; Set the alloca address in the second argument.
42 ; CHECK-NEXT: mov r1, sp
43 ; Set the first argument to zero.
44 ; CHECK-NEXT: mov{{s?}} r0, #0
45 ; CHECK-NEXT: bl{{x?}} _doSomething
46 ;
47 ; With shrink-wrapping, epilogue is just after the call.
48 ; ARM-ENABLE-NEXT: mov sp, r7
49 ; THUMB-ENABLE-NEXT: add sp, #4
50 ; ENABLE-NEXT: pop{{(\.w)?}} {r7, lr}
51 ;
52 ; CHECK: [[EXIT_LABEL]]:
53 ;
54 ; Without shrink-wrapping, epilogue is in the exit block.
55 ; Epilogue code. (What we pop does not matter.)
56 ; ARM-DISABLE: mov sp, r7
57 ; THUMB-DISABLE: add sp,
58 ; DISABLE-NEXT: pop {r7, pc}
59 ;
60 ; ENABLE-NEXT: bx lr
61 define i32 @foo(i32 %a, i32 %b) {
62 %tmp = alloca i32, align 4
63 %tmp2 = icmp slt i32 %a, %b
64 br i1 %tmp2, label %true, label %false
65
66 true:
67 store i32 %a, i32* %tmp, align 4
68 %tmp4 = call i32 @doSomething(i32 0, i32* %tmp)
69 br label %false
70
71 false:
72 %tmp.0 = phi i32 [ %tmp4, %true ], [ %a, %0 ]
73 ret i32 %tmp.0
74 }
75
76 ; Function Attrs: optsize
77 declare i32 @doSomething(i32, i32*)
78
79
80 ; Check that we do not perform the restore inside the loop whereas the save
81 ; is outside.
82 ; CHECK-LABEL: freqSaveAndRestoreOutsideLoop:
83 ;
84 ; Shrink-wrapping allows to skip the prologue in the else case.
85 ; ARM-ENABLE: cmp r0, #0
86 ; ARM-ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
87 ; THUMB-ENABLE: cbz r0, [[ELSE_LABEL:LBB[0-9_]+]]
88 ;
89 ; Prologue code.
90 ; Make sure we save the CSR used in the inline asm: r4.
91 ; CHECK: push {r4, r7, lr}
92 ; CHECK-NEXT: add r7, sp, #4
93 ;
94 ; ARM-DISABLE: cmp r0, #0
95 ; ARM-DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
96 ; THUMB-DISABLE: cbz r0, [[ELSE_LABEL:LBB[0-9_]+]]
97 ;
98 ; SUM is in r0 because it is coalesced with the second
99 ; argument on the else path.
100 ; CHECK: mov{{s?}} [[SUM:r0]], #0
101 ; CHECK-NEXT: mov{{s?}} [[IV:r[0-9]+]], #10
102 ;
103 ; Next BB.
104 ; CHECK: [[LOOP:LBB[0-9_]+]]: @ %for.body
105 ; CHECK: mov{{(\.w)?}} [[TMP:r[0-9]+]], #1
106 ; ARM: subs [[IV]], [[IV]], #1
107 ; THUMB: subs [[IV]], #1
108 ; ARM-NEXT: add [[SUM]], [[TMP]], [[SUM]]
109 ; THUMB-NEXT: add [[SUM]], [[TMP]]
110 ; CHECK-NEXT: bne [[LOOP]]
111 ;
112 ; Next BB.
113 ; SUM << 3.
114 ; CHECK: lsl{{s?}} [[SUM]], [[SUM]], #3
115 ; ENABLE-NEXT: pop {r4, r7, pc}
116 ;
117 ; Duplicated epilogue.
118 ; DISABLE: pop {r4, r7, pc}
119 ;
120 ; CHECK: [[ELSE_LABEL]]: @ %if.else
121 ; Shift second argument by one and store into returned register.
122 ; CHECK: lsl{{s?}} r0, r1, #1
123 ; DISABLE-NEXT: pop {r4, r7, pc}
124 ;
125 ; ENABLE-NEXT: bx lr
126 define i32 @freqSaveAndRestoreOutsideLoop(i32 %cond, i32 %N) {
127 entry:
128 %tobool = icmp eq i32 %cond, 0
129 br i1 %tobool, label %if.else, label %for.preheader
130
131 for.preheader:
132 tail call void asm "nop", ""()
133 br label %for.body
134
135 for.body: ; preds = %entry, %for.body
136 %i.05 = phi i32 [ %inc, %for.body ], [ 0, %for.preheader ]
137 %sum.04 = phi i32 [ %add, %for.body ], [ 0, %for.preheader ]
138 %call = tail call i32 asm sideeffect "mov $0, #1", "=r,~{r4}"()
139 %add = add nsw i32 %call, %sum.04
140 %inc = add nuw nsw i32 %i.05, 1
141 %exitcond = icmp eq i32 %inc, 10
142 br i1 %exitcond, label %for.end, label %for.body
143
144 for.end: ; preds = %for.body
145 %shl = shl i32 %add, 3
146 br label %if.end
147
148 if.else: ; preds = %entry
149 %mul = shl nsw i32 %N, 1
150 br label %if.end
151
152 if.end: ; preds = %if.else, %for.end
153 %sum.1 = phi i32 [ %shl, %for.end ], [ %mul, %if.else ]
154 ret i32 %sum.1
155 }
156
157 declare i32 @something(...)
158
159 ; Check that we do not perform the shrink-wrapping inside the loop even
160 ; though that would be legal. The cost model must prevent that.
161 ; CHECK-LABEL: freqSaveAndRestoreOutsideLoop2:
162 ; Prologue code.
163 ; Make sure we save the CSR used in the inline asm: r4.
164 ; CHECK: push {r4
165 ; CHECK: mov{{s?}} [[SUM:r0]], #0
166 ; CHECK-NEXT: mov{{s?}} [[IV:r[0-9]+]], #10
167 ; CHECK: nop
168 ; Next BB.
169 ; CHECK: [[LOOP_LABEL:LBB[0-9_]+]]: @ %for.body
170 ; CHECK: mov{{(\.w)?}} [[TMP:r[0-9]+]], #1
171 ; ARM: subs [[IV]], [[IV]], #1
172 ; THUMB: subs [[IV]], #1
173 ; ARM: add [[SUM]], [[TMP]], [[SUM]]
174 ; THUMB: add [[SUM]], [[TMP]]
175 ; CHECK-NEXT: bne [[LOOP_LABEL]]
176 ; Next BB.
177 ; CHECK: @ %for.exit
178 ; CHECK: nop
179 ; CHECK: pop {r4
180 define i32 @freqSaveAndRestoreOutsideLoop2(i32 %cond) {
181 entry:
182 br label %for.preheader
183
184 for.preheader:
185 tail call void asm "nop", ""()
186 br label %for.body
187
188 for.body: ; preds = %for.body, %entry
189 %i.04 = phi i32 [ 0, %for.preheader ], [ %inc, %for.body ]
190 %sum.03 = phi i32 [ 0, %for.preheader ], [ %add, %for.body ]
191 %call = tail call i32 asm sideeffect "mov $0, #1", "=r,~{r4}"()
192 %add = add nsw i32 %call, %sum.03
193 %inc = add nuw nsw i32 %i.04, 1
194 %exitcond = icmp eq i32 %inc, 10
195 br i1 %exitcond, label %for.exit, label %for.body
196
197 for.exit:
198 tail call void asm "nop", ""()
199 br label %for.end
200
201 for.end: ; preds = %for.body
202 ret i32 %add
203 }
204
205 ; Check with a more complex case that we do not have save within the loop and
206 ; restore outside.
207 ; CHECK-LABEL: loopInfoSaveOutsideLoop:
208 ;
209 ; ARM-ENABLE: cmp r0, #0
210 ; ARM-ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
211 ; THUMB-ENABLE: cbz r0, [[ELSE_LABEL:LBB[0-9_]+]]
212 ;
213 ; Prologue code.
214 ; Make sure we save the CSR used in the inline asm: r4.
215 ; CHECK: push {r4, r7, lr}
216 ; CHECK-NEXT: add r7, sp, #4
217 ;
218 ; ARM-DISABLE: cmp r0, #0
219 ; ARM-DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
220 ; THUMB-DISABLE: cbz r0, [[ELSE_LABEL:LBB[0-9_]+]]
221 ;
222 ; SUM is in r0 because it is coalesced with the second
223 ; argument on the else path.
224 ; CHECK: mov{{s?}} [[SUM:r0]], #0
225 ; CHECK-NEXT: mov{{s?}} [[IV:r[0-9]+]], #10
226 ;
227 ; Next BB.
228 ; CHECK: [[LOOP:LBB[0-9_]+]]: @ %for.body
229 ; CHECK: mov{{(\.w)?}} [[TMP:r[0-9]+]], #1
230 ; ARM: subs [[IV]], [[IV]], #1
231 ; THUMB: subs [[IV]], #1
232 ; ARM-NEXT: add [[SUM]], [[TMP]], [[SUM]]
233 ; THUMB-NEXT: add [[SUM]], [[TMP]]
234 ; CHECK-NEXT: bne [[LOOP]]
235 ;
236 ; Next BB.
237 ; SUM << 3.
238 ; CHECK: lsl{{s?}} [[SUM]], [[SUM]], #3
239 ; ENABLE: pop {r4, r7, pc}
240 ;
241 ; Duplicated epilogue.
242 ; DISABLE: pop {r4, r7, pc}
243 ;
244 ; CHECK: [[ELSE_LABEL]]: @ %if.else
245 ; Shift second argument by one and store into returned register.
246 ; CHECK: lsl{{s?}} r0, r1, #1
247 ; DISABLE-NEXT: pop {r4, r7, pc}
248 ;
249 ; ENABLE-NEXT: bx lr
250 define i32 @loopInfoSaveOutsideLoop(i32 %cond, i32 %N) {
251 entry:
252 %tobool = icmp eq i32 %cond, 0
253 br i1 %tobool, label %if.else, label %for.preheader
254
255 for.preheader:
256 tail call void asm "nop", ""()
257 br label %for.body
258
259 for.body: ; preds = %entry, %for.body
260 %i.05 = phi i32 [ %inc, %for.body ], [ 0, %for.preheader ]
261 %sum.04 = phi i32 [ %add, %for.body ], [ 0, %for.preheader ]
262 %call = tail call i32 asm sideeffect "mov $0, #1", "=r,~{r4}"()
263 %add = add nsw i32 %call, %sum.04
264 %inc = add nuw nsw i32 %i.05, 1
265 %exitcond = icmp eq i32 %inc, 10
266 br i1 %exitcond, label %for.end, label %for.body
267
268 for.end: ; preds = %for.body
269 tail call void asm "nop", "~{r4}"()
270 %shl = shl i32 %add, 3
271 br label %if.end
272
273 if.else: ; preds = %entry
274 %mul = shl nsw i32 %N, 1
275 br label %if.end
276
277 if.end: ; preds = %if.else, %for.end
278 %sum.1 = phi i32 [ %shl, %for.end ], [ %mul, %if.else ]
279 ret i32 %sum.1
280 }
281
282 declare void @somethingElse(...)
283
284 ; Check with a more complex case that we do not have restore within the loop and
285 ; save outside.
286 ; CHECK-LABEL: loopInfoRestoreOutsideLoop:
287 ;
288 ; ARM-ENABLE: cmp r0, #0
289 ; ARM-ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
290 ; THUMB-ENABLE: cbz r0, [[ELSE_LABEL:LBB[0-9_]+]]
291 ;
292 ; Prologue code.
293 ; Make sure we save the CSR used in the inline asm: r4.
294 ; CHECK: push {r4, r7, lr}
295 ; CHECK-NEXT: add r7, sp, #4
296 ;
297 ; ARM-DISABLE: cmp r0, #0
298 ; ARM-DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
299 ; THUMB-DISABLE: cbz r0, [[ELSE_LABEL:LBB[0-9_]+]]
300 ;
301 ; SUM is in r0 because it is coalesced with the second
302 ; argument on the else path.
303 ; CHECK: mov{{s?}} [[SUM:r0]], #0
304 ; CHECK-NEXT: mov{{s?}} [[IV:r[0-9]+]], #10
305 ;
306 ; Next BB.
307 ; CHECK: [[LOOP:LBB[0-9_]+]]: @ %for.body
308 ; CHECK: mov{{(\.w)?}} [[TMP:r[0-9]+]], #1
309 ; ARM: subs [[IV]], [[IV]], #1
310 ; THUMB: subs [[IV]], #1
311 ; ARM-NEXT: add [[SUM]], [[TMP]], [[SUM]]
312 ; THUMB-NEXT: add [[SUM]], [[TMP]]
313 ; CHECK-NEXT: bne [[LOOP]]
314 ;
315 ; Next BB.
316 ; SUM << 3.
317 ; CHECK: lsl{{s?}} [[SUM]], [[SUM]], #3
318 ; ENABLE-NEXT: pop {r4, r7, pc}
319 ;
320 ; Duplicated epilogue.
321 ; DISABLE: pop {r4, r7, pc}
322 ;
323 ; CHECK: [[ELSE_LABEL]]: @ %if.else
324 ; Shift second argument by one and store into returned register.
325 ; CHECK: lsl{{s?}} r0, r1, #1
326 ; DISABLE-NEXT: pop {r4, r7, pc}
327 ;
328 ; ENABLE-NEXT: bx lr
329 define i32 @loopInfoRestoreOutsideLoop(i32 %cond, i32 %N) #0 {
330 entry:
331 %tobool = icmp eq i32 %cond, 0
332 br i1 %tobool, label %if.else, label %if.then
333
334 if.then: ; preds = %entry
335 tail call void asm "nop", "~{r4}"()
336 br label %for.body
337
338 for.body: ; preds = %for.body, %if.then
339 %i.05 = phi i32 [ 0, %if.then ], [ %inc, %for.body ]
340 %sum.04 = phi i32 [ 0, %if.then ], [ %add, %for.body ]
341 %call = tail call i32 asm sideeffect "mov $0, #1", "=r,~{r4}"()
342 %add = add nsw i32 %call, %sum.04
343 %inc = add nuw nsw i32 %i.05, 1
344 %exitcond = icmp eq i32 %inc, 10
345 br i1 %exitcond, label %for.end, label %for.body
346
347 for.end: ; preds = %for.body
348 %shl = shl i32 %add, 3
349 br label %if.end
350
351 if.else: ; preds = %entry
352 %mul = shl nsw i32 %N, 1
353 br label %if.end
354
355 if.end: ; preds = %if.else, %for.end
356 %sum.1 = phi i32 [ %shl, %for.end ], [ %mul, %if.else ]
357 ret i32 %sum.1
358 }
359
360 ; Check that we handle function with no frame information correctly.
361 ; CHECK-LABEL: emptyFrame:
362 ; CHECK: @ %entry
363 ; CHECK-NEXT: mov{{s?}} r0, #0
364 ; CHECK-NEXT: bx lr
365 define i32 @emptyFrame() {
366 entry:
367 ret i32 0
368 }
369
370 ; Check that we handle inline asm correctly.
371 ; CHECK-LABEL: inlineAsm:
372 ;
373 ; ARM-ENABLE: cmp r0, #0
374 ; ARM-ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
375 ; THUMB-ENABLE: cbz r0, [[ELSE_LABEL:LBB[0-9_]+]]
376 ;
377 ; Prologue code.
378 ; Make sure we save the CSR used in the inline asm: r4.
379 ; CHECK: push {r4, r7, lr}
380 ; CHECK-NEXT: add r7, sp, #4
381 ;
382 ; ARM-DISABLE: cmp r0, #0
383 ; ARM-DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
384 ; THUMB-DISABLE: cbz r0, [[ELSE_LABEL:LBB[0-9_]+]]
385 ;
386 ; CHECK: mov{{s?}} [[IV:r[0-9]+]], #10
387 ;
388 ; Next BB.
389 ; CHECK: [[LOOP:LBB[0-9_]+]]: @ %for.body
390 ; ARM: subs [[IV]], [[IV]], #1
391 ; THUMB: subs [[IV]], #1
392 ; CHECK: add{{(\.w)?}} r4, r4, #1
393 ; CHECK: bne [[LOOP]]
394 ;
395 ; Next BB.
396 ; CHECK: mov{{s?}} r0, #0
397 ;
398 ; Duplicated epilogue.
399 ; DISABLE: pop {r4, r7, pc}
400 ;
401 ; CHECK: [[ELSE_LABEL]]: @ %if.else
402 ; Shift second argument by one and store into returned register.
403 ; CHECK: lsl{{s?}} r0, r1, #1
404 ; DISABLE-NEXT: pop {r4, r7, pc}
405 ;
406 ; ENABLE-NEXT: bx lr
407 define i32 @inlineAsm(i32 %cond, i32 %N) {
408 entry:
409 %tobool = icmp eq i32 %cond, 0
410 br i1 %tobool, label %if.else, label %for.preheader
411
412 for.preheader:
413 tail call void asm "nop", ""()
414 br label %for.body
415
416 for.body: ; preds = %entry, %for.body
417 %i.03 = phi i32 [ %inc, %for.body ], [ 0, %for.preheader ]
418 tail call void asm sideeffect "add r4, #1", "~{r4}"()
419 %inc = add nuw nsw i32 %i.03, 1
420 %exitcond = icmp eq i32 %inc, 10
421 br i1 %exitcond, label %for.exit, label %for.body
422
423 for.exit:
424 tail call void asm "nop", ""()
425 br label %if.end
426
427 if.else: ; preds = %entry
428 %mul = shl nsw i32 %N, 1
429 br label %if.end
430
431 if.end: ; preds = %for.body, %if.else
432 %sum.0 = phi i32 [ %mul, %if.else ], [ 0, %for.exit ]
433 ret i32 %sum.0
434 }
435
436 ; Check that we handle calls to variadic functions correctly.
437 ; CHECK-LABEL: callVariadicFunc:
438 ;
439 ; ARM-ENABLE: cmp r0, #0
440 ; ARM-ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
441 ; THUMB-ENABLE: cbz r0, [[ELSE_LABEL:LBB[0-9_]+]]
442 ;
443 ; Prologue code.
444 ; CHECK: push {r7, lr}
445 ; CHECK-NEXT: mov r7, sp
446 ; CHECK-NEXT: sub sp, {{(sp, )?}}#12
447 ;
448 ; ARM-DISABLE: cmp r0, #0
449 ; ARM-DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
450 ; THUMB-DISABLE-NEXT: cbz r0, [[ELSE_LABEL:LBB[0-9_]+]]
451 ;
452 ; Setup of the varags.
453 ; CHECK: mov r0, r1
454 ; CHECK-NEXT: mov r2, r1
455 ; CHECK-NEXT: mov r3, r1
456 ; ARM-NEXT: str r1, [sp]
457 ; ARM-NEXT: str r1, [sp, #4]
458 ; THUMB-NEXT: strd r1, r1, [sp]
459 ; CHECK-NEXT: str r1, [sp, #8]
460 ; CHECK-NEXT: bl{{x?}} _someVariadicFunc
461 ; CHECK-NEXT: lsl{{s?}} r0, r0, #3
462 ; ARM-NEXT: mov sp, r7
463 ; THUMB-NEXT: add sp, #12
464 ; CHECK-NEXT: pop {r7, pc}
465 ;
466 ; CHECK: [[ELSE_LABEL]]: @ %if.else
467 ; Shift second argument by one and store into returned register.
468 ; CHECK: lsl{{s?}} r0, r1, #1
469 ;
470 ; Epilogue code.
471 ; ENABLE-NEXT: bx lr
472 ;
473 ; ARM-DISABLE-NEXT: mov sp, r7
474 ; THUMB-DISABLE-NEXT: add sp, #12
475 ; DISABLE-NEXT: pop {r7, pc}
476 define i32 @callVariadicFunc(i32 %cond, i32 %N) {
477 entry:
478 %tobool = icmp eq i32 %cond, 0
479 br i1 %tobool, label %if.else, label %if.then
480
481 if.then: ; preds = %entry
482 %call = tail call i32 (i32, ...) @someVariadicFunc(i32 %N, i32 %N, i32 %N, i32 %N, i32 %N, i32 %N, i32 %N)
483 %shl = shl i32 %call, 3
484 br label %if.end
485
486 if.else: ; preds = %entry
487 %mul = shl nsw i32 %N, 1
488 br label %if.end
489
490 if.end: ; preds = %if.else, %if.then
491 %sum.0 = phi i32 [ %shl, %if.then ], [ %mul, %if.else ]
492 ret i32 %sum.0
493 }
494
495 declare i32 @someVariadicFunc(i32, ...)
496
497 ; Make sure we do not insert unreachable code after noreturn function.
498 ; Although this is not incorrect to insert such code, it is useless
499 ; and it hurts the binary size.
500 ;
501 ; CHECK-LABEL: noreturn:
502 ; DISABLE: push
503 ;
504 ; CHECK: tst{{(\.w)?}} r0, #255
505 ; CHECK-NEXT: bne [[ABORT:LBB[0-9_]+]]
506 ;
507 ; CHECK: mov{{s?}} r0, #42
508 ;
509 ; ENABLE-NEXT: bx lr
510 ;
511 ; DISABLE-NEXT: pop
512 ;;
513 ; CHECK: [[ABORT]]: @ %if.abort
514 ;
515 ; ENABLE: push
516 ;
517 ; CHECK: bl{{x?}} _abort
518 ; ENABLE-NOT: pop
519 define i32 @noreturn(i8 signext %bad_thing) {
520 entry:
521 %tobool = icmp eq i8 %bad_thing, 0
522 br i1 %tobool, label %if.end, label %if.abort
523
524 if.abort:
525 %call = tail call i32 asm sideeffect "mov $0, #1", "=r,~{r4}"()
526 tail call void @abort() #0
527 unreachable
528
529 if.end:
530 ret i32 42
531 }
532
533 declare void @abort() #0
534
535 attributes #0 = { noreturn nounwind }
0 ; RUN: llc %s -o - -enable-shrink-wrap=true -ifcvt-fn-start=1 -ifcvt-fn-stop=0 -mtriple=thumb-macho \
1 ; RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=ENABLE
2 ; RUN: llc %s -o - -enable-shrink-wrap=false -ifcvt-fn-start=1 -ifcvt-fn-stop=0 -mtriple=thumb-macho \
3 ; RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=DISABLE
4 ;
5 ; Note: Lots of tests use inline asm instead of regular calls.
6 ; This allows to have a better control on what the allocation will do.
7 ; Otherwise, we may have spill right in the entry block, defeating
8 ; shrink-wrapping. Moreover, some of the inline asm statements (nop)
9 ; are here to ensure that the related paths do not end up as critical
10 ; edges.
11 ; Also disable the late if-converter as it makes harder to reason on
12 ; the diffs.
13
14 ; Initial motivating example: Simple diamond with a call just on one side.
15 ; CHECK-LABEL: foo:
16 ;
17 ; Compare the arguments and jump to exit.
18 ; No prologue needed.
19 ; ENABLE: cmp r0, r1
20 ; ENABLE-NEXT: bge [[EXIT_LABEL:LBB[0-9_]+]]
21 ;
22 ; Prologue code.
23 ; CHECK: push {r7, lr}
24 ; CHECK-NEXT: sub sp, #8
25 ;
26 ; Compare the arguments and jump to exit.
27 ; After the prologue is set.
28 ; DISABLE: cmp r0, r1
29 ; DISABLE-NEXT: bge [[EXIT_LABEL:LBB[0-9_]+]]
30 ;
31 ; Store %a in the alloca.
32 ; CHECK: str r0, [sp, #4]
33 ; Set the alloca address in the second argument.
34 ; Set the first argument to zero.
35 ; CHECK: movs r0, #0
36 ; CHECK-NEXT: add r1, sp, #4
37 ; CHECK-NEXT: bl
38 ;
39 ; With shrink-wrapping, epilogue is just after the call.
40 ; ENABLE-NEXT: add sp, #8
41 ; ENABLE-NEXT: pop {r7, lr}
42 ;
43 ; CHECK: [[EXIT_LABEL]]:
44 ;
45 ; Without shrink-wrapping, epilogue is in the exit block.
46 ; Epilogue code. (What we pop does not matter.)
47 ; DISABLE: add sp, #8
48 ; DISABLE-NEXT: pop {r7, pc}
49 ;
50 ; ENABLE-NEXT: bx lr
51 define i32 @foo(i32 %a, i32 %b) {
52 %tmp = alloca i32, align 4
53 %tmp2 = icmp slt i32 %a, %b
54 br i1 %tmp2, label %true, label %false
55
56 true:
57 store i32 %a, i32* %tmp, align 4
58 %tmp4 = call i32 @doSomething(i32 0, i32* %tmp)
59 br label %false
60
61 false:
62 %tmp.0 = phi i32 [ %tmp4, %true ], [ %a, %0 ]
63 ret i32 %tmp.0
64 }
65
66 ; Function Attrs: optsize
67 declare i32 @doSomething(i32, i32*)
68
69
70 ; Check that we do not perform the restore inside the loop whereas the save
71 ; is outside.
72 ; CHECK-LABEL: freqSaveAndRestoreOutsideLoop:
73 ;
74 ; Shrink-wrapping allows to skip the prologue in the else case.
75 ; ENABLE: cmp r0, #0
76 ; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
77 ;
78 ; Prologue code.
79 ; Make sure we save the CSR used in the inline asm: r4.
80 ; CHECK: push {r4, lr}
81 ;
82 ; DISABLE: cmp r0, #0
83 ; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
84 ;
85 ; SUM is in r0 because it is coalesced with the second
86 ; argument on the else path.
87 ; CHECK: movs [[SUM:r0]], #0
88 ; CHECK-NEXT: movs [[IV:r[0-9]+]], #10
89 ;
90 ; Next BB.
91 ; CHECK: [[LOOP:LBB[0-9_]+]]: @ %for.body
92 ; CHECK: movs [[TMP:r[0-9]+]], #1
93 ; CHECK: adds [[SUM]], [[TMP]], [[SUM]]
94 ; CHECK-NEXT: subs [[IV]], [[IV]], #1
95 ; CHECK-NEXT: cmp [[IV]], #0
96 ; CHECK-NEXT: bne [[LOOP]]
97 ;
98 ; Next BB.
99 ; SUM << 3.
100 ; CHECK: lsls [[SUM]], [[SUM]], #3
101 ;
102 ; Duplicated epilogue.
103 ; DISABLE: pop {r4, pc}
104 ;
105 ; CHECK: [[ELSE_LABEL]]: @ %if.else
106 ; Shift second argument by one and store into returned register.
107 ; CHECK: lsls r0, r1, #1
108 ; DISABLE-NEXT: pop {r4, pc}
109 ;
110 ; ENABLE-NEXT: bx lr
111 define i32 @freqSaveAndRestoreOutsideLoop(i32 %cond, i32 %N) {
112 entry:
113 %tobool = icmp eq i32 %cond, 0
114 br i1 %tobool, label %if.else, label %for.preheader
115
116 for.preheader:
117 tail call void asm "nop", ""()
118 br label %for.body
119
120 for.body: ; preds = %entry, %for.body
121 %i.05 = phi i32 [ %inc, %for.body ], [ 0, %for.preheader ]
122 %sum.04 = phi i32 [ %add, %for.body ], [ 0, %for.preheader ]
123 %call = tail call i32 asm sideeffect "movs $0, #1", "=r,~{r4}"()
124 %add = add nsw i32 %call, %sum.04
125 %inc = add nuw nsw i32 %i.05, 1
126 %exitcond = icmp eq i32 %inc, 10
127 br i1 %exitcond, label %for.end, label %for.body
128
129 for.end: ; preds = %for.body
130 %shl = shl i32 %add, 3
131 br label %if.end
132
133 if.else: ; preds = %entry
134 %mul = shl nsw i32 %N, 1
135 br label %if.end
136
137 if.end: ; preds = %if.else, %for.end
138 %sum.1 = phi i32 [ %shl, %for.end ], [ %mul, %if.else ]
139 ret i32 %sum.1
140 }
141
142 declare i32 @something(...)
143
144 ; Check that we do not perform the shrink-wrapping inside the loop even
145 ; though that would be legal. The cost model must prevent that.
146 ; CHECK-LABEL: freqSaveAndRestoreOutsideLoop2:
147 ; Prologue code.
148 ; Make sure we save the CSR used in the inline asm: r4.
149 ; CHECK: push {r4
150 ; This is the nop.
151 ; CHECK: mov r8, r8
152 ; CHECK: movs [[SUM:r0]], #0
153 ; CHECK-NEXT: movs [[IV:r[0-9]+]], #10
154 ; Next BB.
155 ; CHECK: [[LOOP_LABEL:LBB[0-9_]+]]: @ %for.body
156 ; CHECK: movs [[TMP:r[0-9]+]], #1
157 ; CHECK: adds [[SUM]], [[TMP]], [[SUM]]
158 ; CHECK-NEXT: subs [[IV]], [[IV]], #1
159 ; CHECK-NEXT: cmp [[IV]], #0
160 ; CHECK-NEXT: bne [[LOOP_LABEL]]
161 ; Next BB.
162 ; CHECK: @ %for.exit
163 ; This is the nop.
164 ; CHECK: mov r8, r8
165 ; CHECK: pop {r4
166 define i32 @freqSaveAndRestoreOutsideLoop2(i32 %cond) {
167 entry:
168 br label %for.preheader
169
170 for.preheader:
171 tail call void asm "nop", ""()
172 br label %for.body
173
174 for.body: ; preds = %for.body, %entry
175 %i.04 = phi i32 [ 0, %for.preheader ], [ %inc, %for.body ]
176 %sum.03 = phi i32 [ 0, %for.preheader ], [ %add, %for.body ]
177 %call = tail call i32 asm sideeffect "movs $0, #1", "=r,~{r4}"()
178 %add = add nsw i32 %call, %sum.03
179 %inc = add nuw nsw i32 %i.04, 1
180 %exitcond = icmp eq i32 %inc, 10
181 br i1 %exitcond, label %for.exit, label %for.body
182
183 for.exit:
184 tail call void asm "nop", ""()
185 br label %for.end
186
187 for.end: ; preds = %for.body
188 ret i32 %add
189 }
190
191 ; Check with a more complex case that we do not have save within the loop and
192 ; restore outside.
193 ; CHECK-LABEL: loopInfoSaveOutsideLoop:
194 ;
195 ; ENABLE: cmp r0, #0
196 ; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
197 ;
198 ; Prologue code.
199 ; Make sure we save the CSR used in the inline asm: r4.
200 ; CHECK: push {r4, lr}
201 ;
202 ; DISABLE: cmp r0, #0
203 ; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
204 ;
205 ; SUM is in r0 because it is coalesced with the second
206 ; argument on the else path.
207 ; CHECK: movs [[SUM:r0]], #0
208 ; CHECK-NEXT: movs [[IV:r[0-9]+]], #10
209 ;
210 ; Next BB.
211 ; CHECK: [[LOOP:LBB[0-9_]+]]: @ %for.body
212 ; CHECK: movs [[TMP:r[0-9]+]], #1
213 ; CHECK: adds [[SUM]], [[TMP]], [[SUM]]
214 ; CHECK-NEXT: subs [[IV]], [[IV]], #1
215 ; CHECK-NEXT: cmp [[IV]], #0
216 ; CHECK-NEXT: bne [[LOOP]]
217 ;
218 ; Next BB.
219 ; SUM << 3.
220 ; CHECK: lsls [[SUM]], [[SUM]], #3
221 ; ENABLE-NEXT: pop {r4, lr}
222 ;
223 ; Duplicated epilogue.
224 ; DISABLE: pop {r4, pc}
225 ;
226 ; CHECK: [[ELSE_LABEL]]: @ %if.else
227 ; Shift second argument by one and store into returned register.
228 ; CHECK: lsls r0, r1, #1
229 ; DISABLE-NEXT: pop {r4, pc}
230 ;
231 ; ENABLE-NEXT: bx lr
232 define i32 @loopInfoSaveOutsideLoop(i32 %cond, i32 %N) {
233 entry:
234 %tobool = icmp eq i32 %cond, 0
235 br i1 %tobool, label %if.else, label %for.preheader
236
237 for.preheader:
238 tail call void asm "nop", ""()
239 br label %for.body
240
241 for.body: ; preds = %entry, %for.body
242 %i.05 = phi i32 [ %inc, %for.body ], [ 0, %for.preheader ]
243 %sum.04 = phi i32 [ %add, %for.body ], [ 0, %for.preheader ]
244 %call = tail call i32 asm sideeffect "movs $0, #1", "=r,~{r4}"()
245 %add = add nsw i32 %call, %sum.04
246 %inc = add nuw nsw i32 %i.05, 1
247 %exitcond = icmp eq i32 %inc, 10
248 br i1 %exitcond, label %for.end, label %for.body
249
250 for.end: ; preds = %for.body
251 tail call void asm "nop", "~{r4}"()
252 %shl = shl i32 %add, 3
253 br label %if.end
254
255 if.else: ; preds = %entry
256 %mul = shl nsw i32 %N, 1
257 br label %if.end
258
259 if.end: ; preds = %if.else, %for.end
260 %sum.1 = phi i32 [ %shl, %for.end ], [ %mul, %if.else ]
261 ret i32 %sum.1
262 }
263
264 declare void @somethingElse(...)
265
266 ; Check with a more complex case that we do not have restore within the loop and
267 ; save outside.
268 ; CHECK-LABEL: loopInfoRestoreOutsideLoop:
269 ;
270 ; ENABLE: cmp r0, #0
271 ; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
272 ;
273 ; Prologue code.
274 ; Make sure we save the CSR used in the inline asm: r4.
275 ; CHECK: push {r4, lr}
276 ;
277 ; DISABLE-NEXT: cmp r0, #0
278 ; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
279 ;
280 ; SUM is in r0 because it is coalesced with the second
281 ; argument on the else path.
282 ; CHECK: movs [[SUM:r0]], #0
283 ; CHECK-NEXT: movs [[IV:r[0-9]+]], #10
284 ;
285 ; Next BB.
286 ; CHECK: [[LOOP:LBB[0-9_]+]]: @ %for.body
287 ; CHECK: movs [[TMP:r[0-9]+]], #1
288 ; CHECK: adds [[SUM]], [[TMP]], [[SUM]]
289 ; CHECK-NEXT: subs [[IV]], [[IV]], #1
290 ; CHECK-NEXT: cmp [[IV]], #0
291 ; CHECK-NEXT: bne [[LOOP]]
292 ;
293 ; Next BB.
294 ; SUM << 3.
295 ; CHECK: lsls [[SUM]], [[SUM]], #3
296 ; ENABLE: pop {r4, lr}
297 ;
298 ; Duplicated epilogue.
299 ; DISABLE: pop {r4, pc}
300 ;
301 ; CHECK: [[ELSE_LABEL]]: @ %if.else
302 ; Shift second argument by one and store into returned register.
303 ; CHECK: lsls r0, r1, #1
304 ; DISABLE-NEXT: pop {r4, pc}
305 ;
306 ; ENABLE-NEXT: bx lr
307 define i32 @loopInfoRestoreOutsideLoop(i32 %cond, i32 %N) #0 {
308 entry:
309 %tobool = icmp eq i32 %cond, 0
310 br i1 %tobool, label %if.else, label %if.then
311
312 if.then: ; preds = %entry
313 tail call void asm "nop", "~{r4}"()
314 br label %for.body
315
316 for.body: ; preds = %for.body, %if.then
317 %i.05 = phi i32 [ 0, %if.then ], [ %inc, %for.body ]
318 %sum.04 = phi i32 [ 0, %if.then ], [ %add, %for.body ]
319 %call = tail call i32 asm sideeffect "movs $0, #1", "=r,~{r4}"()
320 %add = add nsw i32 %call, %sum.04
321 %inc = add nuw nsw i32 %i.05, 1
322 %exitcond = icmp eq i32 %inc, 10
323 br i1 %exitcond, label %for.end, label %for.body
324
325 for.end: ; preds = %for.body
326 %shl = shl i32 %add, 3
327 br label %if.end
328
329 if.else: ; preds = %entry
330 %mul = shl nsw i32 %N, 1
331 br label %if.end
332
333 if.end: ; preds = %if.else, %for.end
334 %sum.1 = phi i32 [ %shl, %for.end ], [ %mul, %if.else ]
335 ret i32 %sum.1
336 }
337
338 ; Check that we handle function with no frame information correctly.
339 ; CHECK-LABEL: emptyFrame:
340 ; CHECK: @ %entry
341 ; CHECK-NEXT: movs r0, #0
342 ; CHECK-NEXT: bx lr
343 define i32 @emptyFrame() {
344 entry:
345 ret i32 0
346 }
347
348 ; Check that we handle inline asm correctly.
349 ; CHECK-LABEL: inlineAsm:
350 ;
351 ; ENABLE: cmp r0, #0
352 ; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
353 ;
354 ; Prologue code.
355 ; Make sure we save the CSR used in the inline asm: r4.
356 ; CHECK: push {r4, lr}
357 ;
358 ; DISABLE: cmp r0, #0
359 ; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
360 ;
361 ; CHECK: movs [[IV:r[0-9]+]], #10
362 ;
363 ; Next BB.
364 ; CHECK: [[LOOP:LBB[0-9_]+]]: @ %for.body
365 ; CHECK: movs r4, #1
366 ; CHECK: subs [[IV]], [[IV]], #1
367 ; CHECK-NEXT: cmp [[IV]], #0
368 ; CHECK-NEXT: bne [[LOOP]]
369 ;
370 ; Next BB.
371 ; CHECK: movs r0, #0
372 ; ENABLE-NEXT: pop {r4, lr}
373 ;
374 ; Duplicated epilogue.
375 ; DISABLE-NEXT: pop {r4, pc}
376 ;
377 ; CHECK: [[ELSE_LABEL]]: @ %if.else
378 ; Shift second argument by one and store into returned register.
379 ; CHECK: lsls r0, r1, #1
380 ; DISABLE-NEXT: pop {r4, pc}
381 ;
382 ; ENABLE-NEXT: bx lr
383 define i32 @inlineAsm(i32 %cond, i32 %N) {
384 entry:
385 %tobool = icmp eq i32 %cond, 0
386 br i1 %tobool, label %if.else, label %for.preheader
387
388 for.preheader:
389 tail call void asm "nop", ""()
390 br label %for.body
391
392 for.body: ; preds = %entry, %for.body
393 %i.03 = phi i32 [ %inc, %for.body ], [ 0, %for.preheader ]
394 tail call void asm sideeffect "movs r4, #1", "~{r4}"()
395 %inc = add nuw nsw i32 %i.03, 1
396 %exitcond = icmp eq i32 %inc, 10
397 br i1 %exitcond, label %for.exit, label %for.body
398
399 for.exit:
400 tail call void asm "nop", ""()
401 br label %if.end
402
403 if.else: ; preds = %entry
404 %mul = shl nsw i32 %N, 1
405 br label %if.end
406
407 if.end: ; preds = %for.body, %if.else
408 %sum.0 = phi i32 [ %mul, %if.else ], [ 0, %for.exit ]
409 ret i32 %sum.0
410 }
411
412 ; Check that we handle calls to variadic functions correctly.
413 ; CHECK-LABEL: callVariadicFunc:
414 ;
415 ; ENABLE: cmp r0, #0
416 ; ENABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
417 ;
418 ; Prologue code.
419 ; CHECK: push {[[TMP:r[0-9]+]], lr}
420 ; CHECK-NEXT: sub sp, #16
421 ;
422 ; DISABLE: cmp r0, #0
423 ; DISABLE-NEXT: beq [[ELSE_LABEL:LBB[0-9_]+]]
424 ;
425 ; Setup of the varags.
426 ; CHECK: mov [[TMP_SP:r[0-9]+]], sp
427 ; CHECK-NEXT: str r1, {{\[}}[[TMP_SP]]]
428 ; CHECK-NEXT: str r1, {{\[}}[[TMP_SP]], #4]
429 ; CHECK-NEXT: str r1, {{\[}}[[TMP_SP]], #8]
430 ; Thumb has quite a strange way for moving stuff
431 ; in around. Oh well, match the current sequence.
432 ; CHECK: push {r1}
433 ; CHECK-NEXT: pop {r0}
434 ; CHECK: push {r1}
435 ; CHECK-NEXT: pop {r2}
436 ; CHECK: push {r1}
437 ; CHECK-NEXT: pop {r3}
438 ; CHECK-NEXT: bl
439 ; CHECK-NEXT: lsls r0, r0, #3
440 ; CHECK-NEXT: add sp, #16
441 ;
442 ; ENABLE-NEXT: pop {[[TMP]], lr}
443 ;
444 ; Duplicated epilogue.
445 ; DISABLE-NEXT: pop {[[TMP]], pc}
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 ;
451 ; Epilogue code.
452 ; ENABLE-NEXT: bx lr
453 ;
454 ; DISABLE-NEXT: add sp, #16
455 ; DISABLE-NEXT: pop {[[TMP]], pc}
456 define i32 @callVariadicFunc(i32 %cond, i32 %N) {
457 entry:
458 %tobool = icmp eq i32 %cond, 0
459 br i1 %tobool, label %if.else, label %if.then
460
461 if.then: ; preds = %entry
462 %call = tail call i32 (i32, ...) @someVariadicFunc(i32 %N, i32 %N, i32 %N, i32 %N, i32 %N, i32 %N, i32 %N)
463 %shl = shl i32 %call, 3
464 br label %if.end
465
466 if.else: ; preds = %entry
467 %mul = shl nsw i32 %N, 1
468 br label %if.end
469
470 if.end: ; preds = %if.else, %if.then
471 %sum.0 = phi i32 [ %shl, %if.then ], [ %mul, %if.else ]
472 ret i32 %sum.0
473 }
474
475 declare i32 @someVariadicFunc(i32, ...)
476
477 ; Make sure we do not insert unreachable code after noreturn function.
478 ; Although this is not incorrect to insert such code, it is useless
479 ; and it hurts the binary size.
480 ;
481 ; CHECK-LABEL: noreturn:
482 ; DISABLE: push
483 ;
484 ; CHECK: movs [[TMP:r[0-9]+]], #255
485 ; CHECK-NEXT: tst r0, [[TMP]]
486 ; CHECK-NEXT: bne [[ABORT:LBB[0-9_]+]]
487 ;
488 ; CHECK: movs r0, #42
489 ;
490 ; ENABLE-NEXT: bx lr
491 ;
492 ; DISABLE-NEXT: pop
493 ;;
494 ; CHECK: [[ABORT]]: @ %if.abort
495 ;
496 ; ENABLE: push
497 ;
498 ; CHECK: bl
499 ; ENABLE-NOT: pop
500 define i32 @noreturn(i8 signext %bad_thing) {
501 entry:
502 %tobool = icmp eq i8 %bad_thing, 0
503 br i1 %tobool, label %if.end, label %if.abort
504
505 if.abort:
506 %call = tail call i32 asm sideeffect "movs $0, #1", "=r,~{r4}"()
507 tail call void @abort() #0
508 unreachable
509
510 if.end:
511 ret i32 42
512 }
513
514 declare void @abort() #0
515
516 attributes #0 = { noreturn nounwind }