llvm.org GIT mirror llvm / 85b9ebb
[WinEH] Start EH preparation for 32-bit x86, it uses no arguments 32-bit x86 MSVC-style exceptions are functionaly similar to 64-bit, but they take no arguments. Instead, they implicitly use the value of EBP passed in by the caller as a pointer to the parent's frame. In LLVM, we can represent this as llvm.frameaddress(1), and feed that into all of our calls to llvm.framerecover. The next steps are: - Add an alloca to the fs:00 linked list of handlers - Add something like llvm.sjlj.lsda or generalize it to store in the alloca - Move state number calculation to WinEHPrepare, arrange for FunctionLoweringInfo to call it - Use the state numbers to insert explicit loads and stores in the IR git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@236172 91177308-0d34-0410-b5e6-96231b3b80d8 Reid Kleckner 5 years ago
5 changed file(s) with 110 addition(s) and 57 deletion(s). Raw diff Collapse all Expand all
7272 .Case("__gxx_personality_v0", EHPersonality::GNU_CXX)
7373 .Case("__gcc_personality_v0", EHPersonality::GNU_C)
7474 .Case("__objc_personality_v0", EHPersonality::GNU_ObjC)
75 .Case("__except_handler3", EHPersonality::MSVC_X86SEH)
76 .Case("__except_handler4", EHPersonality::MSVC_X86SEH)
75 .Case("_except_handler3", EHPersonality::MSVC_X86SEH)
76 .Case("_except_handler4", EHPersonality::MSVC_X86SEH)
7777 .Case("__C_specific_handler", EHPersonality::MSVC_Win64SEH)
7878 .Case("__CxxFrameHandler3", EHPersonality::MSVC_CXX)
7979 .Default(EHPersonality::Unknown);
1818 #include "llvm/ADT/STLExtras.h"
1919 #include "llvm/ADT/SmallSet.h"
2020 #include "llvm/ADT/SetVector.h"
21 #include "llvm/ADT/Triple.h"
2122 #include "llvm/ADT/TinyPtrVector.h"
2223 #include "llvm/Analysis/LibCallSemantics.h"
2324 #include "llvm/CodeGen/WinEHFuncInfo.h"
7071 public:
7172 static char ID; // Pass identification, replacement for typeid.
7273 WinEHPrepare(const TargetMachine *TM = nullptr)
73 : FunctionPass(ID), DT(nullptr), SEHExceptionCodeSlot(nullptr) {}
74 : FunctionPass(ID), DT(nullptr), SEHExceptionCodeSlot(nullptr) {
75 if (TM)
76 TheTriple = Triple(TM->getTargetTriple());
77 }
7478
7579 bool runOnFunction(Function &Fn) override;
7680
96100 LandingPadInst *OutlinedLPad,
97101 const LandingPadInst *OriginalLPad,
98102 FrameVarInfoMap &VarInfo);
103 Function *createHandlerFunc(Type *RetTy, const Twine &Name, Module *M,
104 Value *&ParentFP);
99105 bool outlineHandler(ActionHandler *Action, Function *SrcFn,
100106 LandingPadInst *LPad, BasicBlock *StartBB,
101107 FrameVarInfoMap &VarInfo);
108114 BasicBlock *EndBB);
109115
110116 void processSEHCatchHandler(CatchHandler *Handler, BasicBlock *StartBB);
117
118 Triple TheTriple;
111119
112120 // All fields are reset by runOnFunction.
113121 DominatorTree *DT;
137145 // outlined but before the outlined code is pruned from the parent function.
138146 DenseMap LPadTargetBlocks;
139147
148 // Map from outlined handler to call to llvm.frameaddress(1). Only used for
149 // 32-bit EH.
150 DenseMap HandlerToParentFP;
151
140152 AllocaInst *SEHExceptionCodeSlot;
141153 };
142154
143155 class WinEHFrameVariableMaterializer : public ValueMaterializer {
144156 public:
145 WinEHFrameVariableMaterializer(Function *OutlinedFn,
157 WinEHFrameVariableMaterializer(Function *OutlinedFn, Value *ParentFP,
146158 FrameVarInfoMap &FrameVarInfo);
147159 ~WinEHFrameVariableMaterializer() override {}
148160
178190
179191 class WinEHCloningDirectorBase : public CloningDirector {
180192 public:
181 WinEHCloningDirectorBase(Function *HandlerFn, FrameVarInfoMap &VarInfo,
182 LandingPadMap &LPadMap)
183 : Materializer(HandlerFn, VarInfo),
193 WinEHCloningDirectorBase(Function *HandlerFn, Value *ParentFP,
194 FrameVarInfoMap &VarInfo, LandingPadMap &LPadMap)
195 : Materializer(HandlerFn, ParentFP, VarInfo),
184196 SelectorIDType(Type::getInt32Ty(HandlerFn->getContext())),
185197 Int8PtrType(Type::getInt8PtrTy(HandlerFn->getContext())),
186 LPadMap(LPadMap) {
187 auto AI = HandlerFn->getArgumentList().begin();
188 ++AI;
189 EstablisherFrame = AI;
190 }
198 LPadMap(LPadMap), ParentFP(ParentFP) {}
191199
192200 CloningAction handleInstruction(ValueToValueMapTy &VMap,
193201 const Instruction *Inst,
224232 LandingPadMap &LPadMap;
225233
226234 /// The value representing the parent frame pointer.
227 Value *EstablisherFrame;
235 Value *ParentFP;
228236 };
229237
230238 class WinEHCatchDirector : public WinEHCloningDirectorBase {
231239 public:
232240 WinEHCatchDirector(
233 Function *CatchFn, Value *Selector, FrameVarInfoMap &VarInfo,
234 LandingPadMap &LPadMap,
241 Function *CatchFn, Value *ParentFP, Value *Selector,
242 FrameVarInfoMap &VarInfo, LandingPadMap &LPadMap,
235243 DenseMap &NestedLPads)
236 : WinEHCloningDirectorBase(CatchFn, VarInfo, LPadMap),
244 : WinEHCloningDirectorBase(CatchFn, ParentFP, VarInfo, LPadMap),
237245 CurrentSelector(Selector->stripPointerCasts()),
238246 ExceptionObjectVar(nullptr), NestedLPtoOriginalLP(NestedLPads) {}
239247
271279
272280 class WinEHCleanupDirector : public WinEHCloningDirectorBase {
273281 public:
274 WinEHCleanupDirector(Function *CleanupFn, FrameVarInfoMap &VarInfo,
275 LandingPadMap &LPadMap)
276 : WinEHCloningDirectorBase(CleanupFn, VarInfo, LPadMap) {}
282 WinEHCleanupDirector(Function *CleanupFn, Value *ParentFP,
283 FrameVarInfoMap &VarInfo, LandingPadMap &LPadMap)
284 : WinEHCloningDirectorBase(CleanupFn, ParentFP, VarInfo,
285 LPadMap) {}
277286
278287 CloningAction handleBeginCatch(ValueToValueMapTy &VMap,
279288 const Instruction *Inst,
879888 if (TempAlloca == getCatchObjectSentinel())
880889 continue; // Skip catch parameter sentinels.
881890 Function *HandlerFn = TempAlloca->getParent()->getParent();
882 // FIXME: Sink this GEP into the blocks where it is used.
891 llvm::Value *FP = HandlerToParentFP[HandlerFn];
892 assert(FP);
893
894 // FIXME: Sink this framerecover into the blocks where it is used.
883895 Builder.SetInsertPoint(TempAlloca);
884896 Builder.SetCurrentDebugLocation(TempAlloca->getDebugLoc());
885897 Value *RecoverArgs[] = {
886 Builder.CreateBitCast(&F, Int8PtrType, ""),
887 &(HandlerFn->getArgumentList().back()),
898 Builder.CreateBitCast(&F, Int8PtrType, ""), FP,
888899 llvm::ConstantInt::get(Int32Type, AllocasToEscape.size() - 1)};
889 Value *RecoveredAlloca = Builder.CreateCall(RecoverFrameFn, RecoverArgs);
900 Instruction *RecoveredAlloca =
901 Builder.CreateCall(RecoverFrameFn, RecoverArgs);
902
890903 // Add a pointer bitcast if the alloca wasn't an i8.
891904 if (RecoveredAlloca->getType() != TempAlloca->getType()) {
892905 RecoveredAlloca->setName(Twine(TempAlloca->getName()) + ".i8");
893 RecoveredAlloca =
894 Builder.CreateBitCast(RecoveredAlloca, TempAlloca->getType());
906 RecoveredAlloca = cast(
907 Builder.CreateBitCast(RecoveredAlloca, TempAlloca->getType()));
895908 }
896909 TempAlloca->replaceAllUsesWith(RecoveredAlloca);
897910 TempAlloca->removeFromParent();
917930 CatchHandlerMap.clear();
918931 DeleteContainerSeconds(CleanupHandlerMap);
919932 CleanupHandlerMap.clear();
933 HandlerToParentFP.clear();
934 DT = nullptr;
920935
921936 return HandlersOutlined;
922937 }
9861001 IntrinsicInst *EHActions = cast(Recover->clone());
9871002
9881003 // Remap the exception variables into the outlined function.
989 WinEHFrameVariableMaterializer Materializer(OutlinedHandlerFn, FrameVarInfo);
9901004 SmallVector ActionTargets;
9911005 SmallVector ActionList;
9921006 parseEHActions(EHActions, ActionList);
11471161 InvokeInst::Create(F, NewRetBB, StubLandingPad, None, "", OldRetBB);
11481162 }
11491163
1164 // FIXME: Consider sinking this into lib/Target/X86 somehow. TargetLowering
1165 // usually doesn't build LLVM IR, so that's probably the wrong place.
1166 Function *WinEHPrepare::createHandlerFunc(Type *RetTy, const Twine &Name,
1167 Module *M, Value *&ParentFP) {
1168 // x64 uses a two-argument prototype where the parent FP is the second
1169 // argument. x86 uses no arguments, just the incoming EBP value.
1170 LLVMContext &Context = M->getContext();
1171 FunctionType *FnType;
1172 if (TheTriple.getArch() == Triple::x86_64) {
1173 Type *Int8PtrType = Type::getInt8PtrTy(Context);
1174 Type *ArgTys[2] = {Int8PtrType, Int8PtrType};
1175 FnType = FunctionType::get(RetTy, ArgTys, false);
1176 } else {
1177 FnType = FunctionType::get(RetTy, None, false);
1178 }
1179
1180 Function *Handler =
1181 Function::Create(FnType, GlobalVariable::InternalLinkage, Name, M);
1182 BasicBlock *Entry = BasicBlock::Create(Context, "entry");
1183 Handler->getBasicBlockList().push_front(Entry);
1184 if (TheTriple.getArch() == Triple::x86_64) {
1185 ParentFP = &(Handler->getArgumentList().back());
1186 } else {
1187 assert(M);
1188 Function *FrameAddressFn =
1189 Intrinsic::getDeclaration(M, Intrinsic::frameaddress);
1190 Value *Args[1] = {ConstantInt::get(Type::getInt32Ty(Context), 1)};
1191 ParentFP = CallInst::Create(FrameAddressFn, Args, "parent_fp",
1192 &Handler->getEntryBlock());
1193 }
1194 return Handler;
1195 }
1196
11501197 bool WinEHPrepare::outlineHandler(ActionHandler *Action, Function *SrcFn,
11511198 LandingPadInst *LPad, BasicBlock *StartBB,
11521199 FrameVarInfoMap &VarInfo) {
11531200 Module *M = SrcFn->getParent();
11541201 LLVMContext &Context = M->getContext();
1202 Type *Int8PtrType = Type::getInt8PtrTy(Context);
11551203
11561204 // Create a new function to receive the handler contents.
1157 Type *Int8PtrType = Type::getInt8PtrTy(Context);
1158 std::vector ArgTys;
1159 ArgTys.push_back(Int8PtrType);
1160 ArgTys.push_back(Int8PtrType);
1205 Value *ParentFP;
11611206 Function *Handler;
11621207 if (Action->getType() == Catch) {
1163 FunctionType *FnType = FunctionType::get(Int8PtrType, ArgTys, false);
1164 Handler = Function::Create(FnType, GlobalVariable::InternalLinkage,
1165 SrcFn->getName() + ".catch", M);
1208 Handler = createHandlerFunc(Int8PtrType, SrcFn->getName() + ".catch", M,
1209 ParentFP);
11661210 } else {
1167 FunctionType *FnType =
1168 FunctionType::get(Type::getVoidTy(Context), ArgTys, false);
1169 Handler = Function::Create(FnType, GlobalVariable::InternalLinkage,
1170 SrcFn->getName() + ".cleanup", M);
1171 }
1172
1211 Handler = createHandlerFunc(Type::getVoidTy(Context),
1212 SrcFn->getName() + ".cleanup", M, ParentFP);
1213 }
1214 HandlerToParentFP[Handler] = ParentFP;
11731215 Handler->addFnAttr("wineh-parent", SrcFn->getName());
1216 BasicBlock *Entry = &Handler->getEntryBlock();
11741217
11751218 // Generate a standard prolog to setup the frame recovery structure.
11761219 IRBuilder<> Builder(Context);
1177 BasicBlock *Entry = BasicBlock::Create(Context, "entry");
1178 Handler->getBasicBlockList().push_front(Entry);
11791220 Builder.SetInsertPoint(Entry);
11801221 Builder.SetCurrentDebugLocation(LPad->getDebugLoc());
11811222
11881229 LPadMap.mapLandingPad(LPad);
11891230 if (auto *CatchAction = dyn_cast(Action)) {
11901231 Constant *Sel = CatchAction->getSelector();
1191 Director.reset(new WinEHCatchDirector(Handler, Sel, VarInfo, LPadMap,
1232 Director.reset(new WinEHCatchDirector(Handler, ParentFP, Sel,
1233 VarInfo, LPadMap,
11921234 NestedLPtoOriginalLP));
11931235 LPadMap.remapEHValues(VMap, UndefValue::get(Int8PtrType),
11941236 ConstantInt::get(Type::getInt32Ty(Context), 1));
11951237 } else {
1196 Director.reset(new WinEHCleanupDirector(Handler, VarInfo, LPadMap));
1238 Director.reset(
1239 new WinEHCleanupDirector(Handler, ParentFP, VarInfo, LPadMap));
11971240 LPadMap.remapEHValues(VMap, UndefValue::get(Int8PtrType),
11981241 UndefValue::get(Type::getInt32Ty(Context)));
11991242 }
14201463 // When outlining llvm.frameaddress(i32 0), remap that to the second argument,
14211464 // which is the FP of the parent.
14221465 if (isFrameAddressCall(Inst)) {
1423 VMap[Inst] = EstablisherFrame;
1466 VMap[Inst] = ParentFP;
14241467 return CloningDirector::SkipInstruction;
14251468 }
14261469
16591702 }
16601703
16611704 WinEHFrameVariableMaterializer::WinEHFrameVariableMaterializer(
1662 Function *OutlinedFn, FrameVarInfoMap &FrameVarInfo)
1705 Function *OutlinedFn, Value *ParentFP, FrameVarInfoMap &FrameVarInfo)
16631706 : FrameVarInfo(FrameVarInfo), Builder(OutlinedFn->getContext()) {
16641707 BasicBlock *EntryBB = &OutlinedFn->getEntryBlock();
1665 Builder.SetInsertPoint(EntryBB, EntryBB->getFirstInsertionPt());
1708
1709 // New allocas should be inserted in the entry block, but after the parent FP
1710 // is established if it is an instruction.
1711 Instruction *InsertPoint = EntryBB->getFirstInsertionPt();
1712 if (auto *FPInst = dyn_cast(ParentFP))
1713 InsertPoint = FPInst->getNextNode();
1714 Builder.SetInsertPoint(EntryBB, InsertPoint);
16661715 }
16671716
16681717 Value *WinEHFrameVariableMaterializer::materializeValueFor(Value *V) {
None ; RUN: opt -winehprepare -S < %s | FileCheck %s
0 ; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S < %s | FileCheck %s
11
22 ; Notionally based on this C++ source:
33 ; int liveout_catch(int p) {
None ; RUN: opt -mtriple=i386-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s
0 ; RUN: opt -mtriple=x86_64-pc-windows-msvc -winehprepare -S -o - < %s | FileCheck %s
11
22 ; This test is built from the following code:
33 ; struct A {
2323 ; the inalloca instruction was manually sunk into the landingpad.
2424
2525 ; ModuleID = 'cppeh-inalloca.cpp'
26 target datalayout = "e-m:w-p:32:32-i64:64-f80:32-n8:16:32-S32"
27 target triple = "i386-pc-windows-msvc"
2826
2927 %rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] }
3028 %struct.A = type { i32 }
None ; RUN: opt -S -winehprepare -mtriple=x86_64-windows-msvc < %s | FileCheck %s
1
2 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
3 target triple = "x86_64-pc-windows-msvc"
0 ; RUN: opt -S -winehprepare -mtriple=x86_64-windows-msvc < %s \
1 ; RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=X64
2
3 ; This test should also pass in 32-bit using _except_handler3.
4 ; RUN: sed %s -e 's/__C_specific_handler/_except_handler3/' \
5 ; RUN: | opt -S -winehprepare -mtriple=i686-windows-msvc \
6 ; RUN: | FileCheck %s --check-prefix=CHECK --check-prefix=X86
47
58 declare void @cleanup()
69 declare i32 @filt()
138141 ; CHECK: landingpad { i8*, i32 }
139142 ; CHECK-NEXT: cleanup
140143 ; CHECK-NEXT: catch i32 ()* @filt
141 ; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 0, void (i8*, i8*)* @lpad_phi.cleanup, i32 1, i8* bitcast (i32 ()* @filt to i8*), i32 -1, i8* blockaddress(@lpad_phi, %lpad.return_crit_edge))
144 ; CHECK-NEXT: call i8* (...) @llvm.eh.actions(i32 0, void ({{.*}})* @lpad_phi.cleanup, i32 1, i8* bitcast (i32 ()* @filt to i8*), i32 -1, i8* blockaddress(@lpad_phi, %lpad.return_crit_edge))
142145 ; CHECK-NEXT: indirectbr {{.*}} [label %lpad.return_crit_edge]
143146 ;
144147 ; CHECK: lpad.return_crit_edge:
177180 ; CHECK-NEXT: cleanup
178181 ; CHECK-NEXT: catch i32 ()* @filt
179182 ; CHECK-NEXT: call i8* (...) @llvm.eh.actions(
180 ; CHECK: i32 0, void (i8*, i8*)* @cleanup_and_except.cleanup,
183 ; CHECK: i32 0, void ({{.*}})* @cleanup_and_except.cleanup,
181184 ; CHECK: i32 1, i8* bitcast (i32 ()* @filt to i8*), i32 -1, i8* blockaddress(@cleanup_and_except, %lpad.return_crit_edge))
182185 ; CHECK-NEXT: indirectbr {{.*}} [label %lpad.return_crit_edge]
183186 ;
189192 ; CHECK-NEXT: ret i32 %r
190193
191194 ; FIXME: This cleanup is an artifact of bad demotion.
192 ; CHECK-LABEL: define internal void @lpad_phi.cleanup(i8*, i8*)
195 ; X64-LABEL: define internal void @lpad_phi.cleanup(i8*, i8*)
196 ; X86-LABEL: define internal void @lpad_phi.cleanup()
197 ; X86: call i8* @llvm.frameaddress(i32 1)
198 ; CHECK: call i8* @llvm.framerecover({{.*}})
193199 ; CHECK: load i32
194200 ; CHECK: store i32 %{{.*}}, i32*