Support using pinned registers as blockparams#75
Conversation
Pinned registers usually have special semantics and can't be merged with normal vregs. Similar checks already exist when merging `Reuse` operands and moves.
While pinned vregs are always assigned to the same preg and don't require moves across blocks, this doesn't apply to blockparams since the value is transferred to a different vreg.
|
Hi @Amanieu -- unfortunately I don't think this aligns with our eventual goal of getting rid of pinned vregs. We have #3 open for this, and at least in Cranelift I've been largely able to use fixed-reg constraints for everything. The main reason for that goal is to remove significant complexity. The subtle nature of this patch is good evidence of that, I think: it looks ok-ish to me, but the only way I'd really be sure is letting the fuzzer churn on it for a while. And the fuzzer doesn't cover pinned vregs directly. (They're tested somewhat by virtue of Cranelift's fuzzing, but we're moving away from them.) Edge-case complexity also makes it a lot harder to implement other optimizations or improvements. As a specific example, if we get completely to an SSA-only input world (and removing pinned vregs is a prerequisite for this), we can simplify a lot of the constraint fudging and fixing up that makes safepoints, half-instruction-wide constraints, multi-fixed-use cases, and the like work, by allowing for multiple copies of a value to exist. This also allows us to remove the redundant-move eliminator entirely. But we can only get there if we simplify the input that the regalloc core accepts. In your specific cases, I think the core primitive that you might want as an alternative is the ability to not pass an operand for a register, if it's an "undef" or "zero" case. Basically one can build paired behavior in the extract-operands logic and the apply-allocations-to-instruction logic where (i) an operand is emitted only if normal vreg; and (ii) an allocation is consumed only if the operand would have been emitted, otherwise the special reg is passed through. Does that seem reasonable? |
|
I had a look at Cranelift and the closest equivalent to what I am trying to do is the Now imagine that instead of having to emit this move instruction, Perhaps pinned registers are not the right mechanism to support this, but anything I can think of ends up being very similar. In an SSA world these pinned vregs are effectively constants since they are only every used in 2 ways:
|
Right, so in this case I think the mechanism I suggested above should be possible: the operand-producing glue code on the embedder side does not emit any operand at all ("effectively constant" as you say) and the allocation-consuming glue code knows that it should not expect an allocation in return. |
|
The problem is that the allocation-consuming glue doesn't know that it should not expect an allocation, at least not without some out-of-band data. The consumer is usually something like a generic However since #18 blockparams don't use In conclusion, I think that everything I want can be achieve by just re-introducing |
|
That seems reasonable to me as well actually; (If I can make a note of a semantically-important bikeshed color request for that reintroduction, I think we want to encode it by defining a sentinel value for the |
|
Superseded by #77. |
I use pinned registers to represent 2 things:
x0on RISC-V,xzron AArch64) which is hard-wired to zero.const_to_vregfunction to just return the pinned zero register instead of setting a register to 0.undefvalue which indicates that a value is never used.Option<i32>which consist of a tag vreg and a value vreg. If the tag indicatesNonethen the value is set toundef.undefinput or output are eliminated.These pinned registers are only ever used as instruction inputs (
use) and blockparam outputs (jump arguments).Making this work properly requires 2 changes: