Skip to content

Commit

Permalink
Swift Calling Convention: swifterror target-independent change.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
manman-ren committed Apr 5, 2016
1 parent 99d607b commit e221a87
Show file tree
Hide file tree
Showing 7 changed files with 391 additions and 4 deletions.
31 changes: 31 additions & 0 deletions llvm/include/llvm/CodeGen/FunctionLoweringInfo.h
Expand Up @@ -72,6 +72,37 @@ class FunctionLoweringInfo {
/// MBBMap - A mapping from LLVM basic blocks to their machine code entry.
DenseMap<const BasicBlock*, MachineBasicBlock *> MBBMap;

typedef SmallVector<unsigned, 1> SwiftErrorVRegs;
typedef SmallVector<const Value*, 1> SwiftErrorValues;
/// A function can only have a single swifterror argument. And if it does
/// have a swifterror argument, it must be the first entry in
/// SwiftErrorVals.
SwiftErrorValues SwiftErrorVals;

/// Track the virtual register for each swifterror value in a given basic
/// block. Entries in SwiftErrorVRegs have the same ordering as entries
/// in SwiftErrorVals.
/// Note that another choice that is more straight-forward is to use
/// Map<const MachineBasicBlock*, Map<Value*, unsigned/*VReg*/>>. It
/// maintains a map from swifterror values to virtual registers for each
/// machine basic block. This choice does not require a one-to-one
/// correspondence between SwiftErrorValues and SwiftErrorVRegs. But because
/// of efficiency concern, we do not choose it.
llvm::DenseMap<const MachineBasicBlock*, SwiftErrorVRegs> SwiftErrorMap;

/// Track the virtual register for each swifterror value at the end of a basic
/// block when we need the assignment of a virtual register before the basic
/// block is visited. When we actually visit the basic block, we will make
/// sure the swifterror value is in the correct virtual register.
llvm::DenseMap<const MachineBasicBlock*, SwiftErrorVRegs>
SwiftErrorWorklist;

/// Find the swifterror virtual register in SwiftErrorMap. We will assert
/// failure when the value does not exist in swifterror map.
unsigned findSwiftErrorVReg(const MachineBasicBlock*, const Value*) const;
/// Set the swifterror virtual register in SwiftErrorMap.
void setSwiftErrorVReg(const MachineBasicBlock *MBB, const Value*, unsigned);

/// ValueMap - Since we emit code for the function a basic block at a time,
/// we must remember which virtual registers hold the values for
/// cross-basic-block values.
Expand Down
7 changes: 7 additions & 0 deletions llvm/include/llvm/Target/TargetLowering.h
Expand Up @@ -2275,6 +2275,12 @@ class TargetLowering : public TargetLoweringBase {
return false;
}

/// Return true if the target supports swifterror attribute. It optimizes
/// loads and stores to reading and writing a specific register.
virtual bool supportSwiftError() const {
return false;
}

/// Return true if the target supports that a subset of CSRs for the given
/// machine function is handled explicitly via copies.
virtual bool supportSplitCSR(MachineFunction *MF) const {
Expand Down Expand Up @@ -2377,6 +2383,7 @@ class TargetLowering : public TargetLoweringBase {
SmallVector<ISD::OutputArg, 32> Outs;
SmallVector<SDValue, 32> OutVals;
SmallVector<ISD::InputArg, 32> Ins;
SmallVector<SDValue, 4> InVals;

CallLoweringInfo(SelectionDAG &DAG)
: RetTy(nullptr), RetSExt(false), RetZExt(false), IsVarArg(false),
Expand Down
16 changes: 15 additions & 1 deletion llvm/lib/CodeGen/SelectionDAG/FastISel.cpp
Expand Up @@ -1324,6 +1324,15 @@ bool FastISel::selectBitCast(const User *I) {
return true;
}

// Return true if we should copy from swift error to the final vreg as specified
// by SwiftErrorWorklist.
static bool shouldCopySwiftErrorsToFinalVRegs(const TargetLowering &TLI,
FunctionLoweringInfo &FuncInfo) {
if (!TLI.supportSwiftError())
return false;
return FuncInfo.SwiftErrorWorklist.count(FuncInfo.MBB);
}

// Remove local value instructions starting from the instruction after
// SavedLastLocalValue to the current function insert point.
void FastISel::removeDeadLocalValueCode(MachineInstr *SavedLastLocalValue)
Expand All @@ -1347,7 +1356,11 @@ bool FastISel::selectInstruction(const Instruction *I) {
MachineInstr *SavedLastLocalValue = getLastLocalValue();
// Just before the terminator instruction, insert instructions to
// feed PHI nodes in successor blocks.
if (isa<TerminatorInst>(I))
if (isa<TerminatorInst>(I)) {
// If we need to materialize any vreg from worklist, we bail out of
// FastISel.
if (shouldCopySwiftErrorsToFinalVRegs(TLI, FuncInfo))
return false;
if (!handlePHINodesInSuccessorBlocks(I->getParent())) {
// PHI node handling may have generated local value instructions,
// even though it failed to handle all PHI nodes.
Expand All @@ -1356,6 +1369,7 @@ bool FastISel::selectInstruction(const Instruction *I) {
removeDeadLocalValueCode(SavedLastLocalValue);
return false;
}
}

// FastISel does not handle any operand bundles except OB_funclet.
if (ImmutableCallSite CS = ImmutableCallSite(I))
Expand Down
18 changes: 18 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
Expand Up @@ -595,3 +595,21 @@ void llvm::AddLandingPadInfo(const LandingPadInst &I, MachineModuleInfo &MMI,
}
}
}

unsigned FunctionLoweringInfo::findSwiftErrorVReg(const MachineBasicBlock *MBB,
const Value* Val) const {
// Find the index in SwiftErrorVals.
SwiftErrorValues::const_iterator I =
std::find(SwiftErrorVals.begin(), SwiftErrorVals.end(), Val);
assert(I != SwiftErrorVals.end() && "Can't find value in SwiftErrorVals");
return SwiftErrorMap.lookup(MBB)[I - SwiftErrorVals.begin()];
}

void FunctionLoweringInfo::setSwiftErrorVReg(const MachineBasicBlock *MBB,
const Value* Val, unsigned VReg) {
// Find the index in SwiftErrorVals.
SwiftErrorValues::iterator I =
std::find(SwiftErrorVals.begin(), SwiftErrorVals.end(), Val);
assert(I != SwiftErrorVals.end() && "Can't find value in SwiftErrorVals");
SwiftErrorMap[MBB][I - SwiftErrorVals.begin()] = VReg;
}

0 comments on commit e221a87

Please sign in to comment.