Skip to content

Commit 1a949c8

Browse files
committed
[Windows SEH]: HARDWARE EXCEPTION HANDLING (MSVC -EHa) - Part 2
This patch is the Part-2 (BE LLVM) implementation of HW Exception handling. Part-1 (FE Clang) was committed in 797ad70. This new feature adds the support of Hardware Exception for Microsoft Windows SEH (Structured Exception Handling). Compiler options: For clang-cl.exe, the option is -EHa, the same as MSVC. For clang.exe, the extra option is -fasync-exceptions, plus -triple x86_64-windows -fexceptions and -fcxx-exceptions as usual. NOTE:: Without the -EHa or -fasync-exceptions, this patch is a NO-DIFF change. The rules for C code: For C-code, one way (MSVC approach) to achieve SEH -EHa semantic is to follow three rules: First, no exception can move in or out of _try region., i.e., no "potential faulty instruction can be moved across _try boundary. Second, the order of exceptions for instructions 'directly' under a _try must be preserved (not applied to those in callees). Finally, global states (local/global/heap variables) that can be read outside of _try region must be updated in memory (not just in register) before the subsequent exception occurs. The impact to C++ code: Although SEH is a feature for C code, -EHa does have a profound effect on C++ side. When a C++ function (in the same compilation unit with option -EHa ) is called by a SEH C function, a hardware exception occurs in C++ code can also be handled properly by an upstream SEH _try-handler or a C++ catch(...). As such, when that happens in the middle of an object's life scope, the dtor must be invoked the same way as C++ Synchronous Exception during unwinding process. Design: A natural way to achieve the rules above in LLVM today is to allow an EH edge added on memory/computation instruction (previous iload/istore idea) so that exception path is modeled in Flow graph preciously. However, tracking every single memory instruction and potential faulty instruction can create many Invokes, complicate flow graph and possibly result in negative performance impact for downstream optimization and code generation. Making all optimizations be aware of the new semantic is also substantial. This design does not intend to model exception path at instruction level. Instead, the proposed design tracks and reports EH state at BLOCK-level to reduce the complexity of flow graph and minimize the performance-impact on CPP code under -EHa option. One key element of this design is the ability to compute State number at block-level. Our algorithm is based on the following rationales: A _try scope is always a SEME (Single Entry Multiple Exits) region as jumping into a _try is not allowed. The single entry must start with a seh_try_begin() invoke with a correct State number that is the initial state of the SEME. Through control-flow, state number is propagated into all blocks. Side exits marked by seh_try_end() will unwind to parent state based on existing SEHUnwindMap[]. Note side exits can ONLY jump into parent scopes (lower state number). Thus, when a block succeeds various states from its predecessors, the lowest State triumphs others. If some exits flow to unreachable, propagation on those paths terminate, not affecting remaining blocks. For CPP code, object lifetime region is usually a SEME as SEH _try. However there is one rare exception: jumping into a lifetime that has Dtor but has no Ctor is warned, but allowed: Warning: jump bypasses variable with a non-trivial destructor In that case, the region is actually a MEME (multiple entry multiple exits). Our solution is to inject a eha_scope_begin() invoke in the side entry block to ensure a correct State. Implementation: Part-1: Clang implementation (already in): Please see commit 797ad70). Part-2 : LLVM implementation described below. For both C++ & C-code, the state of each block is computed at the same place in BE (WinEHPreparing pass) where all other EH tables/maps are calculated. In addition to _scope_begin & _scope_end, the computation of block state also rely on the existing State tracking code (UnwindMap and InvokeStateMap). For both C++ & C-code, the state of each block with potential trap instruction is marked and reported in DAG Instruction Selection pass, the same place where the state for -EHsc (synchronous exceptions) is done. If the first instruction in a reported block scope can trap, a Nop is injected before this instruction. This nop is needed to accommodate LLVM Windows EH implementation, in which the address in IPToState table is offset by +1. (note the purpose of that is to ensure the return address of a call is in the same scope as the call address. The handler for catch(...) for -EHa must handle HW exception. So it is 'adjective' flag is reset (it cannot be IsStdDotDot (0x40) that only catches C++ exceptions). Suppress push/popTerminate() scope (from noexcept/noTHrow) so that HW exceptions can be passed through. Original llvm-dev [RFC] discussions can be found in these two threads below: https://lists.llvm.org/pipermail/llvm-dev/2020-March/140541.html https://lists.llvm.org/pipermail/llvm-dev/2020-April/141338.html Differential Revision: https://reviews.llvm.org/D102817/new/
1 parent 6aebb5d commit 1a949c8

