-
Notifications
You must be signed in to change notification settings - Fork 53
Description
It's pretty straightforward to add register instructions to the DSL. We can allow
register inst(NAME, (arg1, arg2 -- result)) {
<code>
}
which generates code like this:
{
PyObject *arg1 = REG(oparg1);
PyObject *arg2 = REG(oparg2);
PyObject *result;
<code>
REG(oparg3) = result;
}
There's an obvious restriction that there can be at most three I/O effects altogether (because there are only three opargs).
But what should we do for micro-ops? In the stack VM, the effect of two micro-ops is easily combined into the effect of a single instruction by simulating the stack effects in the generator: each input effect is a POP, each output effect is a PUSH. However, this doesn't work the same way for registers. E.g. if we had two register micro-ops,
register op(X, (arg1 -- res1)) { ... }
register op(Y, (arg2 --)) { ... }
macro(Z) = X + Y;
what should the register effect of Z be? I guess this could be (arg1, arg2 -- res1). But how can we pass info from one micro-op into the next? In the stack world the first op can PUSH something that the second op will POP, and since the PUSH and POP cancel each other out these are not reflected in the overall stack effect.
I can punt for now and only add register inst(...), so Irit can use the generator to define new register ops more easily, but this reduces the power of the story about combining micro-ops into macro-instructions, so I think eventually we will need an answer.
One possibility would be to use name correspondence, so that e.g.
register op(X, (arg1 -- temp1)) { ... }
register op(Y, (temp1 -- res1)) { ... }
macro(Z) = X + Y;
implies that Z has one register input (oparg1==arg1) and one register output (oparg2==res1) and one value that gets transferred between the micro-ops (temp1) -- in the current composition model the latter will just become a local variable that is never spilled to the register array. (In a world where we have a separate micro-op interpreter, we'd just have to spill it. This will be interesting because the bytecode->micro-code translator would have to allocate a register in this case.)
Note that in the register world we're probably not going to have super-instructions, so we won't have to think about those (but since this made me think of them, they would not have this problem because each component has its own three opargs).
Thoughts (@markshannon, @brandtbucher, @iritkatriel)?