Skip to content

Commit 0efe111

Browse files
committed
Reland "[Windows SEH]: HARDWARE EXCEPTION HANDLING (MSVC -EHa) - Part 2"
This reverts commit db6a979. Reland D102817 without any change. The previous revert was a mistake. Differential Revision: https://reviews.llvm.org/D102817
1 parent 4c55fd9 commit 0efe111

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
@@ -337,6 +337,9 @@ class SelectionDAGISel : public MachineFunctionPass {
337337
/// instruction selected, false if no code should be emitted for it.
338338
bool PrepareEHLandingPad();
339339

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

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
@@ -213,6 +213,15 @@ class BasicBlock final : public Value, // Basic blocks are data objects also
213213
.getNonConst();
214214
}
215215

216+
/// Returns the first potential AsynchEH faulty instruction
217+
/// currently it checks for loads/stores (which may dereference a null
218+
/// pointer) and calls/invokes (which may propagate exceptions)
219+
const Instruction* getFirstMayFaultInst() const;
220+
Instruction* getFirstMayFaultInst() {
221+
return const_cast<Instruction*>(
222+
static_cast<const BasicBlock*>(this)->getFirstMayFaultInst());
223+
}
224+
216225
/// Return a const iterator range over the instructions in the block, skipping
217226
/// any debug instructions. Skip any pseudo operations as well if \c
218227
/// SkipPseudoOp is true.

llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp

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