15 files changed

+1558
-4
lines changed

llvm/include/llvm/CodeGen/SelectionDAGISel.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,9 @@ class SelectionDAGISel : public MachineFunctionPass {
339339
/// instruction selected, false if no code should be emitted for it.
340340
bool PrepareEHLandingPad();
341341

342+
// Mark and Report IPToState for each Block under AsynchEH
343+
void reportIPToStateForBlocks(MachineFunction *Fn);
344+
342345
/// Perform instruction selection on all basic blocks in the function.
343346
void SelectAllBasicBlocks(const Function &Fn);
344347

llvm/include/llvm/CodeGen/WinEHFuncInfo.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ struct WinEHFuncInfo {
9292
DenseMap<const FuncletPadInst *, int> FuncletBaseStateMap;
9393
DenseMap<const InvokeInst *, int> InvokeStateMap;
9494
DenseMap<MCSymbol *, std::pair<int, MCSymbol *>> LabelToStateMap;
95+
DenseMap<const BasicBlock *, int> BlockToStateMap; // for AsynchEH
9596
SmallVector<CxxUnwindMapEntry, 4> CxxUnwindMap;
9697
SmallVector<WinEHTryBlockMapEntry, 4> TryBlockMap;
9798
SmallVector<SEHUnwindMapEntry, 4> SEHUnwindMap;
@@ -104,6 +105,8 @@ struct WinEHFuncInfo {
104105
void addIPToStateRange(const InvokeInst *II, MCSymbol *InvokeBegin,
105106
MCSymbol *InvokeEnd);
106107

108+
void addIPToStateRange(int State, MCSymbol *InvokeBegin, MCSymbol *InvokeEnd);
109+
107110
int EHRegNodeFrameIndex = std::numeric_limits<int>::max();
108111
int EHRegNodeEndOffset = std::numeric_limits<int>::max();
109112
int EHGuardFrameIndex = std::numeric_limits<int>::max();
@@ -123,6 +126,12 @@ void calculateSEHStateNumbers(const Function *ParentFn,
123126

124127
void calculateClrEHStateNumbers(const Function *Fn, WinEHFuncInfo &FuncInfo);
125128

129+
// For AsynchEH (VC++ option -EHa)
130+
void calculateCXXStateForAsynchEH(const BasicBlock *BB, int State,
131+
WinEHFuncInfo &FuncInfo);
132+
void calculateSEHStateForAsynchEH(const BasicBlock *BB, int State,
133+
WinEHFuncInfo &FuncInfo);
134+
126135
} // end namespace llvm
127136

128137
#endif // LLVM_CODEGEN_WINEHFUNCINFO_H

llvm/include/llvm/IR/BasicBlock.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,15 @@ class BasicBlock final : public Value, // Basic blocks are data objects also
205205
.getNonConst();
206206
}
207207

208+
/// Returns the first potential AsynchEH faulty instruction
209+
/// currently it checks for loads/stores (which may dereference a null
210+
/// pointer) and calls/invokes (which may propagate exceptions)
211+
const Instruction* getFirstMayFaultInst() const;
212+
Instruction* getFirstMayFaultInst() {
213+
return const_cast<Instruction*>(
214+
static_cast<const BasicBlock*>(this)->getFirstMayFaultInst());
215+
}
216+
208217
/// Return a const iterator range over the instructions in the block, skipping
209218
/// any debug instructions. Skip any pseudo operations as well if \c
210219
/// SkipPseudoOp is true.

llvm/lib/Analysis/EHPersonalities.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "llvm/IR/Constants.h"
1414
#include "llvm/IR/Function.h"
1515
#include "llvm/IR/Instructions.h"
16+
#include "llvm/IR/Module.h"
1617
#include "llvm/Support/Debug.h"
1718
#include "llvm/Support/raw_ostream.h"
1819
using namespace llvm;
@@ -79,7 +80,11 @@ bool llvm::canSimplifyInvokeNoUnwind(const Function *F) {
7980
// We can't simplify any invokes to nounwind functions if the personality
8081
// function wants to catch asynch exceptions. The nounwind attribute only
8182
// implies that the function does not throw synchronous exceptions.
82-
return !isAsynchronousEHPersonality(Personality);
83+
84+
// Cannot simplify CXX Personality under AsynchEH
85+
const llvm::Module *M = (const llvm::Module *)F->getParent();
86+
bool EHa = M->getModuleFlag("eh-asynch");
87+
return !EHa && !isAsynchronousEHPersonality(Personality);
8388
}
8489

8590
DenseMap<BasicBlock *, ColorVector> llvm::colorEHFunclets(Function &F) {

llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1584,6 +1584,7 @@ void AsmPrinter::emitFunctionBody() {
15841584
// Print out code for the function.
15851585
bool HasAnyRealCode = false;
15861586
int NumInstsInFunction = 0;
1587+
bool IsEHa = MMI->getModule()->getModuleFlag("eh-asynch");
15871588

15881589
bool CanDoExtraAnalysis = ORE->allowExtraAnalysis(DEBUG_TYPE);
15891590
for (auto &MBB : *MF) {
@@ -1622,10 +1623,25 @@ void AsmPrinter::emitFunctionBody() {
16221623
emitFrameAlloc(MI);
16231624
break;
16241625
case TargetOpcode::ANNOTATION_LABEL:
1625-
case TargetOpcode::EH_LABEL:
16261626
case TargetOpcode::GC_LABEL:
16271627
OutStreamer->emitLabel(MI.getOperand(0).getMCSymbol());
16281628
break;
1629+
case TargetOpcode::EH_LABEL:
1630+
OutStreamer->emitLabel(MI.getOperand(0).getMCSymbol());
1631+
// For AsynchEH, insert a Nop if followed by a trap inst
1632+
// Or the exception won't be caught.
1633+
// (see MCConstantExpr::create(1,..) in WinException.cpp)
1634+
// Ignore SDiv/UDiv because a DIV with Const-0 divisor
1635+
// must have being turned into an UndefValue.
1636+
// Div with variable opnds won't be the first instruction in
1637+
// an EH region as it must be led by at least a Load
1638+
{
1639+
auto MI2 = std::next(MI.getIterator());
1640+
if (IsEHa && MI2 != MBB.end() &&
1641+
(MI2->mayLoadOrStore() || MI2->mayRaiseFPException()))
1642+
emitNops(1);
1643+
}
1644+
break;
16291645
case TargetOpcode::INLINEASM:
16301646
case TargetOpcode::INLINEASM_BR:
16311647
emitInlineAsm(&MI);

llvm/lib/CodeGen/AsmPrinter/WinException.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -770,7 +770,11 @@ void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) {
770770
OS.emitInt32(0);
771771

772772
AddComment("EHFlags");
773-
OS.emitInt32(1);
773+
if (MMI->getModule()->getModuleFlag("eh-asynch")) {
774+
OS.emitInt32(0);
775+
} else {
776+
OS.emitInt32(1);
777+
}
774778

775779
// UnwindMapEntry {
776780
// int32_t ToState;

llvm/lib/CodeGen/BranchFolding.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1207,7 +1207,7 @@ bool BranchFolder::OptimizeBranches(MachineFunction &MF) {
12071207
MadeChange |= OptimizeBlock(&MBB);
12081208

12091209
// If it is dead, remove it.
1210-
if (MBB.pred_empty()) {
1210+
if (MBB.pred_empty() && !MBB.isMachineBlockAddressTaken()) {
12111211
RemoveDeadBlock(&MBB);
12121212
MadeChange = true;
12131213
++NumDeadBlocks;

llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2926,6 +2926,7 @@ void SelectionDAGBuilder::visitInvoke(const InvokeInst &I) {
29262926
// catchswitch for successors.
29272927
MachineBasicBlock *Return = FuncInfo.MBBMap[I.getSuccessor(0)];
29282928
const BasicBlock *EHPadBB = I.getSuccessor(1);
2929+
MachineBasicBlock *EHPadMBB = FuncInfo.MBBMap[EHPadBB];
29292930

29302931
// Deopt bundles are lowered in LowerCallSiteWithDeoptBundle, and we don't
29312932
// have to do anything here to lower funclet bundles.
@@ -2950,6 +2951,10 @@ void SelectionDAGBuilder::visitInvoke(const InvokeInst &I) {
29502951
case Intrinsic::seh_scope_begin:
29512952
case Intrinsic::seh_try_end:
29522953
case Intrinsic::seh_scope_end:
2954+
if (EHPadMBB)
2955+
// a block referenced by EH table
2956+
// so dtor-funclet not removed by opts
2957+
EHPadMBB->setMachineBlockAddressTaken();
29532958
break;
29542959
case Intrinsic::experimental_patchpoint_void:
29552960
case Intrinsic::experimental_patchpoint_i64:

llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
#include "llvm/CodeGen/TargetRegisterInfo.h"
6060
#include "llvm/CodeGen/TargetSubtargetInfo.h"
6161
#include "llvm/CodeGen/ValueTypes.h"
62+
#include "llvm/CodeGen/WinEHFuncInfo.h"
6263
#include "llvm/IR/BasicBlock.h"
6364
#include "llvm/IR/Constants.h"
6465
#include "llvm/IR/DataLayout.h"
@@ -1280,6 +1281,43 @@ bool SelectionDAGISel::PrepareEHLandingPad() {
12801281
return true;
12811282
}
12821283

1284+
// Mark and Report IPToState for each Block under IsEHa
1285+
void SelectionDAGISel::reportIPToStateForBlocks(MachineFunction *MF) {
1286+
MachineModuleInfo &MMI = MF->getMMI();
1287+
llvm::WinEHFuncInfo *EHInfo = MF->getWinEHFuncInfo();
1288+
if (!EHInfo)
1289+
return;
1290+
for (auto MBBI = MF->begin(), E = MF->end(); MBBI != E; ++MBBI) {
1291+
MachineBasicBlock *MBB = &*MBBI;
1292+
const BasicBlock *BB = MBB->getBasicBlock();
1293+
int State = EHInfo->BlockToStateMap[BB];
1294+
if (BB->getFirstMayFaultInst()) {
1295+
// Report IP range only for blocks with Faulty inst
1296+
auto MBBb = MBB->getFirstNonPHI();
1297+
MachineInstr *MIb = &*MBBb;
1298+
if (MIb->isTerminator())
1299+
continue;
1300+
1301+
// Insert EH Labels
1302+
MCSymbol *BeginLabel = MMI.getContext().createTempSymbol();
1303+
MCSymbol *EndLabel = MMI.getContext().createTempSymbol();
1304+
EHInfo->addIPToStateRange(State, BeginLabel, EndLabel);
1305+
BuildMI(*MBB, MBBb, SDB->getCurDebugLoc(),
1306+
TII->get(TargetOpcode::EH_LABEL))
1307+
.addSym(BeginLabel);
1308+
auto MBBe = MBB->instr_end();
1309+
MachineInstr *MIe = &*(--MBBe);
1310+
// insert before (possible multiple) terminators
1311+
while (MIe->isTerminator())
1312+
MIe = &*(--MBBe);
1313+
++MBBe;
1314+
BuildMI(*MBB, MBBe, SDB->getCurDebugLoc(),
1315+
TII->get(TargetOpcode::EH_LABEL))
1316+
.addSym(EndLabel);
1317+
}
1318+
}
1319+
}
1320+
12831321
/// isFoldedOrDeadInstruction - Return true if the specified instruction is
12841322
/// side-effect free and is either dead or folded into a generated instruction.
12851323
/// Return false if it needs to be emitted.
@@ -1612,6 +1650,10 @@ void SelectionDAGISel::SelectAllBasicBlocks(const Function &Fn) {
16121650
ElidedArgCopyInstrs.clear();
16131651
}
16141652

1653+
// AsynchEH: Report Block State under -AsynchEH
1654+
if (Fn.getParent()->getModuleFlag("eh-asynch"))
1655+
reportIPToStateForBlocks(MF);
1656+
16151657
SP.copyToMachineFrameInfo(MF->getFrameInfo());
16161658

16171659
SwiftError->propagateVRegs();

llvm/lib/CodeGen/WinEHPrepare.cpp

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,127 @@ static void calculateStateNumbersForInvokes(const Function *Fn,
216216
}
217217
}
218218

219+
// See comments below for calculateSEHStateForAsynchEH().
220+
// State - incoming State of normal paths
221+
struct WorkItem {
222+
const BasicBlock *Block;
223+
int State;
224+
WorkItem(const BasicBlock *BB, int St) {
225+
Block = BB;
226+
State = St;
227+
}
228+
};
229+
void llvm::calculateCXXStateForAsynchEH(const BasicBlock *BB, int State,
230+
WinEHFuncInfo &EHInfo) {
231+
SmallVector<struct WorkItem *, 8> WorkList;
232+
struct WorkItem *WI = new WorkItem(BB, State);
233+
WorkList.push_back(WI);
234+
235+
while (!WorkList.empty()) {
236+
WI = WorkList.pop_back_val();
237+
const BasicBlock *BB = WI->Block;
238+
int State = WI->State;
239+
delete WI;
240+
if (EHInfo.BlockToStateMap.count(BB) && EHInfo.BlockToStateMap[BB] <= State)
241+
continue; // skip blocks already visited by lower State
242+
243+
const llvm::Instruction *I = BB->getFirstNonPHI();
244+
const llvm::Instruction *TI = BB->getTerminator();
245+
if (I->isEHPad())
246+
State = EHInfo.EHPadStateMap[I];
247+
EHInfo.BlockToStateMap[BB] = State; // Record state, also flag visiting
248+
249+
if ((isa<CleanupReturnInst>(TI) || isa<CatchReturnInst>(TI)) && State > 0) {
250+
// Retrive the new State
251+
State = EHInfo.CxxUnwindMap[State].ToState; // Retrive next State
252+
} else if (isa<InvokeInst>(TI)) {
253+
auto *Call = dyn_cast<CallBase>(TI);
254+
const Function *Fn = Call->getCalledFunction();
255+
if (Fn && Fn->isIntrinsic() &&
256+
(Fn->getIntrinsicID() == Intrinsic::seh_scope_begin ||
257+
Fn->getIntrinsicID() == Intrinsic::seh_try_begin))
258+
// Retrive the new State from seh_scope_begin
259+
State = EHInfo.InvokeStateMap[cast<InvokeInst>(TI)];
260+
else if (Fn && Fn->isIntrinsic() &&
261+
(Fn->getIntrinsicID() == Intrinsic::seh_scope_end ||
262+
Fn->getIntrinsicID() == Intrinsic::seh_try_end)) {
263+
// In case of conditional ctor, let's retrieve State from Invoke
264+
State = EHInfo.InvokeStateMap[cast<InvokeInst>(TI)];
265+
// end of current state, retrive new state from UnwindMap
266+
State = EHInfo.CxxUnwindMap[State].ToState;
267+
}
268+
}
269+
// Continue push successors into worklist
270+
for (auto *SuccBB : successors(BB)) {
271+
WI = new WorkItem(SuccBB, State);
272+
WorkList.push_back(WI);
273+
}
274+
}
275+
}
276+
277+
// The central theory of this routine is based on the following:
278+
// A _try scope is always a SEME (Single Entry Multiple Exits) region
279+
// as jumping into a _try is not allowed
280+
// The single entry must start with a seh_try_begin() invoke with a
281+
// correct State number that is the initial state of the SEME.
282+
// Through control-flow, state number is propagated into all blocks.
283+
// Side exits marked by seh_try_end() will unwind to parent state via
284+
// existing SEHUnwindMap[].
285+
// Side exits can ONLY jump into parent scopes (lower state number).
286+
// Thus, when a block succeeds various states from its predecessors,
287+
// the lowest State trumphs others.
288+
// If some exits flow to unreachable, propagation on those paths terminate,
289+
// not affecting remaining blocks.
290+
void llvm::calculateSEHStateForAsynchEH(const BasicBlock *BB, int State,
291+
WinEHFuncInfo &EHInfo) {
292+
SmallVector<struct WorkItem *, 8> WorkList;
293+
struct WorkItem *WI = new WorkItem(BB, State);
294+
WorkList.push_back(WI);
295+
296+
while (!WorkList.empty()) {
297+
WI = WorkList.pop_back_val();
298+
const BasicBlock *BB = WI->Block;
299+
int State = WI->State;
300+
delete WI;
301+
if (EHInfo.BlockToStateMap.count(BB) && EHInfo.BlockToStateMap[BB] <= State)
302+
continue; // skip blocks already visited by lower State
303+
304+
const llvm::Instruction *I = BB->getFirstNonPHI();
305+
const llvm::Instruction *TI = BB->getTerminator();
306+
if (I->isEHPad())
307+
State = EHInfo.EHPadStateMap[I];
308+
EHInfo.BlockToStateMap[BB] = State; // Record state
309+
310+
if (isa<CatchPadInst>(I) && isa<CatchReturnInst>(TI)) {
311+
const Constant *FilterOrNull = cast<Constant>(
312+
cast<CatchPadInst>(I)->getArgOperand(0)->stripPointerCasts());
313+
const Function *Filter = dyn_cast<Function>(FilterOrNull);
314+
if (!Filter || !Filter->getName().startswith("__IsLocalUnwind"))
315+
State = EHInfo.SEHUnwindMap[State].ToState; // Retrive next State
316+
} else if ((isa<CleanupReturnInst>(TI) || isa<CatchReturnInst>(TI)) &&
317+
State > 0) {
318+
// Retrive the new State.
319+
State = EHInfo.SEHUnwindMap[State].ToState; // Retrive next State
320+
} else if (isa<InvokeInst>(TI)) {
321+
auto *Call = dyn_cast<CallBase>(TI);
322+
const Function *Fn = Call->getCalledFunction();
323+
if (Fn && Fn->isIntrinsic() &&
324+
Fn->getIntrinsicID() == Intrinsic::seh_try_begin)
325+
// Retrive the new State from seh_try_begin
326+
State = EHInfo.InvokeStateMap[cast<InvokeInst>(TI)];
327+
else if (Fn && Fn->isIntrinsic() &&
328+
Fn->getIntrinsicID() == Intrinsic::seh_try_end)
329+
// end of current state, retrive new state from UnwindMap
330+
State = EHInfo.SEHUnwindMap[State].ToState;
331+
}
332+
// Continue push successors into worklist
333+
for (auto *SuccBB : successors(BB)) {
334+
WI = new WorkItem(SuccBB, State);
335+
WorkList.push_back(WI);
336+
}
337+
}
338+
}
339+
219340
// Given BB which ends in an unwind edge, return the EHPad that this BB belongs
220341
// to. If the unwind edge came from an invoke, return null.
221342
static const BasicBlock *getEHPadFromPredecessor(const BasicBlock *BB,
@@ -276,6 +397,7 @@ static void calculateCXXStateNumbers(WinEHFuncInfo &FuncInfo,
276397

277398
for (const auto *CatchPad : Handlers) {
278399
FuncInfo.FuncletBaseStateMap[CatchPad] = CatchLow;
400+
FuncInfo.EHPadStateMap[CatchPad] = CatchLow;
279401
for (const User *U : CatchPad->users()) {
280402
const auto *UserI = cast<Instruction>(U);
281403
if (auto *InnerCatchSwitch = dyn_cast<CatchSwitchInst>(UserI)) {
@@ -384,6 +506,7 @@ static void calculateSEHStateNumbers(WinEHFuncInfo &FuncInfo,
384506

385507
// Everything in the __try block uses TryState as its parent state.
386508
FuncInfo.EHPadStateMap[CatchSwitch] = TryState;
509+
FuncInfo.EHPadStateMap[CatchPad] = TryState;
387510
LLVM_DEBUG(dbgs() << "Assigning state #" << TryState << " to BB "
388511
<< CatchPadBB->getName() << '\n');
389512
for (const BasicBlock *PredBlock : predecessors(BB))
@@ -464,6 +587,12 @@ void llvm::calculateSEHStateNumbers(const Function *Fn,
464587
}
465588

466589
calculateStateNumbersForInvokes(Fn, FuncInfo);
590+
591+
bool IsEHa = Fn->getParent()->getModuleFlag("eh-asynch");
592+
if (IsEHa) {
593+
const BasicBlock *EntryBB = &(Fn->getEntryBlock());
594+
calculateSEHStateForAsynchEH(EntryBB, -1, FuncInfo);
595+
}
467596
}
468597

469598
void llvm::calculateWinCXXEHStateNumbers(const Function *Fn,
@@ -482,6 +611,12 @@ void llvm::calculateWinCXXEHStateNumbers(const Function *Fn,
482611
}
483612

484613
calculateStateNumbersForInvokes(Fn, FuncInfo);
614+
615+
bool IsEHa = Fn->getParent()->getModuleFlag("eh-asynch");
616+
if (IsEHa) {
617+
const BasicBlock *EntryBB = &(Fn->getEntryBlock());
618+
calculateCXXStateForAsynchEH(EntryBB, -1, FuncInfo);
619+
}
485620
}
486621

487622
static int addClrEHHandler(WinEHFuncInfo &FuncInfo, int HandlerParentState,
@@ -1253,4 +1388,9 @@ void WinEHFuncInfo::addIPToStateRange(const InvokeInst *II,
12531388
LabelToStateMap[InvokeBegin] = std::make_pair(InvokeStateMap[II], InvokeEnd);
12541389
}
12551390

1391+
void WinEHFuncInfo::addIPToStateRange(int State, MCSymbol* InvokeBegin,
1392+
MCSymbol* InvokeEnd) {
1393+
LabelToStateMap[InvokeBegin] = std::make_pair(State, InvokeEnd);
1394+
}
1395+
12561396
WinEHFuncInfo::WinEHFuncInfo() = default;

0 commit comments

Comments
 (0)