Index: include/llvm/CodeGen/FunctionLoweringInfo.h =================================================================== --- include/llvm/CodeGen/FunctionLoweringInfo.h +++ include/llvm/CodeGen/FunctionLoweringInfo.h @@ -62,6 +62,9 @@ /// registers. bool CanLowerReturn; + /// True if part of the CSRs will be handled via explicit copies. + bool SplitCSR; + /// DemoteRegister - if CanLowerReturn is false, DemoteRegister is a vreg /// allocated to hold a pointer to the hidden sret parameter. unsigned DemoteRegister; Index: include/llvm/Target/TargetLowering.h =================================================================== --- include/llvm/Target/TargetLowering.h +++ include/llvm/Target/TargetLowering.h @@ -2263,6 +2263,15 @@ return false; } + virtual bool supportSplitCSR() const { + return false; + } + + virtual void handleSplitCSR(MachineBasicBlock *Entry, + MachineBasicBlock *Exit) const { + llvm_unreachable("Not Implemented"); + } + //===--------------------------------------------------------------------===// // Lowering methods - These methods must be implemented by targets so that // the SelectionDAGBuilder code knows how to lower these. Index: include/llvm/Target/TargetRegisterInfo.h =================================================================== --- include/llvm/Target/TargetRegisterInfo.h +++ include/llvm/Target/TargetRegisterInfo.h @@ -426,6 +426,11 @@ virtual const MCPhysReg* getCalleeSavedRegs(const MachineFunction *MF) const = 0; + virtual const MCPhysReg* + getCalleeSavedRegsViaCopy(const MachineFunction *MF) const { + return nullptr; + } + /// Return a mask of call-preserved registers for the given calling convention /// on the current function. The mask should include all call-preserved /// aliases. This is used by the register allocator to determine which Index: lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -467,6 +467,36 @@ MF->setHasInlineAsm(false); + // We split CSR for CXX_FAST_TLS calling convention if the target supports it + // and the function has a single exit. + FuncInfo->SplitCSR = Fn.getCallingConv() == CallingConv::CXX_FAST_TLS && + TLI->supportSplitCSR(); + MachineBasicBlock *SingleReturn = nullptr; + if (FuncInfo->SplitCSR) { + // Check if the function has a single exit. + bool FoundExit = false; + for (const BasicBlock &BB : Fn) { + bool IsReturn = !BB.empty() && isa(&BB.back()); + if (succ_empty(&BB) || IsReturn) { + // If we already saw an exit, bail out. If this is an exit, but + // not a return, bail out as well. + if (FoundExit || (succ_empty(&BB) && !IsReturn)) { + SingleReturn = nullptr; + break; + } + // This is the first exit and it is a return. + FoundExit = true; + SingleReturn = FuncInfo->MBBMap[&BB]; + } + } + + if (!SingleReturn) + FuncInfo->SplitCSR = false; + } + if (FuncInfo->SplitCSR) + // This performs initialization so lowering for SplitCSR will be correct. + TLI->handleSplitCSR(&MF->front(), nullptr); + SelectAllBasicBlocks(Fn); // If the first basic block in the function has live ins that need to be @@ -476,6 +506,10 @@ const TargetRegisterInfo &TRI = *MF->getSubtarget().getRegisterInfo(); RegInfo->EmitLiveInCopies(EntryMBB, TRI, *TII); + // Insert copies in the entry block and the single exit block. + if (FuncInfo->SplitCSR) + TLI->handleSplitCSR(EntryMBB, SingleReturn); + DenseMap LiveInMap; if (!FuncInfo->ArgDbgValues.empty()) for (MachineRegisterInfo::livein_iterator LI = RegInfo->livein_begin(),