Skip to content

Commit 23fc6c1

Browse files
committed
[ImportVerilog] add sized stream concat operation
[ImportVerilog] fix bugs, enhance testcase and remove irrelevant changes [ImportVerilog] run clang-format [ImportVerilog] polish test case and diagnostics infomation [ImportVerilog] remove wrong 'reverse', update testcase and comment [ImportVerilog] improve file check comment readability [ImportVerilog] fix testcase [ImportVerilog] add fixed size 'with expression' support [ImportVerilog] cleanup
1 parent 99930ad commit 23fc6c1

File tree

3 files changed

+314
-0
lines changed

3 files changed

+314
-0
lines changed

lib/Conversion/ImportVerilog/Expressions.cpp

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,76 @@ struct RvalueExprVisitor {
787787
return visitAssignmentPattern(expr, *count);
788788
}
789789

790+
Value visit(const slang::ast::StreamingConcatenationExpression &expr) {
791+
SmallVector<Value> operands;
792+
for (auto stream : expr.streams()) {
793+
auto operandLoc = context.convertLocation(stream.operand->sourceRange);
794+
if (!stream.constantWithWidth.has_value() && stream.withExpr) {
795+
mlir::emitError(operandLoc)
796+
<< "Moore only support streaming "
797+
"concatenation with fixed size 'with expression'";
798+
return {};
799+
}
800+
Value value;
801+
if (stream.constantWithWidth.has_value()) {
802+
value = context.convertRvalueExpression(*stream.withExpr);
803+
auto type = cast<moore::UnpackedType>(value.getType());
804+
auto intType = moore::IntType::get(
805+
context.getContext(), type.getBitSize().value(), type.getDomain());
806+
// do not care if it's signed, because we will not do expansion
807+
value = context.materializeConversion(intType, value, false, loc);
808+
} else {
809+
value = context.convertRvalueExpression(*stream.operand);
810+
}
811+
812+
if (!value)
813+
return {};
814+
value = context.convertToSimpleBitVector(value);
815+
if (!value) {
816+
return {};
817+
}
818+
operands.push_back(value);
819+
}
820+
Value value;
821+
822+
if (operands.size() == 1) {
823+
// There must be at least one element, otherwise slang will report an
824+
// error
825+
value = operands.front();
826+
} else {
827+
value = builder.create<moore::ConcatOp>(loc, operands).getResult();
828+
}
829+
830+
if (expr.sliceSize == 0) {
831+
return value;
832+
}
833+
834+
auto type = cast<moore::IntType>(value.getType());
835+
SmallVector<Value> slicedOperands;
836+
auto iterMax = type.getWidth() / expr.sliceSize;
837+
auto remainSize = type.getWidth() % expr.sliceSize;
838+
839+
for (size_t i = 0; i < iterMax; i++) {
840+
auto extractResultType = moore::IntType::get(
841+
context.getContext(), expr.sliceSize, type.getDomain());
842+
843+
auto extracted = builder.create<moore::ExtractOp>(
844+
loc, extractResultType, value, i * expr.sliceSize);
845+
slicedOperands.push_back(extracted);
846+
}
847+
// Handle other wire
848+
if (remainSize) {
849+
auto extractResultType = moore::IntType::get(
850+
context.getContext(), remainSize, type.getDomain());
851+
852+
auto extracted = builder.create<moore::ExtractOp>(
853+
loc, extractResultType, value, iterMax * expr.sliceSize);
854+
slicedOperands.push_back(extracted);
855+
}
856+
857+
return builder.create<moore::ConcatOp>(loc, slicedOperands);
858+
}
859+
790860
/// Emit an error for all other expressions.
791861
template <typename T>
792862
Value visit(T &&node) {
@@ -925,6 +995,75 @@ struct LvalueExprVisitor {
925995
dynLowBit);
926996
}
927997

