Repository navigation
spec: Field VM - #971
spec: Field VM#971
Conversation
Kimi Code ReviewAutomated review by Kimi (Moonshot AI) |
Codex Code ReviewFound five issues in the changed specification/tooling:
|
|
Getting the typechecker to be happy with ExtField elements is one of the next steps ;) |
erik-3milabs
left a comment
There was a problem hiding this comment.
Summary:
- instruction and constraints are similar, but not the same. Sketching the right mental model is informative.
- an instruction spans multiple states, which is a new concept in this spec. The reader is not helped to understand this. Sketching the right mental model is informative.
- the concepts of input hinting, output hinting and register hinting and their relation is unclear.
- have another look at the lower and upper bounds of sum. There seem to be some issues with that.
- minor notes/rephrase proposals
| == Register hinting | ||
|
|
||
| Each general-purpose register in the current state can be marked as _hinted_ by the acting instruction. | ||
| This means that from the current state onwards, the register can take a value |
There was a problem hiding this comment.
why are you choosing "onwards" here? It suggests that if for one instruction you set a register to hintable, and it remains that way for the rest of the execution trace. Perhaps worth clarifying that this is a way for the transition constraint not to hold for that particular instruction.
There was a problem hiding this comment.
The onwards is there to avoid making it seem like it's only for this state, i.e. that the transition constraints do carry it forward and it's not a temporary exception.
There was a problem hiding this comment.
Added a footnote to hopefully clarify a bit. We don't really have "transition constraints" yet at this point of the expose.
There was a problem hiding this comment.
We don't really have "transition constraints" yet at this point of the expose. [...] The onwards is there to avoid making it seem like it's only for this state, i.e. that the transition constraints do carry it forward and it's not a temporary exception.
Should we then not start this section with outlining that, in principal, register values of contiguous states are the same (referring to the state machine description at the start of 35.1.1).
That furthermore allows us to explain why hinting should be included in the first place: to permit exceptions to this rule. And then clarify that indicating a "hint" just means severing this "continuity requirement" for one state transition.
wdyt?
38faf79 to
a06c369
Compare
| `MUL d, a, b`][`FMA d == a * b + (0 * X), hint out`][Multiplication][ | ||
| `INV d, a`][`FMA d == (a + 1) * d - 1, hint <register of d>`][Extension field inversion. Note: `d` and `a` cannot use the same register here, and `d` should not be input-hinted in the next instruction.][ | ||
| `J a`][`FMA PC == a, hint out`][Jump. Can be to a register, memory content, or absolute address, depending on the addressing mode of `a`, even relative to PC][ | ||
| `JZA imm`][`FMA PC == (ZERO)*(-1*PC+(imm-1))+(1*PC+1), hint out`][Jump if ZERO, absolute target address][ |
There was a problem hiding this comment.
A) I'm not exactly sure what you mean here, the notation is meant to imply that in the translation of JZA, the immediate used is modified and not copied as-is.
Let me rephrase.
Denoting -1*PC+(imm-1) in JZA suggests that this argument has the form imm_0 * X + imm_1 - imm_2, where imm_0 = -1, X = PC and imm_2 = 1; it does not cleanly fit the imm_0 * X + imm_1 format
Same holds for JNZA, whose notation suggests that the b-argument has either the form
imm_0 * X + imm_1 - imm_2, withimm_1 = 0, orimm_0 * X + imm_1 * imm_2, withimm_1 = -1.
B) Ok, I see. Why do you prefer this way of writing over, say,
#table(
columns: (auto, auto, auto)
[a][b][c]
[d][e][f]
)?
|
|
||
| Since the VM makes use of read-only memory, traditional usage of a program stack does not work. | ||
| We assume that each function invocation (unless other optimizations apply) will have an associated _frame_, | ||
| pointed to by a _frame pointer_ `fp`, one of the general purpose registers. |
There was a problem hiding this comment.
What do you think of rephrasing
- "... pointed to by a frame pointer ..." to "... pointed to by the frame pointer ...", and
- "we assume here that fp is one of the general purpose registers" to "we assume one of the general purpose registers to assume the role of fp"
?
(github doesn't support suggestions on outdated comments :grumble:)
| we perform a _"degree split"_: | ||
| $ f_(i)(x) = f_(i, 0)(x) + x^(d - 1) (f_(i, 1)(x) + x^(d - 2) (f_(i, 2) + x^(d - 2) (f_(i, 3) + ...))), $ | ||
| $ f_(i)(x) &= f_(i, 0)(x) + x^(d - 1) (f_(i, 1)(x) + x^(d - 2) (f_(i, 2) + x^(d - 2) (f_(i, 3) + ...)))\ | ||
| &= 1 dot f_(i,0)(x) + x^(d - 1) f_(i,1)(x) + ... + x^(d - 1 + (t - 1) dot (d - 2)) f(i, t)(x), $ |
There was a problem hiding this comment.
| &= 1 dot f_(i,0)(x) + x^(d - 1) f_(i,1)(x) + ... + x^(d - 1 + (t - 1) dot (d - 2)) f(i, t)(x), $ | |
| &= 1 dot f_(i,0)(x) + x^(d - 1) f_(i,1)(x) + ... + x^(d - 1 + (t - 1) dot (d - 2)) f_(i, t)(x), $ |
| == Register hinting | ||
|
|
||
| Each general-purpose register in the current state can be marked as _hinted_ by the acting instruction. | ||
| This means that from the current state onwards, the register can take a value |
There was a problem hiding this comment.
We don't really have "transition constraints" yet at this point of the expose. [...] The onwards is there to avoid making it seem like it's only for this state, i.e. that the transition constraints do carry it forward and it's not a temporary exception.
Should we then not start this section with outlining that, in principal, register values of contiguous states are the same (referring to the state machine description at the start of 35.1.1).
That furthermore allows us to explain why hinting should be included in the first place: to permit exceptions to this rule. And then clarify that indicating a "hint" just means severing this "continuity requirement" for one state transition.
wdyt?
f43e542 to
d9af179
Compare
| ``` | ||
| FMA [1 * X + 2] == [3 * Y + 4] * (5 * Z) + [W + 6], hint out + Z | ||
| ``` |
There was a problem hiding this comment.
Is this overview supposed to be complete, or just an example? I.e., does Z have an additional sum imm and W a product imm?
Comparing this overview to the below table suggests some of the operations cannot actually be mapped onto this overview.
There was a problem hiding this comment.
It's an example where I wanted to highlight some options to simplify notation for the common case of imm_0 ∈ {0,1} or imm_1 = 0
| A state is then the tuple of all values the registers have at a given point in time during the execution.#footnote[ | ||
| If we consider states across different executions, the contents of `MEM` should also be considered part of the state. | ||
| ] | ||
| Each instruction acts upon _current state_ to produce the _future state_.#footnote[ |
There was a problem hiding this comment.
| Each instruction acts upon _current state_ to produce the _future state_.#footnote[ | |
| Each instruction acts upon the _current state_ to produce the _future state_.#footnote[ |
| The `PC` register stores the program counter: the address of the current instruction, | ||
| and --- except when branches are taken, through register hinting --- is incremented by $1$ | ||
| for every consecutive state. |
There was a problem hiding this comment.
- I don't follow the "..., and --- [...] --- is incremented ..."-segment all that well,
- I find the comma in the em-dashed sentence hard to read.
what about
| The `PC` register stores the program counter: the address of the current instruction, | |
| and --- except when branches are taken, through register hinting --- is incremented by $1$ | |
| for every consecutive state. | |
| The `PC` register stores the program counter: the address of the current instruction. | |
| Almost every instruction increments this value by $1$, except those taking a branch. |
or a variation on this?
| By default, a general-purpose register will have the same value the future state | ||
| as it does in the current state. | ||
| To change register values, each general-purpose register in the current state | ||
| can be marked as _hinted_ by the acting instruction. |
There was a problem hiding this comment.
- At the very least:
| By default, a general-purpose register will have the same value the future state | |
| as it does in the current state. | |
| To change register values, each general-purpose register in the current state | |
| can be marked as _hinted_ by the acting instruction. | |
| By default, a general-purpose register will have the same value in the future state |
- The concepts of current and future state only exist in the context of an instruction. I recommend that we either:
i. mention the instruction as context in the first sentence, or
ii. start more generic by using "consecutive states" or "contiguous states".
There was a problem hiding this comment.
I don't fully agree on the existence of the states being dependent on an instruction, but I also agree that something like "across consecutive states" probably reads better for the first sentence.
| Here all of `d`, `a`, `b` and `c` are arguments following the addressing scheme described below. | ||
|
|
||
| This constraint-based view generally goes well with a read-only memory. | ||
| The memory system gives us that guarantee that whenever we access `MEM` at the same index, |
There was a problem hiding this comment.
| The memory system gives us that guarantee that whenever we access `MEM` at the same index, | |
| The memory system gives us the guarantee that whenever we access `MEM` at the same index, |
| the register can take a value that is independent from the previous value, | ||
| except as constrained by the instruction. | ||
| Additionally, the _output_ can be marked as hinted, meaning that the register used in the `d` argument | ||
| will change from the future state onwards, and as such in the `d` argument too. |
There was a problem hiding this comment.
will change from the future state onwards, and as such in the
dargument too.
The use of "as such ... too" suggests that the d argument will change in the future state onwards? Idk, sounds weird.
What about
| will change from the future state onwards, and as such in the `d` argument too. | |
| will change from the future state onwards, thus impacting the `d` argument of the current transition. |
?
| on the result. | ||
| There may even be situations where hinting multiple values can be chosen simultaneously, such as a decomposition | ||
| $a = b + c$ in a divide-and-conquer algorithm. | ||
| Even hinting registers that are not used in the current instruction may provide useful in limited situations. |
There was a problem hiding this comment.
| Even hinting registers that are not used in the current instruction may provide useful in limited situations. | |
| Even hinting registers that are not used in the current instruction may prove useful in limited situations. |
| implementers and practitioners are encouraged to discover and use their own, | ||
| as experience may point out further useful abstractions. | ||
|
|
||
| #table(columns: (auto, 2fr, 1fr), |
There was a problem hiding this comment.
omitting my comments on this table, as those are being discussed in our chat.
| We again make use of the multiplexing machinery from before. | ||
| The constraints we want to enforce on a register index $r$ are as follows: | ||
| - $!next("hint_input")_r and !#`hint_output` => next("registers")_r = #`registers`_r$,\ `r` could not have been hinted, | ||
| since it was not input-hinted in the next row, and there was no output hint, so the next `r` should remain the same. |
There was a problem hiding this comment.
| since it was not input-hinted in the next row, and there was no output hint, so the next `r` should remain the same. | |
| since it was not input-hinted in the next row, and there was no output hint, so `r'` should remain the same. |
| # PARAM: $limits(sum)_(j = 0)^T #`arg_register_powers`_(i,j) dot limits(sum)_(k = 0)^(d - 1) #`argument_registers`_i^k dot #`RANGE`_(j,k)$ | ||
| constraint = "$limits(sum)_(j = 0)^1 #`arg_register_powers`_(i,j) dot limits(sum)_(k = 0)^4 #`argument_registers`_i^k dot #`RANGE`_(j,k)$" |
erik-3milabs
left a comment
There was a problem hiding this comment.
my remaining remarks are so minor, that I think this is ready to be merged!
| ([`DIV[U][W] rd, rs1, rs2`], [`DIVREM`], [`[W]`], [#sym.not`[U]`], [], [@decode:note:word_instr, <note_signed>]), | ||
| ([`REM[U][W] rd, rs1, rs2`], [`DIVREM`], [`[W]`], [#sym.not`[U]`], [`muldiv_selector`], [@decode:note:word_instr, <note_signed>]), |
There was a problem hiding this comment.
| ([`DIV[U][W] rd, rs1, rs2`], [`DIVREM`], [`[W]`], [#sym.not`[U]`], [], [@decode:note:word_instr, <note_signed>]), | |
| ([`REM[U][W] rd, rs1, rs2`], [`DIVREM`], [`[W]`], [#sym.not`[U]`], [`muldiv_selector`], [@decode:note:word_instr, <note_signed>]), | |
| ([`DIV[U][W] rd, rs1, rs2`], [`DIVREM`], [`[W]`], [#sym.not`[U]`], [], [@decode:note:word_instr@decode:note:signed]), | |
| ([`REM[U][W] rd, rs1, rs2`], [`DIVREM`], [`[W]`], [#sym.not`[U]`], [`muldiv_selector`], [@decode:note:word_instr@decode:note:signed]), |
|
|
||
| #let notelist(prefix, body) = { | ||
| show figure.where(kind: "note"): it => { | ||
| super(it.counter.display(it.numbering)) + box(it) |
There was a problem hiding this comment.
this box(it) doesn't seem to do much here
There was a problem hiding this comment.
on the pdf, address overflows to the next line. Maybe break here and put // address on the next line?
| show math.equation.where(block: false): box // Don't line-break inline equations by default | ||
| show ref: equate.with(sub-numbering: true, breakable: true, number-mode: "label") | ||
| show ref: it => if it.element != none and it.element.func() == figure and it.element.kind == "note" { | ||
| super[[#it]] |
There was a problem hiding this comment.
indeed curious that it does not include the brackets from the numbering here...
Kimi Code ReviewAutomated review by Kimi (Moonshot AI) |
Codex Code ReviewNo actionable issues found in the PR diff. The specification validator passes. Changes are limited to specification documents and tooling; no Rust runtime code changed. |
Co-authored-by: Erik <159244975+erik-3milabs@users.noreply.github.com> Co-authored-by: Robin Jadoul <robin.jadoul@gmail.com>
Co-authored-by: Erik <159244975+erik-3milabs@users.noreply.github.com>
ce9be50 to
e5e4cd8
Compare
No description provided.