[LLVMdev] Proposal: add intrinsics for safe division
Filip Pizlo
fpizlo at apple.com
Fri May 2 11:57:09 PDT 2014
On May 2, 2014 at 11:53:25 AM, Eric Christopher (echristo at gmail.com) wrote:
On Wed, Apr 30, 2014 at 10:34 PM, Philip Reames
<listmail at philipreames.com> wrote:
> Andy - If you're not already following this closely, please start. We've
> gotten into fairly fundamental questions of what a patchpoint does.
>
> Filip,
>
> I think you've hit the nail on the head. What I'm thinking of as being
> patchpoints are not what you think they are. Part of that is that I've got
> a local change which adds a very similar construction (called "statepoints"
> for the moment), but I was trying to keep that separate. That also includes
> a lot of GC semantics which are not under discussion currently. My
> apologies if that experience bled over into this conversation and made
> things more confusing.
>
> I will note that the documentation for patchpoint say explicitly the
> following:
> "The ‘llvm.experimental.patchpoint.*‘ intrinsics creates a function call to
> the specified <target> and records the location of specified values in the
> stack map."
>
> My reading has always been that a patchpoint *that isn't patched* is simply
> a call with a stackmap associated with it. To my reading, this can (and
> did, and does) indicate my proposed usage would be legal.
>
I like the idea that the target can be assumed to be called. It makes
optimization of the call possible, etc. I think it's definitely worth
exploring before we lock down the patchpoint intrinsic.
I will actively oppose this.
-Filip
-eric
> I will agree that I've confused the topic badly on the optimization front.
> My "statepoint" isn't patchable, so a lot more optimizations are legal.
> Sorry about that. To restate what I think you've been saying all along, the
> optimizer can't make assumptions about what function is called by a
> patchpoint because that might change based on later patching. Is this the
> key point you've been trying to make?
>
> I'm not objecting to separating "my patchpoint" from "your patchpoint".
> Let's just hammer out the semantics of each first. :)
>
> Again, longer response to follow in a day or so. :)
>
> Philip
>
>
> On 04/30/2014 10:09 PM, Filip Pizlo wrote:
>
>
>
> On April 30, 2014 at 9:06:20 PM, Philip Reames (listmail at philipreames.com)
> wrote:
>
> On 04/29/2014 12:39 PM, Filip Pizlo wrote:
>
> On April 29, 2014 at 11:27:06 AM, Philip Reames (listmail at philipreames.com)
> wrote:
>
> On 04/29/2014 10:44 AM, Filip Pizlo wrote:
>
> LD;DR: Your desire to use trapping on x86 only further convinces me that
> Michael's proposed intrinsics are the best way to go.
>
> I'm still not convinced, but am not going to actively oppose it either. I'm
> leery of designing a solution with major assumptions we don't have data to
> backup.
>
> I worry your assumptions about deoptimization are potentially unsound. But
> I don't have data to actually show this (yet).
>
> I *think* I may have been unclear about my assumptions; in particular, my
> claims with respect to deoptimization are probably more subtle than they
> appeared. WebKit can use LLVM and it has divisions and we do all possible
> deoptimization/profiling/etc tricks for it, so this is grounded in
> experience. Forgive me if the rest of this e-mail contains a lecture on
> things that are obvious - I'll try to err on the side of clarity and
> completeness since this discussion is sufficiently dense that we run the
> risk of talking cross-purposes unless some baseline assumptions are
> established.
>
> I think we're using the same terminology, but with slightly different sets
> of assumptions. I'll point this out below where relevant.
>
> Also, thanks for taking the time to expand. It help clarify the discussion
> quite a bit.
>
> I think we may be converging to an understanding of what you want versus
> what I want, and I think that there are some points - possibly unrelated to
> division - that are worth clarifying. I think that the main difference is
> that when I say "patchpoint", I am referring to a concrete intrinsic with
> specific semantics that cannot change without breaking WebKit, while you are
> using the term to refer to a broad concept, or rather, a class of
> as-yet-unimplemented intrinsics that share some of the same features with
> patchpoints but otherwise have incompatible semantics.
>
> Also, when I say that you wouldn't want to use the existing patchpoint to do
> your trapping deopt, what I mean is that the performance of doing this would
> suck for reasons that are not related to deoptimization or trapping. I'm
> not claiming that deoptimization performs poorly (trust me, I know better)
> or that trapping to deoptimize is bad (I've done this many, many times and I
> know better). I'm saying that with the current patchpoint intrinsics in
> LLVM, as they are currently specified and implemented, doing it would be a
> bad idea because you'd have to compromise a bunch of other optimizations to
> achieve it.
>
> You have essentially described new intrinsics that would make this less of a
> bad idea and I am interested in your intrinsics, so I'll try to both respond
> with why patchpoints don't currently give you what you want (and why simply
> changing patchpoint semantics would be evil) and I'll also try to comment on
> what I think of the intrinsic that you're effectively proposing. Long story
> short, I think you should formally propose your intrinsic even if it's not
> completely fleshed out. I think that it's an interesting capability and in
> its most basic form, it is a simple variation of the current
> patchpoint/stackmap intrinsics.
>
>
>
>
>
> On April 29, 2014 at 10:09:49 AM, Philip Reames (listmail at philipreames.com)
> wrote:
>
> As the discussion has progressed and I've spent more time thinking about the
> topic, I find myself less and less enthused about the current proposal. I'm
> in full support of having idiomatic ways to express safe division, but I'm
> starting to doubt that using an intrinsic is the right way at the moment.
>
> One case I find myself thinking about is how one would combine profiling
> information and implicit div-by-zero/overflow checks with this proposal. I
> don't really see a clean way. Ideally, for a "safe div" which never has the
> exceptional paths taken, you'd like to completely do away with the control
> flow entirely. (And rely on hardware traps w/exceptions instead.) I don't
> really see a way to represent that type of construct given the current
> proposal.
>
> This is a deeper problem and to solve it you'd need a solution to trapping
> in general. Let's consider the case of Java. A Java program may want to
> catch the arithmetic exception due to divide by zero. How would you do this
> with a trap in LLVM IR? Spill all state that is live at the catch? Use a
> patchpoint for the entire division instruction?
>
> We'd likely use something similar to a patchpoint. You'd need the "abstract
> vm state" (which is not the compiled frame necessarily) available at the div
> instruction. You could then re-enter the interpreter at the specified index
> (part of the vm state). We have all most of these mechanisms in place.
> Ideally, you'd trigger a recompile and otherwise ensure re-entry into
> compiled code at the soonest possible moment.
>
> This requires a lot of runtime support, but we already have most of it
> implemented for another compiler. From our perspective, the runtime
> requirements are not a major blocker.
>
> Right, you'll use a patchpoint. That's way more expensive than using a safe
> division intrinsic with branches, because it's opaque to the optimizer.
>
> This statement is true at the moment, but it shouldn't be. I think this is
> our fundamental difference in approach.
>
> You should be able to write something like:
> i32 %res = invoke patchpoint (... x86_trapping_divide, a, b) normal_dest
> invoke_dest
>
> normal_dest:
> ;; use %res
> invoke_dest:
> landingpad
> ;; dispatch edge cases
> ;; this could be unreachable code if you deopt this frame in the trap
> handler and jump directly to an interpreter or other bit of code
>
> I see. It sounds like you want a generalization of the "div.with.stackmap"
> that I thought you wanted - you want to be able to wrap anything in a
> stackmap.
>
> The current patchpoint intrinsic does not do this, and you run the risk of
> breaking existing semantics if you changed this. You'd probably break
> WebKit, which treats the call target of the patchpoint as nothing more than
> a quirk - we always pass null. Also, the current patchpoint treats the
> callee as an i8* if I remember right and it would be super weird if all LLVM
> phases had to interpret this i8* by unwrapping a possible bitcast to get to
> a declared function that may be an intrinsic. Yuck! Basically, the call
> target of existing patchpoints is meant to be a kind of convenience feature
> rather than the core of the mechanism.
>
> I agree in principle that the intrinsic that you want would be a useful
> intrinsic. But let's not call it a patchpoint for the purposes of this
> discussion, and let's not confuse the discussion by claiming (incorrectly)
> that the existing patchpoint facility gives you what you want. It doesn't:
> patchpoints are designed to make the call target opaque (hence the use of
> i8*) and there shouldn't be a correlation between what the patchpoint does
> at run-time and what the called function would have done. You could make
> the call target be null (like WebKit does) and the patchpoint should still
> mean "this code can do anything" because the expectation is that the client
> JIT will patch over it anyway.
>
> Also, "patchpoint" would probably not be the right term for the intrinsic
> that you want. I think that what you want is "call.with.stackmap". Or
> maybe "stackmap.wrapper". Or just "stackmap" - I'd be OK, in principle,
> with changing the name of the current "stackmap" intrinsic to something that
> reflects the fact that it's less of a stackmap than what you want.
>
> To summarize. A patchpoint's main purpose is that you can patch it with
> arbitrary code. The current "stackmap" means that you can patch it with
> arbitrary code and that patching may be destructive to a shadow of machine
> code bytes, so it's really just like patchpoints - we could change its name
> to "patchpoint.shadow" for example.
>
> If you were to propose such a stackmap intrinsic, then I think there could
> be some ways of doing it that wouldn't be too terrible. Basically you want
> something that is like a patchpoint in that it reports a stackmap via a side
> channel, but unlike patchpoints, it doesn't allow arbitrary patching -
> instead the optimizer should be allowed to assume that the code within the
> patchpoint will always do the same thing that the call target would have
> done. There are downsides to truly doing this. For example, to make
> division efficient with such an intrinsic, you'd have to do something that
> is somewhat worse than just recognizing intrinsics in the optimizer - you'd
> have to first recognize a call to your "stackmap wrapper" intrinsic and then
> observe that its call target argument is in turn another intrinsic. To me
> personally, that's kind of yucky, but I won't deny that it could be useful.
>
> As to the use of invoke: I don't believe that the use of invoke versus my
> suggested "branch on a trap predicate" idea are different in any truly
> meaningful way. I buy that either would work.
>
>
>
> A patchpoint should not require any excess spilling. If values are live in
> registers, that should be reflected in the stack map. (I do not know if
> this is the case for patchpoint at the moment or not.)
>
> Patchpoints do not require spilling.
>
> My point was that with existing patchpoints, you *either* use a patchpoint
> for the entire division which makes the division opaque to the optimizer -
> because a patchpoint means "this code can do anything" - *or* you could
> spill stuff to the stack prior to your trapping division intrinsic, since
> spilling is something that you could do as a workaround if you didn't have a
> patchpoint.
>
> The reason why I brought up spilling at all is that I suspect that spilling
> all state to the stack might be cheaper - for some systems - than turning
> the division into a patchpoint. Turning the division into a patchpoint is
> horrendously brutal - the patchpoint looks like it clobbers the heap (which
> a division doesn't do), has to execute (a division is an obvious DCE
> candidate), cannot be hoisted (hoisting divisions is awesome), etc. Perhaps
> most importantly, though, a patchpoint doesn't tell LLVM that you're *doing
> a division* - so all constant folding, strenght reduction, and algebraic
> reasoning flies out the window. On the other hand, spilling all state to
> the stack is an arguably sound and performant solution to a lot of VM
> problems. I've seen JVM implementations that ensure that there is always a
> copy of state on the stack at some critical points, just because it makes
> loads of stuff simpler (debugging, profiling, GC, and of course deopt). I
> personally prefer to stay away from such a strategy because it's not free.
>
> On the other hand, branches can be cheap. A branch on a divide is cheaper
> than not being able to optimize the divide.
>
>
>
> The Value called by a patchpoint should participate in optimization
> normally.
>
> I agree that you could have a different intrinsic that behaves like this.
>
> We really want the patchpoint part of the call to be supplemental. It
> should still be a call. It should be constant propagated, transformed,
> etc.. This is not the case currently. I've got a couple of off the wall
> ideas for improving the current status, but I'll agree this is a hardish
> problem.
>
> It should be legal to use a patchpoint in an invoke. It's an ABI issue of
> how the invoke path gets invoked. (i.e. side tables for the runtime to
> lookup, etc..) This is not possible today, and probably requires a fair
> amount of work. Some of it, I've already done and will be sharing shortly.
> Other parts, I haven't even thought about.
>
> Right, it's significantly more complex than either the existing patchpoints
> or Michael's proposed safe.div.
>
>
>
> If you didn't want to use the trapping semantics, you'd insert dedicated
> control flow _before_ the divide. This would allow normal optimization of
> the control flow.
>
> Notes:
> 1) This might require a new PATCHPOINT pseudo op in the backend. Haven't
> thought much about that yet.
> 2) I *think* your current intrinsic could be translated into something like
> this. (Leaving aside the question of where the deopt state comes from.) In
> fact, the more I look at this, the less difference I actually see between
> the approaches.
>
>
>
> In a lot of languages, a divide produces some result even in the exceptional
> case and this result requires effectively deoptimizing since the resut won't
> be the one you would have predicted (double instead of int, or BigInt
> instead of small int), which sort of means that if the CPU exception occurs
> you have to be able to reconstruct all state. A patchpoint could do this,
> and so could spilling all state to the stack before the divide - but both
> are very heavy hammers that are sure to be more expensive than just doing a
> branch.
>
> This isn't necessarily as expensive as you might believe. I'd recommend
> reading the Graal project papers on this topic.
>
> Whether deopt or branching is more profitable *in this case*, I can't easily
> say. I'm not yet to the point of being able to run that experiment. We can
> argue about what "should" be better all we want, but real performance data
> is the only way to truly know.
>
> My point may have been confusing. I know that deoptimization is cheap and
> WebKit uses it everywhere, including division corner cases, if profiling
> tells us that it's profitable to do so (which it does, in the common case).
> WebKit is a heavy user of deoptimization in general, so you don't need to
> convince me that it's worth it.
>
> Acknowledged.
>
> Note that I want *both* deopt *and* branching, because in this case, a
> branch is the fastest overall way of detecting when to deopt. In the
> future, I will want to implement the deopt in terms of branching, and when
> we do this, I believe that the most sound and performat approach would be
> using Michael's intrinsics. This is subtle and I'll try to explain why it's
> the case.
>
> The point is that you wouldn't want to do deoptimization by spilling state
> on the main path or by using a patchpoint for the main path of the division.
>
> This is the main point I disagree with. I don't believe that having a
> patchpoint on the main path should be any more expensive then the original
> call. (see above)
>
> The reason why the patchpoint is expensive is that if you use a patchpoint
> to implement a division then the optimizer won't be allowed to assume that
> it's a division, because the whole point of "patchpoint" is to tell the
> optimizer to piss off.
>
>
>
> Worth noting explicitly: I'm assuming that all of your deopt state would
> already be available for other purposes in nearby code. It's on the stack
> or in registers. I'm assuming that by adding the deopt point, you are not
> radically changing the set of computations which need to be done. If that's
> not the case, you should avoid deopt and instead just inline the slow paths
> with explicit checks.
>
> Yes, of course it is. That's not the issue.
>
>
>
> I'll note that given your assumptions about the cost of a patchpoint, the
> rest of your position makes a lot more sense. :) As I spelled out above, I
> believe this cost is not fundamental.
>
> You don't want the common path of executing the division to involve a
> patchpoint instruction, although using a patchpoint or stackmap to implement
> deoptimization on the failing path is great:
>
> Good: if (division would fail) { call @patchpoint(all of my state) } else {
> result = a / b }
>
> Given your cost assumptions, I'd agree.
>
> Not my cost assumptions. The reason why this is better is that the division
> is expressed in LLVM IR so that LLVM can do useful things to it - like
> eliminate it, for example.
>
>
> Bad: call @patchpoint(all of my state) // patch with a divide instruction -
> bad because the optimizer has no clue what you're doing and assumes the very
> worst
>
> Yuck. Agreed.
>
> To be clear, this is what you're proposing - except that you're assuming
> that LLVM will know that you've patched a division because you're expecting
> the call target to have semantic meaning. Or, rather, you're expecting that
> you can make the contents of the patchpoint be a division by having the call
> target be a division intrinsic. In the current implementation and as it is
> currently specified, the call target has no meaning and so you get the yuck
> that I'm showing.
>
>
> Worse: spill all state to the stack; call @trapping.div(a, b) // the spills
> will hurt you far more than a branch, so this should be avoided
>
> I'm assuming this is an explicit spill rather than simply recording a stack
> map *at the div*. If so, agreed.
>
> I suppose we could imagine a fourth option that involves a patchpoint to
> pick up the state and a trapping divide instrinsic. But a trapping divide
> intrinsic alone is not enough. Consider this:
>
> result = call @trapping.div(a, b); call @stackmap(all of my state)
>
> As soon as these are separate instructions, you have no guarantees that the
> state that the stackmap reports is sound for the point at which the div
> would trap.
>
> This is the closest to what I'd propose, except that the two calls would be
> merged into a single patchpoint. Isn't the entire point of a patchpoint to
> record the stack map for a call?
>
> No. It would be bad if that's what the documentation says. That's not at
> all how WebKit uses it or probably any IC client would use it.
>
> Patchpoints are designed to be inline assembly on steroids. They're there
> to allow the client JIT to tell LLVM to piss off.
>
> (Well, ignoring the actual patching part..) Why not write this as:
> patchpoint(..., trapping.div, a, b);
>
> Is there something I'm missing here?
>
> Just to note: I fully agree that the two call proposal is unsound and should
> be avoided.
>
> So, the division itself shouldn't be a trapping instruction and instead you
> want to detect the bad case with a branch.
>
> To be clear:
>
> - Whether you use deoptimization for division or anything else - like WebKit
> has done since before any of the Graal papers were written - is mostly
> unrelated to how you represent the division, unless you wanted to add a new
> intrinsic that is like a trapping-division-with-stackmap:
>
> result = call @trapping.div.with.stackmap(a, b, ... all of my state ...)
>
> Now, maybe you do want such an intrinsic, in which case you should propose
> it!
>
> Given what we already have with patchpoints, I don't think a merged
> intrinsic is necessary. (See above). I believe we have all the parts to
> build this solution, and that - in theory - they should compose neatly.
>
> p.s. The bits I was referring to was not deopt per se. It was particularly
> which set of deopt state you used for each deopt point. That's a bit of
> tangent for the rest of the discussion now though.
>
> The reason why I haven't proposed it is that I think that long-term, the
> currently proposed intrinsics are a better path to getting the trapping
> optimizations. See my previous mail, where I show how we could tell LLVM
> what the failing path is (which may have deoptimization code that uses a
> stackmap or whatever), what the trapping predicate is (it comes from the
> safe.div intrinsic), and the fact that trapping is wise (branch weights).
>
> - If you want to do the deoptimization with a trap, then your only choice
> currently is to use a patchpoint for the main path of the division. This
> will be slower than using a branch to an OSR exit basic block, because
> you're making the division itself opaque to the optimizer (bad) just to get
> rid of a branch (which was probably cheap to begin with).
>
> Hence, what you want to do - one way or another, regardless of whether this
> proposed intrinsic is added - is to branch on the corner case condition, and
> have the slow case of the branch go to a basic block that deoptimizes.
> Unless of course you have profiling that says that the case does happen
> often, in which case you can have that basic block handle the corner case
> inline without leaving optimized code (FWIW, we do have such paths in WebKit
> and they are useful).
>
> So the question for me is whether the branching involves explicit control
> flow or is hidden inside an intrinsic. I prefer for it to be within an
> intrinsic because it:
>
> - allows the optimizer to do more interesting things in the common cases,
> like hoisting the entire division.
>
> - will give us a clearer path for implementing trapping optimizations in the
> future.
>
> - is an immediate win on ARM.
>
> I'd be curious to hear what specific idea you have about how to implement
> trap-based deoptimization with your trapping division intrinsic for x86 -
> maybe it's different from the two "bad" idioms I showed above.
>
> I hope my explanation above helps. If not, ask, and I'll try to explain
> more clearly.
>
> I think I understand it. I think that the only issue is that:
>
> - Patchpoints currently don't do what you want.
>
> - If you made patchpoints do what you want then you'd break WebKit - not to
> mention anyone who wants to use them for inline caches.
>
> So it seems like you want a new intrinsic. You should officially propose
> this new intrinsic, particularly since the core semantic differences are not
> so great from what we have now. OTOH, if you truly believe that patchpoints
> should just be changed to your semantics in a way that does break WebKit,
> then that's probably also something you should get off your chest. ;-)
>
>
>
> One point just for clarity; I don't believe this effects the conclusions of
> our discussion so far. I'm also fairly sure that you (Filip) are aware of
> this, but want to spell it out for other readers.
>
> You seem to be assuming that compiled code needs to explicitly branch to a
> point where deopt state is known to exit a compiled frame.
>
> This is a slightly unclear characterization of my assumptions. Our JIT does
> deoptimization without explicit branches for many, many things. You should
> look at it some time, it's pretty fancy. ;-)
>
> Worth noting is that you can also exit a compiled frame on a trap (without
> an explicitly condition/branch!) if the deopt state is known at the point
> you take the trap. This "exit frame on trap" behavior shows up with null
> pointer exceptions as well. I'll note that both compilers in OpenJDK
> support some combination of "exit-on-trap" conditions for division and null
> dereferences. The two differ on exactly what strategies they use in each
> case though. :)
>
> Yeah, and I've also implemented VMs that do this - and I endorse the basic
> idea. I know what you want, and my only point is that the existing
> patchpoints only give you this if you're willing to make a huge compromise:
> namely, that you're willing to make the division (or heap load for the null
> case) completely opaque to the compiler to the point that GVN, LICM, SCCP,
> and all algebraic reasoning have to give up on optimizing it. The point of
> using LLVM is that it can optimize code. It can optimize branches and
> divisions pretty well. So, eliminating an explicit branch by replacing it
> with a construct that appears opaque to the optimizer is not a smart
> trade-off.
>
> You could add a new intrinsic that, like patchpoints, records the layout of
> state in a side-table, but that is used as a kind of wrapper for operations
> that LLVM understands. This may or may not be hairy - you seem to have sort
> of acknowledged that it's got some complexity and I've also pointed out some
> possible issues. If this is something that you want, you should propose it
> so that others know what you're talking about. One danger of how we're
> discussing this right now is that you're overloading patchpoints to mean the
> thing you want them to mean rather than what they actually mean, which makes
> it seem like we don't need Michael's intrinsics on the grounds that
> patchpoints already offer a solution. They don't already offer a solution
> precisely because patchpoints don't do what your intrinsics would do.
>
>
>
> I'm not really arguing that either scheme is "better" in all cases. I'm
> simply arguing that we should support both and allow optimization and tuning
> between them. As far as I can tell, you seem to be assuming that an
> explicit branch to known exit point is always superior.
>
>
> Ok, back to the topic at hand...
>
> With regards to the current proposal, I'm going to take a step back. You
> guys seem to have already looked in this in a fair amount of depth. I'm not
> necessarily convinced you've come to the best solution, but at some point,
> we need to make forward progress. What you have is clearly better than
> nothing.
>
> Please go ahead and submit your current approach. We can come back and
> revise later if we really need to.
>
> I do request the following changes:
> - Mark it clearly as experimental.
>
>
> - Either don't specify the value computed in the edge cases, or allow those
> values to be specified as constant arguments to the call. This allows
> efficient lowering to x86's div instruction if you want to make use of the
> trapping semantics.
>
> Once again: how would you use this to get trapping semantics without
> throwing all of LLVM's optimizations out the window, in the absence of the
> kind of patchpoint-like intrinsic that you want? I ask just to make sure
> that we're on the same page.
>
>
>
> Finally, as for performance data, which part of this do you want performance
> data for? I concede that I don't have performance data for using Michael's
> new intrinsic. Part of what the intrinsic accomplishes is it gives a less
> ugly way of doing something that is already possible with target intrinsics
> on ARM. I think it would be great if you could get those semantics - along
> with a known-good implementation - on other architectures as well.
>
> I would be very interested in seeing data comparing two schemes:
> - Explicit control flow emited by the frontend
> - The safe.div intrinsic emitted by the frontend, desugared in CodeGenPrep
>
> My strong suspicion is that each would preform well in some cases and not in
> others. At least on x86. Since the edge-checks are essentially free on
> ARM, the second scheme would probably be strictly superior there.
>
> I am NOT asking that we block submission on this data however.
>
> But this discussion has also involved suggestions that we should use
> trapping to implement deoptimization, and the main point of my message is to
> strongly argue against anything like this given the current state of
> trapping semantics and how patchpoints work. My point is that using traps
> for division corner cases would either be unsound (see the stackmap after
> the trap, above), or would require you to do things that are obviously
> inefficient. If you truly believe that the branch to detect division slow
> paths is more expensive than spilling all bytecode state to the stack or
> using a patchpoint for the division, then I could probably hack something up
> in WebKit to show you the performance implications. (Or you could do it
> yourself, the code is open source...)
>
> In a couple of months, I'll probably have the performance data to discuss
> this for real. When that happens, let's pick this up and continue the
> debate. Alternatively, if you want to chat this over more with a beer in
> hand at the social next week, let me know. In the meantime, let's not stall
> the current proposal any more.
>
> Philip
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20140502/c068d1f3/attachment.html>
More information about the llvm-dev
mailing list