r228977 - [ms] Implement codegen for __leave.

Nico Weber nicolasweber at gmx.de
Thu Feb 12 15:16:12 PST 2015


Author: nico
Date: Thu Feb 12 17:16:11 2015
New Revision: 228977

URL: http://llvm.org/viewvc/llvm-project?rev=228977&view=rev
Log:
[ms] Implement codegen for __leave.

Reviewed at http://reviews.llvm.org/D7575

Modified:
    cfe/trunk/lib/CodeGen/CGException.cpp
    cfe/trunk/lib/CodeGen/CGStmt.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.h
    cfe/trunk/test/CodeGen/exceptions-seh-leave.c

Modified: cfe/trunk/lib/CodeGen/CGException.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGException.cpp?rev=228977&r1=228976&r2=228977&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGException.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGException.cpp Thu Feb 12 17:16:11 2015
@@ -1707,9 +1707,18 @@ void CodeGenFunction::EmitSEHTryStmt(con
   SEHFinallyInfo FI;
   EnterSEHTryStmt(S, FI);
   {
+    JumpDest TryExit = getJumpDestInCurrentScope("__try.__leave");
+    SEHTryEpilogueStack.push_back(&TryExit);
+
     // Disable inlining inside SEH __try scopes.
     SaveAndRestore<bool> Saver(IsSEHTryScope, true);
     EmitStmt(S.getTryBlock());
+
+    if (!TryExit.getBlock()->use_empty())
+      EmitBlock(TryExit.getBlock(), /*IsFinished=*/true);
+    else
+      delete TryExit.getBlock();
+    SEHTryEpilogueStack.pop_back();
   }
   ExitSEHTryStmt(S, FI);
 }
@@ -1988,5 +1997,13 @@ void CodeGenFunction::ExitSEHTryStmt(con
 }
 
 void CodeGenFunction::EmitSEHLeaveStmt(const SEHLeaveStmt &S) {
-  CGM.ErrorUnsupported(&S, "SEH __leave");
+  // If this code is reachable then emit a stop point (if generating
+  // debug info). We have to do this ourselves because we are on the
+  // "simple" statement path.
+  if (HaveInsertPoint())
+    EmitStopPoint(&S);
+
+  assert(!SEHTryEpilogueStack.empty() &&
+         "sema should have rejected this __leave");
+  EmitBranchThroughCleanup(*SEHTryEpilogueStack.back());
 }

