Repository navigation
Check that instruction immediates fit their encoding; Add warnings-as-errors option. - #3
Merged
Merged
Conversation
dvp-as keeps only the low bits of an immediate that doesn't fit the instruction's field, without a diagnostic: `iaddi VI03, VI10, -18` assembles to the same word as `+14`, since IADDI's immediate is 5 bits, signed. openvcl passed such values through from the source, and its scheduler could create out-of-range offsets of its own when it shifted a load or store across a pointer update. Each instruction's immediate is now checked when it is parsed, using the value openvcl emits (its own evaluation of the expression, or the integer literal dvp-as reads): - iaddi outside -16..15 is emitted as isubiu/iaddiu of the magnitude, the way SCE vcl 1.4beta7 emits every iaddi (`iaddi a, b, -18` becomes `isubiu a, b, 18`). Outside -32767..32767 it is an error. - iaddiu/isubiu outside 0..32767, fcand/fceq/fcor/fcset beyond 24 bits and fsand/fseq/fsor/fsset beyond 12 bits are errors. vcl 1.4beta7 only warns on iaddiu/isubiu and passes the fc* masks through, and dvp-as then truncates them. - lq/sq/ilw/isw offsets outside -1024..1023 are a warning. vcl 1.4beta7 accepts them, and since VU1 addresses wrap at 1024 quadwords the truncated offset reaches the same address. The scheduler no longer makes a change that would push an offset out of the field: moving a store into a branch delay slot, advancing a pointer update above its stores, software-pipeline prefetches and drained stores (treated like an unknown next-iteration offset), and multi-Q cyclic prefixes. Merging two iaddiu now keeps to IADDIU's unsigned range. test/repro/quad_adc_bug.vcl used `iaddiu vi05, vi00, 0xffff`, which assembles as 0x7fff; it now says 0x7fff. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With it, any warning fails the run with a non-zero exit status, as an error does. The first warning openvcl reports is the out-of-range memory offset added in the previous commit, which a build can now choose to stop on. The warning text is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 20, 2026
fjtrujy
approved these changes
Oct 20, 2026
fjtrujy
left a comment
Member
There was a problem hiding this comment.
Amazing!
Good improvements.
Cheers!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Checking that instruction immediates fit their encoding:
dvp-askeeps only the low bits of an immediate that doesn't fit its field, and truncates without errors or warnings.iaddi VI03, VI10, -18assembles to the same word as+14, because IADDI's immediate is 5 bits, signed.This issue was found on the Quake2 PS2 port project where a check computed
iVertsLeft + 14this way. openvcl passed such values through from the source. Its scheduler could also create out-of-range offsets itself when it moved a load or store across a pointer update.What SCE's vcl 1.4beta7 (distributed with the Tyra engine) does, from this CI run:
iaddi, 5 bits signed-18,16iaddiasisubiu/iaddiu, e.g.isubiu VI01,VI00,18iaddiu/isubiu, 15 bits unsigned40000,-1,32768fcand/fcor/fcset, 24 bits0x1000000fsand/fsset, 12 bits0x1000,4096fsand, deletes thefssetlq/sq/ilw/iswoffset, 11 bits signed1024,-1025,2000With this PR:
An
iaddioutside -16..15 is emitted asisubiu/iaddiuwith the value's magnitude, as SCE's vcl does. Aniaddiwithin -16..15 is unchanged. Outside ±32767 it's an error.An
iaddiu/isubiu,fc*orfs*immediate that doesn't fit is an error, for examplex.vcl(10) : Immediate 40000 is outside 0..32767 (iaddiu iC, iA, >>> 40000 <<<).A memory offset outside -1024..1023 is a warning, for example
warning: Offset 2000 is outside -1024..1023 and assembles as -48. vcl accepts these, and VU1 addresses wrap at 1024 quadwords, so the truncated offset reaches the same address.The value checked is the one openvcl emits: its own evaluation of the expression, or the integer literal dvp-as reads (hex, binary, octal). Symbols are left to the assembler. A line with a bad immediate is still compiled, so later lines don't get follow-on errors.
The scheduler no longer pushes an offset out of the field when it:
optimizationsbranch);Merging two
iaddiunow stays within 0..32767.The second commit adds
--warnings-as-errors, which makes any warning fail the run. We now emit a warning for the memory offset range check.test/repro/quad_adc_bug.vclusediaddiu vi05, vi00, 0xffff. That assembles as0x7fffand would now be an error, so it now says0x7fff.Testing:
test/integration/test_immediate_ranges.cppwith 14 cases.lq VF01, 1024(VI01). With this PR every offset fits, and the output is byte-identical to master's wherever master's already fitted.🤖 Co-authored by Claude Code