[ARM] Change TCReturn to tBL if tailcall optimization fails.
Summary: The tail call optimisation is performed before register allocation, so at that point we don't know if LR is being spilt or not. If LR was spilt to the stack, then we cannot do a tail call optimisation. That would involve popping back into LR which is not possible in Thumb1 code. Reviewers: rengolin, jmolloy, rovka, olista01 Reviewed By: olista01 Subscribers: llvm-commits, aemerson Differential Revision: https://reviews.llvm.org/D29020 llvm-svn: 294000
This commit is contained in:
parent
57b63d6ade
commit
a994185757
|
@ -202,12 +202,12 @@ void ARMSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) {
|
||||||
// support in the assembler and linker to be used. This would need to be
|
// support in the assembler and linker to be used. This would need to be
|
||||||
// fixed to fully support tail calls in Thumb1.
|
// fixed to fully support tail calls in Thumb1.
|
||||||
//
|
//
|
||||||
// Doing this is tricky, since the LDM/POP instruction on Thumb doesn't take
|
// For ARMv8-M, we /do/ implement tail calls. Doing this is tricky for v8-M
|
||||||
// LR. This means if we need to reload LR, it takes an extra instructions,
|
// baseline, since the LDM/POP instruction on Thumb doesn't take LR. This
|
||||||
// which outweighs the value of the tail call; but here we don't know yet
|
// means if we need to reload LR, it takes extra instructions, which outweighs
|
||||||
// whether LR is going to be used. Probably the right approach is to
|
// the value of the tail call; but here we don't know yet whether LR is going
|
||||||
// generate the tail call here and turn it back into CALL/RET in
|
// to be used. We generate the tail call here and turn it back into CALL/RET
|
||||||
// emitEpilogue if LR is used.
|
// in emitEpilogue if LR is used.
|
||||||
|
|
||||||
// Thumb1 PIC calls to external symbols use BX, so they can be tail calls,
|
// Thumb1 PIC calls to external symbols use BX, so they can be tail calls,
|
||||||
// but we need to make sure there are enough registers; the only valid
|
// but we need to make sure there are enough registers; the only valid
|
||||||
|
|
|
@ -888,6 +888,16 @@ restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
|
||||||
// ARMv4T requires BX, see emitEpilogue
|
// ARMv4T requires BX, see emitEpilogue
|
||||||
if (!STI.hasV5TOps())
|
if (!STI.hasV5TOps())
|
||||||
continue;
|
continue;
|
||||||
|
// Tailcall optimization failed; change TCRETURN to a tBL
|
||||||
|
if (MI->getOpcode() == ARM::TCRETURNdi ||
|
||||||
|
MI->getOpcode() == ARM::TCRETURNri) {
|
||||||
|
unsigned Opcode = MI->getOpcode() == ARM::TCRETURNdi
|
||||||
|
? ARM::tBL : ARM::tBLXr;
|
||||||
|
MachineInstrBuilder BL = BuildMI(MF, DL, TII.get(Opcode));
|
||||||
|
BL.add(predOps(ARMCC::AL));
|
||||||
|
BL.add(MI->getOperand(0));
|
||||||
|
MBB.insert(MI, &*BL);
|
||||||
|
}
|
||||||
Reg = ARM::PC;
|
Reg = ARM::PC;
|
||||||
(*MIB).setDesc(TII.get(ARM::tPOP_RET));
|
(*MIB).setDesc(TII.get(ARM::tPOP_RET));
|
||||||
if (MI != MBB.end())
|
if (MI != MBB.end())
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
; RUN: llc %s -o - -mtriple=thumbv8m.base | FileCheck %s
|
||||||
|
|
||||||
|
define void @test() {
|
||||||
|
; CHECK-LABEL: test:
|
||||||
|
entry:
|
||||||
|
%call = tail call i32 @foo()
|
||||||
|
%tail = tail call i32 @foo()
|
||||||
|
ret void
|
||||||
|
; CHECK: bl foo
|
||||||
|
; CHECK: bl foo
|
||||||
|
; CHECK-NOT: b foo
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @test2() {
|
||||||
|
; CHECK-LABEL: test2:
|
||||||
|
entry:
|
||||||
|
%tail = tail call i32 @foo()
|
||||||
|
ret void
|
||||||
|
; CHECK: b foo
|
||||||
|
; CHECK-NOT: bl foo
|
||||||
|
}
|
||||||
|
|
||||||
|
declare i32 @foo()
|
Loading…
Reference in New Issue