Modified: cfe/trunk/lib/CodeGen/CGStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGStmt.cpp?rev=228977&r1=228976&r2=228977&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGStmt.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGStmt.cpp Thu Feb 12 17:16:11 2015
@@ -88,6 +88,7 @@ void CodeGenFunction::EmitStmt(const Stm
   case Stmt::ContinueStmtClass:
   case Stmt::DefaultStmtClass:
   case Stmt::CaseStmtClass:
+  case Stmt::SEHLeaveStmtClass:
     llvm_unreachable("should have emitted these statements as simple");
 
 #define STMT(Type, Base)
@@ -173,9 +174,6 @@ void CodeGenFunction::EmitStmt(const Stm
   case Stmt::SEHTryStmtClass:
     EmitSEHTryStmt(cast<SEHTryStmt>(*S));
     break;
-  case Stmt::SEHLeaveStmtClass:
-    EmitSEHLeaveStmt(cast<SEHLeaveStmt>(*S));
-    break;
   case Stmt::OMPParallelDirectiveClass:
     EmitOMPParallelDirective(cast<OMPParallelDirective>(*S));
     break;
@@ -256,6 +254,7 @@ bool CodeGenFunction::EmitSimpleStmt(con
   case Stmt::ContinueStmtClass: EmitContinueStmt(cast<ContinueStmt>(*S)); break;
   case Stmt::DefaultStmtClass:  EmitDefaultStmt(cast<DefaultStmt>(*S));   break;
   case Stmt::CaseStmtClass:     EmitCaseStmt(cast<CaseStmt>(*S));         break;
+  case Stmt::SEHLeaveStmtClass: EmitSEHLeaveStmt(cast<SEHLeaveStmt>(*S)); break;
   }
 
   return true;

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=228977&r1=228976&r2=228977&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Thu Feb 12 17:16:11 2015
@@ -278,6 +278,7 @@ public:
 
   EHScopeStack EHStack;
   llvm::SmallVector<char, 256> LifetimeExtendedCleanupStack;
+  llvm::SmallVector<const JumpDest *, 2> SEHTryEpilogueStack;
 
   /// Header for data within LifetimeExtendedCleanupStack.
   struct LifetimeExtendedCleanupHeader {

Modified: cfe/trunk/test/CodeGen/exceptions-seh-leave.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/exceptions-seh-leave.c?rev=228977&r1=228976&r2=228977&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/exceptions-seh-leave.c (original)
+++ cfe/trunk/test/CodeGen/exceptions-seh-leave.c Thu Feb 12 17:16:11 2015
@@ -1,19 +1,229 @@
-// RUN: not %clang_cc1 -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s
 
-// This is a codegen test because we only emit the diagnostic when we start
-// generating code.
+void g();
 
-int SaveDiv(int numerator, int denominator, int *res) {
+//////////////////////////////////////////////////////////////////////////////
+// __leave with __except
+
+// Nothing in the __try block can trap, so __try.cont isn't created.
+int __leave_with___except_simple() {
   int myres = 0;
   __try {
-    myres = numerator / denominator;
+    myres = 15;
     __leave;
+    myres = 23;
   } __except (1) {
     return 0;
   }
-  *res = myres;
   return 1;
 }
-// CHECK-NOT: error:
-// CHECK: error: cannot compile this SEH __leave yet
-// CHECK-NOT: error:
+// CHECK-LABEL: define i32 @__leave_with___except_simple()
+// CHECK: store i32 15, i32* %myres
+// CHECK-NEXT: br label %__try.__leave
+// CHECK-NOT: store i32 23
+// CHECK: __try.__leave:
+// CHECK-NEXT: ret i32 1
+
+
+// The "normal" case.
+int __leave_with___except() {
+  int myres = 0;
+  __try {
+    g();
+    __leave;
+    myres = 23;
+  } __except (1) {
+    return 0;
+  }
+  return 1;
+}
+// CHECK-LABEL: define i32 @__leave_with___except()
+// CHECK: invoke void bitcast (void (...)* @g to void ()*)()
+// CHECK-NEXT:       to label %[[cont:.*]] unwind label %{{.*}}
+// For __excepts, instead of an explicit __try.__leave label, we could use
+// use invoke.cont as __leave jump target instead.  However, not doing this
+// keeps the CodeGen code simpler, __leave is very rare, and SimplifyCFG will
+// simplify this anyways.
+// CHECK: [[cont]]
+// CHECK-NEXT: br label %__try.__leave
+// CHECK-NOT: store i32 23
+// CHECK: __try.__leave:
+// CHECK-NEXT: br label %__try.cont
+
+
+//////////////////////////////////////////////////////////////////////////////
+// __leave with __finally
+
+void abort(void) __attribute__((noreturn));
+
+// Nothing in the __try block can trap, so __finally.cont and friends aren't
+// created.
+int __leave_with___finally_simple() {
+  int myres = 0;
+  __try {
+    myres = 15;
+    __leave;
+    myres = 23;
+  } __finally {
+    return 0;
+  }
+  return 1;
+}
+// CHECK-LABEL: define i32 @__leave_with___finally_simple()
+// CHECK: store i32 15, i32* %myres
+// CHECK-NEXT: br label %__try.__leave
+// CHECK-NOT: store i32 23
+// CHECK: __try.__leave:
+// CHECK-NEXT: store i8 0, i8* %abnormal.termination.slot
+// CHECK-NEXT: br label %__finally
+
+// __finally block doesn't return, __finally.cont doesn't exist.
+int __leave_with___finally_noreturn() {
+  int myres = 0;
+  __try {
+    myres = 15;
+    __leave;
+    myres = 23;
+  } __finally {
+    abort();
+  }
+  return 1;
+}
+// CHECK-LABEL: define i32 @__leave_with___finally_noreturn()
+// CHECK: store i32 15, i32* %myres
+// CHECK-NEXT: br label %__try.__leave
+// CHECK-NOT: store i32 23
+// CHECK: __try.__leave:
+// CHECK-NEXT: store i8 0, i8* %abnormal.termination.slot
+// CHECK-NEXT: br label %__finally
+
+// The "normal" case.
+int __leave_with___finally() {
+  int myres = 0;
+  __try {
+    g();
+    __leave;
+    myres = 23;
+  } __finally {
+    return 0;
+  }
+  return 1;
+}
+// CHECK-LABEL: define i32 @__leave_with___finally()
+// CHECK: invoke void bitcast (void (...)* @g to void ()*)()
+// CHECK-NEXT:       to label %[[cont:.*]] unwind label %{{.*}}
+// For __finally, there needs to be an explicit __try.__leave, because
+// abnormal.termination.slot needs to be set there.
+// CHECK: [[cont]]
+// CHECK-NEXT: br label %__try.__leave
+// CHECK-NOT: store i32 23
+// CHECK: __try.__leave:
+// CHECK-NEXT: store i8 0, i8* %abnormal.termination.slot
+// CHECK-NEXT: br label %__finally
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Mixed, nested cases.
+
+// FIXME: Test with outer __finally once PR22553 is fixed.
+
+int nested___except___finally() {
+  int myres = 0;
+  __try {
+    __try {
+      g();
+    } __finally {
+      g();
+      __leave;  // Refers to the outer __try, not the __finally!
+      myres = 23;
+      return 0;
+    }
+
+    myres = 51;
+  } __except (1) {
+  }
+  return 1;
+}
+// The order of basic blocks in the below doesn't matter.
+// CHECK-LABEL: define i32 @nested___except___finally()
+
+// CHECK-LABEL: invoke void bitcast (void (...)* @g to void ()*)()
+// CHECK-NEXT:       to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]]
+
+// CHECK: [[g1_cont]]:
+// CHECK-NEXT: store i8 0, i8* %abnormal.termination.slot
+// CHECK-NEXT: br label %__finally
+
+// CHECK-LABEL: __finally:
+// CHECK-NEXT: invoke void bitcast (void (...)* @g to void ()*)() #3
+// CHECK-NEXT:       to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]]
+
+// CHECK: [[g2_cont]]:
+// CHECK-NOT: store i32 23
+// CHECK: br label %__try.__leave
+
+// CHECK: [[g1_lpad]]:
+// CHECK: store i8 1, i8* %abnormal.termination.slot
+// CHECK-NEXT:  br label %__finally
+
+// CHECK: [[g2_lpad]]:
+// CHECK-NOT: %abnormal.termination.slot
+// CHECK: br label %__except
+
+// CHECK-LABEL: __except:
+// CHECK-NEXT: br label %__try.cont
+
+// CHECK-LABEL: __try.__leave:
+// CHECK-NEXT: br label %__try.cont
+
+int nested___except___except() {
+  int myres = 0;
+  __try {
+    __try {
+      g();
+      myres = 16;
+    } __except (1) {
+      g();
+      __leave;  // Refers to the outer __try, not the __except we're in!
+      myres = 23;
+      return 0;
+    }
+
+    myres = 51;
+  } __except (1) {
+  }
+  return 1;
+}
+// The order of basic blocks in the below doesn't matter.
+// CHECK-LABEL: define i32 @nested___except___except()
+
+// CHECK-LABEL: invoke void bitcast (void (...)* @g to void ()*)()
+// CHECK-NEXT:       to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]]
+
+// CHECK: [[g1_cont]]:
+// CHECK: store i32 16, i32* %myres
+// CHECK-NEXT: br label %__try.cont
+
+// CHECK: [[g1_lpad]]:
+// CHECK:  br label %__except
+
+// CHECK-LABEL: __except:
+// CHECK-NEXT: invoke void bitcast (void (...)* @g to void ()*)() #3
+// CHECK-NEXT:       to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]]
+
+// CHECK: [[g2_cont]]:
+// CHECK-NOT: store i32 23
+// CHECK: br label %__try.__leave
+
+// CHECK: [[g2_lpad]]:
+// CHECK: br label %__except3
+
+// CHECK-LABEL: __except3:
+// CHECK-NEXT: br label %__try.cont4
+
+// CHECK-LABEL: __try.cont:
+// CHECK-NEXT: store i32 51, i32* %myres
+// CHECK-NEXT: br label %__try.__leave
+
+// CHECK-LABEL: __try.__leave:
+// CHECK-NEXT: br label %__try.cont4





More information about the cfe-commits mailing list