AmrDeveloper wrote:
> I apologize for not having raised this issue sooner, but I'm not sure how
> well our current set of instructions will lend itself to Windows support.
> Take a simple case like this:
>
> ```
> int bar() {
> int ret = 0;
> try {
> foo();
> } catch (int n) {
> ret = n;
> }
> return ret;
> }
> ```
>
> We'll generate a catch region that looks something like this in CIR after
> flattening:
>
> ```
> ^bb4: // pred: ^bb2
> %exception_ptr, %type_id = cir.eh.inflight_exception [@_ZTIi]
> cir.br ^bb5(%exception_ptr, %type_id : !cir.ptr<!void>, !u32i)
> ^bb5(%4: !cir.ptr<!void>, %5: !u32i): // pred: ^bb4
> %6 = cir.eh.typeid @_ZTIi
> %7 = cir.cmp(eq, %5, %6) : !u32i, !cir.bool
> cir.brcond %7 ^bb6(%4 : !cir.ptr<!void>), ^bb7(%4, %5 : !cir.ptr<!void>,
> !u32i)
> ^bb6(%8: !cir.ptr<!void>): // pred: ^bb5
> %9 = cir.catch_param.flat begin %8 -> !cir.ptr<!s32i>
> %10 = cir.load align(4) %9 : !cir.ptr<!s32i>, !s32i
> cir.store align(4) %10, %0 : !s32i, !cir.ptr<!s32i>
> %11 = cir.load align(4) %0 : !cir.ptr<!s32i>, !s32i
> cir.store align(4) %11, %2 : !s32i, !cir.ptr<!s32i>
> cir.catch_param.flat end
> cir.br ^bb8
> ^bb7(%12: !cir.ptr<!void>, %13: !u32i): // pred: ^bb5
> cir.resume.flat %12, %13
> ```
>
> On Linux, we need that to result in LLVM IR that looks like this:
>
> ```
> 7:
> %8 = landingpad { ptr, i32 }
> catch ptr @_ZTIi, !dbg !15
> %9 = extractvalue { ptr, i32 } %8, 0
> %10 = extractvalue { ptr, i32 } %8, 1
> br label %11
>
> 11:
> %12 = phi ptr [ %9, %7 ]
> %13 = phi i32 [ %10, %7 ]
> %14 = call i32 @llvm.eh.typeid.for.p0(ptr @_ZTIi)
> %15 = icmp eq i32 %13, %14
> br i1 %15, label %16, label %21
>
> 16:
> %17 = phi ptr [ %12, %11 ]
> %18 = call ptr @__cxa_begin_catch(ptr %17)
> %19 = load i32, ptr %18
> store i32 %19, ptr %1
> %20 = load i32, ptr %1
> store i32 %20, ptr %3
> call void @__cxa_end_catch()
> br label %26
> ```
>
> So far, so good, because `cir.eh.inflight_exception` will get translated to
> the `landingpad` instruction, `cir.catch_param.flat begin` will get
> translated to `__cxa_begin_catch` and `cir.catch_param.flat end` will get
> translated to `__cxa_end_catch`.
>
> But on Windows, we need to be able to lower to LLVM IR that looks like this:
>
> ```
> catch.dispatch:
> %0 = catchswitch within none [label %catch] unwind to caller
>
> catch:
> %1 = catchpad within %0 [ptr @"??_R0H@8", i32 0, ptr %n]
> #dbg_declare(ptr %n, !20
> %2 = load i32, ptr %n
> store i32 %2, ptr %ret
> catchret from %1 to label %catchret.dest
>
> catchret.dest:
> br label %try.cont, !dbg !24
> ```
>
> At this point, I think it's clear that our CIR constructs are too closely
> tied to the Itanium exception handling ABI. The whole business with getting a
> type id as a return value from `cir.eh.inflight_exception` and comparing it
> the type id we're catching is an ABI-specific detail.
>
> We need to step back and redesign our operations to be more ABI-neutral. I
> propose the following (using the example above):
>
> ```
> ^bb4: // pred: ^bb2
> %eh_token = cir.eh.landingpad
> // Dispatch to handlers based on type id globals, with behavior similar
> to cir.switch.flat
> // ^bb7 is the default destination if none of our catch handler match
> cir.eh.dispatch %eh_token : !cir.eh_token, ^bb7 [
> @_ZTIi : ^bb6
> ]
> ^bb6(%8 : !cir.eh_token): // pred: ^bb5
> %catch_token, %exception_ptr = cir.begin_catch %8 -> !cir.ptr<!s32i>
> %10 = cir.load align(4) %exception_ptr : !cir.ptr<!s32i>, !s32i
> cir.store align(4) %10, %0 : !s32i, !cir.ptr<!s32i>
> %11 = cir.load align(4) %0 : !cir.ptr<!s32i>, !s32i
> cir.store align(4) %11, %2 : !s32i, !cir.ptr<!s32i>
> cir.end_catch_param %catch_token
> cir.br ^bb8
> ^bb7(%12: !cir.ptr<!void>, %13: !u32i): // pred: ^bb5
> cir.resume.flat %12, %13
> ```
>
> My thinking here is that `cir.eh.landingpad` would be expanded to a series of
> blocks containing `landingpad` and the subsequent branching for Itanium,
> while on Windows it would create a `cleanuppad` if necessary but otherwise
> would just be used to track the funclet token. Then `cir.eh.dispatch` would
> be lowered to the appropriate type id comparison and branches for Itanium or
> a `catchswitch` for Windows. Finally, `cir.begin_catch`/`cir.end_catch` lower
> to `__cxa_catch_begin`/`__cxa_end_catch` for Itanim and to
> `catchpad`/`catchret` for Windows.
>
> There's another complication on Windows when you have a try-block inside a
> catch because then we need to pass the funclet token through invoke
> instructions, but I think we can work out the details of that later. At this
> point, I just want to make sure we aren't going in a direction that won't
> work at all for Windows.
>
> @rnk did a lot of work on the existing exception handling and offered to help
> with reviews as we rework this, so I'm going to throw him in the deep end by
> asking for his input here. 😇
This is a very good point, and I think you mentioned it before that we need to
check about the catch param for windows, I will also check what the original
codegen does for windows to understand more :D
https://github.com/llvm/llvm-project/pull/172713
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits