summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/CodeGen/FunctionLoweringInfo.h3
-rw-r--r--llvm/include/llvm/Target/TargetLowering.h23
-rw-r--r--llvm/include/llvm/Target/TargetRegisterInfo.h5
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp37
4 files changed, 67 insertions, 1 deletions
diff --git a/llvm/include/llvm/CodeGen/FunctionLoweringInfo.h b/llvm/include/llvm/CodeGen/FunctionLoweringInfo.h
index bd8da736c16..09a9991912d 100644
--- a/llvm/include/llvm/CodeGen/FunctionLoweringInfo.h
+++ b/llvm/include/llvm/CodeGen/FunctionLoweringInfo.h
@@ -62,6 +62,9 @@ public:
/// 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;
diff --git a/llvm/include/llvm/Target/TargetLowering.h b/llvm/include/llvm/Target/TargetLowering.h
index f7152565f91..a105917958d 100644
--- a/llvm/include/llvm/Target/TargetLowering.h
+++ b/llvm/include/llvm/Target/TargetLowering.h
@@ -2263,6 +2263,29 @@ public:
return false;
}
+ /// Return true if the target supports that a subset of CSRs for the given
+ /// calling convention is handled explicitly via copies.
+ virtual bool supportSplitCSR(CallingConv::ID CC) const {
+ return false;
+ }
+
+ /// Perform necessary initialization to handle a subset of CSRs explicitly
+ /// via copies. This function is called at the beginning of instruction
+ /// selection.
+ virtual void initializeSplitCSR(MachineBasicBlock *Entry) const {
+ llvm_unreachable("Not Implemented");
+ }
+
+ /// Insert explicit copies in entry and exit blocks. We copy a subset of
+ /// CSRs to virtual registers in the entry block, and copy them back to
+ /// physical registers in the exit blocks. This function is called at the end
+ /// of instruction selection.
+ virtual void insertCopiesSplitCSR(
+ MachineBasicBlock *Entry,
+ const SmallVectorImpl<MachineBasicBlock *> &Exits) const {
+ llvm_unreachable("Not Implemented");
+ }
+
//===--------------------------------------------------------------------===//
// Lowering methods - These methods must be implemented by targets so that
// the SelectionDAGBuilder code knows how to lower these.
diff --git a/llvm/include/llvm/Target/TargetRegisterInfo.h b/llvm/include/llvm/Target/TargetRegisterInfo.h
index 414255edb23..ffd510440b0 100644
--- a/llvm/include/llvm/Target/TargetRegisterInfo.h
+++ b/llvm/include/llvm/Target/TargetRegisterInfo.h
@@ -426,6 +426,11 @@ public:
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
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
index f6c5d90f47a..5f3e4a02341 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
@@ -467,15 +467,50 @@ bool SelectionDAGISel::runOnMachineFunction(MachineFunction &mf) {
MF->setHasInlineAsm(false);
+ FuncInfo->SplitCSR = false;
+ SmallVector<MachineBasicBlock*, 4> Returns;
+
+ // We split CSR if the target supports it for the given calling convention
+ // and the function has only return exits.
+ if (TLI->supportSplitCSR(Fn.getCallingConv())) {
+ FuncInfo->SplitCSR = true;
+
+ // Collect all the return blocks.
+ for (const BasicBlock &BB : Fn) {
+ if (!succ_empty(&BB))
+ continue;
+
+ const TerminatorInst *Term = BB.getTerminator();
+ if (isa<UnreachableInst>(Term))
+ continue;
+ if (isa<ReturnInst>(Term)) {
+ Returns.push_back(FuncInfo->MBBMap[&BB]);
+ continue;
+ }
+
+ // Bail out if the exit block is not Return nor Unreachable.
+ FuncInfo->SplitCSR = false;
+ break;
+ }
+ }
+
+ MachineBasicBlock *EntryMBB = &MF->front();
+ if (FuncInfo->SplitCSR)
+ // This performs initialization so lowering for SplitCSR will be correct.
+ TLI->initializeSplitCSR(EntryMBB);
+
SelectAllBasicBlocks(Fn);
// If the first basic block in the function has live ins that need to be
// copied into vregs, emit the copies into the top of the block before
// emitting the code for the block.
- MachineBasicBlock *EntryMBB = &MF->front();
const TargetRegisterInfo &TRI = *MF->getSubtarget().getRegisterInfo();
RegInfo->EmitLiveInCopies(EntryMBB, TRI, *TII);
+ // Insert copies in the entry block and the return blocks.
+ if (FuncInfo->SplitCSR)
+ TLI->insertCopiesSplitCSR(EntryMBB, Returns);
+
DenseMap<unsigned, unsigned> LiveInMap;
if (!FuncInfo->ArgDbgValues.empty())
for (MachineRegisterInfo::livein_iterator LI = RegInfo->livein_begin(),
OpenPOWER on IntegriCloud