mirror of https://github.com/llvm/circt.git
[ImportVerilog] add sized stream concat operation (#7784)
This commit is contained in:
parent
99930adae8
commit
b152422ddf
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}}
|
||||
|
|
Loading…
Reference in New Issue