Skip to content

Conversation

@youngar
Copy link
Member

@youngar youngar commented Jul 17, 2025

This adds the ability to specify the constants used to encode enumeration variants in the tag. For example,

wire a : {| A = 10, B = 5 |}

The values can be unspecified, in which case it defaults to one higher than the previous value, or zero if it is the first value. For example, these two enumerations are the same:

{| A = 0, B = 1 |} == {| A, B |}

In FIRRTL, Two enumeration types are considered equal if they have the same variants with the same values and data, without regard to variant order. Internally in FIRRTL dialect IR, enumerations types must have the variants sorted from low to high. For example the following two enumeration types are equivalent:

{| B = 1, A = 0 |} == {| A, B |}

The mlir syntax has been updated to ellide the the tag values and data types if they are implicit. For example, the first type would be roundtripped to the second type:

!firrtl.enum<a = 0 : uint<0>> => !firrtl.enum<a>

Enumerations are no longer lowered to SystemVerilog enumerations, but to regular integer types. This is for a variety of reasons, but mainly because enumerations in SV are nominal and it was not a good fit for our structural enumerations.

In LowerToHW, the firrtl.istag operation lowers to a comparison to a constant value created with a localparam, which can show up in the output depending on how the module is optimized. The FIRRTL code below,

FIRRTL version 4.0.0
circuit Enums:
  public module Enums:
    input in : {|A = 8 : UInt<8>, B = 16 |}
    output out : UInt<8>
    match in:
      A(data):
        connect out, data
      B:
        connect out, UInt<8>(16)

produces:

module Enums(
  input  struct packed {logic [4:0] tag; union packed {logic [7:0] A;/*B: Zero Width;*/ } body; } in,
  output [7:0]                                                                                    out
);

  localparam [4:0] A = 8;
  assign out = in.tag == A ? in.body.A : 8'h10;
endmodule

@youngar youngar added the FIRRTL Involving the `firrtl` dialect label Jul 17, 2025
@youngar youngar force-pushed the firrtl-enum-user-defined-encodings branch from 4105cf8 to db014d5 Compare July 17, 2025 17:31
@youngar
Copy link
Member Author

youngar commented Jul 17, 2025

TagExtractOp's type inference is broken by this change, but I will fix it in a later commit.

@youngar youngar force-pushed the firrtl-enum-user-defined-encodings branch 4 times, most recently from 1f005c2 to 4002d1a Compare July 17, 2025 21:53
This adds the ability to specify the constants used to encode
enumeration variants in the tag. For example,
``` firrtl
wire a : {| A = 10, B = 5 |}
```

The values can be unspecified, in which case it defaults to one higher
than the previous value, or zero if it is the first value. For example,
these two enumerations are the same:
``` firrtl
{| A = 0, B = 1 |} == {| A, B |}
```

In FIRRTL, Two enumeration types are considered equal if they have the
same variants with the same values and data, without regard to variant
order.  Internally in FIRRTL dialect IR, enumerations types must have
the variants sorted from low to high. For example the following two
enumeration types are equivalent:
``` firrtl
{| B = 1, A = 0 |} == {| A, B |}
```

The mlir syntax has been updated to ellide the the tag values and data
types if they are implicit.  For example, the first type would be
roundtripped to the second type:
``` mlir
!firrtl.enum<a = 0 : uint<0>> => !firrtl.enum<a>
```

Enumerations are no longer lowered to SystemVerilog enumerations, but to
regular integer types.  This is for a variety of reasons, but mainly
because enumerations in SV are nominal and it was not a good fit for our
structural enumerations.

In LowerToHW, the `firrtl.istag` operation lowers to a comparison to a
constant value created with  a localparam, which can show up in the
output depending on how the module is optimized. The  FIRRTL code below,

``` firrtl
FIRRTL version 4.0.0
circuit Enums:
  public module Enums:
    input in : {|A = 8 : UInt<8>, B = 16 |}
    output out : UInt<8>
    match in:
      A(data):
        connect out, data
      B:
        connect out, UInt<8>(16)
```
produces:
``` verilog
module Enums(
  input  struct packed {logic [4:0] tag; union packed {logic [7:0] A;/*B: Zero Width;*/ } body; } in,
  output [7:0]                                                                                    out
);

  localparam [4:0] A = 8;
  assign out = in.tag == A ? in.body.A : 8'h10;
endmodule
```
@youngar youngar force-pushed the firrtl-enum-user-defined-encodings branch from 4002d1a to eb98d4b Compare July 17, 2025 21:56
@youngar
Copy link
Member Author

youngar commented Jul 17, 2025

Pushed in some additional enum type verification that I was going to add in a future PR, for completeness.

@youngar youngar force-pushed the firrtl-enum-user-defined-encodings branch from 6cbe8db to 100e095 Compare July 18, 2025 17:36
@youngar youngar merged commit 6ece8a3 into llvm:main Jul 18, 2025
7 checks passed
@youngar youngar deleted the firrtl-enum-user-defined-encodings branch July 18, 2025 18:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

FIRRTL Involving the `firrtl` dialect

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants