No outlining is necessary for SEH catch blocks. Use the blockaddr of the
handler in place of the usual outlined function.
Details
Diff Detail
Event Timeline
lib/CodeGen/WinEHPrepare.cpp | ||
---|---|---|
94 | We should probably add comments to say which of these fields (I guess all of them currently) are reset with each Function the pass is run on. | |
465 | What exactly does this do? I've seen some cases recently where cleanup outlining is choking because of PHINodes that are referring to the return value of the landingpad instruction. This is too late to handle that (which just needs a few more VMap entries before outlining) but it raises the question in my mind of general handling of PHINodes which use values that are being erased from the original landing pads here. I think that all of the code in question will be pruned as part of what we're doing here (it was resume blocks using either the landingpad value or values extracted from it). I'm just raising the issue to see if you can think of anything else that might have a similar issue. | |
474 | This should be 1 according to your recent documentation. | |
482 | This should be 0. | |
728 | In the case of "__except(EXCEPTION_EXECUTE_HANDLER)" I'm seeing the landing pad branch unconditionally to the catch handler. |
I'm going to take a shot at using StartBB instead of using HandlerBB like I did in this patch.
lib/CodeGen/WinEHPrepare.cpp | ||
---|---|---|
94 | Yeah, all of em. :) | |
465 | I was trying to handle except_phi test case: define i32 @except_phi() { entry: invoke void @might_crash() to label %return unwind label %lpad lpad: %ehvals = landingpad { i8*, i32 } personality i32 (...)* @__C_specific_handler catch i32 ()* @filt %sel = extractvalue { i8*, i32 } %ehvals, 1 %filt_sel = tail call i32 @llvm.eh.typeid.for(i8* bitcast (i32 ()* @filt to i8*)) %matches = icmp eq i32 %sel, %filt_sel br i1 %matches, label %return, label %eh.resume return: %r = phi i32 [0, %entry], [1, %lpad] ret i32 %r eh.resume: resume { i8*, i32 } %ehvals } I needed to update the %r phi node. Maybe what I should do instead is split the landingpad block directly, because we might have this kind of code: define i32 @except_phi(i32 %a) { entry: invoke void @might_crash() to label %return unwind label %lpad lpad: %ehvals = landingpad { i8*, i32 } personality i32 (...)* @__C_specific_handler catch i32 ()* @filt %sel = extractvalue { i8*, i32 } %ehvals, 1 %a1 = add i32 %a, 1 ; live SSA value will become unreachable. %filt_sel = tail call i32 @llvm.eh.typeid.for(i8* bitcast (i32 ()* @filt to i8*)) %matches = icmp eq i32 %sel, %filt_sel br i1 %matches, label %return, label %eh.resume return: %r = phi i32 [%a, %entry], [%a1, %lpad] ret i32 %r eh.resume: resume { i8*, i32 } %ehvals } The pass as is will probably crash. I'm OK with that for now, honestly. | |
474 | I'd rather make that a separate change. | |
728 | Right, any catch-all block will ignore the selector and unconditionally branch into the recovery. I haven't handled that yet. I think a better approach might be to keep StartBB and simply discard all EH related instructions. This would also fix the phi case. |
I added support for catch-all, but I didn't end up handling the case where the catch BB contains interesting code. My reasoning was that EH preparation should be identifying that as a cleanup, and we'll need to do something to handle it for C++.
I see just one problem with this.
llvm/trunk/lib/CodeGen/WinEHPrepare.cpp | ||
---|---|---|
1194 ↗ | (On Diff #22206) | This is wrong for the C++ EH case, which can have cleanup code to be executed after a catch-all handler. Setting BB to NULL will prevent use from finding the cleanup in that scenario. |
llvm/trunk/lib/CodeGen/WinEHPrepare.cpp | ||
---|---|---|
1194 ↗ | (On Diff #22206) | Can you elaborate? Is this a cleanup inside the catch, or outside the catch? I don't think it's possible to have exceptional cleanups after a catchall: void f() { HasDtor o; try { g(); } catch (...) { g(); } } |
Actually, I think I was wrong about the clean-up after catch-all. I thought I had a case that would do it, but it doesn't and I think I've convinced myself that it can't happen.
We should probably add comments to say which of these fields (I guess all of them currently) are reset with each Function the pass is run on.