Repository navigation
Read a packed element selected inside an unpacked array's element in compiled code (§7.4.1, §7.4.5, §11.5.1, #985) - #986
Open
chuanseng-ng wants to merge 5 commits into
Conversation
…compiled code (§7.4.1, §7.4.5, §11.5.1, aionhw#985)
…d code (§7.4.1, §7.4.5, §11.5.1, aionhw#985)
…ompiled code (§7.4.1, §7.4.5, §11.5.1, aionhw#985)
… code (§7.4.1, §7.4.5, §11.5.1, aionhw#985)
chuanseng-ng
force-pushed
the
fix/packed-subelem-read
branch
from
November 9, 2026 09:14
20f3cae to
4aebfba
Compare
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.
Fixes #985.
Problem
A packed element selected inside an unpacked array's element read wrong in compiled code (an
alwaysblock, a continuous assignment):d[1][0]onlogic [1:0][7:0] d [2]read0Xinstead of the low byte ofd[1], anda[1][1][1]onlogic [1:0][7:0] a [2][2]read one bit of the element (§7.4.1, §7.4.5, §11.5.1). Writes,initialreads and$displaywere right.The same holds when the element is an array of packed structs:
b[0][1]onle_t [1:0] b [2], withle_ta 40-bit packed struct, is one struct (§7.4.1, §7.2.1), but compiled code read 0, one bit, or a slice that leaves out the struct's own width.Cause
In the
Indexread of the bytecode compiler, the chained packed select (chained_packed_slice,emit_chained_packed_slice_dyn) walks the root's packed dimensions only, sod[1][0]was taken as packed[1][0]of the array's root. A chain longer than the packed dimensions (a[1][1][1]) fell through to the plain bit select of the loaded element.For struct elements,
packed_full_dimslists only the packed array dimensions, not the struct's width. When no dimensions are recorded at all (a single[N-1:0]range, or any range of a typedef-named struct type), the chain was not recognised as selecting into the element.Fix
unpacked_elem_select_depthfinds how many indices address the root's unpacked dimensions: 1 for a one-dimensional array (queues and dynamic arrays included), 2 for a two-dimensional one, the constant prefix that names a stored element for a deeper one. It answers only when the remaining indices select into a multi-dimensional packed element.elem_packed_dimsgives that element's packed dimensions down to single bits. When the element is wider than the product of the recorded packed dimensions (a packed struct), the rest is one more dimension of that width. When none are recorded, the packed element width gives the shape, but not whether the range is[N-1:0],[0:N-1]or offset. Such a read declines to the AST path, which reads the labels from the declaration, instead of placing the select by guess.compile_unpacked_elem_packed_selectreads that element through its existing path and slices the packed element out of it:RangeSelectConstfor constant indices (an out-of-range index reads x, §11.5.1), a run-time offset otherwise. An element that does not compile keeps the read on the AST path.is_unpacked_chain_root, the same testchained_packed_select_widthalready applies).packed_chain_offset/emit_packed_chain_offset/emit_dyn_slice, shared by both paths; the packed chain's own behaviour is unchanged.Tests
tests/types/unpacked_elem_packed_select_read.rs, 10 tests, every expected value from the reference simulator.selects_that_already_work(a bit select of an unpacked vector element, a packed element select, a whole element read, a part-select of a packed vector) passes as a guard.queue_dynamic_array_and_typedef_elementswas added after the fix. Its source on xezim2e4e7f99givesr1=0X r2=0X r3=0X; the reference simulator givesr1=12 r2=78 r3=9a.packed_struct_elements(package, local and inline struct types, typedef-named ranges, ascending and offset ranges, dynamic indices, member and part-selects of a selected struct) fails on the branch before the struct commits.struct_elements_with_recorded_rangesruns its reads in analwaysblock with recorded ranges ([0:1],[2:1],[1:0][1:0]), so they compile toLoadArr+RangeSelectConstrather than taking the AST path.c35707e6always)cont d=ab00000001 a=ab00000001 proc d=ab00000001 a=ab00000001cont d=ab00000001 a=0000000000 proc d=000000000X a=0000000000(on2e4e7f99)r1=12 r2=78 r3=56 r4=9a r5=de r6=21 r7=87 r8=34 r9=7 r10=1 w1=ee w2=ccr1=0X r2=0X r3=00 r4=00 r5=0X r6=0X r7=0x r8=0X r9=X r10=x w1=0X w2=0X(on2e4e7f99)r1=12 r2=78 r3=9ar1=0X r2=0X r3=0X(on2e4e7f99)r1=dead0000a5 r2=1122334455 r3=abcdef0123 r4=a0b0c0d0e0 r5=789abc r6=a r7=1 r8=a5 r9=2222222222 eq=1r1=0000000000 r2=0000000001 r3=0000000000 r4=0000000000 r5=000000 r6=x r7=1 r8=a5 r9=0000000001 eq=0r1=abcdef0123 r2=4567890abc r3=1111111111 r4=010203040506 r5=0708a9 r6=2 eq=1r1=abcdef0123 r2=4567890abc r3=1111111111 r4=00000000000X r5=00000X r6=2 eq=1c35707e6+ this branch, pinned core2ff85ad): 6620 passed, 0 failed, 1 ignored.XEZIM_JIT=1(--features jit): the 10 tests pass on a--features jitbuild.perfis not available on this machine (perf_event_paranoid=4), so no instruction counts. The change is in the compiler, not the VM: compile time adds a table lookup onIndexreads with a chain, and the emitted code is a load of the element and one slice.Caches and notes
METHOD_CACHE_COMPILER_SALTgoes to0x6370_6666_306cwith a comment line: these reads now compile to different instructions, and an element that does not compile now declines.Note …commit adds theNOTES.mdentry under### Unreleased.Related: Default, Row and 6 in #879 are stores and are not changed here. The packed dimensions of a typedef-named struct array (#984) are not recorded by the elaborator; until they are, reads into such arrays with more than one packed select stay on the AST path, which reads them right.