Swift Calling Convention: swifterror target-independent change.
At IR level, the swifterror argument is an input argument with type
ErrorObject**. For targets that support swifterror, we want to optimize it
to behave as an inout value with type ErrorObject*; it will be passed in a
fixed physical register.
The main idea is to track the virtual registers for each swifterror value. We
define swifterror values as AllocaInsts with swifterror attribute or a function
argument with swifterror attribute.
In SelectionDAGISel.cpp, we set up swifterror values (SwiftErrorVals) before
handling the basic blocks.
When iterating over all basic blocks in RPO, before actually visiting the basic
block, we call mergeIncomingSwiftErrors to merge incoming swifterror values when
there are multiple predecessors or to simply propagate them. There, we create a
virtual register for each swifterror value in the entry block. For predecessors
that are not yet visited, we create virtual registers to hold the swifterror
values at the end of the predecessor. The assignments are saved in
SwiftErrorWorklist and will be materialized at the end of visiting the basic
block.
When visiting a load from a swifterror value, we copy from the current virtual
register assignment. When visiting a store to a swifterror value, we create a
virtual register to hold the swifterror value and update SwiftErrorMap to
track the current virtual register assignment.
Differential Revision: http://reviews.llvm.org/D18108
llvm-svn: 265433
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
index 7dd02e4..e9cb6b4 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
@@ -1159,12 +1159,132 @@
}
#endif // NDEBUG
+/// Set up SwiftErrorVals by going through the function. If the function has
+/// swifterror argument, it will be the first entry.
+static void setupSwiftErrorVals(const Function &Fn, const TargetLowering *TLI,
+ FunctionLoweringInfo *FuncInfo) {
+ if (!TLI->supportSwiftError())
+ return;
+
+ FuncInfo->SwiftErrorVals.clear();
+ FuncInfo->SwiftErrorMap.clear();
+ FuncInfo->SwiftErrorWorklist.clear();
+
+ // Check if function has a swifterror argument.
+ for (Function::const_arg_iterator AI = Fn.arg_begin(), AE = Fn.arg_end();
+ AI != AE; ++AI)
+ if (AI->hasSwiftErrorAttr())
+ FuncInfo->SwiftErrorVals.push_back(&*AI);
+
+ for (const auto &LLVMBB : Fn)
+ for (const auto &Inst : LLVMBB) {
+ if (const AllocaInst *Alloca = dyn_cast<AllocaInst>(&Inst))
+ if (Alloca->isSwiftError())
+ FuncInfo->SwiftErrorVals.push_back(Alloca);
+ }
+}
+
+/// For each basic block, merge incoming swifterror values or simply propagate
+/// them. The merged results will be saved in SwiftErrorMap. For predecessors
+/// that are not yet visited, we create virtual registers to hold the swifterror
+/// values and save them in SwiftErrorWorklist.
+static void mergeIncomingSwiftErrors(FunctionLoweringInfo *FuncInfo,
+ const TargetLowering *TLI,
+ const TargetInstrInfo *TII,
+ const BasicBlock *LLVMBB,
+ SelectionDAGBuilder *SDB) {
+ if (!TLI->supportSwiftError())
+ return;
+
+ // We should only do this when we have swifterror parameter or swifterror
+ // alloc.
+ if (FuncInfo->SwiftErrorVals.empty())
+ return;
+
+ // At beginning of a basic block, insert PHI nodes or get the virtual
+ // register from the only predecessor, and update SwiftErrorMap; if one
+ // of the predecessors is not visited, update SwiftErrorWorklist.
+ // At end of a basic block, if a block is in SwiftErrorWorklist, insert copy
+ // to sync up the virtual register assignment.
+
+ // Always create a virtual register for each swifterror value in entry block.
+ auto &DL = SDB->DAG.getDataLayout();
+ const TargetRegisterClass *RC = TLI->getRegClassFor(TLI->getPointerTy(DL));
+ if (pred_begin(LLVMBB) == pred_end(LLVMBB)) {
+ for (unsigned I = 0, E = FuncInfo->SwiftErrorVals.size(); I < E; I++) {
+ unsigned VReg = FuncInfo->MF->getRegInfo().createVirtualRegister(RC);
+ // Assign Undef to Vreg. We construct MI directly to make sure it works
+ // with FastISel.
+ BuildMI(*FuncInfo->MBB, FuncInfo->InsertPt, SDB->getCurDebugLoc(),
+ TII->get(TargetOpcode::IMPLICIT_DEF), VReg);
+ FuncInfo->SwiftErrorMap[FuncInfo->MBB].push_back(VReg);
+ }
+ return;
+ }
+
+ if (auto *UniquePred = LLVMBB->getUniquePredecessor()) {
+ auto *UniquePredMBB = FuncInfo->MBBMap[UniquePred];
+ if (!FuncInfo->SwiftErrorMap.count(UniquePredMBB)) {
+ // Update SwiftErrorWorklist with a new virtual register.
+ for (unsigned I = 0, E = FuncInfo->SwiftErrorVals.size(); I < E; I++) {
+ unsigned VReg = FuncInfo->MF->getRegInfo().createVirtualRegister(RC);
+ FuncInfo->SwiftErrorWorklist[UniquePredMBB].push_back(VReg);
+ // Propagate the information from the single predecessor.
+ FuncInfo->SwiftErrorMap[FuncInfo->MBB].push_back(VReg);
+ }
+ return;
+ }
+ // Propagate the information from the single predecessor.
+ FuncInfo->SwiftErrorMap[FuncInfo->MBB] =
+ FuncInfo->SwiftErrorMap[UniquePredMBB];
+ return;
+ }
+
+ // For the case of multiple predecessors, update SwiftErrorWorklist.
+ // Handle the case where we have two or more predecessors being the same.
+ for (const_pred_iterator PI = pred_begin(LLVMBB), PE = pred_end(LLVMBB);
+ PI != PE; ++PI) {
+ auto *PredMBB = FuncInfo->MBBMap[*PI];
+ if (!FuncInfo->SwiftErrorMap.count(PredMBB) &&
+ !FuncInfo->SwiftErrorWorklist.count(PredMBB)) {
+ for (unsigned I = 0, E = FuncInfo->SwiftErrorVals.size(); I < E; I++) {
+ unsigned VReg = FuncInfo->MF->getRegInfo().createVirtualRegister(RC);
+ // When we actually visit the basic block PredMBB, we will materialize
+ // the virtual register assignment in copySwiftErrorsToFinalVRegs.
+ FuncInfo->SwiftErrorWorklist[PredMBB].push_back(VReg);
+ }
+ }
+ }
+
+ // For the case of multiple predecessors, create a virtual register for
+ // each swifterror value and generate Phi node.
+ for (unsigned I = 0, E = FuncInfo->SwiftErrorVals.size(); I < E; I++) {
+ unsigned VReg = FuncInfo->MF->getRegInfo().createVirtualRegister(RC);
+ FuncInfo->SwiftErrorMap[FuncInfo->MBB].push_back(VReg);
+
+ MachineInstrBuilder SwiftErrorPHI = BuildMI(*FuncInfo->MBB,
+ FuncInfo->MBB->begin(), SDB->getCurDebugLoc(),
+ TII->get(TargetOpcode::PHI), VReg);
+ for (const_pred_iterator PI = pred_begin(LLVMBB), PE = pred_end(LLVMBB);
+ PI != PE; ++PI) {
+ auto *PredMBB = FuncInfo->MBBMap[*PI];
+ unsigned SwiftErrorReg = FuncInfo->SwiftErrorMap.count(PredMBB) ?
+ FuncInfo->SwiftErrorMap[PredMBB][I] :
+ FuncInfo->SwiftErrorWorklist[PredMBB][I];
+ SwiftErrorPHI.addReg(SwiftErrorReg)
+ .addMBB(PredMBB);
+ }
+ }
+}
+
void SelectionDAGISel::SelectAllBasicBlocks(const Function &Fn) {
// Initialize the Fast-ISel state, if needed.
FastISel *FastIS = nullptr;
if (TM.Options.EnableFastISel)
FastIS = TLI->createFastISel(*FuncInfo, LibInfo);
+ setupSwiftErrorVals(Fn, TLI, FuncInfo);
+
// Iterate over all basic blocks in the function.
ReversePostOrderTraversal<const Function*> RPOT(&Fn);
for (ReversePostOrderTraversal<const Function*>::rpo_iterator
@@ -1203,6 +1323,7 @@
if (!FuncInfo->MBB)
continue; // Some blocks like catchpads have no code or MBB.
FuncInfo->InsertPt = FuncInfo->MBB->getFirstNonPHI();
+ mergeIncomingSwiftErrors(FuncInfo, TLI, TII, LLVMBB, SDB);
// Setup an EH landing-pad block.
FuncInfo->ExceptionPointerVirtReg = 0;