On Nov 28, 2007, at 15:18, Chris Lattner wrote:> On Tue, 27 Nov 2007, Gordon Henriksen wrote: >> > >> The codegen for raise is simple. It just reads a saved return >> address from the caml_exception_pointer global and returns through >> several stack frames in one go. > > Nice.Yup.>> The try-with expression is where the trickery lies. The expression >> try body with pattern1 -> catch1 | patternN -> catchN is compiled to: > > This seems pretty straight-forward to normal landing pads.Certainly the primitives are more or less identical to LLVM's. There is a strict stack of handlers, though, and I'm not sure how easy that is to reconstruct.> The only significant difference is how it dynamically registers the > callback and how it continues unwinding.I thought the implications with respect to frame object displacements seemed rather invasive. Within the try block, frame offsets are progressively increased with each level of nesting.> If you were interested in adding this to llvm as some new EH > intrinsics, I wouldn't be opposed to that.Okay. I imagine the SJLJ EH would be a good place to start poking around if I were to give it a shot?> It's basically a form of sjlj exceptions.Right.> It only works if values are not held in registers across throws > though, which is kinda lame ...Though I'm primarily interested in this model only from an interoperability perspective, reloading the register file for a throw seems a comparatively small price to pay compared to, say, symbolically unwinding the stack. :) More importantly, the common case through code does not require a register file save/restore. — Gordon
On Nov 28, 2007, at 10:16 PM, Gordon Henriksen wrote:>> It only works if values are not held in registers across throws >> though, which is kinda lame ... > > > Though I'm primarily interested in this model only from an > interoperability perspective, reloading the register file for a throw > seems a comparatively small price to pay compared to, say, > symbolically unwinding the stack. :) More importantly, the common case > through code does not require a register file save/restore.The issue is in the non-throw case. Consider a function like this: int x = ... try { x++; foo(); use (x); } catch (...) { print x; } Because the 'throw' doesn't restore the callee-save registers as the stack is unwound, the compiler can't put X in a register across the x+ + and use of x in the try block. -Chris
On Nov 29, 2007, at 01:24, Chris Lattner wrote:> On Nov 28, 2007, at 10:16 PM, Gordon Henriksen wrote: > >>> It only works if values are not held in registers across throws >>> though, which is kinda lame ... >> >> Though I'm primarily interested in this model only from an >> interoperability perspective, reloading the register file for a >> throw seems a comparatively small price to pay compared to, say, >> symbolically unwinding the stack. :) More importantly, the common >> case through code does not require a register file save/restore. > > The issue is in the non-throw case. Consider a function like this: > > int x = ... > try { > x++; > foo(); > > use (x); > > } catch (...) { > print x; > } > > Because the 'throw' doesn't restore the callee-save registers as the > stack is unwound, the compiler can't put X in a register across the x > ++ and use of x in the try block.Okay; didn't see that interaction. I'll scrutinize the codegen more closely for this stuff before proceeding. I didn't apply any register pressure in my example cases. — Gordon
On Nov 29, 2007, at 1:24, Chris Lattner <sabre at nondot.org> wrote:> int x = ... > try { > x++; > foo(); > > use (x); > > } catch (...) { > print x; > } > > Because the 'throw' doesn't restore the callee-save registers as the > stack is unwound, the compiler can't put X in a register across the x+ > + and use of x in the try block.Actually, this is difficult to reproduce in Ocaml codes because Ocaml code is in a restricted SSA form: (1) Mutable variables exist only in the heap: let x = 43 ref is literally shorthand for let x = { mutable contents = 43 }, which allocates a single-cell object on the heap. Arrays and strings (also imperative) are also restricted to the heap. (2) Loop index variables from the for expression cannot escape. Still, it could be significant after LLVM transformations. -- Gordon