]> granicus.if.org Git - clang/commitdiff
[SEH] Delete the 32-bit IR lowering for __finally blocks and use x64
authorReid Kleckner <reid@kleckner.net>
Wed, 1 Jul 2015 21:00:00 +0000 (21:00 +0000)
committerReid Kleckner <reid@kleckner.net>
Wed, 1 Jul 2015 21:00:00 +0000 (21:00 +0000)
32-bit finally funclets are intended to be called both directly from the
parent function and indirectly from the EH runtime. Because we aren't
contorting LLVM's X86 prologue to match MSVC's, calling the finally
block directly passes in a different value of EBP than the one that the
runtime provides. We need an adapter thunk to adjust EBP to the expected
value. However, WinEHPrepare already has to solve this problem when
cleanups are not pre-outlined, so we can go ahead and rely on it rather
than duplicating work.

Now we only do the llvm.x86.seh.recoverfp dance for 32-bit SEH filter
functions.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@241187 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGException.cpp
lib/CodeGen/CodeGenFunction.h
test/CodeGen/exceptions-seh-finally.c
test/CodeGen/exceptions-seh.c

index 55ee48fd81fc47c31775a4ae23efbc03e34e1594..c1e7eae405f067814c72d226cf0b4c9cf7ee1284 100644 (file)
@@ -1306,37 +1306,27 @@ struct PerformSEHFinally : EHScopeStack::Cleanup {
     ASTContext &Context = CGF.getContext();
     CodeGenModule &CGM = CGF.CGM;
 
-    // In 64-bit, we call the child function with arguments. In 32-bit, we store
-    // zero in the parent frame and use framerecover to check the value.
-    const CGFunctionInfo *FnInfo;
     CallArgList Args;
-    if (CGF.getTarget().getTriple().getArch() != llvm::Triple::x86) {
-      // Compute the two argument values.
-      QualType ArgTys[2] = {Context.UnsignedCharTy, Context.VoidPtrTy};
-      llvm::Value *FrameAddr = CGM.getIntrinsic(llvm::Intrinsic::frameaddress);
-      llvm::Value *FP =
-          CGF.Builder.CreateCall(FrameAddr, {CGF.Builder.getInt32(0)});
-      llvm::Value *IsForEH =
-          llvm::ConstantInt::get(CGF.ConvertType(ArgTys[0]), F.isForEHCleanup());
-      Args.add(RValue::get(IsForEH), ArgTys[0]);
-      Args.add(RValue::get(FP), ArgTys[1]);
-
-      // Arrange a two-arg function info and type.
-      FunctionProtoType::ExtProtoInfo EPI;
-      const auto *FPT = cast<FunctionProtoType>(
-          Context.getFunctionType(Context.VoidTy, ArgTys, EPI));
-      FnInfo = &CGM.getTypes().arrangeFreeFunctionCall(Args, FPT,
-                                                       /*chainCall=*/false);
-    } else {
-      // Emit the zero store if this is normal control flow. There are no
-      // explicit arguments.
-      if (F.isForNormalCleanup() && CGF.ChildAbnormalTerminationSlot)
-        CGF.Builder.CreateStore(CGF.Builder.getInt32(0),
-                                CGF.ChildAbnormalTerminationSlot);
-      FnInfo = &CGM.getTypes().arrangeNullaryFunction();
-    }
 
-    CGF.EmitCall(*FnInfo, OutlinedFinally, ReturnValueSlot(), Args);
+    // Compute the two argument values.
+    QualType ArgTys[2] = {Context.UnsignedCharTy, Context.VoidPtrTy};
+    llvm::Value *FrameAddr = CGM.getIntrinsic(llvm::Intrinsic::frameaddress);
+    llvm::Value *FP =
+        CGF.Builder.CreateCall(FrameAddr, {CGF.Builder.getInt32(0)});
+    llvm::Value *IsForEH =
+        llvm::ConstantInt::get(CGF.ConvertType(ArgTys[0]), F.isForEHCleanup());
+    Args.add(RValue::get(IsForEH), ArgTys[0]);
+    Args.add(RValue::get(FP), ArgTys[1]);
+
+    // Arrange a two-arg function info and type.
+    FunctionProtoType::ExtProtoInfo EPI;
+    const auto *FPT = cast<FunctionProtoType>(
+        Context.getFunctionType(Context.VoidTy, ArgTys, EPI));
+    const CGFunctionInfo &FnInfo =
+        CGM.getTypes().arrangeFreeFunctionCall(Args, FPT,
+                                               /*chainCall=*/false);
+
+    CGF.EmitCall(FnInfo, OutlinedFinally, ReturnValueSlot(), Args);
   }
 };
 }
