Tidy up compiler utility return addresses.
Use compiled returns for the ones that are likely to return to Scheme
like lookups and assignments, and compiled entries for the ones that
are likely to return to microcode like interrupts.
Architectures on which compiled entries and compiled returns have the
same format will see no difference: compiled code passes in an
untagged return address either way.
On amd64, where compiled entries and compiled returns are different:
- For hooks that act like leaf subroutines and never return to
microcode, use plain CALL/RET in pairs.
- For hooks that are subroutines likely to return to Scheme
immediately but might return to microcode in screw cases, use
(CALL ,hook) ; Invoke hook with untagged ret addr...
(JMP (@PCR ,continuation)) ; ...which jumps to formatted entry.
(WORD ...)
(BLOCK-OFFSET ,continuation)
(QUAD U 0)
(LABEL ,continuation)
... ; continuation instructions
For the non-screw cases this keeps CALL/RET paired.
- For hooks that always defer to microcode, namely to handle
interrupts, use
(LEA Q (R ,rbx) (@PCR ,continuation))
(JMP ,hook)
Here it doesn't really whether the CALL/RET is paired because we're
going to wreck the return address branch prediction stack no matter
what, but it is convenient to have the entry address rather than
the return address in the compiled utility.