998+
Value visit(const slang::ast::StreamingConcatenationExpression &expr) {
999+
SmallVector<Value> operands;
1000+
for (auto stream : expr.streams()) {
1001+
auto operandLoc = context.convertLocation(stream.operand->sourceRange);
1002+
if (!stream.constantWithWidth.has_value() && stream.withExpr) {
1003+
mlir::emitError(operandLoc)
1004+
<< "Moore only support streaming "
1005+
"concatenation with fixed size 'with expression'";
1006+
return {};
1007+
}
1008+
Value value;
1009+
if (stream.constantWithWidth.has_value()) {
1010+
value = context.convertLvalueExpression(*stream.withExpr);
1011+
auto type = cast<moore::UnpackedType>(
1012+
cast<moore::RefType>(value.getType()).getNestedType());
1013+
auto intType = moore::RefType::get(moore::IntType::get(
1014+
context.getContext(), type.getBitSize().value(), type.getDomain()));
1015+
// do not care if it's signed, because we will not do expansion
1016+
value = context.materializeConversion(intType, value, false, loc);
1017+
} else {
1018+
value = context.convertLvalueExpression(*stream.operand);
1019+
}
1020+
1021+
if (!value)
1022+
return {};
1023+
operands.push_back(value);
1024+
}
1025+
Value value;
1026+
if (operands.size() == 1) {
1027+
// There must be at least one element, otherwise slang will report an
1028+
// error
1029+
value = operands.front();
1030+
} else {
1031+
value = builder.create<moore::ConcatRefOp>(loc, operands).getResult();
1032+
}
1033+
1034+
if (expr.sliceSize == 0) {
1035+
return value;
1036+
}
1037+
1038+
auto type = cast<moore::IntType>(
1039+
cast<moore::RefType>(value.getType()).getNestedType());
1040+
SmallVector<Value> slicedOperands;
1041+
auto widthSum = type.getWidth();
1042+
auto domain = type.getDomain();
1043+
auto iterMax = widthSum / expr.sliceSize;
1044+
auto remainSize = widthSum % expr.sliceSize;
1045+
1046+
for (size_t i = 0; i < iterMax; i++) {
1047+
auto extractResultType = moore::RefType::get(
1048+
moore::IntType::get(context.getContext(), expr.sliceSize, domain));
1049+
1050+
auto extracted = builder.create<moore::ExtractRefOp>(
1051+
loc, extractResultType, value, i * expr.sliceSize);
1052+
slicedOperands.push_back(extracted);
1053+
}
1054+
// Handle other wire
1055+
if (remainSize) {
1056+
auto extractResultType = moore::RefType::get(
1057+
moore::IntType::get(context.getContext(), remainSize, domain));
1058+
1059+
auto extracted = builder.create<moore::ExtractRefOp>(
1060+
loc, extractResultType, value, iterMax * expr.sliceSize);
1061+
slicedOperands.push_back(extracted);
1062+
}
1063+
1064+
return builder.create<moore::ConcatRefOp>(loc, slicedOperands);
1065+
}
1066+
9281067
Value visit(const slang::ast::MemberAccessExpression &expr) {
9291068
auto type = context.convertType(*expr.type);
9301069
auto valueType = expr.value().type;

test/Conversion/ImportVerilog/basic.sv

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,19 @@ module Expressions;
604604
// CHECK: %b = moore.variable : <i32>
605605
// CHECK: %c = moore.variable : <i32>
606606
int a, b, c;
607+
// CHECK: %j = moore.variable : <i32>
608+
int j;
609+
// CHECK: %up = moore.variable : <uarray<4 x l11>>
610+
logic [10:0] up [3:0];
611+
// CHECK: %p1 = moore.variable : <l11>
612+
// CHECK: %p2 = moore.variable : <l11>
613+
// CHECK: %p3 = moore.variable : <l11>
614+
// CHECK: %p4 = moore.variable : <l11>
615+
logic [11:1] p1, p2, p3, p4;
616+
// CHECK: %yy = moore.variable : <i96>
617+
bit [96:1] yy;
618+
// CHECK: %dd = moore.variable : <i100>
619+
bit [99:0] dd;
607620
// CHECK: %u = moore.variable : <i32>
608621
// CHECK: %w = moore.variable : <i32>
609622
int unsigned u, w;
@@ -622,8 +635,16 @@ module Expressions;
622635
logic [31:0] vec_1;
623636
// CHECK: %vec_2 = moore.variable : <l32>
624637
logic [0:31] vec_2;
638+
// CHECK: %vec_3 = moore.variable : <l16>
639+
logic [15:0] vec_3;
640+
// CHECK: %vec_4 = moore.variable : <l32>
641+
logic [31:0] vec_4;
642+
// CHECK: %vec_5 = moore.variable : <l48>
643+
logic [47:0] vec_5;
625644
// CHECK: %arr = moore.variable : <uarray<3 x uarray<6 x i4>>>
626645
bit [4:1] arr [1:3][2:7];
646+
647+
logic arr_1 [63:0];
627648
// CHECK: %struct0 = moore.variable : <struct<{a: i32, b: i32}>>
628649
struct packed {
629650
int a, b;
@@ -690,6 +711,117 @@ module Expressions;
690711
{a, b, c} = a;
691712
// CHECK: moore.concat_ref %d, %e : (!moore.ref<l32>, !moore.ref<l32>) -> <l64>
692713
{d, e} = d;
714+
// CHECK: [[TMP1:%.+]] = moore.read %j : <i32>
715+
// CHECK: moore.blocking_assign %a, [[TMP1]] : i32
716+
a = { >> {j}};
717+
// CHECK: [[TMP1:%.+]] = moore.read %j : <i32>
718+
// CHECK: [[TMP2:%.+]] = moore.extract [[TMP1]] from 0 : i32 -> i8
719+
// CHECK: [[TMP3:%.+]] = moore.extract [[TMP1]] from 8 : i32 -> i8
720+
// CHECK: [[TMP4:%.+]] = moore.extract [[TMP1]] from 16 : i32 -> i8
721+
// CHECK: [[TMP5:%.+]] = moore.extract [[TMP1]] from 24 : i32 -> i8
722+
// CHECK: [[TMP6:%.+]] = moore.concat [[TMP2]], [[TMP3]], [[TMP4]], [[TMP5]] : (!moore.i8, !moore.i8, !moore.i8, !moore.i8) -> i32
723+
// CHECK: moore.blocking_assign %a, [[TMP6]] : i32
724+
a = { << byte {j}};
725+
// CHECK: [[TMP1:%.+]] = moore.read %j : <i32>
726+
// CHECK: [[TMP2:%.+]] = moore.extract [[TMP1]] from 0 : i32 -> i16
727+
// CHECK: [[TMP3:%.+]] = moore.extract [[TMP1]] from 16 : i32 -> i16
728+
// CHECK: [[TMP4:%.+]] = moore.concat [[TMP2]], [[TMP3]] : (!moore.i16, !moore.i16) -> i32
729+
// CHECK: moore.blocking_assign %a, [[TMP4]] : i32
730+
a = { << 16 {j}};
731+
// CHECK: [[TMP1:%.+]] = moore.constant 53 : i8
732+
// CHECK: [[TMP2:%.+]] = moore.extract [[TMP1]] from 0 : i8 -> i1
733+
// CHECK: [[TMP3:%.+]] = moore.extract [[TMP1]] from 1 : i8 -> i1
734+
// CHECK: [[TMP4:%.+]] = moore.extract [[TMP1]] from 2 : i8 -> i1
735+
// CHECK: [[TMP5:%.+]] = moore.extract [[TMP1]] from 3 : i8 -> i1
736+
// CHECK: [[TMP6:%.+]] = moore.extract [[TMP1]] from 4 : i8 -> i1
737+
// CHECK: [[TMP7:%.+]] = moore.extract [[TMP1]] from 5 : i8 -> i1
738+
// CHECK: [[TMP8:%.+]] = moore.extract [[TMP1]] from 6 : i8 -> i1
739+
// CHECK: [[TMP9:%.+]] = moore.extract [[TMP1]] from 7 : i8 -> i1
740+
// CHECK: [[TMP10:%.+]] = moore.concat [[TMP2]], [[TMP3]], [[TMP4]], [[TMP5]], [[TMP6]], [[TMP7]], [[TMP8]], [[TMP9]] : (!moore.i1, !moore.i1, !moore.i1, !moore.i1, !moore.i1, !moore.i1, !moore.i1, !moore.i1) -> i8
741+
// CHECK: [[TMP11:%.+]] = moore.zext [[TMP10]] : i8 -> i32
742+
// CHECK: moore.blocking_assign %a, [[TMP11]] : i32
743+
a = { << { 8'b0011_0101 }};
744+
// CHECK: [[TMP1:%.+]] = moore.constant -11 : i6
745+
// CHECK: [[TMP2:%.+]] = moore.extract [[TMP1]] from 0 : i6 -> i4
746+
// CHECK: [[TMP3:%.+]] = moore.extract [[TMP1]] from 4 : i6 -> i2
747+
// CHECK: [[TMP4:%.+]] = moore.concat [[TMP2]], [[TMP3]] : (!moore.i4, !moore.i2) -> i6
748+
// CHECK: [[TMP5:%.+]] = moore.zext [[TMP4]] : i6 -> i32
749+
// CHECK: moore.blocking_assign %a, [[TMP5]] : i32
750+
a = { << 4 { 6'b11_0101 }};
751+
// CHECK: [[TMP1:%.+]] = moore.constant -11 : i6
752+
// CHECK: [[TMP2:%.+]] = moore.zext [[TMP1]] : i6 -> i32
753+
// CHECK: moore.blocking_assign %a, [[TMP2]] : i32
754+
a = { >> 4 { 6'b11_0101 }};
755+
// CHECK: [[TMP1:%.+]] = moore.constant -3 : i4
756+
// CHECK: [[TMP2:%.+]] = moore.extract [[TMP1]] from 0 : i4 -> i1
757+
// CHECK: [[TMP3:%.+]] = moore.extract [[TMP1]] from 1 : i4 -> i1
758+
// CHECK: [[TMP4:%.+]] = moore.extract [[TMP1]] from 2 : i4 -> i1
759+
// CHECK: [[TMP5:%.+]] = moore.extract [[TMP1]] from 3 : i4 -> i1
760+
// CHECK: [[TMP6:%.+]] = moore.concat [[TMP2]], [[TMP3]], [[TMP4]], [[TMP5]] : (!moore.i1, !moore.i1, !moore.i1, !moore.i1) -> i4
761+
// CHECK: [[TMP7:%.+]] = moore.extract [[TMP6]] from 0 : i4 -> i2
762+
// CHECK: [[TMP8:%.+]] = moore.extract [[TMP6]] from 2 : i4 -> i2
763+
// CHECK: [[TMP9:%.+]] = moore.concat [[TMP7]], [[TMP8]] : (!moore.i2, !moore.i2) -> i4
764+
// CHECK: [[TMP10:%.+]] = moore.zext [[TMP9]] : i4 -> i32
765+
// CHECK: moore.blocking_assign %a, [[TMP10]] : i32
766+
a = { << 2 { { << { 4'b1101 }} }};
767+
// CHECK: [[TMP1:%.+]] = moore.read %a : <i32>
768+
// CHECK: [[TMP2:%.+]] = moore.read %b : <i32>
769+
// CHECK: [[TMP3:%.+]] = moore.read %c : <i32>
770+
// CHECK: [[TMP4:%.+]] = moore.concat [[TMP1]], [[TMP2]], [[TMP3]] : (!moore.i32, !moore.i32, !moore.i32) -> i96
771+
// CHECK: moore.blocking_assign %yy, [[TMP4]] : i96
772+
yy = {>>{ a, b, c }};
773+
// CHECK: [[TMP1:%.+]] = moore.read %a : <i32>
774+
// CHECK: [[TMP2:%.+]] = moore.read %b : <i32>
775+
// CHECK: [[TMP3:%.+]] = moore.read %c : <i32>
776+
// CHECK: [[TMP4:%.+]] = moore.concat [[TMP1]], [[TMP2]], [[TMP3]] : (!moore.i32, !moore.i32, !moore.i32) -> i96
777+
// CHECK: [[TMP5:%.+]] = moore.zext [[TMP4]] : i96 -> i100
778+
// CHECK: moore.blocking_assign %dd, [[TMP5]] : i100
779+
dd = {>>{ a, b, c }};
780+
// CHECK: [[TMP1:%.+]] = moore.concat_ref %a, %b, %c : (!moore.ref<i32>, !moore.ref<i32>, !moore.ref<i32>) -> <i96>
781+
// CHECK: [[TMP2:%.+]] = moore.constant 1 : i96
782+
// CHECK: moore.blocking_assign [[TMP1]], [[TMP2]] : i96
783+
{>>{ a, b, c }} = 96'b1;
784+
// CHECK: [[TMP1:%.+]] = moore.concat_ref %a, %b, %c : (!moore.ref<i32>, !moore.ref<i32>, !moore.ref<i32>) -> <i96>
785+
// CHECK: [[TMP2:%.+]] = moore.constant 31 : i100
786+
// CHECK: [[TMP3:%.+]] = moore.trunc [[TMP2]] : i100 -> i96
787+
// CHECK: moore.blocking_assign [[TMP1]], [[TMP3]] : i96
788+
{>>{ a, b, c }} = 100'b11111;
789+
// CHECK: [[TMP1:%.+]] = moore.concat_ref %p1, %p2, %p3, %p4 : (!moore.ref<l11>, !moore.ref<l11>, !moore.ref<l11>, !moore.ref<l11>) -> <l44>
790+
// CHECK: [[TMP2:%.+]] = moore.read %up : <uarray<4 x l11>>
791+
// CHECK: [[TMP3:%.+]] = moore.conversion [[TMP2]] : !moore.uarray<4 x l11> -> !moore.l44
792+
// CHECK: moore.blocking_assign [[TMP1]], [[TMP3]] : l44
793+
{ >> {p1, p2, p3, p4}} = up;
794+
// CHECK: [[TMP1:%.+]] = moore.extract_ref %a from 0 : <i32> -> <i8>
795+
// CHECK: [[TMP2:%.+]] = moore.extract_ref %a from 8 : <i32> -> <i8>
796+
// CHECK: [[TMP3:%.+]] = moore.extract_ref %a from 16 : <i32> -> <i8>
797+
// CHECK: [[TMP4:%.+]] = moore.extract_ref %a from 24 : <i32> -> <i8>
798+
// CHECK: [[TMP5:%.+]] = moore.concat_ref [[TMP1]], [[TMP2]], [[TMP3]], [[TMP4]] : (!moore.ref<i8>, !moore.ref<i8>, !moore.ref<i8>, !moore.ref<i8>) -> <i32>
799+
// CHECK: [[TMP6:%.+]] = moore.constant 1 : i32
800+
// CHECK: moore.blocking_assign [[TMP5]], [[TMP6]] : i32
801+
{<< byte {a}} = 32'b1;
802+
// CHECK: %[[TMP1:.*]] = moore.read %vec_3 : <l16>
803+
// CHECK: %[[TMP2:.*]] = moore.read %arr_1 : <uarray<64 x l1>>
804+
// CHECK: %[[TMP3:.*]] = moore.extract %[[TMP2]] from 0 : uarray<64 x l1> -> uarray<16 x l1>
805+
// CHECK: %[[TMP4:.*]] = moore.conversion %[[TMP3]] : !moore.uarray<16 x l1> -> !moore.l16
806+
// CHECK: %[[TMP5:.*]] = moore.concat %[[TMP1]], %[[TMP4]] : (!moore.l16, !moore.l16) -> l32
807+
// CHECK: %[[TMP6:.*]] = moore.extract %[[TMP5]] from 0 : l32 -> l8
808+
// CHECK: %[[TMP7:.*]] = moore.extract %[[TMP5]] from 8 : l32 -> l8
809+
// CHECK: %[[TMP8:.*]] = moore.extract %[[TMP5]] from 16 : l32 -> l8
810+
// CHECK: %[[TMP9:.*]] = moore.extract %[[TMP5]] from 24 : l32 -> l8
811+
// CHECK: %[[TMP10:.*]] = moore.concat %[[TMP6]], %[[TMP7]], %[[TMP8]], %[[TMP9]] : (!moore.l8, !moore.l8, !moore.l8, !moore.l8) -> l32
812+
// CHECK: moore.blocking_assign %vec_1, %[[TMP10]] : l32
813+
vec_1 = {<<byte{vec_3, arr_1 with [15:0]}};
814+
// CHECK: %[[TMP1:.*]] = moore.extract_ref %arr_1 from 0 : <uarray<64 x l1>> -> <uarray<16 x l1>>
815+
// CHECK: %[[TMP2:.*]] = moore.conversion %[[TMP1]] : !moore.ref<uarray<16 x l1>> -> !moore.ref<l16>
816+
// CHECK: %[[TMP3:.*]] = moore.concat_ref %vec_3, %[[TMP2]] : (!moore.ref<l16>, !moore.ref<l16>) -> <l32>
817+
// CHECK: %[[TMP4:.*]] = moore.extract_ref %[[TMP3]] from 0 : <l32> -> <l8>
818+
// CHECK: %[[TMP5:.*]] = moore.extract_ref %[[TMP3]] from 8 : <l32> -> <l8>
819+
// CHECK: %[[TMP6:.*]] = moore.extract_ref %[[TMP3]] from 16 : <l32> -> <l8>
820+
// CHECK: %[[TMP7:.*]] = moore.extract_ref %[[TMP3]] from 24 : <l32> -> <l8>
821+
// CHECK: %[[TMP8:.*]] = moore.concat_ref %[[TMP4]], %[[TMP5]], %[[TMP6]], %[[TMP7]] : (!moore.ref<l8>, !moore.ref<l8>, !moore.ref<l8>, !moore.ref<l8>) -> <l32>
822+
// CHECK: %[[TMP9:.*]] = moore.read %vec_1 : <l32>
823+
// CHECK: moore.blocking_assign %[[TMP8]], %[[TMP9]] : l32
824+
{<<byte{vec_3, arr_1 with [15:0]}} = vec_1;
693825
// CHECK: [[TMP1:%.+]] = moore.constant 0 : i1
694826
// CHECK: [[TMP2:%.+]] = moore.concat [[TMP1]] : (!moore.i1) -> i1
695827
// CHECK: moore.replicate [[TMP2]] : i1 -> i32

test/Conversion/ImportVerilog/errors.sv

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,49 @@ module Foo;
7373
int c = a inside { b };
7474
endmodule
7575

76+
// -----
77+
module Foo;
78+
int a, b, c;
79+
int j;
80+
initial begin
81+
// expected-error @below {{streaming operator target size 32 does not fit source size 96}}
82+
j = {>>{ a, b, c }}; // error: j is 32 bits < 96 bits
83+
end
84+
endmodule
85+
86+
87+
// -----
88+
module Foo;
89+
int a, b, c;
90+
int j;
91+
initial begin
92+
// expected-error @below {{streaming operator target size 96 does not fit source size 23}}
93+
{>>{ a, b, c }} = 23'b1;
94+
end
95+
endmodule
96+
97+
// -----
98+
module Foo;
99+
initial begin
100+
logic [15:0] vec_0;
101+
logic [47:0] vec_1;
102+
logic arr [63:0];
103+
int c;
104+
// expected-error @below {{Moore only support streaming concatenation with fixed size 'with expression'}}
105+
vec_1 = {<<byte{vec_0, arr with [c:0]}};
106+
end
107+
endmodule
108+
109+
// -----
110+
module Foo;
111+
initial begin
112+
int my_queue[];
113+
logic [31:0] vec_0;
114+
// expected-error @below {{expression of type '!moore.open_uarray<i32>' cannot be cast to a simple bit vector}}
115+
vec_0 = {<<byte{my_queue}};
116+
end
117+
endmodule
118+
76119
// -----
77120
module Foo;
78121
// expected-remark @below {{hello}}

0 commit comments

Comments
 (0)