[PATCH] D47988: [CodeGen] Emit MSVC funclet IR for Obj-C exceptions
smeenai added inline comments. Comment at: lib/CodeGen/CGCXXABI.h:248 +llvm_unreachable("Only needed for the Microsoft ABI"); + } rjmccall wrote: > Should you just generalize the existing method to only take a VarDecl* so it > can be used for either kind of catch? The Itanium version of emitBeginCatch actually uses the statement for location info (it calls `getLocStart` on it). I suppose I could generalize the existing method to take both a VarDecl* and a SourceLocation though. Repository: rC Clang https://reviews.llvm.org/D47988 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D47988: [CodeGen] Emit MSVC funclet IR for Obj-C exceptions
rjmccall added a comment. In https://reviews.llvm.org/D47988#1135929, @rnk wrote: > In https://reviews.llvm.org/D47988#1135533, @rjmccall wrote: > > > In general, it's unfortunate that this has to leave so many > > C++-runtime-specific tendrils in the ObjC code. Unlike the EH type patch, > > though, I'm not sure I can see a great alternative here, especially because > > of the semantic restrictions required by outlining. > > > It's technically possible to lift those restrictions by returning an i32 from > the outlined function and switching on it. Right? The question is, is it > worth it? The catch funclet would effectively store the i32 to the stack > frame, then "catchret" via the runtime, and then we'd switch out to the jump > target. I don't think it's important. Uses of control flow out of `@finally` are rare, and we could probably forbid it entirely without significant loss. Repository: rC Clang https://reviews.llvm.org/D47988 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D47988: [CodeGen] Emit MSVC funclet IR for Obj-C exceptions
rnk added a comment. In https://reviews.llvm.org/D47988#1135533, @rjmccall wrote: > In general, it's unfortunate that this has to leave so many > C++-runtime-specific tendrils in the ObjC code. Unlike the EH type patch, > though, I'm not sure I can see a great alternative here, especially because > of the semantic restrictions required by outlining. It's technically possible to lift those restrictions by returning an i32 from the outlined function and switching on it. Right? The question is, is it worth it? The catch funclet would effectively store the i32 to the stack frame, then "catchret" via the runtime, and then we'd switch out to the jump target. Repository: rC Clang https://reviews.llvm.org/D47988 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D47988: [CodeGen] Emit MSVC funclet IR for Obj-C exceptions
rjmccall added a comment. In general, it's unfortunate that this has to leave so many C++-runtime-specific tendrils in the ObjC code. Unlike the EH type patch, though, I'm not sure I can see a great alternative here, especially because of the semantic restrictions required by outlining. Comment at: lib/CodeGen/CGCXXABI.h:248 +llvm_unreachable("Only needed for the Microsoft ABI"); + } Should you just generalize the existing method to only take a VarDecl* so it can be used for either kind of catch? Repository: rC Clang https://reviews.llvm.org/D47988 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D47988: [CodeGen] Emit MSVC funclet IR for Obj-C exceptions
smeenai added a comment. Ping. Repository: rC Clang https://reviews.llvm.org/D47988 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D47988: [CodeGen] Emit MSVC funclet IR for Obj-C exceptions
rnk added a comment. In https://reviews.llvm.org/D47988#1127432, @smeenai wrote: > Any idea why we would see inlining in one case and not the other? i686 vs. > x86-64 doesn't make any difference, and neither does -Os vs. -O1 vs. -O2. My theory is that the inliner is attempting to avoid inlining on cold codepaths that are post-dominated by unreachable. When you put an outer try around it, the function may continue by unwinding, so the inline cost analysis gives different results. Of course, that's all just a wild guess. Repository: rC Clang https://reviews.llvm.org/D47988 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D47988: [CodeGen] Emit MSVC funclet IR for Obj-C exceptions
smeenai added a comment. @rnk remember how I was asking you about inlining into catchpads on IRC a few days back? It was in relation to this change. If I have a file `finally1.m`: void f(void); void g() { @try { f(); } @finally { f(); } } and compile it with: clang -cc1 -triple i686-windows-msvc -fobjc-runtime=ios-6.0 -fexceptions -fobjc-exceptions -Os -emit-llvm -o - finally1.m the @finally calls out to the captured statement instead of inlining it: finally.catchall: ; preds = %catch.dispatch %1 = catchpad within %0 [i8* null, i32 64, i8* null] call fastcc void @__captured_stmt() [ "funclet"(token %1) ] call void @_CxxThrowException(i8* null, %eh.ThrowInfo* null) #3 [ "funclet"(token %1) ] unreachable If I add an outer try-catch scope, as in `finally2.m`: void f(void); void g() { @try { @try { f(); } @finally { f(); } } @catch (...) { } } and run the same compilation command: clang -cc1 -triple i686-windows-msvc -fobjc-runtime=ios-6.0 -fexceptions -fobjc-exceptions -Os -emit-llvm -o - finally2.m the @finally inlines the captured statement: finally.catchall: ; preds = %catch.dispatch %2 = catchpad within %0 [i8* null, i32 64, i8* null] invoke void @f() #2 [ "funclet"(token %2) ] to label %invoke.cont1 unwind label %catch.dispatch4 invoke.cont1: ; preds = %finally.catchall invoke void @_CxxThrowException(i8* null, %eh.ThrowInfo* null) #3 [ "funclet"(token %2) ] to label %unreachable unwind label %catch.dispatch4 Any idea why we would see inlining in one case and not the other? i686 vs. x86-64 doesn't make any difference, and neither does -Os vs. -O1 vs. -O2. Repository: rC Clang https://reviews.llvm.org/D47988 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D47988: [CodeGen] Emit MSVC funclet IR for Obj-C exceptions
smeenai created this revision. smeenai added reviewers: DHowett-MSFT, compnerd, majnemer, rjmccall, rnk. We're implementing funclet-compatible code generation for Obj-C exceptions when using the MSVC ABI. The idea is that the Obj-C runtime will wrap Obj-C exceptions inside C++ exceptions, which allows for interoperability with C++ exceptions (for Obj-C++) and zero-cost exceptions. This is the approach taken by e.g. WinObjC, and I believe it to be the best approach for Obj-C exceptions in the MSVC ABI. This change implements emitting the actual funclet-compatible IR. The generic exceptions codegen already takes care of emitting the proper catch dispatch structures, but we need to ensure proper handling of catch parameters and scoping (emitting the catchret). Finally blocks are handled quite differently from Itanium; they're expected to be outlined by the frontend, which limits some control flow possibilities but also greatly simplifies their codegen. See r334251 for further discussion of why frontend outlining is used. Worked on with Saleem Abdulrasool . Repository: rC Clang https://reviews.llvm.org/D47988 Files: lib/CodeGen/CGCXXABI.h lib/CodeGen/CGException.cpp lib/CodeGen/CGObjCGNU.cpp lib/CodeGen/CGObjCMac.cpp lib/CodeGen/CGObjCRuntime.cpp lib/CodeGen/CGStmt.cpp lib/CodeGen/CodeGenFunction.h lib/CodeGen/MicrosoftCXXABI.cpp test/CodeGenObjC/catch-lexical-block.m test/CodeGenObjC/exceptions-msvc.m Index: test/CodeGenObjC/exceptions-msvc.m === --- test/CodeGenObjC/exceptions-msvc.m +++ test/CodeGenObjC/exceptions-msvc.m @@ -1,7 +1,7 @@ -// RUN: %clang_cc1 -triple i686--windows-msvc -fobjc-runtime=ios-6.0 -fdeclspec -fexceptions -fobjc-exceptions -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK,X86 %s -// RUN: %clang_cc1 -triple i686--windows-msvc -fobjc-runtime=ios-6.0 -fobjc-arc -fdeclspec -fexceptions -fobjc-exceptions -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK,X86 %s -// RUN: %clang_cc1 -triple x86_64--windows-msvc -fobjc-runtime=ios-6.0 -fdeclspec -fexceptions -fobjc-exceptions -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK,X64 %s -// RUN: %clang_cc1 -triple x86_64--windows-msvc -fobjc-runtime=ios-6.0 -fobjc-arc -fdeclspec -fexceptions -fobjc-exceptions -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK,X64 %s +// RUN: %clang_cc1 -triple i686--windows-msvc -fobjc-runtime=ios-6.0 -fdeclspec -fexceptions -fobjc-exceptions -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK,X86 --enable-var-scope %s +// RUN: %clang_cc1 -triple i686--windows-msvc -fobjc-runtime=ios-6.0 -fobjc-arc -fdeclspec -fexceptions -fobjc-exceptions -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK,X86,ARC --enable-var-scope %s +// RUN: %clang_cc1 -triple x86_64--windows-msvc -fobjc-runtime=ios-6.0 -fdeclspec -fexceptions -fobjc-exceptions -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK,X64 --enable-var-scope %s +// RUN: %clang_cc1 -triple x86_64--windows-msvc -fobjc-runtime=ios-6.0 -fobjc-arc -fdeclspec -fexceptions -fobjc-exceptions -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK,X64,ARC --enable-var-scope %s #if __has_feature(objc_arc) #define WEAK __weak @@ -67,8 +67,9 @@ @protocol P; void f(void); +void __declspec(nothrow) g(void); -void g() { +void generate_ehtypes() { @try { f(); } @catch (I *) { @@ -79,3 +80,393 @@ } @catch (id) { } } + +void basic_try_catch_1() { + @try { +f(); + } @catch (...) { +g(); + } +} + +// CHECK-LABEL: define {{.*}}void @basic_try_catch_1(){{.*}} { +// CHECK-NEXT: entry: +// CHECK-NEXT:invoke void @f() +// CHECK-NEXT:to label %[[INVOKECONT:[^ ]+]] unwind label %[[DISPATCH:[^ ]+]] +// CHECK: [[DISPATCH]]: +// CHECK-NEXT:%[[CATCHSWITCH:[^ ]+]] = catchswitch within none [label %[[CATCH:[^ ]+]]] unwind to caller +// CHECK: [[INVOKECONT]]: +// CHECK-NEXT:br label %[[EHCONT:[^ ]+]] +// CHECK: [[EHCONT]]: +// CHECK-NEXT:ret void +// CHECK: [[CATCH]]: +// CHECK-NEXT:%[[CATCHPAD:[^ ]+]] = catchpad within %[[CATCHSWITCH]] [i8* null, i32 64, i8* null] +// CHECK-NEXT:call void @g(){{.*}} [ "funclet"(token %[[CATCHPAD]]) ] +// CHECK-NEXT:catchret from %[[CATCHPAD]] to label %[[CATCHRETDEST:[^ ]+]] +// CHECK: [[CATCHRETDEST]]: +// CHECK-NEXT:br label %[[EHCONT]] +// CHECK-NEXT: } + +void basic_try_catch_2() { + @try { +f(); + } @catch (id) { +g(); + } +} + +// CHECK-LABEL: define {{.*}}void @basic_try_catch_2(){{.*}} { +// CHECK-NEXT: entry: +// CHECK-NEXT:invoke void @f() +// CHECK-NEXT:to label %[[INVOKECONT:[^ ]+]] unwind label %[[DISPATCH:[^ ]+]] +// CHECK: [[DISPATCH]]: +// CHECK-NEXT:%[[CATCHSWITCH:[^ ]+]] = catchswitch within none [label %[[CATCH:[^ ]+]]] unwind to caller +// CHECK: [[INVOKECONT]]: +// CHECK-NEXT:br label %[[EHCONT:[^ ]+]] +// CHECK: [[EHCONT]]: +// CHECK-NEXT:ret void +// CHECK: