struct WinEHUnwindMapEntry {
int ToState;
- Function *Cleanup;
+ const Value *Cleanup;
};
struct WinEHHandlerType {
int Adjectives;
GlobalVariable *TypeDescriptor;
int CatchObjRecoverIdx;
- Function *Handler;
+ const Value *Handler;
};
struct WinEHTryBlockMapEntry {
int TryLow;
int TryHigh;
+ int CatchHigh = -1;
SmallVector<WinEHHandlerType, 1> HandlerArray;
};
DenseMap<const Function *, const InvokeInst *> LastInvoke;
DenseMap<const Function *, int> HandlerEnclosedState;
DenseMap<const Function *, bool> LastInvokeVisited;
- DenseMap<const LandingPadInst *, int> LandingPadStateMap;
+ DenseMap<const Instruction *, int> EHPadStateMap;
DenseMap<const Function *, int> CatchHandlerParentFrameObjIdx;
DenseMap<const Function *, int> CatchHandlerParentFrameObjOffset;
DenseMap<const Function *, int> CatchHandlerMaxState;
int UnwindHelpFrameOffset = -1;
unsigned NumIPToStateFuncsVisited = 0;
+ int getLastStateNumber() const { return UnwindMap.size() - 1; }
+
/// localescape index of the 32-bit EH registration node. Set by
/// WinEHStatePass and used indirectly by SEH filter functions of the parent.
int EHRegNodeEscapeIndex = INT_MAX;
Asm->OutContext);
}
-const MCExpr *WinException::create32bitRef(const GlobalValue *GV) {
- if (!GV)
+const MCExpr *WinException::create32bitRef(const Value *V) {
+ if (!V)
return MCConstantExpr::create(0, Asm->OutContext);
- return create32bitRef(Asm->getSymbol(GV));
+ return create32bitRef(Asm->getSymbol(cast<GlobalValue>(V)));
}
/// Emit the language-specific data that __C_specific_handler expects. This
int CatchHigh = -1;
for (WinEHHandlerType &HT : TBME.HandlerArray)
CatchHigh =
- std::max(CatchHigh, FuncInfo.CatchHandlerMaxState[HT.Handler]);
+ std::max(CatchHigh,
+ FuncInfo.CatchHandlerMaxState[cast<Function>(HT.Handler)]);
assert(TBME.TryLow <= TBME.TryHigh);
OS.EmitIntValue(TBME.TryLow, 4); // TryLow
namespace llvm {
class Function;
-class GlobalValue;
class MachineFunction;
class MCExpr;
+class Value;
struct WinEHFuncInfo;
class LLVM_LIBRARY_VISIBILITY WinException : public EHStreamer {
StringRef FLinkageName);
const MCExpr *create32bitRef(const MCSymbol *Value);
- const MCExpr *create32bitRef(const GlobalValue *GV);
+ const MCExpr *create32bitRef(const Value *V);
public:
//===--------------------------------------------------------------------===//
Personality == EHPersonality::MSVC_X86SEH) {
for (const LandingPadInst *LP : LPads) {
MachineBasicBlock *LPadMBB = MBBMap[LP->getParent()];
- MMI.addWinEHState(LPadMBB, EHInfo.LandingPadStateMap[LP]);
+ MMI.addWinEHState(LPadMBB, EHInfo.EHPadStateMap[LP]);
}
}
}
};
}
-void WinEHNumbering::createUnwindMapEntry(int ToState, ActionHandler *AH) {
+static int addUnwindMapEntry(WinEHFuncInfo &FuncInfo, int ToState,
+ const Value *V) {
WinEHUnwindMapEntry UME;
UME.ToState = ToState;
- if (auto *CH = dyn_cast_or_null<CleanupHandler>(AH))
- UME.Cleanup = cast<Function>(CH->getHandlerBlockOrFunc());
- else
- UME.Cleanup = nullptr;
+ UME.Cleanup = V;
FuncInfo.UnwindMap.push_back(UME);
+ return FuncInfo.getLastStateNumber();
+}
+
+static void addTryBlockMapEntry(WinEHFuncInfo &FuncInfo, int TryLow,
+ int TryHigh, int CatchHigh,
+ ArrayRef<const CatchPadInst *> Handlers) {
+ WinEHTryBlockMapEntry TBME;
+ TBME.TryLow = TryLow;
+ TBME.TryHigh = TryHigh;
+ TBME.CatchHigh = CatchHigh;
+ assert(TBME.TryLow <= TBME.TryHigh);
+ for (const CatchPadInst *CPI : Handlers) {
+ WinEHHandlerType HT;
+ Constant *TypeInfo = cast<Constant>(CPI->getArgOperand(0));
+ if (TypeInfo->isNullValue()) {
+ HT.Adjectives = 0x40;
+ HT.TypeDescriptor = nullptr;
+ } else {
+ auto *GV = cast<GlobalVariable>(TypeInfo->stripPointerCasts());
+ // Selectors are always pointers to GlobalVariables with 'struct' type.
+ // The struct has two fields, adjectives and a type descriptor.
+ auto *CS = cast<ConstantStruct>(GV->getInitializer());
+ HT.Adjectives =
+ cast<ConstantInt>(CS->getAggregateElement(0U))->getZExtValue();
+ HT.TypeDescriptor =
+ cast<GlobalVariable>(CS->getAggregateElement(1)->stripPointerCasts());
+ }
+ HT.Handler = CPI->getParent();
+ // FIXME: Pass CPI->getArgOperand(1).
+ HT.CatchObjRecoverIdx = -1;
+ TBME.HandlerArray.push_back(HT);
+ }
+ FuncInfo.TryBlockMap.push_back(TBME);
+}
+
+void WinEHNumbering::createUnwindMapEntry(int ToState, ActionHandler *AH) {
+ Value *V = nullptr;
+ if (auto *CH = dyn_cast_or_null<CleanupHandler>(AH))
+ V = cast<Function>(CH->getHandlerBlockOrFunc());
+ addUnwindMapEntry(FuncInfo, ToState, V);
}
void WinEHNumbering::createTryBlockMapEntry(int TryLow, int TryHigh,
continue;
processCallSite(ActionList, II);
ActionList.clear();
- FuncInfo.LandingPadStateMap[LPI] = currentEHNumber();
+ FuncInfo.EHPadStateMap[LPI] = currentEHNumber();
DEBUG(dbgs() << "Assigning state " << currentEHNumber()
<< " to landing pad at " << LPI->getParent()->getName()
<< '\n');
}
}
+static const BasicBlock *getSingleCatchPadPredecessor(const BasicBlock &BB) {
+ for (const BasicBlock *PredBlock : predecessors(&BB))
+ if (isa<CatchPadInst>(PredBlock->getFirstNonPHI()))
+ return PredBlock;
+ return nullptr;
+}
+
+// Given BB which ends in an unwind edge, return the EHPad that this BB belongs
+// to. If the unwind edge came from an invoke, return null.
+static const BasicBlock *getEHPadFromPredecessor(const BasicBlock *BB) {
+ const TerminatorInst *TI = BB->getTerminator();
+ if (isa<InvokeInst>(TI))
+ return nullptr;
+ if (isa<CatchPadInst>(TI) || isa<CatchEndPadInst>(TI) ||
+ isa<TerminatePadInst>(TI))
+ return BB;
+ return cast<CleanupPadInst>(cast<CleanupReturnInst>(TI)->getReturnValue())
+ ->getParent();
+}
+
+static void calculateExplicitStateNumbers(WinEHFuncInfo &FuncInfo,
+ const BasicBlock &BB,
+ int ParentState) {
+ assert(BB.isEHPad());
+ const Instruction *FirstNonPHI = BB.getFirstNonPHI();
+ // All catchpad instructions will be handled when we process their
+ // respective catchendpad instruction.
+ if (isa<CatchPadInst>(FirstNonPHI))
+ return;
+
+ if (isa<CatchEndPadInst>(FirstNonPHI)) {
+ const BasicBlock *TryPad = &BB;
+ const BasicBlock *LastTryPad = nullptr;
+ SmallVector<const CatchPadInst *, 2> Handlers;
+ do {
+ LastTryPad = TryPad;
+ TryPad = getSingleCatchPadPredecessor(*TryPad);
+ if (TryPad)
+ Handlers.push_back(cast<CatchPadInst>(TryPad->getFirstNonPHI()));
+ } while (TryPad);
+ // We've pushed these back into reverse source order. Reverse them to get
+ // the list back into source order.
+ std::reverse(Handlers.begin(), Handlers.end());
+ int TryLow = addUnwindMapEntry(FuncInfo, ParentState, nullptr);
+ FuncInfo.EHPadStateMap[Handlers.front()] = TryLow;
+ for (const BasicBlock *PredBlock : predecessors(LastTryPad))
+ if ((PredBlock = getEHPadFromPredecessor(PredBlock)))
+ calculateExplicitStateNumbers(FuncInfo, *PredBlock, TryLow);
+ int CatchLow = addUnwindMapEntry(FuncInfo, ParentState, nullptr);
+ FuncInfo.EHPadStateMap[FirstNonPHI] = CatchLow;
+ int TryHigh = CatchLow - 1;
+ for (const BasicBlock *PredBlock : predecessors(&BB))
+ if ((PredBlock = getEHPadFromPredecessor(PredBlock)))
+ calculateExplicitStateNumbers(FuncInfo, *PredBlock, CatchLow);
+ int CatchHigh = FuncInfo.getLastStateNumber();
+ addTryBlockMapEntry(FuncInfo, TryLow, TryHigh, CatchHigh, Handlers);
+ DEBUG(dbgs() << "TryLow[" << LastTryPad->getName() << "]: " << TryLow
+ << '\n');
+ DEBUG(dbgs() << "TryHigh[" << LastTryPad->getName() << "]: " << TryHigh
+ << '\n');
+ DEBUG(dbgs() << "CatchHigh[" << LastTryPad->getName() << "]: " << CatchHigh
+ << '\n');
+ } else if (isa<CleanupPadInst>(FirstNonPHI)) {
+ int CleanupState = addUnwindMapEntry(FuncInfo, ParentState, &BB);
+ FuncInfo.EHPadStateMap[FirstNonPHI] = CleanupState;
+ DEBUG(dbgs() << "Assigning state #" << CleanupState << " to BB "
+ << BB.getName() << '\n');
+ for (const BasicBlock *PredBlock : predecessors(&BB))
+ if ((PredBlock = getEHPadFromPredecessor(PredBlock)))
+ calculateExplicitStateNumbers(FuncInfo, *PredBlock, CleanupState);
+ } else if (isa<TerminatePadInst>(FirstNonPHI)) {
+ report_fatal_error("Not yet implemented!");
+ } else {
+ llvm_unreachable("unexpected EH Pad!");
+ }
+}
+
void llvm::calculateWinCXXEHStateNumbers(const Function *ParentFn,
WinEHFuncInfo &FuncInfo) {
// Return if it's already been done.
- if (!FuncInfo.LandingPadStateMap.empty())
+ if (!FuncInfo.EHPadStateMap.empty())
+ return;
+
+ bool IsExplicit = false;
+ for (const BasicBlock &BB : *ParentFn) {
+ if (!BB.isEHPad())
+ continue;
+ // Check if the EH Pad has no exceptional successors (i.e. it unwinds to
+ // caller). Cleanups are a little bit of a special case because their
+ // control flow cannot be determined by looking at the pad but instead by
+ // the pad's users.
+ bool HasNoSuccessors = false;
+ const Instruction *FirstNonPHI = BB.getFirstNonPHI();
+ if (FirstNonPHI->mayThrow()) {
+ HasNoSuccessors = true;
+ } else if (auto *CPI = dyn_cast<CleanupPadInst>(FirstNonPHI)) {
+ HasNoSuccessors =
+ CPI->use_empty() ||
+ cast<CleanupReturnInst>(CPI->user_back())->unwindsToCaller();
+ }
+
+ if (!HasNoSuccessors)
+ continue;
+ calculateExplicitStateNumbers(FuncInfo, BB, -1);
+ IsExplicit = true;
+ }
+
+ if (IsExplicit)
return;
WinEHNumbering Num(FuncInfo);
BlockColors.clear();
FuncletBlocks.clear();
+
return true;
}
cl::desc("Enable the machine combiner pass"),
cl::init(true), cl::Hidden);
+namespace llvm {
+void initializeWinEHStatePassPass(PassRegistry &);
+}
+
extern "C" void LLVMInitializeX86Target() {
// Register the target.
RegisterTargetMachine<X86TargetMachine> X(TheX86_32Target);
RegisterTargetMachine<X86TargetMachine> Y(TheX86_64Target);
+
+ PassRegistry &PR = *PassRegistry::getPassRegistry();
+ initializeWinEHStatePassPass(PR);
}
static std::unique_ptr<TargetLoweringObjectFile> createTLOF(const Triple &TT) {
#define DEBUG_TYPE "winehstate"
+namespace llvm { void initializeWinEHStatePassPass(PassRegistry &); }
+
namespace {
class WinEHStatePass : public FunctionPass {
public:
static char ID; // Pass identification, replacement for typeid.
- WinEHStatePass() : FunctionPass(ID) {}
+ WinEHStatePass() : FunctionPass(ID) {
+ initializeWinEHStatePassPass(*PassRegistry::getPassRegistry());
+ }
bool runOnFunction(Function &Fn) override;
void linkExceptionRegistration(IRBuilder<> &Builder, Function *Handler);
void unlinkExceptionRegistration(IRBuilder<> &Builder);
- void addCXXStateStores(Function &F, MachineModuleInfo &MMI);
- void addSEHStateStores(Function &F, MachineModuleInfo &MMI);
+ void addCXXStateStores(Function &F, WinEHFuncInfo &FuncInfo);
+ void addSEHStateStores(Function &F, WinEHFuncInfo &FuncInfo);
void addCXXStateStoresToFunclet(Value *ParentRegNode, WinEHFuncInfo &FuncInfo,
Function &F, int BaseState);
void insertStateNumberStore(Value *ParentRegNode, Instruction *IP, int State);
char WinEHStatePass::ID = 0;
+INITIALIZE_PASS(WinEHStatePass, "x86-winehstate",
+ "Insert stores for EH state numbers", false, false)
+
bool WinEHStatePass::doInitialization(Module &M) {
TheModule = &M;
FrameEscape = Intrinsic::getDeclaration(TheModule, Intrinsic::localescape);
emitExceptionRegistrationRecord(&F);
- auto *MMIPtr = getAnalysisIfAvailable<MachineModuleInfo>();
- assert(MMIPtr && "MachineModuleInfo should always be available");
- MachineModuleInfo &MMI = *MMIPtr;
+ auto *MMI = getAnalysisIfAvailable<MachineModuleInfo>();
+ // If MMI is null, create our own WinEHFuncInfo. This only happens in opt
+ // tests.
+ std::unique_ptr<WinEHFuncInfo> FuncInfoPtr;
+ if (!MMI)
+ FuncInfoPtr.reset(new WinEHFuncInfo());
+ WinEHFuncInfo &FuncInfo =
+ *(MMI ? &MMI->getWinEHFuncInfo(&F) : FuncInfoPtr.get());
+
switch (Personality) {
default: llvm_unreachable("unexpected personality function");
- case EHPersonality::MSVC_CXX: addCXXStateStores(F, MMI); break;
- case EHPersonality::MSVC_X86SEH: addSEHStateStores(F, MMI); break;
+ case EHPersonality::MSVC_CXX:
+ addCXXStateStores(F, FuncInfo);
+ break;
+ case EHPersonality::MSVC_X86SEH:
+ addSEHStateStores(F, FuncInfo);
+ break;
}
// Reset per-function state.
Builder.CreateStore(Next, FSZero);
}
-void WinEHStatePass::addCXXStateStores(Function &F, MachineModuleInfo &MMI) {
- WinEHFuncInfo &FuncInfo = MMI.getWinEHFuncInfo(&F);
+void WinEHStatePass::addCXXStateStores(Function &F, WinEHFuncInfo &FuncInfo) {
calculateWinCXXEHStateNumbers(&F, FuncInfo);
// The base state for the parent is -1.
insertStateNumberStore(ParentRegNode, CI, BaseState);
} else if (auto *II = dyn_cast<InvokeInst>(&I)) {
// Look up the state number of the landingpad this unwinds to.
- LandingPadInst *LPI = II->getUnwindDest()->getLandingPadInst();
+ Instruction *PadInst = II->getUnwindDest()->getFirstNonPHI();
// FIXME: Why does this assertion fail?
- //assert(FuncInfo.LandingPadStateMap.count(LPI) && "LP has no state!");
- int State = FuncInfo.LandingPadStateMap[LPI];
+ //assert(FuncInfo.EHPadStateMap.count(PadInst) && "EH Pad has no state!");
+ int State = FuncInfo.EHPadStateMap[PadInst];
insertStateNumberStore(ParentRegNode, II, State);
}
}
/// handlers aren't outlined and the runtime doesn't have to figure out which
/// catch handler frame to unwind to.
/// FIXME: __finally blocks are outlined, so this approach may break down there.
-void WinEHStatePass::addSEHStateStores(Function &F, MachineModuleInfo &MMI) {
- WinEHFuncInfo &FuncInfo = MMI.getWinEHFuncInfo(&F);
-
+void WinEHStatePass::addSEHStateStores(Function &F, WinEHFuncInfo &FuncInfo) {
// Remember and return the index that we used. We save it in WinEHFuncInfo so
// that we can lower llvm.x86.seh.recoverfp later in filter functions without
// too much trouble.
// Look up the state number of the landingpad this unwinds to.
LandingPadInst *LPI = II->getUnwindDest()->getLandingPadInst();
auto InsertionPair =
- FuncInfo.LandingPadStateMap.insert(std::make_pair(LPI, CurState));
+ FuncInfo.EHPadStateMap.insert(std::make_pair(LPI, CurState));
auto Iter = InsertionPair.first;
int &State = Iter->second;
bool Inserted = InsertionPair.second;
--- /dev/null
+; RUN: opt -mtriple=i686-pc-windows-msvc -S -x86-winehstate < %s | FileCheck %s
+
+target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
+target triple = "i686-pc-windows-msvc"
+
+%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] }
+%eh.CatchableType = type { i32, i8*, i32, i32, i32, i32, i8* }
+%eh.CatchableTypeArray.1 = type { i32, [1 x %eh.CatchableType*] }
+%eh.ThrowInfo = type { i32, i8*, i8*, i8* }
+
+$"\01??_R0H@8" = comdat any
+
+$"_CT??_R0H@84" = comdat any
+
+$_CTA1H = comdat any
+
+$_TI1H = comdat any
+
+@"\01??_7type_info@@6B@" = external constant i8*
+@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
+@"_CT??_R0H@84" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 1, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*), i32 0, i32 -1, i32 0, i32 4, i8* null }, section ".xdata", comdat
+@_CTA1H = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.1 { i32 1, [1 x %eh.CatchableType*] [%eh.CatchableType* @"_CT??_R0H@84"] }, section ".xdata", comdat
+@_TI1H = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i8* null, i8* null, i8* bitcast (%eh.CatchableTypeArray.1* @_CTA1H to i8*) }, section ".xdata", comdat
+
+define i32 @main() #0 personality i32 (...)* @__CxxFrameHandler3 {
+entry:
+ %tmp = alloca i32, align 4
+ ; CHECK: entry:
+ ; CHECK: store i32 -1
+ ; CHECK: call void @g(i32 3)
+ call void @g(i32 3)
+ store i32 0, i32* %tmp, align 4
+ %0 = bitcast i32* %tmp to i8*
+ ; CHECK: store i32 0
+ ; CHECK: invoke void @_CxxThrowException(
+ invoke void @_CxxThrowException(i8* %0, %eh.ThrowInfo* nonnull @_TI1H) #1
+ to label %unreachable.for.entry unwind label %catch.dispatch
+
+catch.dispatch: ; preds = %entry
+ %1 = catchpad token [i8* null, i8* null] to label %catch unwind label %catchendblock
+
+catch: ; preds = %catch.dispatch
+ ; CHECK: catch:
+ ; CHECK: store i32 2
+ ; CHECK: invoke void @_CxxThrowException(
+ invoke void @_CxxThrowException(i8* null, %eh.ThrowInfo* null) #1
+ to label %unreachable unwind label %catch.dispatch.1
+
+catch.dispatch.1: ; preds = %catch
+ %2 = catchpad token [i8* null, i8* null] to label %catch.3 unwind label %catchendblock.2
+
+catch.3: ; preds = %catch.dispatch.1
+ ; CHECK: catch.3:
+ ; CHECK: store i32 3
+ ; CHECK: invoke void @g(i32 1)
+ invoke void @g(i32 1)
+ to label %invoke.cont unwind label %catchendblock.2
+
+invoke.cont: ; preds = %catch.3
+ catchret token %2 to label %try.cont
+
+try.cont: ; preds = %invoke.cont
+ ; CHECK: try.cont:
+ ; CHECK: store i32 1
+ ; CHECK: invoke void @g(i32 2)
+ invoke void @g(i32 2)
+ to label %invoke.cont.4 unwind label %catchendblock
+
+invoke.cont.4: ; preds = %try.cont
+ unreachable
+
+catchendblock.2: ; preds = %catch.3, %catch.dispatch.1
+ catchendpad unwind label %catchendblock
+
+catchendblock: ; preds = %catchendblock.2, %try.cont, %catch.dispatch
+ catchendpad unwind to caller
+
+unreachable: ; preds = %catch
+ unreachable
+
+unreachable.for.entry: ; preds = %entry
+ unreachable
+}
+
+declare void @g(i32) #0
+
+declare x86_stdcallcc void @_CxxThrowException(i8*, %eh.ThrowInfo*)
+
+declare i32 @__CxxFrameHandler3(...)
+
+attributes #0 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-realign-stack" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { noreturn }
+
+!llvm.ident = !{!0}
+
+!0 = !{!"clang version 3.8.0 (trunk 245153) (llvm/trunk 245238)"}