On Wed, Apr 22, 2015 at 11:44 PM, Andrew Trick <atrick at apple.com> wrote:> > This feature will keep being requested. I agree LLVM should support it, > and am happy to see it being done right.+1> > I plan to break the design into two parts, roughly following the > > statepoint philosophy: > > > > # invokable @llvm.(load|store)_with_trap intrinsics > > > > We introduce two new intrinsic families > > > > T @llvm.load_with_trap(T*) [modulo name mangling] > > void @llvm.store_with_trap(T, T*) [modulo name mangling] > > > > They cannot be `call`ed, they can only be `invoke`d. >Why not allow non-nounwind calls, in other words, an intrinsic call that may throw? In most languages with implicit null checks, there are far more functions that do field accesses and method calls than there are functions that catch exceptions. The common case is that the frame with the load will have nothing to do other than propagate the exception to the parent frame, and we should allow the runtime to handle that efficiently. Essentially, in this model, the signal handler is responsible for identifying the signal as a null pointer exception (i.e. SIGSEGVs on a small pointer value with a PC in code known to use this EH personality) and transitioning to the exception handling machinery in the language runtime.> Semantically, they try to load from or store to the pointer passed to > > them as normal load / store instructions do. @llvm.load_with_trap > > returns the loaded value on the normal return path. If the load or > > store traps then they dispatch to their unwind destination. The > > landingpad for the unwind destination can only be a cleanup > > landingpad, and the result of the landingpad instruction itself is > > always undef. The personality function in the landingpad instruction > > is ignored. >The landingpad personality normally controls what kind of EH tables are emitted, so if you want something other than the __gxx_personality_v0 LSDA table, you could invent your own personality and use that to control what gets emitted. This might be useful for interoperating with existing language runtimes.> These intrinsics require support from the language runtime to work. > > During code generation, the invokes are lowered into normal load or > > store instructions, followed by a branch (explicit `jmp` or just > > fall-through) to the normal destination. The PC for the unwind > > destination is recorded in a side-table along with the PC for the load > > or store. When a load or store traps or segfaults at runtime, the > > runtime searches this table to see if the trap is from a PC recorded > > in the side-table. If so, it the runtime jumps to the unwind > > destination, otherwise it aborts. > > The intrinsics need to be lowered to a pseudo instruction just like > patchpoint (so that a stackmap can be emitted). In my mind the real issue > here is how to teaching this pseudo instruction to emit the proper > load/store for the target.Does it really have to be a per-target pseudo? The way I see it, we can handle this all in selection dag. All we need to do is emit the before label, the load/store operation, and the end label, and establish control dependence between them all to prevent folding. Does that seem reasonable, or is this an overly simplistic perspective? :-)> Note that the signal handler / runtime do not themselves raise > > exceptions at the ABI level (though they do so conceptually), but the > > landing pad block can raise one if it wants to. > > > > The table mapping load/store PCs to unwind PCs can be reported to the > > language runtime via an __llvm_stackmaps like section. I am strongly > > in favor of making this section as easy to parse as possible. > > Let’s just be clear that it is not recommended for the frontend to produce > these intrinsics. They are a compiler backend convenience. (I don’t want > InstCombine or any other standard pass to start trafficking in these.)Would you be OK with simply documenting that these intrinsics are optimization-hostile, in the same way that early safepoint insertion is? There are some language constructs (__try / __except) that allow catching memory faults like this. Such constructs are rare and don't really need to be optimized. I just want to make sure that mid-level optimizations don't actively break these.> > Running this pass sufficiently late in the optimization pipeline will > > allow for all the usual memory related optimization passes to work as > > is -- they won't have to learn about the special semantics for the new > > (load|store)_with_trap intrinsics to be effective. > > Good. This is a codegen feature. We can’t say that enough. If you really > cared about the best codegen this would be done in machine IR after > scheduling and target LoadStore opts.I agree, with the caveat above. Mid-level passes shouldn't actively break these intrinsics.> > This pass will have to be a profile-guided optimization pass for > > fundamental reasons: implicit null checks are a pessimization even if > > a small fraction of the implicit null checks fail. Typically language > > runtimes that use page-fault based null checks recompile methods with > > failed implicit null checks to use an explicit null check instead (e.g. > [2]). > > I don’t think making it profile-guided is important. Program behavior can > change after compilation and you’re back to the same problem. I think > recovering from repeated traps is important. That’s why you need to combine > this feature with either code invalidation points or patching implemented > via llvm.stackmap, patchpoint, (or statepoint) — they’re all the same thing. > > > What do you think? Does this make sense? > > Well, you need the features that patchpoint gives you (stackmaps entries) > and you’ll need to use patchpoints or stackmaps anyway for invalidation or > patching. So why are you bothering with a totally new, independent > intrinsic? Why not just extend the existing intrinsics. We could have a > variant that > > - emits a load instead of a call > > - looks at the landing pad to generate a special stackmap entry in > addition to the normal exception table (I don’t even see why you need this, > except that the runtime doesn’t know how to parse an exception table.)-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20150423/eb8519fc/attachment.html>
> Why not allow non-nounwind calls, in other words, an intrinsic call that may > throw? > > In most languages with implicit null checks, there are far more functions > that do field accesses and method calls than there are functions that catch > exceptions. The common case is that the frame with the load will have > nothing to do other than propagate the exception to the parent frame, and we > should allow the runtime to handle that efficiently. > > Essentially, in this model, the signal handler is responsible for > identifying the signal as a null pointer exception (i.e. SIGSEGVs on a small > pointer value with a PC in code known to use this EH personality) and > transitioning to the exception handling machinery in the language runtime.I have no problems in semantically allowing unwinding calls to these intrinsics that get your runtime to unwind the stack and propagate an exception object. But this proposal is specifically to only introduce LLVM side changes to generate the appropriate side-tables for implicit exceptions. I think getting signal handlers and runtimes to throw exceptions will be quite a bit of work beyond that. One thing to note: it is usually impractical for managed languages to use implicit null pointer exceptions unless they have some way to "heal" the implicit null check sites into explicit null checks as they fail. Unless you have a way to quickly converge your program to a point where no implicit null checks actually fail at runtime, checking for null pointers via virtual memory tricks is a pessimization. This can be done via code patching / invalidation etc. as Andy mentioned.> The landingpad personality normally controls what kind of EH tables are > emitted, so if you want something other than the __gxx_personality_v0 LSDA > table, you could invent your own personality and use that to control what > gets emitted. This might be useful for interoperating with existing language > runtimes.That's a great idea. Do you think it is reasonable to standardize a "__llvm_implicit_null_check" personality function that emits information into the stackmaps sections instead?> Does it really have to be a per-target pseudo? The way I see it, we can > handle this all in selection dag. All we need to do is emit the before > label, the load/store operation, and the end label, and establish control > dependence between them all to prevent folding. Does that seem reasonable, > or is this an overly simplistic perspective? :-)That was my impression also. :)> Would you be OK with simply documenting that these intrinsics are > optimization-hostile, in the same way that early safepoint insertion is? > There are some language constructs (__try / __except) that allow catching > memory faults like this. Such constructs are rare and don't really need to > be optimized. I just want to make sure that mid-level optimizations don't > actively break these.Personally, I'm okay with your proposal; but I will wait for Andy to respond on this.> I agree, with the caveat above. Mid-level passes shouldn't actively break > these intrinsics.Agreed. Mid-level passes should treat these as opaque calls. -- Sanjoy
> One thing to note: it is usually impractical for managed languages to > use implicit null pointer exceptions unless they have some way to > "heal" the implicit null check sites into explicit null checks as they > fail. Unless you have a way to quickly converge your program to a > point where no implicit null checks actually fail at runtime, checking > for null pointers via virtual memory tricks is a pessimization. > > This can be done via code patching / invalidation etc. as Andy > mentioned.^^ you can ignore these two paragraphs. They're not incorrect, but I realized that they're not relevant to what you were suggesting.
> On Apr 23, 2015, at 10:18 AM, Reid Kleckner <rnk at google.com> wrote: > > The intrinsics need to be lowered to a pseudo instruction just like patchpoint (so that a stackmap can be emitted). In my mind the real issue here is how to teaching this pseudo instruction to emit the proper load/store for the target. > > Does it really have to be a per-target pseudo? The way I see it, we can handle this all in selection dag. All we need to do is emit the before label, the load/store operation, and the end label, and establish control dependence between them all to prevent folding. Does that seem reasonable, or is this an overly simplistic perspective? :-)It would be really nice to just emit a label next to an instruction and assume the stackmap entry will end up at the right address. I don’t think the backend can make that guarantee. Any Machine pass can insert instructions wherever it wants without looking for labels. I think labels are only employed just before code emission. Is there any existing example of labels being used earlier (I think GCRootLowering is the earliest)?> > Note that the signal handler / runtime do not themselves raise > > exceptions at the ABI level (though they do so conceptually), but the > > landing pad block can raise one if it wants to. > > > > The table mapping load/store PCs to unwind PCs can be reported to the > > language runtime via an __llvm_stackmaps like section. I am strongly > > in favor of making this section as easy to parse as possible. > > Let’s just be clear that it is not recommended for the frontend to produce these intrinsics. They are a compiler backend convenience. (I don’t want InstCombine or any other standard pass to start trafficking in these.) > > Would you be OK with simply documenting that these intrinsics are optimization-hostile, in the same way that early safepoint insertion is? There are some language constructs (__try / __except) that allow catching memory faults like this. Such constructs are rare and don't really need to be optimized. I just want to make sure that mid-level optimizations don't actively break these.Documentation is fine. There’s no reason to prevent a frontend from generating these. I just want the intention to be clear. Andy -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20150423/80354699/attachment.html>
On Thu, Apr 23, 2015 at 3:31 PM, Andrew Trick <atrick at apple.com> wrote:> > It would be really nice to just emit a label next to an instruction and > assume the stackmap entry will end up at the right address. I don’t think > the backend can make that guarantee. Any Machine pass can insert > instructions wherever it wants without looking for labels. > > I think labels are only employed just before code emission. Is there any > existing example of labels being used earlier (I think GCRootLowering is > the earliest)? >SelectionDAGBuilder::lowerInvokable() inserts EH_LABELs into the DAG for normal invokes, and it more or less works out. I don't know much about what transformations MI passes typically do, but my guess is that you're concerned that some pass might re-schedule possibly trapping operations inside the label range? -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20150423/4108f5ca/attachment.html>