mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-24 03:33:20 +01:00
[WinEH] Add an EH registration and state insertion pass for 32-bit x86
This pass is responsible for constructing the EH registration object that gets linked into fs:00, which is all it does in this change. In the future, it will also insert stores to update the EH state number. I considered keeping this functionality in WinEHPrepare, but it's pretty separable and X86 specific. It has conceptually very little to do with the task of WinEHPrepare, which is currently outlining. WinEHPrepare is also in theory useful on ARM, but this logic is pretty x86 specific. Reviewers: andrew.w.kaylor, majnemer Differential Revision: http://reviews.llvm.org/D9422 llvm-svn: 236339
This commit is contained in:
parent
2c1b4fde0b
commit
ec21431851
@ -37,6 +37,7 @@ enum class EncodingType {
|
||||
ARM, /// Windows NT (Windows on ARM)
|
||||
CE, /// Windows CE ARM, PowerPC, SH3, SH4
|
||||
Itanium, /// Windows x64, Windows Itanium (IA-64)
|
||||
X86, /// Windows x86, uses no CFI, just EH tables
|
||||
MIPS = Alpha,
|
||||
};
|
||||
}
|
||||
@ -506,12 +507,13 @@ public:
|
||||
/// frame information to unwind.
|
||||
bool usesCFIForEH() const {
|
||||
return (ExceptionsType == ExceptionHandling::DwarfCFI ||
|
||||
ExceptionsType == ExceptionHandling::ARM ||
|
||||
ExceptionsType == ExceptionHandling::WinEH);
|
||||
ExceptionsType == ExceptionHandling::ARM || usesWindowsCFI());
|
||||
}
|
||||
|
||||
bool usesWindowsCFI() const {
|
||||
return ExceptionsType == ExceptionHandling::WinEH;
|
||||
return ExceptionsType == ExceptionHandling::WinEH &&
|
||||
(WinEHEncodingType != WinEH::EncodingType::Invalid &&
|
||||
WinEHEncodingType != WinEH::EncodingType::X86);
|
||||
}
|
||||
|
||||
bool doesDwarfUseRelocationsAcrossSections() const {
|
||||
|
@ -266,6 +266,8 @@ bool AsmPrinter::doInitialization(Module &M) {
|
||||
case ExceptionHandling::WinEH:
|
||||
switch (MAI->getWinEHEncodingType()) {
|
||||
default: llvm_unreachable("unsupported unwinding information encoding");
|
||||
case WinEH::EncodingType::Invalid:
|
||||
break;
|
||||
case WinEH::EncodingType::Itanium:
|
||||
ES = new Win64Exception(this);
|
||||
break;
|
||||
|
@ -8,9 +8,11 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This pass lowers LLVM IR exception handling into something closer to what the
|
||||
// backend wants. It snifs the personality function to see which kind of
|
||||
// preparation is necessary. If the personality function uses the Itanium LSDA,
|
||||
// this pass delegates to the DWARF EH preparation pass.
|
||||
// backend wants for functions using a personality function from a runtime
|
||||
// provided by MSVC. Functions with other personality functions are left alone
|
||||
// and may be prepared by other passes. In particular, all supported MSVC
|
||||
// personality functions require cleanup code to be outlined, and the C++
|
||||
// personality requires catch handler code to be outlined.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@ -31,7 +33,6 @@
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/PatternMatch.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||
@ -922,7 +923,7 @@ bool WinEHPrepare::prepareExceptionHandlers(
|
||||
if (SEHExceptionCodeSlot) {
|
||||
if (SEHExceptionCodeSlot->hasNUses(0))
|
||||
SEHExceptionCodeSlot->eraseFromParent();
|
||||
else
|
||||
else if (isAllocaPromotable(SEHExceptionCodeSlot))
|
||||
PromoteMemToReg(SEHExceptionCodeSlot, *DT);
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,7 @@ set(sources
|
||||
X86TargetTransformInfo.cpp
|
||||
X86VZeroUpper.cpp
|
||||
X86FixupLEAs.cpp
|
||||
X86WinEHState.cpp
|
||||
)
|
||||
|
||||
if( CMAKE_CL_64 )
|
||||
|
@ -132,9 +132,10 @@ X86MCAsmInfoMicrosoft::X86MCAsmInfoMicrosoft(const Triple &Triple) {
|
||||
PrivateLabelPrefix = ".L";
|
||||
PointerSize = 8;
|
||||
WinEHEncodingType = WinEH::EncodingType::Itanium;
|
||||
ExceptionsType = ExceptionHandling::WinEH;
|
||||
}
|
||||
|
||||
ExceptionsType = ExceptionHandling::WinEH;
|
||||
|
||||
AssemblerDialect = AsmWriterFlavor;
|
||||
|
||||
TextAlignFillValue = 0x90;
|
||||
|
@ -69,6 +69,12 @@ FunctionPass *createX86FixupLEAs();
|
||||
/// esp-relative movs with pushes.
|
||||
FunctionPass *createX86CallFrameOptimization();
|
||||
|
||||
/// createX86WinEHStatePass - Return an IR pass that inserts EH registration
|
||||
/// stack objects and explicit EH state updates. This pass must run after EH
|
||||
/// preparation, which does Windows-specific but architecture-neutral
|
||||
/// preparation.
|
||||
FunctionPass *createX86WinEHStatePass();
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
||||
|
@ -185,6 +185,7 @@ public:
|
||||
void addIRPasses() override;
|
||||
bool addInstSelector() override;
|
||||
bool addILPOpts() override;
|
||||
bool addPreISel() override;
|
||||
void addPreRegAlloc() override;
|
||||
void addPostRegAlloc() override;
|
||||
void addPreEmitPass() override;
|
||||
@ -220,6 +221,14 @@ bool X86PassConfig::addILPOpts() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool X86PassConfig::addPreISel() {
|
||||
// Only add this pass for 32-bit x86.
|
||||
Triple TT(TM->getTargetTriple());
|
||||
if (TT.getArch() == Triple::x86)
|
||||
addPass(createX86WinEHStatePass());
|
||||
return true;
|
||||
}
|
||||
|
||||
void X86PassConfig::addPreRegAlloc() {
|
||||
addPass(createX86CallFrameOptimization());
|
||||
}
|
||||
|
317
lib/Target/X86/X86WinEHState.cpp
Normal file
317
lib/Target/X86/X86WinEHState.cpp
Normal file
@ -0,0 +1,317 @@
|
||||
//===-- X86WinEHState - Insert EH state updates for win32 exceptions ------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// All functions using an MSVC EH personality use an explicitly updated state
|
||||
// number stored in an exception registration stack object. The registration
|
||||
// object is linked into a thread-local chain of registrations stored at fs:00.
|
||||
// This pass adds the registration object and EH state updates.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "X86.h"
|
||||
#include "llvm/Analysis/LibCallSemantics.h"
|
||||
#include "llvm/CodeGen/Passes.h"
|
||||
#include "llvm/CodeGen/WinEHFuncInfo.h"
|
||||
#include "llvm/IR/Dominators.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/IntrinsicInst.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/PatternMatch.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||
#include "llvm/Transforms/Utils/Cloning.h"
|
||||
#include "llvm/Transforms/Utils/Local.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::PatternMatch;
|
||||
|
||||
#define DEBUG_TYPE "winehstate"
|
||||
|
||||
namespace {
|
||||
class WinEHStatePass : public FunctionPass {
|
||||
public:
|
||||
static char ID; // Pass identification, replacement for typeid.
|
||||
|
||||
WinEHStatePass() : FunctionPass(ID) {}
|
||||
|
||||
bool runOnFunction(Function &Fn) override;
|
||||
|
||||
bool doInitialization(Module &M) override;
|
||||
|
||||
bool doFinalization(Module &M) override;
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
const char *getPassName() const override {
|
||||
return "Windows 32-bit x86 EH state insertion";
|
||||
}
|
||||
|
||||
private:
|
||||
void emitExceptionRegistrationRecord(Function *F);
|
||||
|
||||
void linkExceptionRegistration(IRBuilder<> &Builder, Value *RegNode,
|
||||
Value *Handler);
|
||||
void unlinkExceptionRegistration(IRBuilder<> &Builder, Value *RegNode);
|
||||
|
||||
// Module-level type getters.
|
||||
Type *getEHRegistrationType();
|
||||
Type *getSEH3RegistrationType();
|
||||
Type *getSEH4RegistrationType();
|
||||
Type *getCXXEH3RegistrationType();
|
||||
|
||||
// Per-module data.
|
||||
Module *TheModule = nullptr;
|
||||
StructType *EHRegistrationTy = nullptr;
|
||||
StructType *CXXEH3RegistrationTy = nullptr;
|
||||
StructType *SEH3RegistrationTy = nullptr;
|
||||
StructType *SEH4RegistrationTy = nullptr;
|
||||
|
||||
// Per-function state
|
||||
EHPersonality Personality = EHPersonality::Unknown;
|
||||
Function *PersonalityFn = nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
FunctionPass *llvm::createX86WinEHStatePass() { return new WinEHStatePass(); }
|
||||
|
||||
char WinEHStatePass::ID = 0;
|
||||
|
||||
bool WinEHStatePass::doInitialization(Module &M) {
|
||||
TheModule = &M;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WinEHStatePass::doFinalization(Module &M) {
|
||||
assert(TheModule == &M);
|
||||
TheModule = nullptr;
|
||||
EHRegistrationTy = nullptr;
|
||||
CXXEH3RegistrationTy = nullptr;
|
||||
SEH3RegistrationTy = nullptr;
|
||||
SEH4RegistrationTy = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
void WinEHStatePass::getAnalysisUsage(AnalysisUsage &AU) const {
|
||||
// This pass should only insert a stack allocation, memory accesses, and
|
||||
// framerecovers.
|
||||
AU.setPreservesCFG();
|
||||
}
|
||||
|
||||
bool WinEHStatePass::runOnFunction(Function &F) {
|
||||
// Check the personality. Do nothing if this is not an MSVC personality.
|
||||
LandingPadInst *LP = nullptr;
|
||||
for (BasicBlock &BB : F) {
|
||||
LP = BB.getLandingPadInst();
|
||||
if (LP)
|
||||
break;
|
||||
}
|
||||
if (!LP)
|
||||
return false;
|
||||
PersonalityFn =
|
||||
dyn_cast<Function>(LP->getPersonalityFn()->stripPointerCasts());
|
||||
if (!PersonalityFn)
|
||||
return false;
|
||||
Personality = classifyEHPersonality(PersonalityFn);
|
||||
if (!isMSVCEHPersonality(Personality))
|
||||
return false;
|
||||
|
||||
emitExceptionRegistrationRecord(&F);
|
||||
// FIXME: State insertion.
|
||||
|
||||
// Reset per-function state.
|
||||
PersonalityFn = nullptr;
|
||||
Personality = EHPersonality::Unknown;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Get the common EH registration subobject:
|
||||
/// struct EHRegistrationNode {
|
||||
/// EHRegistrationNode *Next;
|
||||
/// EXCEPTION_DISPOSITION (*Handler)(...);
|
||||
/// };
|
||||
Type *WinEHStatePass::getEHRegistrationType() {
|
||||
if (EHRegistrationTy)
|
||||
return EHRegistrationTy;
|
||||
LLVMContext &Context = TheModule->getContext();
|
||||
EHRegistrationTy = StructType::create(Context, "EHRegistrationNode");
|
||||
Type *FieldTys[] = {
|
||||
EHRegistrationTy->getPointerTo(0), // EHRegistrationNode *Next
|
||||
Type::getInt8PtrTy(Context) // EXCEPTION_DISPOSITION (*Handler)(...)
|
||||
};
|
||||
EHRegistrationTy->setBody(FieldTys, false);
|
||||
return EHRegistrationTy;
|
||||
}
|
||||
|
||||
/// The __CxxFrameHandler3 registration node:
|
||||
/// struct CXXExceptionRegistration {
|
||||
/// void *SavedESP;
|
||||
/// EHRegistrationNode SubRecord;
|
||||
/// int32_t TryLevel;
|
||||
/// };
|
||||
Type *WinEHStatePass::getCXXEH3RegistrationType() {
|
||||
if (CXXEH3RegistrationTy)
|
||||
return CXXEH3RegistrationTy;
|
||||
LLVMContext &Context = TheModule->getContext();
|
||||
Type *FieldTys[] = {
|
||||
Type::getInt8PtrTy(Context), // void *SavedESP
|
||||
getEHRegistrationType(), // EHRegistrationNode SubRecord
|
||||
Type::getInt32Ty(Context) // int32_t TryLevel
|
||||
};
|
||||
CXXEH3RegistrationTy =
|
||||
StructType::create(FieldTys, "CXXExceptionRegistration");
|
||||
return CXXEH3RegistrationTy;
|
||||
}
|
||||
|
||||
/// The _except_handler3 registration node:
|
||||
/// struct EH3ExceptionRegistration {
|
||||
/// EHRegistrationNode SubRecord;
|
||||
/// void *ScopeTable;
|
||||
/// int32_t TryLevel;
|
||||
/// };
|
||||
Type *WinEHStatePass::getSEH3RegistrationType() {
|
||||
if (SEH3RegistrationTy)
|
||||
return SEH3RegistrationTy;
|
||||
LLVMContext &Context = TheModule->getContext();
|
||||
Type *FieldTys[] = {
|
||||
getEHRegistrationType(), // EHRegistrationNode SubRecord
|
||||
Type::getInt8PtrTy(Context), // void *ScopeTable
|
||||
Type::getInt32Ty(Context) // int32_t TryLevel
|
||||
};
|
||||
SEH3RegistrationTy = StructType::create(FieldTys, "EH3ExceptionRegistration");
|
||||
return SEH3RegistrationTy;
|
||||
}
|
||||
|
||||
/// The _except_handler4 registration node:
|
||||
/// struct EH4ExceptionRegistration {
|
||||
/// void *SavedESP;
|
||||
/// _EXCEPTION_POINTERS *ExceptionPointers;
|
||||
/// EHRegistrationNode SubRecord;
|
||||
/// int32_t EncodedScopeTable;
|
||||
/// int32_t TryLevel;
|
||||
/// };
|
||||
Type *WinEHStatePass::getSEH4RegistrationType() {
|
||||
if (SEH4RegistrationTy)
|
||||
return SEH4RegistrationTy;
|
||||
LLVMContext &Context = TheModule->getContext();
|
||||
Type *FieldTys[] = {
|
||||
Type::getInt8PtrTy(Context), // void *SavedESP
|
||||
Type::getInt8PtrTy(Context), // void *ExceptionPointers
|
||||
getEHRegistrationType(), // EHRegistrationNode SubRecord
|
||||
Type::getInt32Ty(Context), // int32_t EncodedScopeTable
|
||||
Type::getInt32Ty(Context) // int32_t TryLevel
|
||||
};
|
||||
SEH4RegistrationTy = StructType::create(FieldTys, "EH4ExceptionRegistration");
|
||||
return SEH4RegistrationTy;
|
||||
}
|
||||
|
||||
// Emit an exception registration record. These are stack allocations with the
|
||||
// common subobject of two pointers: the previous registration record (the old
|
||||
// fs:00) and the personality function for the current frame. The data before
|
||||
// and after that is personality function specific.
|
||||
void WinEHStatePass::emitExceptionRegistrationRecord(Function *F) {
|
||||
assert(Personality == EHPersonality::MSVC_CXX ||
|
||||
Personality == EHPersonality::MSVC_X86SEH);
|
||||
|
||||
StringRef PersonalityName = PersonalityFn->getName();
|
||||
IRBuilder<> Builder(&F->getEntryBlock(), F->getEntryBlock().begin());
|
||||
Type *Int8PtrType = Builder.getInt8PtrTy();
|
||||
Value *SubRecord = nullptr;
|
||||
if (PersonalityName == "__CxxFrameHandler3") {
|
||||
Type *RegNodeTy = getCXXEH3RegistrationType();
|
||||
Value *RegNode = Builder.CreateAlloca(RegNodeTy);
|
||||
// FIXME: We can skip this in -GS- mode, when we figure that out.
|
||||
// SavedESP = llvm.stacksave()
|
||||
Value *SP = Builder.CreateCall(
|
||||
Intrinsic::getDeclaration(TheModule, Intrinsic::stacksave));
|
||||
Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
|
||||
// TryLevel = -1
|
||||
Builder.CreateStore(Builder.getInt32(-1),
|
||||
Builder.CreateStructGEP(RegNodeTy, RegNode, 2));
|
||||
// FIXME: 'Personality' is incorrect here. We need to generate a trampoline
|
||||
// that effectively gets the LSDA.
|
||||
SubRecord = Builder.CreateStructGEP(RegNodeTy, RegNode, 1);
|
||||
linkExceptionRegistration(Builder, SubRecord, PersonalityFn);
|
||||
} else if (PersonalityName == "_except_handler3") {
|
||||
Type *RegNodeTy = getSEH3RegistrationType();
|
||||
Value *RegNode = Builder.CreateAlloca(RegNodeTy);
|
||||
// TryLevel = -1
|
||||
Builder.CreateStore(Builder.getInt32(-1),
|
||||
Builder.CreateStructGEP(RegNodeTy, RegNode, 2));
|
||||
// FIXME: Generalize llvm.eh.sjljl.lsda for this.
|
||||
// ScopeTable = nullptr
|
||||
Builder.CreateStore(Constant::getNullValue(Int8PtrType),
|
||||
Builder.CreateStructGEP(RegNodeTy, RegNode, 1));
|
||||
SubRecord = Builder.CreateStructGEP(RegNodeTy, RegNode, 0);
|
||||
linkExceptionRegistration(Builder, SubRecord, PersonalityFn);
|
||||
} else if (PersonalityName == "_except_handler4") {
|
||||
Type *RegNodeTy = getSEH4RegistrationType();
|
||||
Value *RegNode = Builder.CreateAlloca(RegNodeTy);
|
||||
// SavedESP = llvm.stacksave()
|
||||
Value *SP = Builder.CreateCall(
|
||||
Intrinsic::getDeclaration(TheModule, Intrinsic::stacksave));
|
||||
Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
|
||||
// TryLevel = -2
|
||||
Builder.CreateStore(Builder.getInt32(-2),
|
||||
Builder.CreateStructGEP(RegNodeTy, RegNode, 4));
|
||||
// FIXME: Generalize llvm.eh.sjljl.lsda for this, and then do the stack
|
||||
// cookie xor.
|
||||
// ScopeTable = nullptr
|
||||
Builder.CreateStore(Builder.getInt32(0),
|
||||
Builder.CreateStructGEP(RegNodeTy, RegNode, 3));
|
||||
SubRecord = Builder.CreateStructGEP(RegNodeTy, RegNode, 2);
|
||||
linkExceptionRegistration(Builder, SubRecord, PersonalityFn);
|
||||
} else {
|
||||
llvm_unreachable("unexpected personality function");
|
||||
}
|
||||
|
||||
// FIXME: Insert an unlink before all returns.
|
||||
for (BasicBlock &BB : *F) {
|
||||
TerminatorInst *T = BB.getTerminator();
|
||||
if (!isa<ReturnInst>(T))
|
||||
continue;
|
||||
Builder.SetInsertPoint(T);
|
||||
unlinkExceptionRegistration(Builder, SubRecord);
|
||||
}
|
||||
}
|
||||
|
||||
void WinEHStatePass::linkExceptionRegistration(IRBuilder<> &Builder,
|
||||
Value *RegNode, Value *Handler) {
|
||||
Type *RegNodeTy = getEHRegistrationType();
|
||||
// Handler = Handler
|
||||
Handler = Builder.CreateBitCast(Handler, Builder.getInt8PtrTy());
|
||||
Builder.CreateStore(Handler, Builder.CreateStructGEP(RegNodeTy, RegNode, 1));
|
||||
// Next = [fs:00]
|
||||
Constant *FSZero =
|
||||
Constant::getNullValue(RegNodeTy->getPointerTo()->getPointerTo(257));
|
||||
Value *Next = Builder.CreateLoad(FSZero);
|
||||
Builder.CreateStore(Next, Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
|
||||
// [fs:00] = RegNode
|
||||
Builder.CreateStore(RegNode, FSZero);
|
||||
}
|
||||
|
||||
void WinEHStatePass::unlinkExceptionRegistration(IRBuilder<> &Builder,
|
||||
Value *RegNode) {
|
||||
// Clone RegNode into the current BB for better address mode folding.
|
||||
if (auto *GEP = dyn_cast<GetElementPtrInst>(RegNode)) {
|
||||
GEP = cast<GetElementPtrInst>(GEP->clone());
|
||||
Builder.Insert(GEP);
|
||||
RegNode = GEP;
|
||||
}
|
||||
Type *RegNodeTy = getEHRegistrationType();
|
||||
// [fs:00] = RegNode->Next
|
||||
Value *Next =
|
||||
Builder.CreateLoad(Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
|
||||
Constant *FSZero =
|
||||
Constant::getNullValue(RegNodeTy->getPointerTo()->getPointerTo(257));
|
||||
Builder.CreateStore(Next, FSZero);
|
||||
}
|
@ -4,6 +4,7 @@
|
||||
|
||||
%frame.reverse = type { %Iter, %Iter }
|
||||
|
||||
declare i32 @pers(...)
|
||||
declare void @llvm.stackrestore(i8*)
|
||||
declare i8* @llvm.stacksave()
|
||||
declare void @begin(%Iter* sret)
|
||||
@ -22,8 +23,7 @@ blah:
|
||||
|
||||
; CHECK: calll __chkstk
|
||||
; CHECK: movl %esp, %[[beg:[^ ]*]]
|
||||
; CHECK: movl %esp, %[[end:[^ ]*]]
|
||||
; CHECK: addl $12, %[[end]]
|
||||
; CHECK: leal 12(%[[beg]]), %[[end:[^ ]*]]
|
||||
|
||||
call void @begin(%Iter* sret %temp.lvalue)
|
||||
; CHECK: calll _begin
|
||||
@ -49,7 +49,7 @@ invoke.cont5: ; preds = %invoke.cont
|
||||
ret i32 0
|
||||
|
||||
lpad: ; preds = %invoke.cont, %entry
|
||||
%lp = landingpad { i8*, i32 } personality i8* null
|
||||
%lp = landingpad { i8*, i32 } personality i32 (...)* @pers
|
||||
cleanup
|
||||
unreachable
|
||||
}
|
||||
|
77
test/CodeGen/X86/win32-eh.ll
Normal file
77
test/CodeGen/X86/win32-eh.ll
Normal file
@ -0,0 +1,77 @@
|
||||
; RUN: llc -mtriple=i686-pc-windows-msvc < %s | FileCheck %s
|
||||
|
||||
declare void @may_throw_or_crash()
|
||||
declare i32 @_except_handler3(...)
|
||||
declare i32 @_except_handler4(...)
|
||||
declare i32 @__CxxFrameHandler3(...)
|
||||
declare void @llvm.eh.begincatch(i8*, i8*)
|
||||
declare void @llvm.eh.endcatch()
|
||||
|
||||
define void @use_except_handler3() {
|
||||
invoke void @may_throw_or_crash()
|
||||
to label %cont unwind label %catchall
|
||||
cont:
|
||||
ret void
|
||||
catchall:
|
||||
landingpad { i8*, i32 } personality i32 (...)* @_except_handler3
|
||||
catch i8* null
|
||||
br label %cont
|
||||
}
|
||||
|
||||
; CHECK-LABEL: _use_except_handler3:
|
||||
; CHECK: subl ${{[0-9]+}}, %esp
|
||||
; CHECK: movl %fs:0, %[[next:[^ ,]*]]
|
||||
; CHECK: movl %[[next]], (%esp)
|
||||
; CHECK: leal (%esp), %[[node:[^ ,]*]]
|
||||
; CHECK: movl %[[node]], %fs:0
|
||||
; CHECK: calll _may_throw_or_crash
|
||||
; CHECK: movl (%esp), %[[next:[^ ,]*]]
|
||||
; CHECK: movl %[[next]], %fs:0
|
||||
; CHECK: retl
|
||||
|
||||
define void @use_except_handler4() {
|
||||
invoke void @may_throw_or_crash()
|
||||
to label %cont unwind label %catchall
|
||||
cont:
|
||||
ret void
|
||||
catchall:
|
||||
landingpad { i8*, i32 } personality i32 (...)* @_except_handler4
|
||||
catch i8* null
|
||||
br label %cont
|
||||
}
|
||||
|
||||
; CHECK-LABEL: _use_except_handler4:
|
||||
; CHECK: subl ${{[0-9]+}}, %esp
|
||||
; CHECK: leal 8(%esp), %[[node:[^ ,]*]]
|
||||
; CHECK: movl %fs:0, %[[next:[^ ,]*]]
|
||||
; CHECK: movl %[[next]], 8(%esp)
|
||||
; CHECK: movl %[[node]], %fs:0
|
||||
; CHECK: calll _may_throw_or_crash
|
||||
; CHECK: movl 8(%esp), %[[next:[^ ,]*]]
|
||||
; CHECK: movl %[[next]], %fs:0
|
||||
; CHECK: retl
|
||||
|
||||
define void @use_CxxFrameHandler3() {
|
||||
invoke void @may_throw_or_crash()
|
||||
to label %cont unwind label %catchall
|
||||
cont:
|
||||
ret void
|
||||
catchall:
|
||||
%ehvals = landingpad { i8*, i32 } personality i32 (...)* @__CxxFrameHandler3
|
||||
catch i8* null
|
||||
%ehptr = extractvalue { i8*, i32 } %ehvals, 0
|
||||
call void @llvm.eh.begincatch(i8* %ehptr, i8* null)
|
||||
call void @llvm.eh.endcatch()
|
||||
br label %cont
|
||||
}
|
||||
|
||||
; CHECK-LABEL: _use_CxxFrameHandler3:
|
||||
; CHECK: subl ${{[0-9]+}}, %esp
|
||||
; CHECK: leal 4(%esp), %[[node:[^ ,]*]]
|
||||
; CHECK: movl %fs:0, %[[next:[^ ,]*]]
|
||||
; CHECK: movl %[[next]], 4(%esp)
|
||||
; CHECK: movl %[[node]], %fs:0
|
||||
; CHECK: calll _may_throw_or_crash
|
||||
; CHECK: movl 4(%esp), %[[next:[^ ,]*]]
|
||||
; CHECK: movl %[[next]], %fs:0
|
||||
; CHECK: retl
|
Loading…
Reference in New Issue
Block a user