struct WinEHFuncInfo {
DenseMap<const Instruction *, int> EHPadStateMap;
+ DenseMap<const CatchReturnInst *, const BasicBlock *>
+ CatchRetSuccessorColorMap;
DenseMap<MCSymbol *, std::pair<int, MCSymbol *>> InvokeToStateMap;
SmallVector<WinEHUnwindMapEntry, 4> UnwindMap;
SmallVector<WinEHTryBlockMapEntry, 4> TryBlockMap;
void calculateSEHStateNumbers(const Function *ParentFn,
WinEHFuncInfo &FuncInfo);
+
+void calculateCatchReturnSuccessorColors(const Function *Fn,
+ WinEHFuncInfo &FuncInfo);
}
#endif // LLVM_CODEGEN_WINEHFUNCINFO_H
TargetInstrInfo(const TargetInstrInfo &) = delete;
void operator=(const TargetInstrInfo &) = delete;
public:
- TargetInstrInfo(unsigned CFSetupOpcode = ~0u, unsigned CFDestroyOpcode = ~0u)
- : CallFrameSetupOpcode(CFSetupOpcode),
- CallFrameDestroyOpcode(CFDestroyOpcode) {
- }
+ TargetInstrInfo(unsigned CFSetupOpcode = ~0u, unsigned CFDestroyOpcode = ~0u,
+ unsigned CatchRetOpcode = ~0u)
+ : CallFrameSetupOpcode(CFSetupOpcode),
+ CallFrameDestroyOpcode(CFDestroyOpcode),
+ CatchRetOpcode(CatchRetOpcode) {}
virtual ~TargetInstrInfo();
unsigned getCallFrameSetupOpcode() const { return CallFrameSetupOpcode; }
unsigned getCallFrameDestroyOpcode() const { return CallFrameDestroyOpcode; }
+ unsigned getCatchReturnOpcode() const { return CatchRetOpcode; }
+
/// Returns the actual stack pointer adjustment made by an instruction
/// as part of a call sequence. By default, only call frame setup/destroy
/// instructions adjust the stack, but targets may want to override this
private:
unsigned CallFrameSetupOpcode, CallFrameDestroyOpcode;
+ unsigned CatchRetOpcode;
};
/// \brief Provide DenseMapInfo for TargetInstrInfo::RegSubRegPair.
SDTCisPtrTy<0>
]>;
+def SDTCatchret : SDTypeProfile<0, 2, [ // catchret
+ SDTCisVT<0, OtherVT>, SDTCisVT<1, OtherVT>
+]>;
+
def SDTNone : SDTypeProfile<0, 0, []>; // ret, trap
def SDTLoad : SDTypeProfile<1, 1, [ // load
def brcond : SDNode<"ISD::BRCOND" , SDTBrcond, [SDNPHasChain]>;
def brind : SDNode<"ISD::BRIND" , SDTBrind, [SDNPHasChain]>;
def br : SDNode<"ISD::BR" , SDTBr, [SDNPHasChain]>;
-def catchret : SDNode<"ISD::CATCHRET" , SDTBr, [SDNPHasChain]>;
+def catchret : SDNode<"ISD::CATCHRET" , SDTCatchret, [SDNPHasChain]>;
def cleanupret : SDNode<"ISD::CLEANUPRET" , SDTNone, [SDNPHasChain]>;
def trap : SDNode<"ISD::TRAP" , SDTNone,
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/Target/TargetInstrInfo.h"
+#include "llvm/Target/TargetSubtargetInfo.h"
using namespace llvm;
#define DEBUG_TYPE "funclet-layout"
collectFuncletMembers(DenseMap<MachineBasicBlock *, int> &FuncletMembership,
int Funclet, MachineBasicBlock *MBB) {
// Don't revisit blocks.
- if (FuncletMembership.count(MBB) > 0)
+ if (FuncletMembership.count(MBB) > 0) {
+ // FIXME: This is a hack, we need to assert this unconditionally.
+ bool IsProbablyUnreachableBlock =
+ MBB->empty() ||
+ (MBB->succ_empty() && !MBB->getFirstTerminator()->isReturn() &&
+ MBB->size() == 1);
+
+ if (!IsProbablyUnreachableBlock) {
+ if (FuncletMembership[MBB] != Funclet) {
+ assert(false && "MBB is part of two funclets!");
+ report_fatal_error("MBB is part of two funclets!");
+ }
+ }
return;
+ }
// Add this MBB to our funclet.
FuncletMembership[MBB] = Funclet;
if (!F.getMMI().hasEHFunclets())
return false;
+ const TargetInstrInfo *TII = F.getSubtarget().getInstrInfo();
SmallVector<MachineBasicBlock *, 16> FuncletBlocks;
- for (MachineBasicBlock &MBB : F)
+ SmallVector<std::pair<MachineBasicBlock *, int>, 16> CatchRetSuccessors;
+ for (MachineBasicBlock &MBB : F) {
if (MBB.isEHFuncletEntry())
FuncletBlocks.push_back(&MBB);
+ MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator();
+ if (MBBI->getOpcode() != TII->getCatchReturnOpcode())
+ continue;
+
+ MachineBasicBlock *Successor = MBBI->getOperand(0).getMBB();
+ MachineBasicBlock *SuccessorColor = MBBI->getOperand(1).getMBB();
+ CatchRetSuccessors.push_back({Successor, SuccessorColor->getNumber()});
+ }
+
// We don't have anything to do if there aren't any EH pads.
if (FuncletBlocks.empty())
return false;
DenseMap<MachineBasicBlock *, int> FuncletMembership;
+ // Identify all the basic blocks reachable from the function entry.
+ collectFuncletMembers(FuncletMembership, F.front().getNumber(), F.begin());
+ // Next, identify all the blocks inside the funclets.
for (MachineBasicBlock *MBB : FuncletBlocks)
collectFuncletMembers(FuncletMembership, MBB->getNumber(), MBB);
+ // Finally, identify all the targets of a catchret.
+ for (std::pair<MachineBasicBlock *, int> CatchRetPair : CatchRetSuccessors)
+ collectFuncletMembers(FuncletMembership, CatchRetPair.second,
+ CatchRetPair.first);
F.sort([&](MachineBasicBlock &x, MachineBasicBlock &y) {
return FuncletMembership[&x] < FuncletMembership[&y];
const Function *WinEHParentFn = MMI.getWinEHParent(&fn);
if (Personality == EHPersonality::MSVC_CXX)
calculateWinCXXEHStateNumbers(WinEHParentFn, EHInfo);
- else
+ else if (isAsynchronousEHPersonality(Personality))
calculateSEHStateNumbers(WinEHParentFn, EHInfo);
+ calculateCatchReturnSuccessorColors(WinEHParentFn, EHInfo);
+
// Map all BB references in the WinEH data to MBBs.
for (WinEHTryBlockMapEntry &TBME : EHInfo.TryBlockMap) {
for (WinEHHandlerType &H : TBME.HandlerArray) {
MachineBasicBlock *TargetMBB = FuncInfo.MBBMap[I.getSuccessor()];
FuncInfo.MBB->addSuccessor(TargetMBB);
+ // Figure out the funclet membership for the catchret's successor.
+ // This will be used by the FuncletLayout pass to determine how to order the
+ // BB's.
+ MachineModuleInfo &MMI = DAG.getMachineFunction().getMMI();
+ WinEHFuncInfo &EHInfo =
+ MMI.getWinEHFuncInfo(DAG.getMachineFunction().getFunction());
+ const BasicBlock *SuccessorColor = EHInfo.CatchRetSuccessorColorMap[&I];
+ assert(SuccessorColor && "No parent funclet for catchret!");
+ MachineBasicBlock *SuccessorColorMBB = FuncInfo.MBBMap[SuccessorColor];
+ assert(SuccessorColorMBB && "No MBB for SuccessorColor!");
+
// Create the terminator node.
SDValue Ret = DAG.getNode(ISD::CATCHRET, getCurSDLoc(), MVT::Other,
- getControlRoot(), DAG.getBasicBlock(TargetMBB));
+ getControlRoot(), DAG.getBasicBlock(TargetMBB),
+ DAG.getBasicBlock(SuccessorColorMBB));
DAG.setRoot(Ret);
}
return new WinEHPrepare(TM);
}
+static bool
+findExceptionalConstructs(Function &Fn,
+ SmallVectorImpl<LandingPadInst *> &LPads,
+ SmallVectorImpl<ResumeInst *> &Resumes,
+ SmallVectorImpl<BasicBlock *> &EntryBlocks) {
+ bool ForExplicitEH = false;
+ for (BasicBlock &BB : Fn) {
+ Instruction *First = BB.getFirstNonPHI();
+ if (auto *LP = dyn_cast<LandingPadInst>(First)) {
+ LPads.push_back(LP);
+ } else if (First->isEHPad()) {
+ if (!ForExplicitEH)
+ EntryBlocks.push_back(&Fn.getEntryBlock());
+ if (!isa<CatchEndPadInst>(First) && !isa<CleanupEndPadInst>(First))
+ EntryBlocks.push_back(&BB);
+ ForExplicitEH = true;
+ }
+ if (auto *Resume = dyn_cast<ResumeInst>(BB.getTerminator()))
+ Resumes.push_back(Resume);
+ }
+ return ForExplicitEH;
+}
+
bool WinEHPrepare::runOnFunction(Function &Fn) {
if (!Fn.hasPersonalityFn())
return false;
SmallVector<LandingPadInst *, 4> LPads;
SmallVector<ResumeInst *, 4> Resumes;
SmallVector<BasicBlock *, 4> EntryBlocks;
- bool ForExplicitEH = false;
- for (BasicBlock &BB : Fn) {
- Instruction *First = BB.getFirstNonPHI();
- if (auto *LP = dyn_cast<LandingPadInst>(First)) {
- LPads.push_back(LP);
- } else if (First->isEHPad()) {
- if (!ForExplicitEH)
- EntryBlocks.push_back(&Fn.getEntryBlock());
- if (!isa<CatchEndPadInst>(First) && !isa<CleanupEndPadInst>(First))
- EntryBlocks.push_back(&BB);
- ForExplicitEH = true;
- }
- if (auto *Resume = dyn_cast<ResumeInst>(BB.getTerminator()))
- Resumes.push_back(Resume);
- }
+ bool ForExplicitEH =
+ findExceptionalConstructs(Fn, LPads, Resumes, EntryBlocks);
if (ForExplicitEH)
return prepareExplicitEH(Fn, EntryBlocks);
}
}
-void WinEHPrepare::colorFunclets(Function &F,
- SmallVectorImpl<BasicBlock *> &EntryBlocks) {
+static void
+colorFunclets(Function &F, SmallVectorImpl<BasicBlock *> &EntryBlocks,
+ std::map<BasicBlock *, std::set<BasicBlock *>> &BlockColors,
+ std::map<BasicBlock *, std::set<BasicBlock *>> &FuncletBlocks,
+ std::map<BasicBlock *, std::set<BasicBlock *>> &FuncletChildren) {
SmallVector<std::pair<BasicBlock *, BasicBlock *>, 16> Worklist;
BasicBlock *EntryBlock = &F.getEntryBlock();
}
}
+void WinEHPrepare::colorFunclets(Function &F,
+ SmallVectorImpl<BasicBlock *> &EntryBlocks) {
+ ::colorFunclets(F, EntryBlocks, BlockColors, FuncletBlocks, FuncletChildren);
+}
+
+void llvm::calculateCatchReturnSuccessorColors(const Function *Fn,
+ WinEHFuncInfo &FuncInfo) {
+ SmallVector<LandingPadInst *, 4> LPads;
+ SmallVector<ResumeInst *, 4> Resumes;
+ SmallVector<BasicBlock *, 4> EntryBlocks;
+ // colorFunclets needs the set of EntryBlocks, get them using
+ // findExceptionalConstructs.
+ bool ForExplicitEH = findExceptionalConstructs(const_cast<Function &>(*Fn),
+ LPads, Resumes, EntryBlocks);
+ if (!ForExplicitEH)
+ return;
+
+ std::map<BasicBlock *, std::set<BasicBlock *>> BlockColors;
+ std::map<BasicBlock *, std::set<BasicBlock *>> FuncletBlocks;
+ std::map<BasicBlock *, std::set<BasicBlock *>> FuncletChildren;
+ // Figure out which basic blocks belong to which funclets.
+ colorFunclets(const_cast<Function &>(*Fn), EntryBlocks, BlockColors,
+ FuncletBlocks, FuncletChildren);
+
+ // We need to find the catchret successors. To do this, we must first find
+ // all the catchpad funclets.
+ for (auto &Funclet : FuncletBlocks) {
+ // Figure out what kind of funclet we are looking at; We only care about
+ // catchpads.
+ BasicBlock *FuncletPadBB = Funclet.first;
+ Instruction *FirstNonPHI = FuncletPadBB->getFirstNonPHI();
+ auto *CatchPad = dyn_cast<CatchPadInst>(FirstNonPHI);
+ if (!CatchPad)
+ continue;
+
+ // The users of a catchpad are always catchrets.
+ for (User *Exit : CatchPad->users()) {
+ auto *CatchReturn = cast<CatchReturnInst>(Exit);
+ BasicBlock *CatchRetSuccessor = CatchReturn->getSuccessor();
+ std::set<BasicBlock *> &SuccessorColors = BlockColors[CatchRetSuccessor];
+ assert(SuccessorColors.size() == 1 && "Expected BB to be monochrome!");
+ BasicBlock *Color = *SuccessorColors.begin();
+ if (auto *CPI = dyn_cast<CatchPadInst>(Color->getFirstNonPHI()))
+ Color = CPI->getNormalDest();
+ // Record the catchret successor's funclet membership.
+ FuncInfo.CatchRetSuccessorColorMap[CatchReturn] = Color;
+ }
+ }
+}
+
void WinEHPrepare::demotePHIsOnFunclets(Function &F) {
// Strip PHI nodes off of EH pads.
SmallVector<PHINode *, 16> PHINodes;
BuildMI(*RestoreMBB, RestoreMBBI, DL, TII.get(X86::JMP_4))
.addMBB(TargetMBB);
}
- // Replace CATCHRET with the appropriate RET.
- unsigned RetOp = STI.is64Bit() ? X86::RETQ : X86::RETL;
- MachineBasicBlock::iterator NewExit =
- BuildMI(MBB, MBBI, DL, TII.get(RetOp)).addReg(ReturnReg);
- MBBI->eraseFromParent();
- MBBI = NewExit;
} else if (MBBI->getOpcode() == X86::CLEANUPRET) {
NumBytes = MFI->getMaxCallFrameSize();
assert(hasFP(MF) && "EH funclets without FP not yet implemented");
BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r),
MachineFramePtr)
.setMIFlag(MachineInstr::FrameDestroy);
- // Replace CLEANUPRET with the appropriate RET.
- unsigned RetOp = STI.is64Bit() ? X86::RETQ : X86::RETL;
- MachineBasicBlock::iterator NewExit =
- BuildMI(MBB, MBBI, DL, TII.get(RetOp));
- MBBI->eraseFromParent();
- MBBI = NewExit;
} else if (hasFP(MF)) {
// Calculate required stack adjustment.
uint64_t FrameSize = StackSize - SlotSize;
}
-let isTerminator = 1, isBarrier = 1, hasCtrlDep = 1, isCodeGenOnly = 1, isReturn = 1 in {
-def CATCHRET : I<0, Pseudo, (outs), (ins brtarget32:$dst),
- "# CATCHRET",
- [(catchret bb:$dst)]>;
+let isTerminator = 1, hasSideEffects = 1, isBarrier = 1, hasCtrlDep = 1, isCodeGenOnly = 1, isReturn = 1 in {
+def CATCHRET : I<0, Pseudo, (outs), (ins brtarget32:$dst, brtarget32:$from),
+ "# CATCHRET",
+ [(catchret bb:$dst, bb:$from)]>;
def CLEANUPRET : I<0, Pseudo, (outs), (ins), "# CLEANUPRET", [(cleanupret)]>;
}
void X86InstrInfo::anchor() {}
X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
- : X86GenInstrInfo(
- (STI.isTarget64BitLP64() ? X86::ADJCALLSTACKDOWN64 : X86::ADJCALLSTACKDOWN32),
- (STI.isTarget64BitLP64() ? X86::ADJCALLSTACKUP64 : X86::ADJCALLSTACKUP32)),
+ : X86GenInstrInfo((STI.isTarget64BitLP64() ? X86::ADJCALLSTACKDOWN64
+ : X86::ADJCALLSTACKDOWN32),
+ (STI.isTarget64BitLP64() ? X86::ADJCALLSTACKUP64
+ : X86::ADJCALLSTACKUP32),
+ X86::CATCHRET),
Subtarget(STI), RI(STI.getTargetTriple()) {
static const X86MemoryFoldTableEntry MemoryFoldTable2Addr[] = {
break;
}
+ case X86::CLEANUPRET: {
+ // Replace CATCHRET with the appropriate RET.
+ OutMI = MCInst();
+ OutMI.setOpcode(getRetOpcode(AsmPrinter.getSubtarget()));
+ break;
+ }
+
+ case X86::CATCHRET: {
+ // Replace CATCHRET with the appropriate RET.
+ const X86Subtarget &Subtarget = AsmPrinter.getSubtarget();
+ unsigned ReturnReg = Subtarget.is64Bit() ? X86::RAX : X86::EAX;
+ OutMI = MCInst();
+ OutMI.setOpcode(getRetOpcode(Subtarget));
+ OutMI.addOperand(MCOperand::createReg(ReturnReg));
+ break;
+ }
+
// TAILJMPd, TAILJMPd64 - Lower to the correct jump instructions.
case X86::TAILJMPr:
case X86::TAILJMPd:
X86ATTInstPrinter::getRegisterName(Reg));
break;
}
+ case X86::CLEANUPRET: {
+ // Lower these as normal, but add some comments.
+ OutStreamer->AddComment("CLEANUPRET");
+ break;
+ }
+
+ case X86::CATCHRET: {
+ // Lower these as normal, but add some comments.
+ OutStreamer->AddComment("CATCHRET");
+ break;
+ }
+
case X86::TAILJMPr:
case X86::TAILJMPm:
case X86::TAILJMPd:
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"
-define void @f(i1 %B) personality i32 (...)* @__CxxFrameHandler3 {
+%eh.ThrowInfo = type { i32, i32, i32, i32 }
+
+define void @test1(i1 %B) personality i32 (...)* @__CxxFrameHandler3 {
entry:
invoke void @g()
to label %unreachable unwind label %catch.dispatch
unreachable
}
-; CHECK-LABEL: f:
+; CHECK-LABEL: test1:
; The entry funclet contains %entry and %try.cont
; CHECK: # %entry
declare void @g()
+
+define i32 @test2(i1 %B) personality i32 (...)* @__CxxFrameHandler3 {
+entry:
+ invoke void @_CxxThrowException(i8* null, %eh.ThrowInfo* null) #1
+ to label %unreachable unwind label %catch.dispatch
+
+catch.dispatch: ; preds = %entry
+ %0 = catchpad [i8* null, i32 64, i8* null]
+ to label %catch unwind label %catchendblock
+
+catch: ; preds = %catch.dispatch
+ invoke void @_CxxThrowException(i8* null, %eh.ThrowInfo* null) #1
+ to label %unreachable unwind label %catch.dispatch.1
+
+catch.dispatch.1: ; preds = %catch
+ %1 = catchpad [i8* null, i32 64, i8* null]
+ to label %catch.3 unwind label %catchendblock.2
+
+catch.3: ; preds = %catch.dispatch.1
+ catchret %1 to label %try.cont
+
+try.cont: ; preds = %catch.3
+ catchret %0 to label %try.cont.5
+
+try.cont.5: ; preds = %try.cont
+ ret i32 0
+
+catchendblock.2: ; preds = %catch.dispatch.1
+ catchendpad unwind label %catchendblock
+
+catchendblock: ; preds = %catchendblock.2, %catch.dispatch
+ catchendpad unwind to caller
+
+unreachable: ; preds = %catch, %entry
+ unreachable
+
+}
+
+; CHECK-LABEL: test2:
+
+; The entry funclet contains %entry and %try.cont.5
+; CHECK: # %entry
+; CHECK: # %try.cont.5
+; CHECK: retq
+
+; The inner catch funclet contains %catch.3
+; CHECK: # %catch.3
+; CHECK: retq
+
+; The outer catch funclet contains %catch and %try.cont
+; CHECK: # %catch
+; CHECK: # %try.cont
+; CHECK: retq
+
+declare void @_CxxThrowException(i8*, %eh.ThrowInfo*)
declare i32 @__CxxFrameHandler3(...)
OS << "namespace llvm {\n";
OS << "struct " << ClassName << " : public TargetInstrInfo {\n"
<< " explicit " << ClassName
- << "(int CFSetupOpcode = -1, int CFDestroyOpcode = -1);\n"
+ << "(int CFSetupOpcode = -1, int CFDestroyOpcode = -1, int CatchRetOpcode = -1);\n"
<< " ~" << ClassName << "() override {}\n"
<< "};\n";
OS << "} // end llvm namespace \n";
OS << "extern const unsigned " << TargetName << "InstrNameIndices[];\n";
OS << "extern const char " << TargetName << "InstrNameData[];\n";
OS << ClassName << "::" << ClassName
- << "(int CFSetupOpcode, int CFDestroyOpcode)\n"
- << " : TargetInstrInfo(CFSetupOpcode, CFDestroyOpcode) {\n"
+ << "(int CFSetupOpcode, int CFDestroyOpcode, int CatchRetOpcode)\n"
+ << " : TargetInstrInfo(CFSetupOpcode, CFDestroyOpcode, CatchRetOpcode) {\n"
<< " InitMCInstrInfo(" << TargetName << "Insts, " << TargetName
<< "InstrNameIndices, " << TargetName << "InstrNameData, "
<< NumberedInstructions.size() << ");\n}\n";