int getArgumentFrameIndex(const Argument *A);
private:
- void addSEHHandlersForLPads();
+ void addSEHHandlersForLPads(ArrayRef<const LandingPadInst *> LPads);
/// LiveOutRegInfo - Information about live out vregs.
IndexedMap<LiveOutInfo, VirtReg2IndexFunctor> LiveOutRegInfo;
// Represents the list of actions to take when an exception is thrown.
def int_eh_actions : Intrinsic<[llvm_ptr_ty], [llvm_vararg_ty], []>;
+def int_eh_exceptioncode : Intrinsic<[llvm_i32_ty], []>;
+
// __builtin_unwind_init is an undocumented GCC intrinsic that causes all
// callee-saved registers to be saved and restored (regardless of whether they
// are used) in the calling function. It is used by libgcc_eh.
}
// Mark landing pad blocks.
- const LandingPadInst *LP = nullptr;
+ SmallVector<const LandingPadInst *, 4> LPads;
for (BB = Fn->begin(); BB != EB; ++BB) {
if (const auto *Invoke = dyn_cast<InvokeInst>(BB->getTerminator()))
MBBMap[Invoke->getSuccessor(1)]->setIsLandingPad();
if (BB->isLandingPad())
- LP = BB->getLandingPadInst();
+ LPads.push_back(BB->getLandingPadInst());
}
- // Calculate EH numbers for MSVC C++ EH and save SEH handlers if necessary.
+ // If this is an MSVC EH personality, we need to do a bit more work.
EHPersonality Personality = EHPersonality::Unknown;
- if (LP)
- Personality = classifyEHPersonality(LP->getPersonalityFn());
+ if (!LPads.empty())
+ Personality = classifyEHPersonality(LPads.back()->getPersonalityFn());
+ if (!isMSVCEHPersonality(Personality))
+ return;
+
+ WinEHFuncInfo *EHInfo = nullptr;
if (Personality == EHPersonality::MSVC_Win64SEH) {
- addSEHHandlersForLPads();
+ addSEHHandlersForLPads(LPads);
} else if (Personality == EHPersonality::MSVC_CXX) {
const Function *WinEHParentFn = MMI.getWinEHParent(&fn);
- WinEHFuncInfo &FI = MMI.getWinEHFuncInfo(WinEHParentFn);
- if (FI.LandingPadStateMap.empty()) {
- WinEHNumbering Num(FI);
+ EHInfo = &MMI.getWinEHFuncInfo(WinEHParentFn);
+ if (EHInfo->LandingPadStateMap.empty()) {
+ WinEHNumbering Num(*EHInfo);
Num.calculateStateNumbers(*WinEHParentFn);
// Pop everything on the handler stack.
Num.processCallSite(None, ImmutableCallSite());
}
+
+ // Copy the state numbers to LandingPadInfo for the current function, which
+ // could be a handler or the parent.
+ for (const LandingPadInst *LP : LPads) {
+ MachineBasicBlock *LPadMBB = MBBMap[LP->getParent()];
+ MMI.addWinEHState(LPadMBB, EHInfo->LandingPadStateMap[LP]);
+ }
}
}
-void FunctionLoweringInfo::addSEHHandlersForLPads() {
+void FunctionLoweringInfo::addSEHHandlersForLPads(
+ ArrayRef<const LandingPadInst *> LPads) {
MachineModuleInfo &MMI = MF->getMMI();
// Iterate over all landing pads with llvm.eh.actions calls.
- for (const BasicBlock &BB : *Fn) {
- const LandingPadInst *LP = BB.getLandingPadInst();
- if (!LP)
- continue;
+ for (const LandingPadInst *LP : LPads) {
const IntrinsicInst *ActionsCall =
dyn_cast<IntrinsicInst>(LP->getNextNode());
if (!ActionsCall ||
case Intrinsic::eh_begincatch:
case Intrinsic::eh_endcatch:
llvm_unreachable("begin/end catch intrinsics not lowered in codegen");
+ case Intrinsic::eh_exceptioncode: {
+ unsigned Reg = TLI.getExceptionPointerRegister();
+ assert(Reg && "cannot get exception code on this platform");
+ MVT PtrVT = TLI.getPointerTy();
+ const TargetRegisterClass *PtrRC = TLI.getRegClassFor(PtrVT);
+ unsigned VReg = FuncInfo.MBB->addLiveIn(Reg, PtrRC);
+ SDValue N =
+ DAG.getCopyFromReg(DAG.getEntryNode(), getCurSDLoc(), VReg, PtrVT);
+ N = DAG.getZExtOrTrunc(N, getCurSDLoc(), MVT::i32);
+ setValue(&I, N);
+ return nullptr;
+ }
}
}
for (MachineBasicBlock *InvokeBB : InvokeBBs)
InvokeBB->removeSuccessor(MBB);
- // Transfer EH state number assigned to the IR block to the MBB.
- if (Personality == EHPersonality::MSVC_CXX) {
- WinEHFuncInfo &FI = MF->getMMI().getWinEHFuncInfo(MF->getFunction());
- MF->getMMI().addWinEHState(MBB, FI.LandingPadStateMap[LPadInst]);
- }
-
// Don't select instructions for the landingpad.
return false;
}
public:
static char ID; // Pass identification, replacement for typeid.
WinEHPrepare(const TargetMachine *TM = nullptr)
- : FunctionPass(ID), DT(nullptr) {}
+ : FunctionPass(ID), DT(nullptr), SEHExceptionCodeSlot(nullptr) {}
bool runOnFunction(Function &Fn) override;
// outlined into a handler. This is done after all handlers have been
// outlined but before the outlined code is pruned from the parent function.
DenseMap<const BasicBlock *, BasicBlock *> LPadTargetBlocks;
+
+ AllocaInst *SEHExceptionCodeSlot;
};
class WinEHFrameVariableMaterializer : public ValueMaterializer {
Type *Int32Type = Type::getInt32Ty(Context);
Function *ActionIntrin = Intrinsic::getDeclaration(M, Intrinsic::eh_actions);
+ if (isAsynchronousEHPersonality(Personality)) {
+ // FIXME: Switch the ehptr type to i32 and then switch this.
+ SEHExceptionCodeSlot =
+ new AllocaInst(Int8PtrType, nullptr, "seh_exception_code",
+ F.getEntryBlock().getFirstInsertionPt());
+ }
+
for (LandingPadInst *LPad : LPads) {
// Look for evidence that this landingpad has already been processed.
bool LPadHasActionList = false;
// Replace all extracted values with undef and ultimately replace the
// landingpad with undef.
- // FIXME: This doesn't handle SEH GetExceptionCode(). For now, we just give
- // out undef until we figure out the codegen support.
- SmallVector<Instruction *, 4> Extracts;
+ SmallVector<Instruction *, 4> SEHCodeUses;
+ SmallVector<Instruction *, 4> EHUndefs;
for (User *U : LPad->users()) {
auto *E = dyn_cast<ExtractValueInst>(U);
if (!E)
continue;
assert(E->getNumIndices() == 1 &&
"Unexpected operation: extracting both landing pad values");
- Extracts.push_back(E);
+ unsigned Idx = *E->idx_begin();
+ assert((Idx == 0 || Idx == 1) && "unexpected index");
+ if (Idx == 0 && isAsynchronousEHPersonality(Personality))
+ SEHCodeUses.push_back(E);
+ else
+ EHUndefs.push_back(E);
}
- for (Instruction *E : Extracts) {
+ for (Instruction *E : EHUndefs) {
E->replaceAllUsesWith(UndefValue::get(E->getType()));
E->eraseFromParent();
}
LPad->replaceAllUsesWith(UndefValue::get(LPad->getType()));
+ // Rewrite uses of the exception pointer to loads of an alloca.
+ for (Instruction *E : SEHCodeUses) {
+ SmallVector<Use *, 4> Uses;
+ for (Use &U : E->uses())
+ Uses.push_back(&U);
+ for (Use *U : Uses) {
+ auto *I = cast<Instruction>(U->getUser());
+ if (isa<ResumeInst>(I))
+ continue;
+ LoadInst *LI;
+ if (auto *Phi = dyn_cast<PHINode>(I))
+ LI = new LoadInst(SEHExceptionCodeSlot, "sehcode", false,
+ Phi->getIncomingBlock(*U));
+ else
+ LI = new LoadInst(SEHExceptionCodeSlot, "sehcode", false, I);
+ U->set(LI);
+ }
+ E->replaceAllUsesWith(UndefValue::get(E->getType()));
+ E->eraseFromParent();
+ }
+
// Add a call to describe the actions for this landing pad.
std::vector<Value *> ActionArgs;
for (ActionHandler *Action : Actions) {
Builder.SetInsertPoint(&F.getEntryBlock().back());
Builder.CreateCall(FrameEscapeFn, AllocasToEscape);
+ if (SEHExceptionCodeSlot) {
+ if (SEHExceptionCodeSlot->hasNUses(0))
+ SEHExceptionCodeSlot->eraseFromParent();
+ else
+ PromoteMemToReg(SEHExceptionCodeSlot, *DT);
+ }
+
// Clean up the handler action maps we created for this function
DeleteContainerSeconds(CatchHandlerMap);
CatchHandlerMap.clear();
/// target.
void WinEHPrepare::processSEHCatchHandler(CatchHandler *CatchAction,
BasicBlock *StartBB) {
+ LLVMContext &Context = StartBB->getContext();
BasicBlock *HandlerBB;
BasicBlock *NextBB;
Constant *Selector;
HandlerBB =
StartBB->splitBasicBlock(StartBB->getFirstInsertionPt(), "catch.all");
}
+ IRBuilder<> Builder(HandlerBB->getFirstInsertionPt());
+ Function *EHCodeFn = Intrinsic::getDeclaration(
+ StartBB->getParent()->getParent(), Intrinsic::eh_exceptioncode);
+ Value *Code = Builder.CreateCall(EHCodeFn, "sehcode");
+ Code = Builder.CreateIntToPtr(Code, SEHExceptionCodeSlot->getAllocatedType());
+ Builder.CreateStore(Code, SEHExceptionCodeSlot);
CatchAction->setHandlerBlockOrFunc(BlockAddress::get(HandlerBB));
TinyPtrVector<BasicBlock *> Targets(HandlerBB);
CatchAction->setReturnTargets(Targets);
; CHECK-NEXT: indirectbr {{.*}} [label %__except]
;
; CHECK: __except:
-; FIXME: This should not be undef, it should be the new landingpad value, which
-; should ultimately lower down to eax.
-; CHECK: invoke void @might_crash(i8* undef)
+; CHECK: call i32 @llvm.eh.exceptioncode()
+; CHECK: invoke void @might_crash(i8* %{{.*}})
; CHECK: landingpad { i8*, i32 }
; CHECK-NEXT: cleanup
; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 0, void (i8*, i8*)* @resume_phi.cleanup)
; RUN: llc -mtriple=x86_64-windows-msvc < %s | FileCheck %s
-@str = internal unnamed_addr constant [10 x i8] c"recovered\00", align 1
+@str = linkonce_odr unnamed_addr constant [27 x i8] c"GetExceptionCode(): 0x%lx\0A\00", align 1
declare i32 @__C_specific_handler(...)
declare void @crash()
-declare i32 @puts(i8*)
+declare i32 @printf(i8* nocapture readonly, ...) nounwind
define i32 @main() {
entry:
lpad:
%0 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
catch i8* null
- call i32 @puts(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @str, i64 0, i64 0))
+ %1 = extractvalue { i8*, i32 } %0, 0
+ %2 = ptrtoint i8* %1 to i64
+ %3 = trunc i64 %2 to i32
+ call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([27 x i8], [27 x i8]* @str, i64 0, i64 0), i32 %3)
br label %__try.cont
__try.cont:
resume { i8*, i32 } %0
}
+; Check that we can get the exception code from eax to the printf.
+
; CHECK-LABEL: main:
+; CHECK: retq
+; CHECK: # Block address taken
+; CHECK: leaq str(%rip), %rcx
+; CHECK: movl %eax, %edx
+; CHECK: callq printf
+
; CHECK: .seh_handlerdata
; CHECK-NEXT: .long 1
; CHECK-NEXT: .Ltmp{{[0-9]+}}@IMGREL