Skip to content

Verilog: assignments between unpacked arrays of equivalent types - #2100

Draft
kroening wants to merge 1 commit into
mainfrom
kroening/fix-array-of-structs-port
Draft

Verilog: assignments between unpacked arrays of equivalent types#2100
kroening wants to merge 1 commit into
mainfrom
kroening/fix-array-of-structs-port

Conversation

@kroening

Copy link
Copy Markdown
Collaborator

Fixes the KNOWNBUG from #2099. Based on #2099, please merge that one first.

Per 1800-2017 section 7.6, an unpacked array can be assigned an unpacked array of
an equivalent type, and section 6.22.1 gives the equivalence rules:

  • (c) fixed-size unpacked arrays are equivalent when they have the same size and
    equivalent element types;
  • (d) packed arrays, packed structs, packed unions and the built-in integral
    types are equivalent when they have the same number of bits, are all 2-state or
    all 4-state, and are all signed or all unsigned.

An unpacked array of an eight-bit packed struct is therefore assignable to, and
connectable to a port of, an unpacked array of [7:0].

Changes

  • src/verilog/verilog_typecheck_expr.cpp — new equivalent_type
    implementing 6.22.1, with is_integral_type (6.11.1) and is_signed_type
    (7.2.1, 7.4.1) helpers. assignment_conversion now inserts a typecast where
    the two unpacked array types are equivalent but not identical, instead of
    rejecting the assignment.
  • src/verilog/verilog_lowering.cpp — the lowering of a typecast to a
    struct, union or array passed the operand to from_bitvector without
    converting it to a bit vector first, which tripped the src.type().id() != ID_array precondition in extract once the operand was itself of a composite
    type. It now goes through to_bitvector, which returns non-composite operands
    unchanged, so the existing paths are unaffected.

Note that the elaborated types do not record whether a vector was declared as
2-state or 4-state (logic [7:0] and bit [7:0] both elaborate to the same
type), so the 2-state/4-state condition only rules out the types that carry x
and z. This is noted in a comment.

Tests

  • structs/array_of_structs2 — flipped KNOWNBUG to CORE (the reported port
    connection).
  • structs/array_of_structs3 — new CORE test asserting the conversion in both
    directions, checking the order of the array elements and the order of the
    struct members, using a two-field struct against [15:0] so a swap would be
    caught.
  • structs/array_of_structs4 — new CORE test that non-equivalent element widths
    are still rejected.

Also checked by hand, and still rejected: array size mismatch, signedness
mismatch, and an unpacked struct as the element type. Nested
array of array of struct works via the recursive case.

Full regression/{verilog,ebmc,smv,vlindex} in -C and -K modes plus the unit
tests pass.

@kroening
kroening marked this pull request as draft August 12, 2026 21:07
@kroening
kroening marked this pull request as ready for review August 12, 2026 22:45
@kroening
kroening marked this pull request as draft August 12, 2026 22:45
@kroening
kroening changed the base branch from kroening/knownbug-array-of-structs-port to main August 13, 2026 09:11
Per 1800-2017 section 7.6, an unpacked array can be assigned an unpacked
array of an equivalent type, and section 6.22.1 gives the rules for type
equivalence: fixed-size unpacked arrays are equivalent when they have the
same size and equivalent element types, and packed arrays, packed structs,
packed unions and the built-in integral types are equivalent when they
have the same number of bits, the same 2-state/4-state property, and the
same signing.  An unpacked array of a packed struct that is eight bits
wide can therefore be assigned to, or connected to a port of, an unpacked
array of [7:0].

The type checker now implements this equivalence rule, and inserts a
typecast where the two types are equivalent but not identical.  The
lowering of a typecast to a struct, union or array passed the operand to
from_bitvector without converting it to a bit vector first, which tripped
a precondition in extract when the operand was itself of a composite
type; this now goes through to_bitvector, which leaves non-composite
operands unchanged.

Note that the elaborated types do not record whether a vector was
declared as 2-state or 4-state, and hence the 2-state/4-state condition
only rules out the types that carry x and z.
@kroening
kroening force-pushed the kroening/fix-array-of-structs-port branch from df4878e to 094aebd Compare August 13, 2026 15:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant