llvm.org GIT mirror llvm / 4def1cb
Re-land "[WinEH] Add an EH registration and state insertion pass for 32-bit x86" This reverts commit r236360. This change exposed a bug in WinEHPrepare by opting win32 code into EH preparation. We already knew that WinEHPrepare has bugs, and is the status quo for x64, so I don't think that's a reason to hold off on this change. I disabled exceptions in the sanitizer tests in r236505 and an earlier revision. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@236508 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