[LLVMdev] Stackmaps: caller-save-registers passed as deopt args

Andrew Trick atrick at apple.com
Thu Nov 6 16:47:07 PST 2014


> On Nov 6, 2014, at 1:53 PM, Sanjoy Das <sanjoy at playingwithpointers.com> wrote:
> 
>> An easier option would be to generate a second
>> pseudo instruction immediately after the patchpoint that simply uses
>> all the live-on-return values.
> 
> Do you mean some variant of
> 
> PATCHPOINT ... (live_values = %vreg0, %vreg1)
> FAKE-USE %vreg1 ;; %vreg1 needs to be live on return
> 
> For this kind of a solution, we'll have to prevent the register
> allocator (and other lowering components, I'm not sure) playing tricks
> with inserting fills and remats.  IOW, the above code should not
> compile to
> 
> mov 16(%rsp), %r11
> mov 24(%rsp), %r10
> inc %r10
> 
> PATCHPOINT ... (live_values = %r11, %r10)
> mov 24(%rsp), %r10
> inc %r10
> FAKE-USE %r10
> 
> Naively, both the register assignments to %vreg1, in PATCHPOINT and
> FAKE-USE, are caller-saved and not live on return.  It may be possible
> to reverse-engineer the computation that will compute the value of
> %r10, but that's non-trivial.

I was thinking FAKE_USE would need special handling. It would be bundled before and after register allocation, but unbundled during register allocation so the live interval of the live values would span the call instruction. The problem is that the register allocator itself is free do something like you’ve shown above, so it’s not a very robust solution and I don’t particularly like it. I thought it would be easier than adding a “LateUse” MachineOperand flag, but now I’m not so sure. Any ideas Quentin?

> One simple solution is to force spilling of live-on-return values at
> the SelectionDAG layer (we do this for statepoints currently); but
> that prevents us from using callee-saved registers and may be
> suboptimal.

If you need to do that then the design is broken. But it is an option for Kevin to get things working.

> A completely orthogonal idea: it should also be possible to do
> deopt-on-return only using live-on-call values if you're willing to
> use invokes instead of calls.  Instead of
> 
>  call void @patchpoint(@callee_that_may_deopt, args, live_values)
> 
> emit
> 
>  invoke @callee_that_may_deopt(args)
> 
>  deopt_pad:
>    ... landingpad ...
>    call void @patchpoint(@deoptimize_me, ... live_values ...)
> 
> 
> ... live_values ... in deopt_pad now only needs to be live-on-call.  It
> can actually even be function arguments to @deoptimize_me -- the
> register / stack slot shuffling due to a fixed calling convention will
> no longer happen on the (presumably hot) call, but only when
> deoptimizing.  You'd have to deoptimize by "throwing" an exception in
> this case.

That’s an elegant approach to avoiding the backend problems. The IR representation makes perfect sense. I think your deopt mechanism would need to patch the return address as if an exception were thrown (I guess that’s what you mean by “throwing an exception”). Also, you will end up with exception tables that need to be parsed in addition to stackmaps, which seems fairly horrible. Agree?

I assume that statepoints have the same issue with both deopt values and GC roots once you stop spilling them. Do you have a preferred or tentative solution for it?

-Andy

> 
> -- Sanjoy





More information about the llvm-dev mailing list