New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Forbid passing values in Registers between code::Machine::State
s
#6
Comments
I'm going to hold off on this until we have register allocation working. I think the requirements will be clearer then. |
ProposalI've gone round in circles a bit but I think a good approach might be as follows:
If a trap occurs, only the globals will be preserved. x86 registers and all other spill slots are corrupted. The trap handler can re-enter the Machine in whatever State it wants, and is responsible for initializing all the spill slots that are live in that State. Mijit instructions (as proposed) can be translated fairly directly into x86 code. If an operation has a source that is not a register, the The optimizer already has code for caching globals, in order to eliminate unnecessary LoadGlobal and StoreGlobal instructions when constructing the dataflow graph. This can be generalized to all spill slots. The optimizer allocates both x86 registers and spill slots. It tries to keep values in registers if possible, but if it runs out, it can allocate spill slots for long-lived values. The output format of the optimizer is Mijit code, i.e. exactly the same as its input format. The only difference from the Machine specification is that registers can be used more freely. The CallingConvention of a history specifies (among other things) which spill slots and x86 registers are live. For a root history, this is just the result of the liveness analysis for the corresponding State (so all x86 registers are dead). For a history constructed by the optimizer, liveness is inferred from its retire code (and x86 registers can be live). |
We've made good progress on this. We have done the data structures and made consequential changes to the Beetle implementation. We noticed that the design still does not allow us to generate good code for immediate constants. We decided to reserve one slot to hold the value Allowing any source or destination to be a slot (as opposed to a register) complicates The hardest case is when both This indicates that the Mijit code is inadequately representing the register allocation decisions. I think it is worth a slight rethink. Proposal (#16): the destination must be a register (not a slot). This allows us to delete half the cases, including all the hard cases. It shifts the burden of choosing a destination register onto whatever generates the Mijit code, thereby better representing the register allocation in the code. Spilling a computed value requires an extra Mijit instruction, which is fine. |
Currently the
State
s ofbeetle::Machine
pass values to each other in registers. If an exception occurs (e.g. the specializer runs) what will happen to the register contents?I think this is a design bug. We should specify that registers are corrupted between
State
s.State
s should useGlobal
s to pass values. Beetle should have some extraGlobal
sOp1
,Op2
,Target
etc. for this purpose.Mijit's cache will optimize away unnecessary
LoadGlobal
instructions. Mijit should do dead value analysis to optimize away unnecessaryStoreGlobal
instructions.There should be a way to mark a
Global
as "observable" to suppress dead value analysis. This would force Mijit to maintain the value of theGlobal
even if it is write-only. I can't think of an example in Beetle;NotAddress
andBad
are close.The text was updated successfully, but these errors were encountered: