[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:
Heejin Ahn 2018-05-23 00:32:46 +00:00
parent 9062bbf419
commit 1e4d35044f
8 changed files with 62 additions and 36 deletions

View File

@ -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

View File

@ -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; }

View File

@ -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; }

View File

@ -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;
} }

View File

@ -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; ) {

View File

@ -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;

View File

@ -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);
} }

View File

@ -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 {