Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@Scheremo
Copy link
Contributor

@Scheremo Scheremo commented Sep 18, 2025

This PR fixes a bug where RValue Conversion is not called when a struct is created from immediate values.

Per IEEE 1800-2023 Section 10.9.2 "Structure assignment patterns", the following assignment pattern is valid:

structType st = '{member: value, memberTwo: valueTwo, ...};

In ImportVerilog, this pattern is recognized and mapped to a moore:StructCreate operator.

Until now the RValue expressions for value and valueTwo were converted without a target type.
This leads to a failure to convert e.g. between ArrayType instances and IntType instances.
This PR fixes this by passing the structType member types to the convertRValueExpression function to have them be cast explicitly.

@Scheremo Scheremo changed the title [Moore] Fix missing RValue conversion for struct_create [ImportVerilog] Fix missing RValue conversion for struct_create Sep 18, 2025
@Scheremo Scheremo marked this pull request as ready for review September 18, 2025 16:54
Copy link
Contributor

@fabianschuiki fabianschuiki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Excellent find πŸ™! Might be worth extending to the arrays as well πŸ™‚

if (auto arrayType = dyn_cast<moore::ArrayType>(type)) {
assert(arrayType.getSize() == elements.size());
return moore::ArrayCreateOp::create(builder, loc, arrayType, elements);
auto elements = convertElements(expr, {}, replCount);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to pass the expected element type in for arrays? They might suffer from the same issue as the struct patterns. You could have an std::variant<Type, ArrayRef<Type>> on convertElements to distinguish between a uniform type across all elements, and a specific type per element. Or maybe a separate Type uniformType operand? Or treat expectedTypes of size 1 as the uniform type for all elements?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can definitely adapt that. I haven't been able to produce the same bug for Array conversions though - should we still go for it?

Copy link
Contributor Author

@Scheremo Scheremo Sep 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored to use a std::variant<Type, ArrayRef<Type>> and applying it to array elements as well.
Since int-casts are anyway on the "direct and happy path" in convertRvalueExpression and the current code treats IntType assignment over optionally multiple RValues, I left those out as it seems unsafe (e.g. you could concat a 2-bit and two 1-bit expressions to a 4-bit expression, explicit casts would mess this up, probably).

Comment on lines +3199 to +3215

// CHECK-LABEL: func.func private @StructCreateConversion(
// CHECK-SAME: [[ARRAY:%.+]]: !moore.array<8 x l8>
// CHECK-SAME: [[IMM:%.+]]: !moore.l64
function void StructCreateConversion (logic [7:0][7:0] array, logic [63:0] immediate);

typedef struct packed {
logic [63:0] structField;
} testStruct;

// CHECK: [[TS:%.+]] = moore.struct_create [[IMM]] : !moore.l64 -> struct<{structField: l64}>
testStruct ts = '{structField: immediate};
// CHECK: [[CAST:%.+]] = moore.packed_to_sbv [[ARRAY]] : array<8 x l8>
// CHECK-NEXT: [[TS2:%.+]] = moore.struct_create [[CAST]] : !moore.l64 -> struct<{structField: l64}>
testStruct ts2 = '{structField: array};

endfunction
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This exact pattern might also break for arrays. Might be worth a test to see if you can trigger the issue there.

Copy link
Contributor Author

@Scheremo Scheremo Sep 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I think arrays are okay; I tried the following:

logic [7:0][7:0] array;
logic [63:0] ts3 = array;

And it gets lowered correctly to:

%arg0: !moore.array<8 x l8>
...
%3 = moore.packed_to_sbv %arg0 : array<8 x l8>
%ts3 = moore.variable %3 : <l64>

Copy link
Contributor Author

@Scheremo Scheremo Sep 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also tried struct -> arrary, which also works.

   typedef struct packed {
      logic [63:0] structField;
   } testStruct;
   logic [63:0] immediate;
   testStruct ts = '{structField: immediate};
   logic [7:0][7:0] ts3 = ts;

turns into

    %0 = moore.struct_create %arg1 : !moore.l64 -> struct<{structField: l64}>
    %ts = moore.variable %0 : <struct<{structField: l64}>>
    ...
    %3 = moore.read %ts : <struct<{structField: l64}>>
    %4 = moore.packed_to_sbv %3 : struct<{structField: l64}>
    %5 = moore.sbv_to_packed %4 : array<8 x l8>
    %ts3 = moore.variable %5 : <array<8 x l8>>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh that's very interesting! So might truly just be the structs that have this behavior. πŸ‘ No need to fix stuff that isn't broken 😁

Comment on lines -1049 to +1113
assert(intType.getWidth() == elements.size());
std::reverse(elements.begin(), elements.end());
return moore::ConcatOp::create(builder, loc, intType, elements);
auto elements = convertElements(expr, {}, replCount);

if (failed(elements))
return {};

assert(intType.getWidth() == elements->size());
std::reverse(elements->begin(), elements->end());
return moore::ConcatOp::create(builder, loc, intType, *elements);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Integers might also suffer from this lack of a cast. Maybe we need to convert all elements to simple bit vectors with the same domain as the intType? Probably worth adding a test to see if you can produce the same failure you've seen for structs also for an assignment pattern to an integer πŸ€”

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I've tried so far I haven't been able to trigger the same issue with direct-to-int assignment.
I adapted the test code described above for int ts, logic [63:0] ts, and integer ts. All seem to work fine on my end.

@fabianschuiki fabianschuiki added the bug Something isn't working label Sep 18, 2025
This PR fixes a bug where RValue Conversion is not called when a struct is created from immediate values.

Per IEEE 1800-2023 Section 10.9.2 "Structure assignment patterns", the following assignment pattern is valid:

structType st = '{member: value, memberTwo: valueTwo, ...};
In ImportVerilog, this pattern is recognized and mapped to a moore:StructCreate operator.

Until now the RValue expressions for value and valueTwo were converted without a target type.
This leads to a failure to convert e.g. between ArrayType instances and IntType instances.
This PR fixes this by passing the structType member types to the convertRValueExpression function to have them be cast explicitly.
@Scheremo
Copy link
Contributor Author

As far as I can tell I've addressed all comments, please feel free to raise more or point out ones I might've missed. Otherwise I am okay to merge πŸ˜„

@fabianschuiki fabianschuiki merged commit 09f0bbe into llvm:main Sep 18, 2025
7 checks passed
@Scheremo Scheremo deleted the pr-struct-create branch October 21, 2025 07:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working ImportVerilog Moore

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants