llvm.org GIT mirror llvm / 018ed7b
[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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@236339 91177308-0d34-0410-b5e6-96231b3b80d8 Reid Kleckner 5 years ago
10 changed file(s) with 428 addition(s) and 12 deletion(s). Raw diff Collapse all Expand all
3636 ARM, /// Windows NT (Windows on ARM)
3737 CE, /// Windows CE ARM, PowerPC, SH3, SH4
3838 Itanium, /// Windows x64, Windows Itanium (IA-64)
39 X86, /// Windows x86, uses no CFI, just EH tables
3940 MIPS = Alpha,
4041 };
4142 }
505506 /// frame information to unwind.
506507 bool usesCFIForEH() const {
507508 return (ExceptionsType == ExceptionHandling::DwarfCFI ||
508 ExceptionsType == ExceptionHandling::ARM ||
509 ExceptionsType == ExceptionHandling::WinEH);
509 ExceptionsType == ExceptionHandling::ARM || usesWindowsCFI());
510510 }
511511
512512 bool usesWindowsCFI() const {
513 return ExceptionsType == ExceptionHandling::WinEH;
513 return ExceptionsType == ExceptionHandling::WinEH &&
514 (WinEHEncodingType != WinEH::EncodingType::Invalid &&
515 WinEHEncodingType != WinEH::EncodingType::X86);
514516 }
515517
516518 bool doesDwarfUseRelocationsAcrossSections() const {
265265 case ExceptionHandling::WinEH:
266266 switch (MAI->getWinEHEncodingType()) {
267267 default: llvm_unreachable("unsupported unwinding information encoding");
268 case WinEH::EncodingType::Invalid:
269 break;
268270 case WinEH::EncodingType::Itanium:
269271 ES = new Win64Exception(this);
270272 break;
77 //===----------------------------------------------------------------------===//
88 //
99 // This pass lowers LLVM IR exception handling into something closer to what the
10 // backend wants. It snifs the personality function to see which kind of
11 // preparation is necessary. If the personality function uses the Itanium LSDA,
12 // this pass delegates to the DWARF EH preparation pass.
10 // backend wants for functions using a personality function from a runtime
11 // provided by MSVC. Functions with other personality functions are left alone
12 // and may be prepared by other passes. In particular, all supported MSVC
13 // personality functions require cleanup code to be outlined, and the C++
14 // personality requires catch handler code to be outlined.
1315 //
1416 //===----------------------------------------------------------------------===//
1517
3032 #include "llvm/IR/Module.h"
3133 #include "llvm/IR/PatternMatch.h"
3234 #include "llvm/Pass.h"
33 #include "llvm/Support/CommandLine.h"
3435 #include "llvm/Support/Debug.h"
3536 #include "llvm/Support/raw_ostream.h"
3637 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
921922 if (SEHExceptionCodeSlot) {
922923 if (SEHExceptionCodeSlot->hasNUses(0))
923924 SEHExceptionCodeSlot->eraseFromParent();
924 else
925 else if (isAllocaPromotable(SEHExceptionCodeSlot))
925926 PromoteMemToReg(SEHExceptionCodeSlot, *DT);
926927 }
927928
3131 X86TargetTransformInfo.cpp
3232 X86VZeroUpper.cpp
3333 X86FixupLEAs.cpp
34 X86WinEHState.cpp
3435 )
3536
3637 if( CMAKE_CL_64 )
131131 PrivateLabelPrefix = ".L";
132132 PointerSize = 8;
133133 WinEHEncodingType = WinEH::EncodingType::Itanium;
134 ExceptionsType = ExceptionHandling::WinEH;
135134 }
135
136 ExceptionsType = ExceptionHandling::WinEH;
136137
137138 AssemblerDialect = AsmWriterFlavor;
138139
6868 /// esp-relative movs with pushes.
6969 FunctionPass *createX86CallFrameOptimization();
7070
71 /// createX86WinEHStatePass - Return an IR pass that inserts EH registration
72 /// stack objects and explicit EH state updates. This pass must run after EH
73 /// preparation, which does Windows-specific but architecture-neutral
74 /// preparation.
75 FunctionPass *createX86WinEHStatePass();
76
7177 } // End llvm namespace
7278
7379 #endif
184184 void addIRPasses() override;
185185 bool addInstSelector() override;
186186 bool addILPOpts() override;
187 bool addPreISel() override;
187188 void addPreRegAlloc() override;
188189 void addPostRegAlloc() override;
189190 void addPreEmitPass() override;
219220 return true;
220221 }
221222
223 bool X86PassConfig::addPreISel() {
224 // Only add this pass for 32-bit x86.
225 Triple TT(TM->getTargetTriple());
226 if (TT.getArch() == Triple::x86)
227 addPass(createX86WinEHStatePass());
228 return true;
229 }
230
222231 void X86PassConfig::addPreRegAlloc() {
223232 addPass(createX86CallFrameOptimization());
224233 }
0 //===-- X86WinEHState - Insert EH state updates for win32 exceptions ------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // All functions using an MSVC EH personality use an explicitly updated state
10 // number stored in an exception registration stack object. The registration
11 // object is linked into a thread-local chain of registrations stored at fs:00.
12 // This pass adds the registration object and EH state updates.
13 //
14 //===----------------------------------------------------------------------===//
15
16 #include "X86.h"
17 #include "llvm/Analysis/LibCallSemantics.h"
18 #include "llvm/CodeGen/Passes.h"
19 #include "llvm/CodeGen/WinEHFuncInfo.h"
20 #include "llvm/IR/Dominators.h"
21 #include "llvm/IR/Function.h"
22 #include "llvm/IR/IRBuilder.h"
23 #include "llvm/IR/Instructions.h"
24 #include "llvm/IR/IntrinsicInst.h"
25 #include "llvm/IR/Module.h"
26 #include "llvm/IR/PatternMatch.h"
27 #include "llvm/Pass.h"
28 #include "llvm/Support/Debug.h"
29 #include "llvm/Support/raw_ostream.h"
30 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
31 #include "llvm/Transforms/Utils/Cloning.h"
32 #include "llvm/Transforms/Utils/Local.h"
33
34 using namespace llvm;
35 using namespace llvm::PatternMatch;
36
37 #define DEBUG_TYPE "winehstate"
38
39 namespace {
40 class WinEHStatePass : public FunctionPass {
41 public:
42 static char ID; // Pass identification, replacement for typeid.
43
44 WinEHStatePass() : FunctionPass(ID) {}
45
46 bool runOnFunction(Function &Fn) override;
47
48 bool doInitialization(Module &M) override;
49
50 bool doFinalization(Module &M) override;
51
52 void getAnalysisUsage(AnalysisUsage &AU) const override;
53
54 const char *getPassName() const override {
55 return "Windows 32-bit x86 EH state insertion";
56 }
57
58 private:
59 void emitExceptionRegistrationRecord(Function *F);
60
61 void linkExceptionRegistration(IRBuilder<> &Builder, Value *RegNode,
62 Value *Handler);
63 void unlinkExceptionRegistration(IRBuilder<> &Builder, Value *RegNode);
64
65 // Module-level type getters.
66 Type *getEHRegistrationType();
67 Type *getSEH3RegistrationType();
68 Type *getSEH4RegistrationType();
69 Type *getCXXEH3RegistrationType();
70
71 // Per-module data.
72 Module *TheModule = nullptr;
73 StructType *EHRegistrationTy = nullptr;
74 StructType *CXXEH3RegistrationTy = nullptr;
75 StructType *SEH3RegistrationTy = nullptr;
76 StructType *SEH4RegistrationTy = nullptr;
77
78 // Per-function state
79 EHPersonality Personality = EHPersonality::Unknown;
80 Function *PersonalityFn = nullptr;
81 };
82 }
83
84 FunctionPass *llvm::createX86WinEHStatePass() { return new WinEHStatePass(); }
85
86 char WinEHStatePass::ID = 0;
87
88 bool WinEHStatePass::doInitialization(Module &M) {
89 TheModule = &M;
90 return false;
91 }
92
93 bool WinEHStatePass::doFinalization(Module &M) {
94 assert(TheModule == &M);
95 TheModule = nullptr;
96 EHRegistrationTy = nullptr;
97 CXXEH3RegistrationTy = nullptr;
98 SEH3RegistrationTy = nullptr;
99 SEH4RegistrationTy = nullptr;
100 return false;
101 }
102
103 void WinEHStatePass::getAnalysisUsage(AnalysisUsage &AU) const {
104 // This pass should only insert a stack allocation, memory accesses, and
105 // framerecovers.
106 AU.setPreservesCFG();
107 }
108
109 bool WinEHStatePass::runOnFunction(Function &F) {
110 // Check the personality. Do nothing if this is not an MSVC personality.
111 LandingPadInst *LP = nullptr;
112 for (BasicBlock &BB : F) {
113 LP = BB.getLandingPadInst();
114 if (LP)
115 break;
116 }
117 if (!LP)
118 return false;
119 PersonalityFn =
120 dyn_cast(LP->getPersonalityFn()->stripPointerCasts());
121 if (!PersonalityFn)
122 return false;
123 Personality = classifyEHPersonality(PersonalityFn);
124 if (!isMSVCEHPersonality(Personality))
125 return false;
126
127 emitExceptionRegistrationRecord(&F);
128 // FIXME: State insertion.
129
130 // Reset per-function state.
131 PersonalityFn = nullptr;
132 Personality = EHPersonality::Unknown;
133 return true;
134 }
135
136 /// Get the common EH registration subobject:
137 /// struct EHRegistrationNode {
138 /// EHRegistrationNode *Next;
139 /// EXCEPTION_DISPOSITION (*Handler)(...);
140 /// };
141 Type *WinEHStatePass::getEHRegistrationType() {
142 if (EHRegistrationTy)
143 return EHRegistrationTy;
144 LLVMContext &Context = TheModule->getContext();
145 EHRegistrationTy = StructType::create(Context, "EHRegistrationNode");
146 Type *FieldTys[] = {
147 EHRegistrationTy->getPointerTo(0), // EHRegistrationNode *Next
148 Type::getInt8PtrTy(Context) // EXCEPTION_DISPOSITION (*Handler)(...)
149 };
150 EHRegistrationTy->setBody(FieldTys, false);
151 return EHRegistrationTy;
152 }
153
154 /// The __CxxFrameHandler3 registration node:
155 /// struct CXXExceptionRegistration {
156 /// void *SavedESP;
157 /// EHRegistrationNode SubRecord;
158 /// int32_t TryLevel;
159 /// };
160 Type *WinEHStatePass::getCXXEH3RegistrationType() {
161 if (CXXEH3RegistrationTy)
162 return CXXEH3RegistrationTy;
163 LLVMContext &Context = TheModule->getContext();
164 Type *FieldTys[] = {
165 Type::getInt8PtrTy(Context), // void *SavedESP
166 getEHRegistrationType(), // EHRegistrationNode SubRecord
167 Type::getInt32Ty(Context) // int32_t TryLevel
168 };
169 CXXEH3RegistrationTy =
170 StructType::create(FieldTys, "CXXExceptionRegistration");
171 return CXXEH3RegistrationTy;
172 }
173
174 /// The _except_handler3 registration node:
175 /// struct EH3ExceptionRegistration {
176 /// EHRegistrationNode SubRecord;
177 /// void *ScopeTable;
178 /// int32_t TryLevel;
179 /// };
180 Type *WinEHStatePass::getSEH3RegistrationType() {
181 if (SEH3RegistrationTy)
182 return SEH3RegistrationTy;
183 LLVMContext &Context = TheModule->getContext();
184 Type *FieldTys[] = {
185 getEHRegistrationType(), // EHRegistrationNode SubRecord
186 Type::getInt8PtrTy(Context), // void *ScopeTable
187 Type::getInt32Ty(Context) // int32_t TryLevel
188 };
189 SEH3RegistrationTy = StructType::create(FieldTys, "EH3ExceptionRegistration");
190 return SEH3RegistrationTy;
191 }
192
193 /// The _except_handler4 registration node:
194 /// struct EH4ExceptionRegistration {
195 /// void *SavedESP;
196 /// _EXCEPTION_POINTERS *ExceptionPointers;
197 /// EHRegistrationNode SubRecord;
198 /// int32_t EncodedScopeTable;
199 /// int32_t TryLevel;
200 /// };
201 Type *WinEHStatePass::getSEH4RegistrationType() {
202 if (SEH4RegistrationTy)
203 return SEH4RegistrationTy;
204 LLVMContext &Context = TheModule->getContext();
205 Type *FieldTys[] = {
206 Type::getInt8PtrTy(Context), // void *SavedESP
207 Type::getInt8PtrTy(Context), // void *ExceptionPointers
208 getEHRegistrationType(), // EHRegistrationNode SubRecord
209 Type::getInt32Ty(Context), // int32_t EncodedScopeTable
210 Type::getInt32Ty(Context) // int32_t TryLevel
211 };
212 SEH4RegistrationTy = StructType::create(FieldTys, "EH4ExceptionRegistration");
213 return SEH4RegistrationTy;
214 }
215
216 // Emit an exception registration record. These are stack allocations with the
217 // common subobject of two pointers: the previous registration record (the old
218 // fs:00) and the personality function for the current frame. The data before
219 // and after that is personality function specific.
220 void WinEHStatePass::emitExceptionRegistrationRecord(Function *F) {
221 assert(Personality == EHPersonality::MSVC_CXX ||
222 Personality == EHPersonality::MSVC_X86SEH);
223
224 StringRef PersonalityName = PersonalityFn->getName();
225 IRBuilder<> Builder(&F->getEntryBlock(), F->getEntryBlock().begin());
226 Type *Int8PtrType = Builder.getInt8PtrTy();
227 Value *SubRecord = nullptr;
228 if (PersonalityName == "__CxxFrameHandler3") {
229 Type *RegNodeTy = getCXXEH3RegistrationType();
230 Value *RegNode = Builder.CreateAlloca(RegNodeTy);
231 // FIXME: We can skip this in -GS- mode, when we figure that out.
232 // SavedESP = llvm.stacksave()
233 Value *SP = Builder.CreateCall(
234 Intrinsic::getDeclaration(TheModule, Intrinsic::stacksave));
235 Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
236 // TryLevel = -1
237 Builder.CreateStore(Builder.getInt32(-1),
238 Builder.CreateStructGEP(RegNodeTy, RegNode, 2));
239 // FIXME: 'Personality' is incorrect here. We need to generate a trampoline
240 // that effectively gets the LSDA.
241 SubRecord = Builder.CreateStructGEP(RegNodeTy, RegNode, 1);
242 linkExceptionRegistration(Builder, SubRecord, PersonalityFn);
243 } else if (PersonalityName == "_except_handler3") {
244 Type *RegNodeTy = getSEH3RegistrationType();
245 Value *RegNode = Builder.CreateAlloca(RegNodeTy);
246 // TryLevel = -1
247 Builder.CreateStore(Builder.getInt32(-1),
248 Builder.CreateStructGEP(RegNodeTy, RegNode, 2));
249 // FIXME: Generalize llvm.eh.sjljl.lsda for this.
250 // ScopeTable = nullptr
251 Builder.CreateStore(Constant::getNullValue(Int8PtrType),
252 Builder.CreateStructGEP(RegNodeTy, RegNode, 1));
253 SubRecord = Builder.CreateStructGEP(RegNodeTy, RegNode, 0);
254 linkExceptionRegistration(Builder, SubRecord, PersonalityFn);
255 } else if (PersonalityName == "_except_handler4") {
256 Type *RegNodeTy = getSEH4RegistrationType();
257 Value *RegNode = Builder.CreateAlloca(RegNodeTy);
258 // SavedESP = llvm.stacksave()
259 Value *SP = Builder.CreateCall(
260 Intrinsic::getDeclaration(TheModule, Intrinsic::stacksave));
261 Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
262 // TryLevel = -2
263 Builder.CreateStore(Builder.getInt32(-2),
264 Builder.CreateStructGEP(RegNodeTy, RegNode, 4));
265 // FIXME: Generalize llvm.eh.sjljl.lsda for this, and then do the stack
266 // cookie xor.
267 // ScopeTable = nullptr
268 Builder.CreateStore(Builder.getInt32(0),
269 Builder.CreateStructGEP(RegNodeTy, RegNode, 3));
270 SubRecord = Builder.CreateStructGEP(RegNodeTy, RegNode, 2);
271 linkExceptionRegistration(Builder, SubRecord, PersonalityFn);
272 } else {
273 llvm_unreachable("unexpected personality function");
274 }
275
276 // FIXME: Insert an unlink before all returns.
277 for (BasicBlock &BB : *F) {
278 TerminatorInst *T = BB.getTerminator();
279 if (!isa(T))
280 continue;
281 Builder.SetInsertPoint(T);
282 unlinkExceptionRegistration(Builder, SubRecord);
283 }
284 }
285
286 void WinEHStatePass::linkExceptionRegistration(IRBuilder<> &Builder,
287 Value *RegNode, Value *Handler) {
288 Type *RegNodeTy = getEHRegistrationType();
289 // Handler = Handler
290 Handler = Builder.CreateBitCast(Handler, Builder.getInt8PtrTy());
291 Builder.CreateStore(Handler, Builder.CreateStructGEP(RegNodeTy, RegNode, 1));
292 // Next = [fs:00]
293 Constant *FSZero =
294 Constant::getNullValue(RegNodeTy->getPointerTo()->getPointerTo(257));
295 Value *Next = Builder.CreateLoad(FSZero);
296 Builder.CreateStore(Next, Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
297 // [fs:00] = RegNode
298 Builder.CreateStore(RegNode, FSZero);
299 }
300
301 void WinEHStatePass::unlinkExceptionRegistration(IRBuilder<> &Builder,
302 Value *RegNode) {
303 // Clone RegNode into the current BB for better address mode folding.
304 if (auto *GEP = dyn_cast(RegNode)) {
305 GEP = cast(GEP->clone());
306 Builder.Insert(GEP);
307 RegNode = GEP;
308 }
309 Type *RegNodeTy = getEHRegistrationType();
310 // [fs:00] = RegNode->Next
311 Value *Next =
312 Builder.CreateLoad(Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
313 Constant *FSZero =
314 Constant::getNullValue(RegNodeTy->getPointerTo()->getPointerTo(257));
315 Builder.CreateStore(Next, FSZero);
316 }
33
44 %frame.reverse = type { %Iter, %Iter }
55
6 declare i32 @pers(...)
67 declare void @llvm.stackrestore(i8*)
78 declare i8* @llvm.stacksave()
89 declare void @begin(%Iter* sret)
2122
2223 ; CHECK: calll __chkstk
2324 ; CHECK: movl %esp, %[[beg:[^ ]*]]
24 ; CHECK: movl %esp, %[[end:[^ ]*]]
25 ; CHECK: addl $12, %[[end]]
25 ; CHECK: leal 12(%[[beg]]), %[[end:[^ ]*]]
2626
2727 call void @begin(%Iter* sret %temp.lvalue)
2828 ; CHECK: calll _begin
4848 ret i32 0
4949
5050 lpad: ; preds = %invoke.cont, %entry
51 %lp = landingpad { i8*, i32 } personality i8* null
51 %lp = landingpad { i8*, i32 } personality i32 (...)* @pers
5252 cleanup
5353 unreachable
5454 }
0 ; RUN: llc -mtriple=i686-pc-windows-msvc < %s | FileCheck %s
1
2 declare void @may_throw_or_crash()
3 declare i32 @_except_handler3(...)
4 declare i32 @_except_handler4(...)
5 declare i32 @__CxxFrameHandler3(...)
6 declare void @llvm.eh.begincatch(i8*, i8*)
7 declare void @llvm.eh.endcatch()
8
9 define void @use_except_handler3() {
10 invoke void @may_throw_or_crash()
11 to label %cont unwind label %catchall
12 cont:
13 ret void
14 catchall:
15 landingpad { i8*, i32 } personality i32 (...)* @_except_handler3
16 catch i8* null
17 br label %cont
18 }
19
20 ; CHECK-LABEL: _use_except_handler3:
21 ; CHECK: subl ${{[0-9]+}}, %esp
22 ; CHECK: movl %fs:0, %[[next:[^ ,]*]]
23 ; CHECK: movl %[[next]], (%esp)
24 ; CHECK: leal (%esp), %[[node:[^ ,]*]]
25 ; CHECK: movl %[[node]], %fs:0
26 ; CHECK: calll _may_throw_or_crash
27 ; CHECK: movl (%esp), %[[next:[^ ,]*]]
28 ; CHECK: movl %[[next]], %fs:0
29 ; CHECK: retl
30
31 define void @use_except_handler4() {
32 invoke void @may_throw_or_crash()
33 to label %cont unwind label %catchall
34 cont:
35 ret void
36 catchall:
37 landingpad { i8*, i32 } personality i32 (...)* @_except_handler4
38 catch i8* null
39 br label %cont
40 }
41
42 ; CHECK-LABEL: _use_except_handler4:
43 ; CHECK: subl ${{[0-9]+}}, %esp
44 ; CHECK: leal 8(%esp), %[[node:[^ ,]*]]
45 ; CHECK: movl %fs:0, %[[next:[^ ,]*]]
46 ; CHECK: movl %[[next]], 8(%esp)
47 ; CHECK: movl %[[node]], %fs:0
48 ; CHECK: calll _may_throw_or_crash
49 ; CHECK: movl 8(%esp), %[[next:[^ ,]*]]
50 ; CHECK: movl %[[next]], %fs:0
51 ; CHECK: retl
52
53 define void @use_CxxFrameHandler3() {
54 invoke void @may_throw_or_crash()
55 to label %cont unwind label %catchall
56 cont:
57 ret void
58 catchall:
59 %ehvals = landingpad { i8*, i32 } personality i32 (...)* @__CxxFrameHandler3
60 catch i8* null
61 %ehptr = extractvalue { i8*, i32 } %ehvals, 0
62 call void @llvm.eh.begincatch(i8* %ehptr, i8* null)
63 call void @llvm.eh.endcatch()
64 br label %cont
65 }
66
67 ; CHECK-LABEL: _use_CxxFrameHandler3:
68 ; CHECK: subl ${{[0-9]+}}, %esp
69 ; CHECK: leal 4(%esp), %[[node:[^ ,]*]]
70 ; CHECK: movl %fs:0, %[[next:[^ ,]*]]
71 ; CHECK: movl %[[next]], 4(%esp)
72 ; CHECK: movl %[[node]], %fs:0
73 ; CHECK: calll _may_throw_or_crash
74 ; CHECK: movl 4(%esp), %[[next:[^ ,]*]]
75 ; CHECK: movl %[[next]], %fs:0
76 ; CHECK: retl