Bill Wendling
2011-Sep-27 11:10 UTC
[LLVMdev] How to code catch-all in the new exception handling scheme?
On Sep 25, 2011, at 1:02 AM, Duncan Sands wrote:> Hi Talin, > >> I'm looking at the docs, and while it refers to a "catch-all" clause, > > hopefully Bill will get rid of the first reference to "catch-all" since > that section is inaccurate. >I *think* this is now correct. Please check. :)> it doesn't >> describe how to construct one. > > There is in general no such thing as a catch-all: it depends on the personality > function (i.e. the language), and, for example, the Ada language doesn't have > one (it has something that catches all Ada exceptions, but it won't catch C++ > exceptions). >This is true in a sense that a catch-all is encoded the same way as any other catch type. So for C++, you would specify a catch-all like this: %exn = landingpad { i8*, i32 } personality i32 (...)* __gxx_personality_v0 catch i8* @_ZTIi catch i8* null A 'null' value is C++'s way of saying "this is a catch-all". Ada uses a global variable (function?) for this. To the new EH scheme, they are indistinguishable from a "normal" catch.> To get a cleanup add the "cleanup" flag to the landingpad instruction. That > said, I'm ruminating on whether the cleanup flag should be removed: instead > there would always be an implicit cleanup. As an optimization, the code > generators would not output a cleanup into the exception handling tables if > no useful code is executed when the cleanup is run. This seems to be what > recent versions of GCC do. >I'm not a big fan of implicit behavior. :) And it requires an optimization to "cleanup" (yeah, a pun...sue me) the extraneous code we generate, which won't happen at -O0 (right?). Though the optimization you mentioned here would be a nice thing to have with our current scheme. -bw
Duncan Sands
2011-Sep-27 11:58 UTC
[LLVMdev] How to code catch-all in the new exception handling scheme?
Hi Bill,>>> I'm looking at the docs, and while it refers to a "catch-all" clause, >> >> hopefully Bill will get rid of the first reference to "catch-all" since >> that section is inaccurate. >> > I *think* this is now correct. Please check. :)I still have some niggles: The unwinder delegates the decision of whether to stop in a call frame to that call frame's language-specific personality function. Not all personality functions guarantee that they will stop to perform cleanups. This is incorrect: it is not the personality function that makes the decision, it is who-ever is doing the unwinding. For example if you use the Ada "throw" method it will always run all C++ cleanups, even if that's all there is to do. While if you use the C++ throw method it won't bother running Ada cleanups if that is all there is to do. All personality functions that I am familiar with treat cleanups in the same way. For example, the GNU C++ personality function doesn't do so unless the exception is actually caught somewhere further up the stack. As mentioned above, this has nothing to do with the personality function. When using this personality to implement EH for a language that guarantees that cleanups will always be run (e.g. Ada), be sure to indicate a catch-all in the landingpad instruction rather than just cleanups. I suggest you just delete this last bit. This isn't how Ada does it itself for example.> >> it doesn't >>> describe how to construct one. >> >> There is in general no such thing as a catch-all: it depends on the personality >> function (i.e. the language), and, for example, the Ada language doesn't have >> one (it has something that catches all Ada exceptions, but it won't catch C++ >> exceptions). >> > This is true in a sense that a catch-all is encoded the same way as any other catch type. So for C++, you would specify a catch-all like this: > > %exn = landingpad { i8*, i32 } personality i32 (...)* __gxx_personality_v0 > catch i8* @_ZTIi > catch i8* null > > A 'null' value is C++'s way of saying "this is a catch-all". Ada uses a global variable (function?) for this.Yes, Ada has a global variable that plays this role. However calling it "catch-all" is misleading since it doesn't match any C++ exceptions (unlike the C++ catch-all which also matches foreign exceptions). This means that the old exception handling scheme wouldn't always work properly if C++ code was inlined into Ada code. Not a big deal since it wouldn't work properly anyway for all kinds of other reasons (eg: multiple personality functions in the same function). To the new EH scheme, they are indistinguishable from a "normal" catch.> >> To get a cleanup add the "cleanup" flag to the landingpad instruction. That >> said, I'm ruminating on whether the cleanup flag should be removed: instead >> there would always be an implicit cleanup. As an optimization, the code >> generators would not output a cleanup into the exception handling tables if >> no useful code is executed when the cleanup is run. This seems to be what >> recent versions of GCC do. >> > I'm not a big fan of implicit behavior. :)It would be explicitly documented, so then it wouldn't be implicit! In fact it would mean that "invoke" has the traditional LLVM semantics: if an exception is unwound then control branches to the landing pad. With the new scheme that is currently no longer so - meaning that some of the PruneEH logic is currently wrong :) That said, I'm also a bit dubious about this "always has a cleanup" idea. And it requires an optimization to "cleanup" (yeah, a pun...sue me) the extraneous code we generate, which won't happen at -O0 (right?). The only effect of this optimization would be to not output a cleanup entry (0) in the action table if its not needed. That's pretty mild, and at -O0 who cares if there are some pointless but harmless (except for slowing down unwinding) cleanup entries in the action table? I'm not sure what you mean by "the extraneous code we generate". Though the optimization you mentioned here would be a nice thing to have with our current scheme. My plan is to implement the optimization (clearing of the cleanup flag on the landingpad instruction) at the IR level as a warm-up. If it seems like a good idea to eliminate the cleanup flag from the definition of landingpad instruction then the logic can be moved to a codegen analysis instead, and used to see if we can avoid adding a cleanup entry to the landing pad table. Note that I already implemented the optimization that if all a landing pad does is call "resume", then the invoke+landingpad is removed in favour of a call, in case that is what you are thinking of. Ciao, Duncan.
Garrison Venn
2011-Sep-27 18:38 UTC
[LLVMdev] How to code catch-all in the new exception handling scheme?
Hi Duncan, On Sep 27, 2011, at 7:58, Duncan Sands wrote:> Hi Bill, > >>>> I'm looking at the docs, and while it refers to a "catch-all" clause, >>> >>> hopefully Bill will get rid of the first reference to "catch-all" since >>> that section is inaccurate. >>> >> I *think* this is now correct. Please check. :) > > I still have some niggles: > > The unwinder delegates the decision of whether to stop in a call frame to > that call frame's language-specific personality function. Not all personality > functions guarantee that they will stop to perform cleanups. > > This is incorrect: it is not the personality function that makes the decision, > it is who-ever is doing the unwinding. For example if you use the Ada "throw" > method it will always run all C++ cleanups, even if that's all there is to do. > While if you use the C++ throw method it won't bother running Ada cleanups if > that is all there is to do. All personality functions that I am familiar with > treat cleanups in the same way.How does one incorporate their own LLVM backend unwinding mechanism? I'm assuming that you have an Ada backend. Does your backend not call _Unwind_RaiseException for example? [snip] ...> Ciao, Duncan. > _______________________________________________ > LLVM Developers mailing list > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdevThanks in advance Garrison
Bill Wendling
2011-Sep-27 20:18 UTC
[LLVMdev] How to code catch-all in the new exception handling scheme?
On Sep 27, 2011, at 4:58 AM, Duncan Sands wrote:> Hi Bill, > >>>> I'm looking at the docs, and while it refers to a "catch-all" clause, >>> >>> hopefully Bill will get rid of the first reference to "catch-all" since >>> that section is inaccurate. >>> >> I *think* this is now correct. Please check. :) > > I still have some niggles: > > The unwinder delegates the decision of whether to stop in a call frame to > that call frame's language-specific personality function. Not all personality > functions guarantee that they will stop to perform cleanups. > > This is incorrect: it is not the personality function that makes the decision, > it is who-ever is doing the unwinding. For example if you use the Ada "throw" > method it will always run all C++ cleanups, even if that's all there is to do. > While if you use the C++ throw method it won't bother running Ada cleanups if > that is all there is to do. All personality functions that I am familiar with > treat cleanups in the same way. >Wait...the personality function is the bit of code that finds the handler and tells the unwinder about it. The unwinder, at least the C++ unwinder, calls the personality function in phase 2 telling it that it's in the "cleanup" phase. If it's not at the handler frame, then the personality will install the context and switch to that landing pad. The Ada unwinder (at least in 4.2) is much simpler, and will install the context in phase 2 if it finds anything that it should execute. In your example, the C++ personality function doesn't know about Ada exceptions. All it knows is that there are no catches for the exception, and thus calls terminate on its own. I don't know about Ada, but perhaps it lies to the C++ personality and tells it that there is a handler above it?> For example, the GNU C++ personality function doesn't do so unless the > exception is actually caught somewhere further up the stack. > > As mentioned above, this has nothing to do with the personality function. > > When using this personality to implement EH for a language that guarantees > that cleanups will always be run (e.g. Ada), be sure to indicate a catch-all > in the landingpad instruction rather than just cleanups. > > I suggest you just delete this last bit. This isn't how Ada does it itself for > example. >Sure.>>> To get a cleanup add the "cleanup" flag to the landingpad instruction. That >>> said, I'm ruminating on whether the cleanup flag should be removed: instead >>> there would always be an implicit cleanup. As an optimization, the code >>> generators would not output a cleanup into the exception handling tables if >>> no useful code is executed when the cleanup is run. This seems to be what >>> recent versions of GCC do. >>> >> I'm not a big fan of implicit behavior. :) > > It would be explicitly documented, so then it wouldn't be implicit! In fact > it would mean that "invoke" has the traditional LLVM semantics: if an exception > is unwound then control branches to the landing pad. With the new scheme that > is currently no longer so - meaning that some of the PruneEH logic is currently > wrong :) That said, I'm also a bit dubious about this "always has a cleanup" > idea. >The traditional LLVM semantics of exception handling were broken. I don't want to go back to them. :-)> And it requires an optimization to "cleanup" (yeah, a pun...sue me) the extraneous code we generate, which won't happen at -O0 (right?). > > The only effect of this optimization would be to not output a cleanup entry (0) > in the action table if its not needed. That's pretty mild, and at -O0 who cares > if there are some pointless but harmless (except for slowing down unwinding) > cleanup entries in the action table? I'm not sure what you mean by "the > extraneous code we generate". >Extra entries in the tables when we don't need them. Possibly slowing down unwinding because it's stopping at functions which have no cleanups and don't catch. Even at O0 we don't want to penalize people.> Though the optimization you mentioned here would be a nice thing to have with our current scheme. > > My plan is to implement the optimization (clearing of the cleanup flag on the > landingpad instruction) at the IR level as a warm-up. If it seems like a good > idea to eliminate the cleanup flag from the definition of landingpad instruction > then the logic can be moved to a codegen analysis instead, and used to see if > we can avoid adding a cleanup entry to the landing pad table. Note that I > already implemented the optimization that if all a landing pad does is call > "resume", then the invoke+landingpad is removed in favour of a call, in case > that is what you are thinking of. >
Reasonably Related Threads
- [LLVMdev] How to code catch-all in the new exception handling scheme?
- [LLVMdev] How to code catch-all in the new exception handling scheme?
- [LLVMdev] How to code catch-all in the new exception handling scheme?
- [LLVMdev] How to code catch-all in the new exception handling scheme?
- [LLVMdev] How to code catch-all in the new exception handling scheme?