Index: llvm/lib/Target/RISCV/RISCVFrameLowering.cpp =================================================================== --- llvm/lib/Target/RISCV/RISCVFrameLowering.cpp +++ llvm/lib/Target/RISCV/RISCVFrameLowering.cpp @@ -193,7 +193,8 @@ // If this function will not use save/restore libcalls, then return a nullptr. static const char * getRestoreLibCallName(const MachineFunction &MF, - const std::vector &CSI) { + const std::vector &CSI, + bool TailCallSite) { static const char *const RestoreLibCalls[] = { "__riscv_restore_0", "__riscv_restore_1", @@ -209,10 +210,27 @@ "__riscv_restore_11", "__riscv_restore_12" }; + static const char *const RestoreLibCallsTC[] = { + "__riscv_restore_tailcall_0", + "__riscv_restore_tailcall_1", + "__riscv_restore_tailcall_2", + "__riscv_restore_tailcall_3", + "__riscv_restore_tailcall_4", + "__riscv_restore_tailcall_5", + "__riscv_restore_tailcall_6", + "__riscv_restore_tailcall_7", + "__riscv_restore_tailcall_8", + "__riscv_restore_tailcall_9", + "__riscv_restore_tailcall_10", + "__riscv_restore_tailcall_11", + "__riscv_restore_tailcall_12" + }; int LibCallID = getLibCallID(MF, CSI); if (LibCallID == -1) return nullptr; + if (TailCallSite) + return RestoreLibCallsTC[LibCallID]; return RestoreLibCalls[LibCallID]; } @@ -815,19 +833,69 @@ assert(MI != MBB.begin() && "loadRegFromStackSlot didn't insert any code!"); } - const char *RestoreLibCall = getRestoreLibCallName(*MF, CSI); + bool IsTailCall = + MI != MBB.end() && (MI->getOpcode() == RISCV::PseudoTAIL || + MI->getOpcode() == RISCV::PseudoTAILIndirect); + const char *RestoreLibCall = getRestoreLibCallName(*MF, CSI, IsTailCall); if (RestoreLibCall) { - // Add restore libcall via tail call. - MachineBasicBlock::iterator NewMI = - BuildMI(MBB, MI, DL, TII.get(RISCV::PseudoTAIL)) - .addExternalSymbol(RestoreLibCall, RISCVII::MO_CALL) + if (IsTailCall) { + // Add restore libcall via tail call. X6/T1 is added as use as this holds + // the pointer to tailcall to. + MachineBasicBlock::iterator NewMI = + BuildMI(MBB, MI, DL, TII.get(RISCV::PseudoTAIL)) + .addExternalSymbol(RestoreLibCall, RISCVII::MO_CALL) + .addReg(RISCV::X6 /*T1*/, RegState::Implicit) + .setMIFlag(MachineInstr::FrameDestroy); + + switch (MI->getOperand(0).getType()) { + default: +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) + MI->dump(); +#endif + llvm_unreachable("Unexpected operand type for restore_tailcall!"); + case MachineOperand::MO_GlobalAddress: + BuildMI(MBB, NewMI, DL, TII.get(RISCV::LUI), RISCV::X6 /*T1*/) + .addGlobalAddress(MI->getOperand(0).getGlobal(), 0, RISCVII::MO_HI) .setMIFlag(MachineInstr::FrameDestroy); - - // Remove trailing returns, since the terminator is now a tail call to the - // restore function. - if (MI != MBB.end() && MI->getOpcode() == RISCV::PseudoRET) { + BuildMI(MBB, NewMI, DL, TII.get(RISCV::ADDI), RISCV::X6 /*T1*/) + .addReg(RISCV::X6 /*T1*/) + .addGlobalAddress(MI->getOperand(0).getGlobal(), 0, RISCVII::MO_LO) + .setMIFlag(MachineInstr::FrameDestroy); + break; + case MachineOperand::MO_ExternalSymbol: + BuildMI(MBB, NewMI, DL, TII.get(RISCV::LUI), RISCV::X6 /*T1*/) + .addExternalSymbol(MI->getOperand(0).getSymbolName(), + RISCVII::MO_HI) + .setMIFlag(MachineInstr::FrameDestroy); + BuildMI(MBB, NewMI, DL, TII.get(RISCV::ADDI), RISCV::X6 /*T1*/) + .addReg(RISCV::X6 /*T1*/) + .addExternalSymbol(MI->getOperand(0).getSymbolName(), + RISCVII::MO_LO) + .setMIFlag(MachineInstr::FrameDestroy); + break; + case MachineOperand::MO_Register: + if (MI->getOperand(0).getReg() != RISCV::X6 /*T1*/) + BuildMI(MBB, NewMI, DL, TII.get(RISCV::ADDI), RISCV::X6 /*T1*/) + .addReg(MI->getOperand(0).getReg()) + .addImm(0) + .setMIFlag(MachineInstr::FrameDestroy); + break; + } NewMI->copyImplicitOps(*MF, *MI); MI->eraseFromParent(); + } else { + // Add restore libcall via tail call. + MachineBasicBlock::iterator NewMI = + BuildMI(MBB, MI, DL, TII.get(RISCV::PseudoTAIL)) + .addExternalSymbol(RestoreLibCall, RISCVII::MO_CALL) + .setMIFlag(MachineInstr::FrameDestroy); + + // Remove trailing returns, since the terminator is now a tail call to the + // restore function. + if (MI != MBB.end() && MI->getOpcode() == RISCV::PseudoRET) { + NewMI->copyImplicitOps(*MF, *MI); + MI->eraseFromParent(); + } } } Index: llvm/lib/Target/RISCV/RISCVMachineFunctionInfo.h =================================================================== --- llvm/lib/Target/RISCV/RISCVMachineFunctionInfo.h +++ llvm/lib/Target/RISCV/RISCVMachineFunctionInfo.h @@ -56,7 +56,7 @@ // We cannot use fixed locations for the callee saved spill slots if the // function uses a varargs save area. return MF.getSubtarget().enableSaveRestore() && - VarArgsSaveSize == 0 && !MF.getFrameInfo().hasTailCall(); + VarArgsSaveSize == 0; } }; Index: llvm/test/CodeGen/RISCV/saverestore.ll =================================================================== --- llvm/test/CodeGen/RISCV/saverestore.ll +++ llvm/test/CodeGen/RISCV/saverestore.ll @@ -153,24 +153,28 @@ ; RV64I-NOT: tail __riscv_restore ; ; RV32I-SR-LABEL: tail_call: -; RV32I-SR-NOT: call t0, __riscv_save -; RV32I-SR: tail tail_callee -; RV32I-SR-NOT: tail __riscv_restore +; RV32I-SR: call t0, __riscv_save +; RV32I-SR: lui t1, %hi(tail_callee) +; RV32I-SR: addi t1, t1, %lo(tail_callee) +; RV32I-SR: tail __riscv_restore_tailcall_6 ; ; RV64I-SR-LABEL: tail_call: -; RV64I-SR-NOT: call t0, __riscv_save -; RV64I-SR: tail tail_callee -; RV64I-SR-NOT: tail __riscv_restore +; RV64I-SR: call t0, __riscv_save +; RV64I-SR: lui t1, %hi(tail_callee) +; RV64I-SR: addi t1, t1, %lo(tail_callee) +; RV64I-SR: tail __riscv_restore_tailcall_6 ; ; RV32I-FP-SR-LABEL: tail_call: -; RV32I-FP-SR-NOT: call t0, __riscv_save -; RV32I-FP-SR: tail tail_callee -; RV32I-FP-SR-NOT: tail __riscv_restore +; RV32I-FP-SR: call t0, __riscv_save +; RV32I-FP-SR: lui t1, %hi(tail_callee) +; RV32I-FP-SR: addi t1, t1, %lo(tail_callee) +; RV32I-FP-SR: tail __riscv_restore_tailcall_6 ; ; RV64I-FP-SR-LABEL: tail_call: -; RV64I-FP-SR-NOT: call t0, __riscv_save -; RV64I-FP-SR: tail tail_callee -; RV64I-FP-SR-NOT: tail __riscv_restore +; RV64I-FP-SR: call t0, __riscv_save +; RV64I-FP-SR: lui t1, %hi(tail_callee) +; RV64I-FP-SR: addi t1, t1, %lo(tail_callee) +; RV64I-FP-SR: tail __riscv_restore_tailcall_6 entry: %val = load [18 x i32], [18 x i32]* @var0 store volatile [18 x i32] %val, [18 x i32]* @var0