[ImportVerilog] add sized stream concat operation (#7784)

This commit is contained in:
chenbo 2024-11-28 15:18:28 +08:00 committed by GitHub
parent 99930adae8
commit b152422ddf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 314 additions and 0 deletions

View File

@ -787,6 +787,76 @@ struct RvalueExprVisitor {
return visitAssignmentPattern(expr, *count);
}
Value visit(const slang::ast::StreamingConcatenationExpression &expr) {
SmallVector<Value> operands;
for (auto stream : expr.streams()) {
auto operandLoc = context.convertLocation(stream.operand->sourceRange);
if (!stream.constantWithWidth.has_value() && stream.withExpr) {
mlir::emitError(operandLoc)
<< "Moore only support streaming "
"concatenation with fixed size 'with expression'";
return {};
}
Value value;
if (stream.constantWithWidth.has_value()) {
value = context.convertRvalueExpression(*stream.withExpr);
auto type = cast<moore::UnpackedType>(value.getType());
auto intType = moore::IntType::get(
context.getContext(), type.getBitSize().value(), type.getDomain());
// do not care if it's signed, because we will not do expansion
value = context.materializeConversion(intType, value, false, loc);
} else {
value = context.convertRvalueExpression(*stream.operand);
}
if (!value)
return {};
value = context.convertToSimpleBitVector(value);
if (!value) {
return {};
}
operands.push_back(value);
}
Value value;
if (operands.size() == 1) {
// There must be at least one element, otherwise slang will report an
// error
value = operands.front();
} else {
value = builder.create<moore::ConcatOp>(loc, operands).getResult();
}
if (expr.sliceSize == 0) {
return value;
}
auto type = cast<moore::IntType>(value.getType());
SmallVector<Value> slicedOperands;
auto iterMax = type.getWidth() / expr.sliceSize;
auto remainSize = type.getWidth() % expr.sliceSize;
for (size_t i = 0; i < iterMax; i++) {
auto extractResultType = moore::IntType::get(
context.getContext(), expr.sliceSize, type.getDomain());
auto extracted = builder.create<moore::ExtractOp>(
loc, extractResultType, value, i * expr.sliceSize);
slicedOperands.push_back(extracted);
}
// Handle other wire
if (remainSize) {
auto extractResultType = moore::IntType::get(
context.getContext(), remainSize, type.getDomain());
auto extracted = builder.create<moore::ExtractOp>(
loc, extractResultType, value, iterMax * expr.sliceSize);
slicedOperands.push_back(extracted);
}
return builder.create<moore::ConcatOp>(loc, slicedOperands);
}
/// Emit an error for all other expressions.
template <typename T>
Value visit(T &&node) {
@ -925,6 +995,75 @@ struct LvalueExprVisitor {
dynLowBit);
}
Value visit(const slang::ast::StreamingConcatenationExpression &expr) {
SmallVector<Value> operands;
for (auto stream : expr.streams()) {
auto operandLoc = context.convertLocation(stream.operand->sourceRange);
if (!stream.constantWithWidth.has_value() && stream.withExpr) {
mlir::emitError(operandLoc)
<< "Moore only support streaming "
"concatenation with fixed size 'with expression'";
return {};
}
Value value;
if (stream.constantWithWidth.has_value()) {
value = context.convertLvalueExpression(*stream.withExpr);
auto type = cast<moore::UnpackedType>(
cast<moore::RefType>(value.getType()).getNestedType());
auto intType = moore::RefType::get(moore::IntType::get(
context.getContext(), type.getBitSize().value(), type.getDomain()));
// do not care if it's signed, because we will not do expansion
value = context.materializeConversion(intType, value, false, loc);
} else {
value = context.convertLvalueExpression(*stream.operand);
}
if (!value)
return {};
operands.push_back(value);
}
Value value;
if (operands.size() == 1) {
// There must be at least one element, otherwise slang will report an
// error
value = operands.front();
} else {
value = builder.create<moore::ConcatRefOp>(loc, operands).getResult();
}
if (expr.sliceSize == 0) {
return value;
}
auto type = cast<moore::IntType>(
cast<moore::RefType>(value.getType()).getNestedType());
SmallVector<Value> slicedOperands;
auto widthSum = type.getWidth();
auto domain = type.getDomain();
auto iterMax = widthSum / expr.sliceSize;
auto remainSize = widthSum % expr.sliceSize;
for (size_t i = 0; i < iterMax; i++) {
auto extractResultType = moore::RefType::get(
moore::IntType::get(context.getContext(), expr.sliceSize, domain));
auto extracted = builder.create<moore::ExtractRefOp>(
loc, extractResultType, value, i * expr.sliceSize);
slicedOperands.push_back(extracted);
}
// Handle other wire
if (remainSize) {
auto extractResultType = moore::RefType::get(
moore::IntType::get(context.getContext(), remainSize, domain));
auto extracted = builder.create<moore::ExtractRefOp>(
loc, extractResultType, value, iterMax * expr.sliceSize);
slicedOperands.push_back(extracted);
}
return builder.create<moore::ConcatRefOp>(loc, slicedOperands);
}
Value visit(const slang::ast::MemberAccessExpression &expr) {
auto type = context.convertType(*expr.type);
auto valueType = expr.value().type;

View File

@ -604,6 +604,19 @@ module Expressions;
// CHECK: %b = moore.variable : <i32>
// CHECK: %c = moore.variable : <i32>
int a, b, c;
// CHECK: %j = moore.variable : <i32>
int j;
// CHECK: %up = moore.variable : <uarray<4 x l11>>
logic [10:0] up [3:0];
// CHECK: %p1 = moore.variable : <l11>
// CHECK: %p2 = moore.variable : <l11>
// CHECK: %p3 = moore.variable : <l11>
// CHECK: %p4 = moore.variable : <l11>
logic [11:1] p1, p2, p3, p4;
// CHECK: %yy = moore.variable : <i96>
bit [96:1] yy;
// CHECK: %dd = moore.variable : <i100>
bit [99:0] dd;
// CHECK: %u = moore.variable : <i32>
// CHECK: %w = moore.variable : <i32>
int unsigned u, w;
@ -622,8 +635,16 @@ module Expressions;
logic [31:0] vec_1;
// CHECK: %vec_2 = moore.variable : <l32>
logic [0:31] vec_2;
// CHECK: %vec_3 = moore.variable : <l16>
logic [15:0] vec_3;
// CHECK: %vec_4 = moore.variable : <l32>
logic [31:0] vec_4;
// CHECK: %vec_5 = moore.variable : <l48>
logic [47:0] vec_5;
// CHECK: %arr = moore.variable : <uarray<3 x uarray<6 x i4>>>
bit [4:1] arr [1:3][2:7];
logic arr_1 [63:0];
// CHECK: %struct0 = moore.variable : <struct<{a: i32, b: i32}>>
struct packed {
int a, b;
@ -690,6 +711,117 @@ module Expressions;
{a, b, c} = a;
// CHECK: moore.concat_ref %d, %e : (!moore.ref<l32>, !moore.ref<l32>) -> <l64>
{d, e} = d;
// CHECK: [[TMP1:%.+]] = moore.read %j : <i32>
// CHECK: moore.blocking_assign %a, [[TMP1]] : i32
a = { >> {j}};
// CHECK: [[TMP1:%.+]] = moore.read %j : <i32>
// CHECK: [[TMP2:%.+]] = moore.extract [[TMP1]] from 0 : i32 -> i8
// CHECK: [[TMP3:%.+]] = moore.extract [[TMP1]] from 8 : i32 -> i8
// CHECK: [[TMP4:%.+]] = moore.extract [[TMP1]] from 16 : i32 -> i8
// CHECK: [[TMP5:%.+]] = moore.extract [[TMP1]] from 24 : i32 -> i8
// CHECK: [[TMP6:%.+]] = moore.concat [[TMP2]], [[TMP3]], [[TMP4]], [[TMP5]] : (!moore.i8, !moore.i8, !moore.i8, !moore.i8) -> i32
// CHECK: moore.blocking_assign %a, [[TMP6]] : i32
a = { << byte {j}};
// CHECK: [[TMP1:%.+]] = moore.read %j : <i32>
// CHECK: [[TMP2:%.+]] = moore.extract [[TMP1]] from 0 : i32 -> i16
// CHECK: [[TMP3:%.+]] = moore.extract [[TMP1]] from 16 : i32 -> i16
// CHECK: [[TMP4:%.+]] = moore.concat [[TMP2]], [[TMP3]] : (!moore.i16, !moore.i16) -> i32
// CHECK: moore.blocking_assign %a, [[TMP4]] : i32
a = { << 16 {j}};
// CHECK: [[TMP1:%.+]] = moore.constant 53 : i8
// CHECK: [[TMP2:%.+]] = moore.extract [[TMP1]] from 0 : i8 -> i1
// CHECK: [[TMP3:%.+]] = moore.extract [[TMP1]] from 1 : i8 -> i1
// CHECK: [[TMP4:%.+]] = moore.extract [[TMP1]] from 2 : i8 -> i1
// CHECK: [[TMP5:%.+]] = moore.extract [[TMP1]] from 3 : i8 -> i1
// CHECK: [[TMP6:%.+]] = moore.extract [[TMP1]] from 4 : i8 -> i1
// CHECK: [[TMP7:%.+]] = moore.extract [[TMP1]] from 5 : i8 -> i1
// CHECK: [[TMP8:%.+]] = moore.extract [[TMP1]] from 6 : i8 -> i1
// CHECK: [[TMP9:%.+]] = moore.extract [[TMP1]] from 7 : i8 -> i1
// 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
// CHECK: [[TMP11:%.+]] = moore.zext [[TMP10]] : i8 -> i32
// CHECK: moore.blocking_assign %a, [[TMP11]] : i32
a = { << { 8'b0011_0101 }};
// CHECK: [[TMP1:%.+]] = moore.constant -11 : i6
// CHECK: [[TMP2:%.+]] = moore.extract [[TMP1]] from 0 : i6 -> i4
// CHECK: [[TMP3:%.+]] = moore.extract [[TMP1]] from 4 : i6 -> i2
// CHECK: [[TMP4:%.+]] = moore.concat [[TMP2]], [[TMP3]] : (!moore.i4, !moore.i2) -> i6
// CHECK: [[TMP5:%.+]] = moore.zext [[TMP4]] : i6 -> i32
// CHECK: moore.blocking_assign %a, [[TMP5]] : i32
a = { << 4 { 6'b11_0101 }};
// CHECK: [[TMP1:%.+]] = moore.constant -11 : i6
// CHECK: [[TMP2:%.+]] = moore.zext [[TMP1]] : i6 -> i32
// CHECK: moore.blocking_assign %a, [[TMP2]] : i32
a = { >> 4 { 6'b11_0101 }};
// CHECK: [[TMP1:%.+]] = moore.constant -3 : i4
// CHECK: [[TMP2:%.+]] = moore.extract [[TMP1]] from 0 : i4 -> i1
// CHECK: [[TMP3:%.+]] = moore.extract [[TMP1]] from 1 : i4 -> i1
// CHECK: [[TMP4:%.+]] = moore.extract [[TMP1]] from 2 : i4 -> i1
// CHECK: [[TMP5:%.+]] = moore.extract [[TMP1]] from 3 : i4 -> i1
// CHECK: [[TMP6:%.+]] = moore.concat [[TMP2]], [[TMP3]], [[TMP4]], [[TMP5]] : (!moore.i1, !moore.i1, !moore.i1, !moore.i1) -> i4
// CHECK: [[TMP7:%.+]] = moore.extract [[TMP6]] from 0 : i4 -> i2
// CHECK: [[TMP8:%.+]] = moore.extract [[TMP6]] from 2 : i4 -> i2
// CHECK: [[TMP9:%.+]] = moore.concat [[TMP7]], [[TMP8]] : (!moore.i2, !moore.i2) -> i4
// CHECK: [[TMP10:%.+]] = moore.zext [[TMP9]] : i4 -> i32
// CHECK: moore.blocking_assign %a, [[TMP10]] : i32
a = { << 2 { { << { 4'b1101 }} }};
// CHECK: [[TMP1:%.+]] = moore.read %a : <i32>
// CHECK: [[TMP2:%.+]] = moore.read %b : <i32>
// CHECK: [[TMP3:%.+]] = moore.read %c : <i32>
// CHECK: [[TMP4:%.+]] = moore.concat [[TMP1]], [[TMP2]], [[TMP3]] : (!moore.i32, !moore.i32, !moore.i32) -> i96
// CHECK: moore.blocking_assign %yy, [[TMP4]] : i96
yy = {>>{ a, b, c }};
// CHECK: [[TMP1:%.+]] = moore.read %a : <i32>
// CHECK: [[TMP2:%.+]] = moore.read %b : <i32>
// CHECK: [[TMP3:%.+]] = moore.read %c : <i32>
// CHECK: [[TMP4:%.+]] = moore.concat [[TMP1]], [[TMP2]], [[TMP3]] : (!moore.i32, !moore.i32, !moore.i32) -> i96
// CHECK: [[TMP5:%.+]] = moore.zext [[TMP4]] : i96 -> i100
// CHECK: moore.blocking_assign %dd, [[TMP5]] : i100
dd = {>>{ a, b, c }};
// CHECK: [[TMP1:%.+]] = moore.concat_ref %a, %b, %c : (!moore.ref<i32>, !moore.ref<i32>, !moore.ref<i32>) -> <i96>
// CHECK: [[TMP2:%.+]] = moore.constant 1 : i96
// CHECK: moore.blocking_assign [[TMP1]], [[TMP2]] : i96
{>>{ a, b, c }} = 96'b1;
// CHECK: [[TMP1:%.+]] = moore.concat_ref %a, %b, %c : (!moore.ref<i32>, !moore.ref<i32>, !moore.ref<i32>) -> <i96>
// CHECK: [[TMP2:%.+]] = moore.constant 31 : i100
// CHECK: [[TMP3:%.+]] = moore.trunc [[TMP2]] : i100 -> i96
// CHECK: moore.blocking_assign [[TMP1]], [[TMP3]] : i96
{>>{ a, b, c }} = 100'b11111;
// CHECK: [[TMP1:%.+]] = moore.concat_ref %p1, %p2, %p3, %p4 : (!moore.ref<l11>, !moore.ref<l11>, !moore.ref<l11>, !moore.ref<l11>) -> <l44>
// CHECK: [[TMP2:%.+]] = moore.read %up : <uarray<4 x l11>>
// CHECK: [[TMP3:%.+]] = moore.conversion [[TMP2]] : !moore.uarray<4 x l11> -> !moore.l44
// CHECK: moore.blocking_assign [[TMP1]], [[TMP3]] : l44
{ >> {p1, p2, p3, p4}} = up;
// CHECK: [[TMP1:%.+]] = moore.extract_ref %a from 0 : <i32> -> <i8>
// CHECK: [[TMP2:%.+]] = moore.extract_ref %a from 8 : <i32> -> <i8>
// CHECK: [[TMP3:%.+]] = moore.extract_ref %a from 16 : <i32> -> <i8>
// CHECK: [[TMP4:%.+]] = moore.extract_ref %a from 24 : <i32> -> <i8>
// CHECK: [[TMP5:%.+]] = moore.concat_ref [[TMP1]], [[TMP2]], [[TMP3]], [[TMP4]] : (!moore.ref<i8>, !moore.ref<i8>, !moore.ref<i8>, !moore.ref<i8>) -> <i32>
// CHECK: [[TMP6:%.+]] = moore.constant 1 : i32
// CHECK: moore.blocking_assign [[TMP5]], [[TMP6]] : i32
{<< byte {a}} = 32'b1;
// CHECK: %[[TMP1:.*]] = moore.read %vec_3 : <l16>
// CHECK: %[[TMP2:.*]] = moore.read %arr_1 : <uarray<64 x l1>>
// CHECK: %[[TMP3:.*]] = moore.extract %[[TMP2]] from 0 : uarray<64 x l1> -> uarray<16 x l1>
// CHECK: %[[TMP4:.*]] = moore.conversion %[[TMP3]] : !moore.uarray<16 x l1> -> !moore.l16
// CHECK: %[[TMP5:.*]] = moore.concat %[[TMP1]], %[[TMP4]] : (!moore.l16, !moore.l16) -> l32
// CHECK: %[[TMP6:.*]] = moore.extract %[[TMP5]] from 0 : l32 -> l8
// CHECK: %[[TMP7:.*]] = moore.extract %[[TMP5]] from 8 : l32 -> l8
// CHECK: %[[TMP8:.*]] = moore.extract %[[TMP5]] from 16 : l32 -> l8
// CHECK: %[[TMP9:.*]] = moore.extract %[[TMP5]] from 24 : l32 -> l8
// CHECK: %[[TMP10:.*]] = moore.concat %[[TMP6]], %[[TMP7]], %[[TMP8]], %[[TMP9]] : (!moore.l8, !moore.l8, !moore.l8, !moore.l8) -> l32
// CHECK: moore.blocking_assign %vec_1, %[[TMP10]] : l32
vec_1 = {<<byte{vec_3, arr_1 with [15:0]}};
// CHECK: %[[TMP1:.*]] = moore.extract_ref %arr_1 from 0 : <uarray<64 x l1>> -> <uarray<16 x l1>>
// CHECK: %[[TMP2:.*]] = moore.conversion %[[TMP1]] : !moore.ref<uarray<16 x l1>> -> !moore.ref<l16>
// CHECK: %[[TMP3:.*]] = moore.concat_ref %vec_3, %[[TMP2]] : (!moore.ref<l16>, !moore.ref<l16>) -> <l32>
// CHECK: %[[TMP4:.*]] = moore.extract_ref %[[TMP3]] from 0 : <l32> -> <l8>
// CHECK: %[[TMP5:.*]] = moore.extract_ref %[[TMP3]] from 8 : <l32> -> <l8>
// CHECK: %[[TMP6:.*]] = moore.extract_ref %[[TMP3]] from 16 : <l32> -> <l8>
// CHECK: %[[TMP7:.*]] = moore.extract_ref %[[TMP3]] from 24 : <l32> -> <l8>
// CHECK: %[[TMP8:.*]] = moore.concat_ref %[[TMP4]], %[[TMP5]], %[[TMP6]], %[[TMP7]] : (!moore.ref<l8>, !moore.ref<l8>, !moore.ref<l8>, !moore.ref<l8>) -> <l32>
// CHECK: %[[TMP9:.*]] = moore.read %vec_1 : <l32>
// CHECK: moore.blocking_assign %[[TMP8]], %[[TMP9]] : l32
{<<byte{vec_3, arr_1 with [15:0]}} = vec_1;
// CHECK: [[TMP1:%.+]] = moore.constant 0 : i1
// CHECK: [[TMP2:%.+]] = moore.concat [[TMP1]] : (!moore.i1) -> i1
// CHECK: moore.replicate [[TMP2]] : i1 -> i32

View File

@ -73,6 +73,49 @@ module Foo;
int c = a inside { b };
endmodule
// -----
module Foo;
int a, b, c;
int j;
initial begin
// expected-error @below {{streaming operator target size 32 does not fit source size 96}}
j = {>>{ a, b, c }}; // error: j is 32 bits < 96 bits
end
endmodule
// -----
module Foo;
int a, b, c;
int j;
initial begin
// expected-error @below {{streaming operator target size 96 does not fit source size 23}}
{>>{ a, b, c }} = 23'b1;
end
endmodule
// -----
module Foo;
initial begin
logic [15:0] vec_0;
logic [47:0] vec_1;
logic arr [63:0];
int c;
// expected-error @below {{Moore only support streaming concatenation with fixed size 'with expression'}}
vec_1 = {<<byte{vec_0, arr with [c:0]}};
end
endmodule
// -----
module Foo;
initial begin
int my_queue[];
logic [31:0] vec_0;
// expected-error @below {{expression of type '!moore.open_uarray<i32>' cannot be cast to a simple bit vector}}
vec_0 = {<<byte{my_queue}};
end
endmodule
// -----
module Foo;
// expected-remark @below {{hello}}