Currently it states in the language manual that the results of division by zero are undefined. However, I'm curious as to how you would normally handle either divide by zero or other "hardware" exceptions (null pointer dereference and so on) and turn them into LLVM exceptions. It seems to me that you would need some way to set up the unwind labels beforehand, just like you do for the invoke instruction. For the specific case of divide by zero, I can imagine an optional unwind label parameter for the divide instruction, however that won't work too well for other kinds of exceptions since any load or store instruction could potentially produce them. I would think that you would want some means to declare a trap handler (possibly via an intrinsic) that says "execute this function if a hardware exception occurs". The trap handler would be responsible for doing the appropriate unwind instruction or other cleanup. You could either define some standard constants representing different exception types, or have a different trap handler function for each known type (illegal address, divide by zero, etc.) This assumes of course that the lowered form of 'unwind' will be able to thread its way through a stack frame that was interrupted in the middle of an operation. If the trap occurred inside non-LLVM-generated code, for example, I imagine it might be difficult to get the frame address of the innermost enclosing LLVM-generated stack frame. -- Talin
Talin wrote:> Currently it states in the language manual that the results of division > by zero are undefined. However, I'm curious as to how you would normally > handle either divide by zero or other "hardware" exceptions (null > pointer dereference and so on) and turn them into LLVM exceptions.Ultimately, what we'd like to do is attach a bit to each instruction which specifies whether it may trap. If something happens (like an invalid pointer dereference or divide by zero), it would have to become an LLVM 'exception' if the bit is true, or else execute undefined behaviour. The goal being to allow language frontends that want to trap (like Java) to set the bit, and others (like C) can clear it on all instructions and never pay any performance penalty. http://nondot.org/sabre/LLVMNotes/ExceptionHandlingChanges.txt> It seems to me that you would need some way to set up the unwind labels > beforehand, just like you do for the invoke instruction. For the > specific case of divide by zero, I can imagine an optional unwind label > parameter for the divide instruction, however that won't work too well > for other kinds of exceptions since any load or store instruction could > potentially produce them.The major problem is how you define "dominance" once you've modified the concept of a basic block to allow edges coming out the middle instead of the bottom. We've had an extensive thread on this in the past where the consensus was: * given a block A with an 'unwinds to' label to B: - A is a predecessor to B (B is a successor of A) - for the dominator tree, A and B are treated as if they shared the same predecessor. * we permit 'unwinds to' on the entry block, even though this means that there is no singular dominator root to the function. The domtree calculations already support this, though it means that you can't just add an AllocaInst to the entry block and the load/store it in any arbitrary block in the problem (if it were only reachable from the 'unwinds to' edge of the entry block). There already exists a branch where this work is in progress, named "llvm-non-call-eh". I haven't been able to give it as much attention as it deserves, and would appreciate any help working on it. Nick Lewycky
On May 8, 2008, at 9:35 PM, Nick Lewycky wrote:> Talin wrote: >> Currently it states in the language manual that the results of >> division >> by zero are undefined. However, I'm curious as to how you would >> normally >> handle either divide by zero or other "hardware" exceptions (null >> pointer dereference and so on) and turn them into LLVM exceptions. > > Ultimately, what we'd like to do is attach a bit to each instruction > which specifies whether it may trap. If something happens (like an > invalid pointer dereference or divide by zero), it would have to > become > an LLVM 'exception' if the bit is true, or else execute undefined > behaviour. The goal being to allow language frontends that want to > trap > (like Java) to set the bit, and others (like C) can clear it on all > instructions and never pay any performance penalty. > > http://nondot.org/sabre/LLVMNotes/ExceptionHandlingChanges.txt > >> It seems to me that you would need some way to set up the unwind >> labels >> beforehand, just like you do for the invoke instruction. For the >> specific case of divide by zero, I can imagine an optional unwind >> label >> parameter for the divide instruction, however that won't work too >> well >> for other kinds of exceptions since any load or store instruction >> could >> potentially produce them. > > The major problem is how you define "dominance" once you've modified > the > concept of a basic block to allow edges coming out the middle > instead of > the bottom. We've had an extensive thread on this in the past where > the > consensus was: > > * given a block A with an 'unwinds to' label to B: > - A is a predecessor to B (B is a successor of A) > - for the dominator tree, A and B are treated as if they shared the > same predecessor. > * we permit 'unwinds to' on the entry block, even though this means > that there is no singular dominator root to the function. The domtree > calculations already support this, though it means that you can't just > add an AllocaInst to the entry block and the load/store it in any > arbitrary block in the problem (if it were only reachable from the > 'unwinds to' edge of the entry block).I had attempted to read the relevant email threads and perhaps I missed where the consensus was reached. Please correct me if I missed some of the discussion. Having a dom tree with multiple roots, where blocks may not be dominated by the entry block is pretty scary. Having "predecessor" mean different things in the context of the CFG versus the context of the dom tree is very scary. Say we have this CFG: A | B X | C and B "unwinds to" X. Instead of having X be a successor to B, how about making X a successor to A (and A a predecessor of X)? A would need a special new kind of terminator instruction which looks something like a conditional branch with B and X as destinations, though it would always branch to B when executed. Then, X would have to begin with a special instruction, maybe an intrinsic call, which would be a magic place-holder in X for all the side-effects that could potentially be produced by (interrupted) execution of B. I think this would preserve all the usual CFG and SSA assumptions, and would produce the same dom tree that you're proposing, but without the need for bending the definition of "predecessor". Would this be an acceptable approach? Or has this been discussed already? Dan
On May 8, 2008, at 7:17 PM, Talin wrote:> Currently it states in the language manual that the results of > division > by zero are undefined. However, I'm curious as to how you would > normally > handle either divide by zero or other "hardware" exceptions (null > pointer dereference and so on) and turn them into LLVM exceptions.See Java and Ada in gcc for an example of how this is done. Essentially, you install a trap handler on the OS for the traps your interested in and have them create an exception. The inline code is `normal', no special funniness to it, other than exception tables and unwind tables that explain what to do. This scheme can even be made to work for asynchronous events as well.
Possibly Parallel Threads
- [LLVMdev] How to handle divide-by-zero exception?
- [LLVMdev] How to handle divide-by-zero exception?
- [LLVMdev] How to handle divide-by-zero exception?
- [LLVMdev] How to handle divide-by-zero exception?
- [LLVMdev] Is LLVM expressive enough to represent asynchronous exceptions?