16311632
bool CanDoExtraAnalysis = ORE->allowExtraAnalysis(DEBUG_TYPE);
16321633
for (auto &MBB : *MF) {
@@ -1665,10 +1666,25 @@ void AsmPrinter::emitFunctionBody() {
16651666
emitFrameAlloc(MI);
16661667
break;
16671668
case TargetOpcode::ANNOTATION_LABEL:
1668-
case TargetOpcode::EH_LABEL:
16691669
case TargetOpcode::GC_LABEL:
16701670
OutStreamer->emitLabel(MI.getOperand(0).getMCSymbol());
16711671
break;
1672+
case TargetOpcode::EH_LABEL:
1673+
OutStreamer->emitLabel(MI.getOperand(0).getMCSymbol());
1674+
// For AsynchEH, insert a Nop if followed by a trap inst
1675+
// Or the exception won't be caught.
1676+
// (see MCConstantExpr::create(1,..) in WinException.cpp)
1677+
// Ignore SDiv/UDiv because a DIV with Const-0 divisor
1678+
// must have being turned into an UndefValue.
1679+
// Div with variable opnds won't be the first instruction in
1680+
// an EH region as it must be led by at least a Load
1681+
{
1682+
auto MI2 = std::next(MI.getIterator());
1683+
if (IsEHa && MI2 != MBB.end() &&
1684+
(MI2->mayLoadOrStore() || MI2->mayRaiseFPException()))
1685+
emitNops(1);
1686+
}
1687+
break;
16721688
case TargetOpcode::INLINEASM:
16731689
case TargetOpcode::INLINEASM_BR:
16741690
emitInlineAsm(&MI);

llvm/lib/CodeGen/AsmPrinter/WinException.cpp

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

764764
AddComment("EHFlags");
765-
OS.emitInt32(1);
765+
if (MMI->getModule()->getModuleFlag("eh-asynch")) {
766+
OS.emitInt32(0);
767+
} else {
768+
OS.emitInt32(1);
769+
}
766770

767771
// UnwindMapEntry {
768772
// 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
@@ -2971,6 +2971,7 @@ void SelectionDAGBuilder::visitInvoke(const InvokeInst &I) {
29712971
// catchswitch for successors.
29722972
MachineBasicBlock *Return = FuncInfo.MBBMap[I.getSuccessor(0)];
29732973
const BasicBlock *EHPadBB = I.getSuccessor(1);
2974+
MachineBasicBlock *EHPadMBB = FuncInfo.MBBMap[EHPadBB];
29742975

29752976
// Deopt bundles are lowered in LowerCallSiteWithDeoptBundle, and we don't
29762977
// have to do anything here to lower funclet bundles.
@@ -2995,6 +2996,10 @@ void SelectionDAGBuilder::visitInvoke(const InvokeInst &I) {
29952996
case Intrinsic::seh_scope_begin:
29962997
case Intrinsic::seh_try_end:
29972998
case Intrinsic::seh_scope_end:
2999+
if (EHPadMBB)
3000+
// a block referenced by EH table
3001+
// so dtor-funclet not removed by opts
3002+
EHPadMBB->setMachineBlockAddressTaken();
29983003
break;
29993004
case Intrinsic::experimental_patchpoint_void:
30003005
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"
@@ -1292,6 +1293,43 @@ bool SelectionDAGISel::PrepareEHLandingPad() {
12921293
return true;
12931294
}
12941295

1296+
// Mark and Report IPToState for each Block under IsEHa
1297+
void SelectionDAGISel::reportIPToStateForBlocks(MachineFunction *MF) {
1298+
MachineModuleInfo &MMI = MF->getMMI();
1299+
llvm::WinEHFuncInfo *EHInfo = MF->getWinEHFuncInfo();
1300+
if (!EHInfo)
1301+
return;
1302+
for (auto MBBI = MF->begin(), E = MF->end(); MBBI != E; ++MBBI) {
1303+
MachineBasicBlock *MBB = &*MBBI;
1304+
const BasicBlock *BB = MBB->getBasicBlock();
1305+
int State = EHInfo->BlockToStateMap[BB];
1306+
if (BB->getFirstMayFaultInst()) {
1307+
// Report IP range only for blocks with Faulty inst
1308+
auto MBBb = MBB->getFirstNonPHI();
1309+
MachineInstr *MIb = &*MBBb;
1310+
if (MIb->isTerminator())
1311+
continue;
1312+
1313+
// Insert EH Labels
1314+
MCSymbol *BeginLabel = MMI.getContext().createTempSymbol();
1315+
MCSymbol *EndLabel = MMI.getContext().createTempSymbol();
1316+
EHInfo->addIPToStateRange(State, BeginLabel, EndLabel);
1317+
BuildMI(*MBB, MBBb, SDB->getCurDebugLoc(),
1318+
TII->get(TargetOpcode::EH_LABEL))
1319+
.addSym(BeginLabel);
1320+
auto MBBe = MBB->instr_end();
1321+
MachineInstr *MIe = &*(--MBBe);
1322+
// insert before (possible multiple) terminators
1323+
while (MIe->isTerminator())
1324+
MIe = &*(--MBBe);
1325+
++MBBe;
1326+
BuildMI(*MBB, MBBe, SDB->getCurDebugLoc(),
1327+
TII->get(TargetOpcode::EH_LABEL))
1328+
.addSym(EndLabel);
1329+
}
1330+
}
1331+
}
1332+
12951333
/// isFoldedOrDeadInstruction - Return true if the specified instruction is
12961334
/// side-effect free and is either dead or folded into a generated instruction.
12971335
/// Return false if it needs to be emitted.
@@ -1649,6 +1687,10 @@ void SelectionDAGISel::SelectAllBasicBlocks(const Function &Fn) {
16491687
ElidedArgCopyInstrs.clear();
16501688
}
16511689

1690+
// AsynchEH: Report Block State under -AsynchEH
1691+
if (Fn.getParent()->getModuleFlag("eh-asynch"))
1692+
reportIPToStateForBlocks(MF);
1693+
16521694
SP.copyToMachineFrameInfo(MF->getFrameInfo());
16531695

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

llvm/lib/IR/BasicBlock.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,15 @@ const CallInst *BasicBlock::getPostdominatingDeoptimizeCall() const {
205205
return BB->getTerminatingDeoptimizeCall();
206206
}
207207

208+
const Instruction *BasicBlock::getFirstMayFaultInst() const {
209+
if (InstList.empty())
210+
return nullptr;
211+
for (const Instruction &I : *this)
212+
if (isa<LoadInst>(I) || isa<StoreInst>(I) || isa<CallBase>(I))
213+
return &I;
214+
return nullptr;
215+
}
216+
208217
const Instruction* BasicBlock::getFirstNonPHI() const {
209218
for (const Instruction &I : *this)
210219
if (!isa<PHINode>(I))

0 commit comments

Comments
 (0)