@@ -1347,14 +1337,13 @@ struct CaptureFinder : ConstStmtVisitor<CaptureFinder> {
   CodeGenFunction &ParentCGF;
   const VarDecl *ParentThis;
   SmallVector<const VarDecl *, 4> Captures;
-  llvm::Value *AbnormalTermination = nullptr;
   llvm::Value *SEHCodeSlot = nullptr;
   CaptureFinder(CodeGenFunction &ParentCGF, const VarDecl *ParentThis)
       : ParentCGF(ParentCGF), ParentThis(ParentThis) {}
 
   // Return true if we need to do any capturing work.
   bool foundCaptures() {
-    return !Captures.empty() || AbnormalTermination || SEHCodeSlot;
+    return !Captures.empty() || SEHCodeSlot;
   }
 
   void Visit(const Stmt *S) {
@@ -1388,15 +1377,6 @@ struct CaptureFinder : ConstStmtVisitor<CaptureFinder> {
 
     unsigned ID = E->getBuiltinCallee();
     switch (ID) {
-    case Builtin::BI__abnormal_termination:
-    case Builtin::BI_abnormal_termination:
-      // This is the simple case where we are the outermost finally. All we
-      // have to do here is make sure we escape this and recover it in the
-      // outlined handler.
-      if (!AbnormalTermination)
-        AbnormalTermination = ParentCGF.CreateMemTemp(
-            ParentCGF.getContext().IntTy, "abnormal_termination");
-      break;
     case Builtin::BI__exception_code:
     case Builtin::BI_exception_code:
       // This is the simple case where we are the outermost finally. All we
@@ -1516,15 +1496,6 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF,
         recoverAddrOfEscapedLocal(ParentCGF, ParentVar, ParentFP);
   }
 
-  // The __abnormal_termination and __exception_code values are just more
-  // captures.
-  if (Finder.AbnormalTermination) {
-    AbnormalTerminationSlot = recoverAddrOfEscapedLocal(
-        ParentCGF, Finder.AbnormalTermination, ParentFP);
-    // Save the slot on the parent so it can store 1 and 0 to it.
-    ParentCGF.ChildAbnormalTerminationSlot = Finder.AbnormalTermination;
-  }
-
   if (Finder.SEHCodeSlot) {
     SEHCodeSlotStack.push_back(
         recoverAddrOfEscapedLocal(ParentCGF, Finder.SEHCodeSlot, ParentFP));
@@ -1557,7 +1528,9 @@ void CodeGenFunction::startOutlinedSEHHelper(CodeGenFunction &ParentCGF,
   }
 
   FunctionArgList Args;
-  if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86) {
+  if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86 || !IsFilter) {
+    // All SEH finally functions take two parameters. Win64 filters take two
+    // parameters. Win32 filters take no parameters.
     if (IsFilter) {
       Args.push_back(ImplicitParamDecl::Create(
           getContext(), nullptr, StartLoc,
@@ -1698,8 +1671,6 @@ llvm::Value *CodeGenFunction::EmitSEHExceptionCode() {
 }
 
 llvm::Value *CodeGenFunction::EmitSEHAbnormalTermination() {
-  if (CGM.getTarget().getTriple().getArch() == llvm::Triple::x86)
-    return Builder.CreateLoad(AbnormalTerminationSlot);
   // Abnormal termination is just the first parameter to the outlined finally
   // helper.
   auto AI = CurFn->arg_begin();
@@ -1713,10 +1684,6 @@ void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) {
     llvm::Function *FinallyFunc =
         HelperCGF.GenerateSEHFinallyFunction(*this, *Finally);
 
-    // Store 1 to indicate abnormal termination if an exception is thrown.
-    if (ChildAbnormalTerminationSlot)
-      Builder.CreateStore(Builder.getInt32(1), ChildAbnormalTerminationSlot);
-
     // Push a cleanup for __finally blocks.
     EHStack.pushCleanup<PerformSEHFinally>(NormalAndEHCleanup, FinallyFunc);
     return;
@@ -1753,7 +1720,6 @@ void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S) {
   // Just pop the cleanup if it's a __finally block.
   if (S.getFinallyHandler()) {
     PopCleanupBlock();
-    ChildAbnormalTerminationSlot = nullptr;
     return;
   }
 
index a587f001f4bf9301b7b4b8e7e3f84f274f9bdfea..2ba893e6a358f052c6cc1a4e73bacfec6f44cc15 100644 (file)
@@ -324,14 +324,6 @@ public:
   /// write the current selector value into this alloca.
   llvm::AllocaInst *EHSelectorSlot;
 
-  /// Entering and leaving an SEH __try / __finally scope causes stores to this
-  /// slot.
-  llvm::Value *ChildAbnormalTerminationSlot = nullptr;
-
-  /// The SEH __abnormal_termination() intrinsic lowers down to loads from this
-  /// slot from a parent function.
-  llvm::Value *AbnormalTerminationSlot = nullptr;
-
   /// A stack of exception code slots. Entering an __except block pushes a slot
   /// on the stack and leaving pops one. The __exception_code() intrinsic loads
   /// a value from the top of the stack.
index ad90e4d2b4abf37dcedd2aa68fcea4a37f66ea4f..d7653dda9126b22c3d53612555a34dea28815c1f 100644 (file)
@@ -1,7 +1,5 @@
-// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - \
-// RUN:         | FileCheck %s --check-prefix=CHECK --check-prefix=X64
-// RUN: %clang_cc1 %s -triple i686-pc-win32 -fms-extensions -emit-llvm -o - \
-// RUN:         | FileCheck %s --check-prefix=CHECK --check-prefix=X86
+// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -triple i686-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s
 
 void abort(void) __attribute__((noreturn));
 void might_crash(void);
@@ -20,17 +18,15 @@ void basic_finally(void) {
 // CHECK:     to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
 //
 // CHECK: [[invoke_cont]]
-// X64: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
-// X64: call void @"\01?fin$0@0@basic_finally@@"(i8 0, i8* %[[fp]])
-// X86: call void @"\01?fin$0@0@basic_finally@@"()
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@basic_finally@@"({{i8( zeroext)?}} 0, i8* %[[fp]])
 // CHECK-NEXT: ret void
 //
 // CHECK: [[lpad]]
 // CHECK-NEXT: landingpad
 // CHECK-NEXT: cleanup
-// X64: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
-// X64: call void @"\01?fin$0@0@basic_finally@@"(i8 1, i8* %[[fp]])
-// X86: call void @"\01?fin$0@0@basic_finally@@"()
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@basic_finally@@"({{i8( zeroext)?}} 1, i8* %[[fp]])
 // CHECK: resume { i8*, i32 }
 
 // CHECK: define internal void @"\01?fin$0@0@basic_finally@@"({{.*}})
@@ -62,9 +58,8 @@ l:
 // CHECK:     to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
 //
 // CHECK: [[invoke_cont]]
-// X64: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
-// X64: call void @"\01?fin$0@0@label_in_finally@@"(i8 0, i8* %[[fp]])
-// X86: call void @"\01?fin$0@0@label_in_finally@@"()
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@label_in_finally@@"({{i8( zeroext)?}} 0, i8* %[[fp]])
 // CHECK: ret void
 
 // CHECK: define internal void @"\01?fin$0@0@label_in_finally@@"({{.*}})
@@ -86,34 +81,23 @@ void use_abnormal_termination(void) {
 }
 
 // CHECK-LABEL: define void @use_abnormal_termination()
-// X86: call void (...) @llvm.frameescape(i32* %[[abnormal_termination:[^ ),]*]])
-// X86: store i32 1, i32* %[[abnormal_termination]]
 // CHECK: invoke void @might_crash()
 // CHECK:     to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
 //
 // CHECK: [[invoke_cont]]
-// X64: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
-// X64: call void @"\01?fin$0@0@use_abnormal_termination@@"(i8 0, i8* %[[fp]])
-// X86: store i32 0, i32* %[[abnormal_termination]]
-// X86: call void @"\01?fin$0@0@use_abnormal_termination@@"()
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@use_abnormal_termination@@"({{i8( zeroext)?}} 0, i8* %[[fp]])
 // CHECK: ret void
 //
 // CHECK: [[lpad]]
 // CHECK-NEXT: landingpad
 // CHECK-NEXT: cleanup
-// X64: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
-// X64: call void @"\01?fin$0@0@use_abnormal_termination@@"(i8 1, i8* %[[fp]])
-// X86: call void @"\01?fin$0@0@use_abnormal_termination@@"()
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@use_abnormal_termination@@"({{i8( zeroext)?}} 1, i8* %[[fp]])
 // CHECK: resume { i8*, i32 }
 
-// X64: define internal void @"\01?fin$0@0@use_abnormal_termination@@"(i8 %[[abnormal:abnormal_termination]], i8* %frame_pointer)
-// X64: %[[abnormal_zext:[^ ]*]] = zext i8 %[[abnormal]] to i32
-// X86: define internal void @"\01?fin$0@0@use_abnormal_termination@@"()
-// X86: %[[ebp:[^ ]*]] = call i8* @llvm.frameaddress(i32 1)
-// X86: %[[fp:[^ ]*]] = call i8* @llvm.x86.seh.recoverfp(i8* bitcast (void ()* @use_abnormal_termination to i8*), i8* %[[ebp]])
-// X86: %[[abnormal_i8:[^ ]*]] = call i8* @llvm.framerecover(i8* bitcast (void ()* @use_abnormal_termination to i8*), i8* %[[fp]], i32 0)
-// X86: %[[abnormal:[^ ]*]] = bitcast i8* %[[abnormal_i8]] to i32*
-// X86: %[[abnormal_zext:[^ ]*]] = load i32, i32* %[[abnormal]]
+// CHECK: define internal void @"\01?fin$0@0@use_abnormal_termination@@"({{i8( zeroext)?}} %[[abnormal:abnormal_termination]], i8* %frame_pointer)
+// CHECK: %[[abnormal_zext:[^ ]*]] = zext i8 %[[abnormal]] to i32
 // CHECK: store i32 %[[abnormal_zext]], i32* @crashed
 // CHECK-NEXT: ret void
 
index ab6fad6f3effc2ea5a07e421766f537f41ca5417..772fe547ba5ffdc44ccb635e74c95d52bc25142e 100644 (file)
@@ -188,17 +188,15 @@ void basic_finally(void) {
 // CHECK:       to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
 //
 // CHECK: [[cont]]
-// X64: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
-// X64: call void @"\01?fin$0@0@basic_finally@@"(i8 0, i8* %[[fp]])
-// X86: call void @"\01?fin$0@0@basic_finally@@"()
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@basic_finally@@"({{i8( zeroext)?}} 0, i8* %[[fp]])
 // CHECK: ret void
 //
 // CHECK: [[lpad]]
 // CHECK: landingpad { i8*, i32 }
 // CHECK-NEXT: cleanup
-// X64: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
-// X64: call void @"\01?fin$0@0@basic_finally@@"(i8 1, i8* %[[fp]])
-// X86: call void @"\01?fin$0@0@basic_finally@@"()
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0@0@basic_finally@@"({{i8( zeroext)?}} 1, i8* %[[fp]])
 // CHECK: resume
 
 // CHECK: define internal void @"\01?fin$0@0@basic_finally@@"({{.*}})