forked from OSchip/llvm-project
[WebAssembly] Add functions for EHScopes
Summary: There are functions using the term 'funclet' to refer to both 1. an EH scopes, the structure of BBs that starts with catchpad/cleanuppad and ends with catchret/cleanupret, and 2. a small function that gets outlined in AsmPrinter, which is the original meaning of 'funclet'. So far the two have been the same thing; EH scopes are always outlined in AsmPrinter as funclets at the end of the compilation pipeline. But now wasm also uses scope-based EH but does not outline those, so we now need to correctly distinguish those two use cases in functions. This patch splits `MachineBasicBlock::isFuncletEntry` into `isFuncletEntry` and `isEHScopeEntry`, and `MachineFunction::hasFunclets` into `hasFunclets` and `hasEHScopes`, in order to distinguish the two different use cases. And this also changes some uses of the term 'funclet' to 'scope' in `getFuncletMembership` and change the function name to `getEHScopeMembership` because this function is not about outlined funclets but about EH scope memberships. This change is in the same vein as D45559. Reviewers: majnemer, dschuff Subscribers: sbc100, jgravelle-google, sunfish, llvm-commits Differential Revision: https://reviews.llvm.org/D47005 llvm-svn: 333045
This commit is contained in:
parent
9062bbf419
commit
1e4d35044f
|
@ -124,7 +124,7 @@ bool returnTypeIsEligibleForTailCall(const Function *F, const Instruction *I,
|
||||||
const TargetLoweringBase &TLI);
|
const TargetLoweringBase &TLI);
|
||||||
|
|
||||||
DenseMap<const MachineBasicBlock *, int>
|
DenseMap<const MachineBasicBlock *, int>
|
||||||
getFuncletMembership(const MachineFunction &MF);
|
getEHScopeMembership(const MachineFunction &MF);
|
||||||
|
|
||||||
} // End llvm namespace
|
} // End llvm namespace
|
||||||
|
|
||||||
|
|
|
@ -115,6 +115,11 @@ private:
|
||||||
/// branch.
|
/// branch.
|
||||||
bool AddressTaken = false;
|
bool AddressTaken = false;
|
||||||
|
|
||||||
|
/// Indicate that this basic block is the entry block of an EH scope, i.e.,
|
||||||
|
/// the block that used to have a catchpad or cleanuppad instruction in the
|
||||||
|
/// LLVM IR.
|
||||||
|
bool IsEHScopeEntry = false;
|
||||||
|
|
||||||
/// Indicate that this basic block is the entry block of an EH funclet.
|
/// Indicate that this basic block is the entry block of an EH funclet.
|
||||||
bool IsEHFuncletEntry = false;
|
bool IsEHFuncletEntry = false;
|
||||||
|
|
||||||
|
@ -375,6 +380,14 @@ public:
|
||||||
|
|
||||||
bool hasEHPadSuccessor() const;
|
bool hasEHPadSuccessor() const;
|
||||||
|
|
||||||
|
/// Returns true if this is the entry block of an EH scope, i.e., the block
|
||||||
|
/// that used to have a catchpad or cleanuppad instruction in the LLVM IR.
|
||||||
|
bool isEHScopeEntry() const { return IsEHScopeEntry; }
|
||||||
|
|
||||||
|
/// Indicates if this is the entry block of an EH scope, i.e., the block that
|
||||||
|
/// that used to have a catchpad or cleanuppad instruction in the LLVM IR.
|
||||||
|
void setIsEHScopeEntry(bool V = true) { IsEHScopeEntry = V; }
|
||||||
|
|
||||||
/// Returns true if this is the entry block of an EH funclet.
|
/// Returns true if this is the entry block of an EH funclet.
|
||||||
bool isEHFuncletEntry() const { return IsEHFuncletEntry; }
|
bool isEHFuncletEntry() const { return IsEHFuncletEntry; }
|
||||||
|
|
||||||
|
|
|
@ -319,6 +319,7 @@ class MachineFunction {
|
||||||
|
|
||||||
bool CallsEHReturn = false;
|
bool CallsEHReturn = false;
|
||||||
bool CallsUnwindInit = false;
|
bool CallsUnwindInit = false;
|
||||||
|
bool HasEHScopes = false;
|
||||||
bool HasEHFunclets = false;
|
bool HasEHFunclets = false;
|
||||||
|
|
||||||
/// List of C++ TypeInfo used.
|
/// List of C++ TypeInfo used.
|
||||||
|
@ -760,6 +761,9 @@ public:
|
||||||
bool callsUnwindInit() const { return CallsUnwindInit; }
|
bool callsUnwindInit() const { return CallsUnwindInit; }
|
||||||
void setCallsUnwindInit(bool b) { CallsUnwindInit = b; }
|
void setCallsUnwindInit(bool b) { CallsUnwindInit = b; }
|
||||||
|
|
||||||
|
bool hasEHScopes() const { return HasEHScopes; }
|
||||||
|
void setHasEHScopes(bool V) { HasEHScopes = V; }
|
||||||
|
|
||||||
bool hasEHFunclets() const { return HasEHFunclets; }
|
bool hasEHFunclets() const { return HasEHFunclets; }
|
||||||
void setHasEHFunclets(bool V) { HasEHFunclets = V; }
|
void setHasEHFunclets(bool V) { HasEHFunclets = V; }
|
||||||
|
|
||||||
|
|
|
@ -629,26 +629,26 @@ bool llvm::returnTypeIsEligibleForTailCall(const Function *F,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void collectFuncletMembers(
|
static void
|
||||||
DenseMap<const MachineBasicBlock *, int> &FuncletMembership, int Funclet,
|
collectEHScopeMembers(DenseMap<const MachineBasicBlock *, int> &ScopeMembership,
|
||||||
const MachineBasicBlock *MBB) {
|
int Scope, const MachineBasicBlock *MBB) {
|
||||||
SmallVector<const MachineBasicBlock *, 16> Worklist = {MBB};
|
SmallVector<const MachineBasicBlock *, 16> Worklist = {MBB};
|
||||||
while (!Worklist.empty()) {
|
while (!Worklist.empty()) {
|
||||||
const MachineBasicBlock *Visiting = Worklist.pop_back_val();
|
const MachineBasicBlock *Visiting = Worklist.pop_back_val();
|
||||||
// Don't follow blocks which start new funclets.
|
// Don't follow blocks which start new scopes.
|
||||||
if (Visiting->isEHPad() && Visiting != MBB)
|
if (Visiting->isEHPad() && Visiting != MBB)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Add this MBB to our funclet.
|
// Add this MBB to our scope.
|
||||||
auto P = FuncletMembership.insert(std::make_pair(Visiting, Funclet));
|
auto P = ScopeMembership.insert(std::make_pair(Visiting, Scope));
|
||||||
|
|
||||||
// Don't revisit blocks.
|
// Don't revisit blocks.
|
||||||
if (!P.second) {
|
if (!P.second) {
|
||||||
assert(P.first->second == Funclet && "MBB is part of two funclets!");
|
assert(P.first->second == Scope && "MBB is part of two scopes!");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns are boundaries where funclet transfer can occur, don't follow
|
// Returns are boundaries where scope transfer can occur, don't follow
|
||||||
// successors.
|
// successors.
|
||||||
if (Visiting->isReturnBlock())
|
if (Visiting->isReturnBlock())
|
||||||
continue;
|
continue;
|
||||||
|
@ -659,25 +659,25 @@ static void collectFuncletMembers(
|
||||||
}
|
}
|
||||||
|
|
||||||
DenseMap<const MachineBasicBlock *, int>
|
DenseMap<const MachineBasicBlock *, int>
|
||||||
llvm::getFuncletMembership(const MachineFunction &MF) {
|
llvm::getEHScopeMembership(const MachineFunction &MF) {
|
||||||
DenseMap<const MachineBasicBlock *, int> FuncletMembership;
|
DenseMap<const MachineBasicBlock *, int> ScopeMembership;
|
||||||
|
|
||||||
// We don't have anything to do if there aren't any EH pads.
|
// We don't have anything to do if there aren't any EH pads.
|
||||||
if (!MF.hasEHFunclets())
|
if (!MF.hasEHScopes())
|
||||||
return FuncletMembership;
|
return ScopeMembership;
|
||||||
|
|
||||||
int EntryBBNumber = MF.front().getNumber();
|
int EntryBBNumber = MF.front().getNumber();
|
||||||
bool IsSEH = isAsynchronousEHPersonality(
|
bool IsSEH = isAsynchronousEHPersonality(
|
||||||
classifyEHPersonality(MF.getFunction().getPersonalityFn()));
|
classifyEHPersonality(MF.getFunction().getPersonalityFn()));
|
||||||
|
|
||||||
const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
|
const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo();
|
||||||
SmallVector<const MachineBasicBlock *, 16> FuncletBlocks;
|
SmallVector<const MachineBasicBlock *, 16> ScopeBlocks;
|
||||||
SmallVector<const MachineBasicBlock *, 16> UnreachableBlocks;
|
SmallVector<const MachineBasicBlock *, 16> UnreachableBlocks;
|
||||||
SmallVector<const MachineBasicBlock *, 16> SEHCatchPads;
|
SmallVector<const MachineBasicBlock *, 16> SEHCatchPads;
|
||||||
SmallVector<std::pair<const MachineBasicBlock *, int>, 16> CatchRetSuccessors;
|
SmallVector<std::pair<const MachineBasicBlock *, int>, 16> CatchRetSuccessors;
|
||||||
for (const MachineBasicBlock &MBB : MF) {
|
for (const MachineBasicBlock &MBB : MF) {
|
||||||
if (MBB.isEHFuncletEntry()) {
|
if (MBB.isEHScopeEntry()) {
|
||||||
FuncletBlocks.push_back(&MBB);
|
ScopeBlocks.push_back(&MBB);
|
||||||
} else if (IsSEH && MBB.isEHPad()) {
|
} else if (IsSEH && MBB.isEHPad()) {
|
||||||
SEHCatchPads.push_back(&MBB);
|
SEHCatchPads.push_back(&MBB);
|
||||||
} else if (MBB.pred_empty()) {
|
} else if (MBB.pred_empty()) {
|
||||||
|
@ -686,8 +686,8 @@ llvm::getFuncletMembership(const MachineFunction &MF) {
|
||||||
|
|
||||||
MachineBasicBlock::const_iterator MBBI = MBB.getFirstTerminator();
|
MachineBasicBlock::const_iterator MBBI = MBB.getFirstTerminator();
|
||||||
|
|
||||||
// CatchPads are not funclets for SEH so do not consider CatchRet to
|
// CatchPads are not scopes for SEH so do not consider CatchRet to
|
||||||
// transfer control to another funclet.
|
// transfer control to another scope.
|
||||||
if (MBBI == MBB.end() || MBBI->getOpcode() != TII->getCatchReturnOpcode())
|
if (MBBI == MBB.end() || MBBI->getOpcode() != TII->getCatchReturnOpcode())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -700,24 +700,24 @@ llvm::getFuncletMembership(const MachineFunction &MF) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't have anything to do if there aren't any EH pads.
|
// We don't have anything to do if there aren't any EH pads.
|
||||||
if (FuncletBlocks.empty())
|
if (ScopeBlocks.empty())
|
||||||
return FuncletMembership;
|
return ScopeMembership;
|
||||||
|
|
||||||
// Identify all the basic blocks reachable from the function entry.
|
// Identify all the basic blocks reachable from the function entry.
|
||||||
collectFuncletMembers(FuncletMembership, EntryBBNumber, &MF.front());
|
collectEHScopeMembers(ScopeMembership, EntryBBNumber, &MF.front());
|
||||||
// All blocks not part of a funclet are in the parent function.
|
// All blocks not part of a scope are in the parent function.
|
||||||
for (const MachineBasicBlock *MBB : UnreachableBlocks)
|
for (const MachineBasicBlock *MBB : UnreachableBlocks)
|
||||||
collectFuncletMembers(FuncletMembership, EntryBBNumber, MBB);
|
collectEHScopeMembers(ScopeMembership, EntryBBNumber, MBB);
|
||||||
// Next, identify all the blocks inside the funclets.
|
// Next, identify all the blocks inside the scopes.
|
||||||
for (const MachineBasicBlock *MBB : FuncletBlocks)
|
for (const MachineBasicBlock *MBB : ScopeBlocks)
|
||||||
collectFuncletMembers(FuncletMembership, MBB->getNumber(), MBB);
|
collectEHScopeMembers(ScopeMembership, MBB->getNumber(), MBB);
|
||||||
// SEH CatchPads aren't really funclets, handle them separately.
|
// SEH CatchPads aren't really scopes, handle them separately.
|
||||||
for (const MachineBasicBlock *MBB : SEHCatchPads)
|
for (const MachineBasicBlock *MBB : SEHCatchPads)
|
||||||
collectFuncletMembers(FuncletMembership, EntryBBNumber, MBB);
|
collectEHScopeMembers(ScopeMembership, EntryBBNumber, MBB);
|
||||||
// Finally, identify all the targets of a catchret.
|
// Finally, identify all the targets of a catchret.
|
||||||
for (std::pair<const MachineBasicBlock *, int> CatchRetPair :
|
for (std::pair<const MachineBasicBlock *, int> CatchRetPair :
|
||||||
CatchRetSuccessors)
|
CatchRetSuccessors)
|
||||||
collectFuncletMembers(FuncletMembership, CatchRetPair.second,
|
collectEHScopeMembers(ScopeMembership, CatchRetPair.second,
|
||||||
CatchRetPair.first);
|
CatchRetPair.first);
|
||||||
return FuncletMembership;
|
return ScopeMembership;
|
||||||
}
|
}
|
||||||
|
|
|
@ -200,7 +200,7 @@ bool BranchFolder::OptimizeFunction(MachineFunction &MF,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recalculate funclet membership.
|
// Recalculate funclet membership.
|
||||||
FuncletMembership = getFuncletMembership(MF);
|
FuncletMembership = getEHScopeMembership(MF);
|
||||||
|
|
||||||
bool MadeChangeThisIteration = true;
|
bool MadeChangeThisIteration = true;
|
||||||
while (MadeChangeThisIteration) {
|
while (MadeChangeThisIteration) {
|
||||||
|
@ -1293,7 +1293,7 @@ bool BranchFolder::OptimizeBranches(MachineFunction &MF) {
|
||||||
// Make sure blocks are numbered in order
|
// Make sure blocks are numbered in order
|
||||||
MF.RenumberBlocks();
|
MF.RenumberBlocks();
|
||||||
// Renumbering blocks alters funclet membership, recalculate it.
|
// Renumbering blocks alters funclet membership, recalculate it.
|
||||||
FuncletMembership = getFuncletMembership(MF);
|
FuncletMembership = getEHScopeMembership(MF);
|
||||||
|
|
||||||
for (MachineFunction::iterator I = std::next(MF.begin()), E = MF.end();
|
for (MachineFunction::iterator I = std::next(MF.begin()), E = MF.end();
|
||||||
I != E; ) {
|
I != E; ) {
|
||||||
|
|
|
@ -42,7 +42,7 @@ INITIALIZE_PASS(FuncletLayout, DEBUG_TYPE,
|
||||||
|
|
||||||
bool FuncletLayout::runOnMachineFunction(MachineFunction &F) {
|
bool FuncletLayout::runOnMachineFunction(MachineFunction &F) {
|
||||||
DenseMap<const MachineBasicBlock *, int> FuncletMembership =
|
DenseMap<const MachineBasicBlock *, int> FuncletMembership =
|
||||||
getFuncletMembership(F);
|
getEHScopeMembership(F);
|
||||||
if (FuncletMembership.empty())
|
if (FuncletMembership.empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
@ -226,9 +226,10 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf,
|
||||||
const Instruction *PadInst = BB.getFirstNonPHI();
|
const Instruction *PadInst = BB.getFirstNonPHI();
|
||||||
// If this is a non-landingpad EH pad, mark this function as using
|
// If this is a non-landingpad EH pad, mark this function as using
|
||||||
// funclets.
|
// funclets.
|
||||||
// FIXME: SEH catchpads do not create funclets, so we could avoid setting
|
// FIXME: SEH catchpads do not create EH scope/funclets, so we could avoid
|
||||||
// this in such cases in order to improve frame layout.
|
// setting this in such cases in order to improve frame layout.
|
||||||
if (!isa<LandingPadInst>(PadInst)) {
|
if (!isa<LandingPadInst>(PadInst)) {
|
||||||
|
MF->setHasEHScopes(true);
|
||||||
MF->setHasEHFunclets(true);
|
MF->setHasEHFunclets(true);
|
||||||
MF->getFrameInfo().setHasOpaqueSPAdjustment(true);
|
MF->getFrameInfo().setHasOpaqueSPAdjustment(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1379,7 +1379,10 @@ void SelectionDAGBuilder::visitCatchPad(const CatchPadInst &I) {
|
||||||
auto Pers = classifyEHPersonality(FuncInfo.Fn->getPersonalityFn());
|
auto Pers = classifyEHPersonality(FuncInfo.Fn->getPersonalityFn());
|
||||||
bool IsMSVCCXX = Pers == EHPersonality::MSVC_CXX;
|
bool IsMSVCCXX = Pers == EHPersonality::MSVC_CXX;
|
||||||
bool IsCoreCLR = Pers == EHPersonality::CoreCLR;
|
bool IsCoreCLR = Pers == EHPersonality::CoreCLR;
|
||||||
|
bool IsSEH = isAsynchronousEHPersonality(Pers);
|
||||||
MachineBasicBlock *CatchPadMBB = FuncInfo.MBB;
|
MachineBasicBlock *CatchPadMBB = FuncInfo.MBB;
|
||||||
|
if (!IsSEH)
|
||||||
|
CatchPadMBB->setIsEHScopeEntry();
|
||||||
// In MSVC C++ and CoreCLR, catchblocks are funclets and need prologues.
|
// In MSVC C++ and CoreCLR, catchblocks are funclets and need prologues.
|
||||||
if (IsMSVCCXX || IsCoreCLR)
|
if (IsMSVCCXX || IsCoreCLR)
|
||||||
CatchPadMBB->setIsEHFuncletEntry();
|
CatchPadMBB->setIsEHFuncletEntry();
|
||||||
|
@ -1427,7 +1430,8 @@ void SelectionDAGBuilder::visitCatchRet(const CatchReturnInst &I) {
|
||||||
|
|
||||||
void SelectionDAGBuilder::visitCleanupPad(const CleanupPadInst &CPI) {
|
void SelectionDAGBuilder::visitCleanupPad(const CleanupPadInst &CPI) {
|
||||||
// Don't emit any special code for the cleanuppad instruction. It just marks
|
// Don't emit any special code for the cleanuppad instruction. It just marks
|
||||||
// the start of a funclet.
|
// the start of an EH scope/funclet.
|
||||||
|
FuncInfo.MBB->setIsEHScopeEntry();
|
||||||
FuncInfo.MBB->setIsEHFuncletEntry();
|
FuncInfo.MBB->setIsEHFuncletEntry();
|
||||||
FuncInfo.MBB->setIsCleanupFuncletEntry();
|
FuncInfo.MBB->setIsCleanupFuncletEntry();
|
||||||
}
|
}
|
||||||
|
@ -1449,6 +1453,7 @@ static void findUnwindDestinations(
|
||||||
classifyEHPersonality(FuncInfo.Fn->getPersonalityFn());
|
classifyEHPersonality(FuncInfo.Fn->getPersonalityFn());
|
||||||
bool IsMSVCCXX = Personality == EHPersonality::MSVC_CXX;
|
bool IsMSVCCXX = Personality == EHPersonality::MSVC_CXX;
|
||||||
bool IsCoreCLR = Personality == EHPersonality::CoreCLR;
|
bool IsCoreCLR = Personality == EHPersonality::CoreCLR;
|
||||||
|
bool IsSEH = isAsynchronousEHPersonality(Personality);
|
||||||
|
|
||||||
while (EHPadBB) {
|
while (EHPadBB) {
|
||||||
const Instruction *Pad = EHPadBB->getFirstNonPHI();
|
const Instruction *Pad = EHPadBB->getFirstNonPHI();
|
||||||
|
@ -1461,6 +1466,7 @@ static void findUnwindDestinations(
|
||||||
// Stop on cleanup pads. Cleanups are always funclet entries for all known
|
// Stop on cleanup pads. Cleanups are always funclet entries for all known
|
||||||
// personalities.
|
// personalities.
|
||||||
UnwindDests.emplace_back(FuncInfo.MBBMap[EHPadBB], Prob);
|
UnwindDests.emplace_back(FuncInfo.MBBMap[EHPadBB], Prob);
|
||||||
|
UnwindDests.back().first->setIsEHScopeEntry();
|
||||||
UnwindDests.back().first->setIsEHFuncletEntry();
|
UnwindDests.back().first->setIsEHFuncletEntry();
|
||||||
break;
|
break;
|
||||||
} else if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(Pad)) {
|
} else if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(Pad)) {
|
||||||
|
@ -1470,6 +1476,8 @@ static void findUnwindDestinations(
|
||||||
// For MSVC++ and the CLR, catchblocks are funclets and need prologues.
|
// For MSVC++ and the CLR, catchblocks are funclets and need prologues.
|
||||||
if (IsMSVCCXX || IsCoreCLR)
|
if (IsMSVCCXX || IsCoreCLR)
|
||||||
UnwindDests.back().first->setIsEHFuncletEntry();
|
UnwindDests.back().first->setIsEHFuncletEntry();
|
||||||
|
if (!IsSEH)
|
||||||
|
UnwindDests.back().first->setIsEHScopeEntry();
|
||||||
}
|
}
|
||||||
NewEHPadBB = CatchSwitch->getUnwindDest();
|
NewEHPadBB = CatchSwitch->getUnwindDest();
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue