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