[ImportVerilog] Add replicate and extract operations. (#6906)

This commit is contained in:
Hailong Sun 2024-04-22 09:57:29 +08:00 committed by GitHub
parent 7598a8e067
commit 80c6602d37
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 217 additions and 1 deletions

View File

@ -656,4 +656,65 @@ def ConcatOp : MooreOp<"concat", [
}];
}
def ReplicateOp : MooreOp<"replicate", [
Pure
]> {
let summary = "Multiple concatenation of expressions";
let description = [{
This operation indicates a joining together of that many copies of the
concatenation `{constant{w}}`. Which enclosed together within brace.
The 'constant' must a non-negative, non-x, and non-z constant expression.
The 'constant' may be a value of zero, but it only exists in parameterized
code, and it will be ignored(type is changed to the void).
Example:
```
{0{w}} // empty! ignore it.
{4{w}} // the same as {w, w, w, w}
```
See IEEE 1800-2017 §11.4.12 "Concatenation operators".
}];
let arguments = (ins SimpleBitVectorType:$value);
let results = (outs SimpleBitVectorType:$result);
let assemblyFormat = [{
$value attr-dict `:` functional-type($value, $result)
}];
}
def ExtractOp : MooreOp<"extract"> {
let summary = "Addressing operation";
let description = [{
This operation includes the vector bit/part-select, array, and memory
addressing.If the address is invalid--out of bounds or has x or z bit--
then it will produce x for 4-state or 0 for 2-state.
Bit-select results are unsigned, regardless of the operands.
Part-select results are unsigned, regardless of the operands even if
the part-select specifies the entire vector.
See IEEE 1800-2017 § 11.8.1 "Rules for expression types"
Example:
```
logic v [7:0];
v[1]; // the bit-select addressing
v[3:0]; // the part-select addressing
v[3-:4]; v[0+:4]; // They are equivalent to v[3:0]
```
See IEEE 1800-2017 § 11.5.1 "Vector bit-select and part-select addressing".
Example:
```
// an array of 256-by-256 8-bit elements
logic [7:0] twod_array [0:255][0:255];
logic [7:0] mem_name [0:1023]; // a memory of 1024 8-bit words
```
See IEEE 1800-2017 § 11.5.2 "Array and memory addressing".
}];
let arguments = (ins UnpackedType:$input, UnpackedType:$lowBit);
let results = (outs UnpackedType:$result);
let assemblyFormat = [{
$input `from` $lowBit attr-dict `:`
type($input) `,` type($lowBit) `->` type($result)
}];
}
#endif // CIRCT_DIALECT_MOORE_MOOREOPS

View File

@ -361,12 +361,60 @@ struct ExprVisitor {
for (auto *operand : expr.operands()) {
auto value = context.convertExpression(*operand);
if (!value)
return {};
continue;
value = convertToSimpleBitVector(value);
operands.push_back(value);
}
return builder.create<moore::ConcatOp>(loc, operands);
}
// Handle replications.
Value visit(const slang::ast::ReplicationExpression &expr) {
auto type = context.convertType(*expr.type);
if (isa<moore::VoidType>(type))
return {};
auto value = context.convertExpression(expr.concat());
if (!value)
return {};
return builder.create<moore::ReplicateOp>(loc, type, value);
}
// Handle single bit selections.
Value visit(const slang::ast::ElementSelectExpression &expr) {
auto type = context.convertType(*expr.type);
auto value = context.convertExpression(expr.value());
auto lowBit = context.convertExpression(expr.selector());
if (!value || !lowBit)
return {};
return builder.create<moore::ExtractOp>(loc, type, value, lowBit);
}
// Handle range bits selections.
Value visit(const slang::ast::RangeSelectExpression &expr) {
auto type = context.convertType(*expr.type);
auto value = context.convertExpression(expr.value());
Value lowBit;
if (expr.getSelectionKind() == slang::ast::RangeSelectionKind::Simple) {
if (expr.left().constant && expr.right().constant) {
auto lhs = expr.left().constant->integer().as<uint64_t>().value();
auto rhs = expr.right().constant->integer().as<uint64_t>().value();
lowBit = lhs < rhs ? context.convertExpression(expr.left())
: context.convertExpression(expr.right());
} else {
mlir::emitError(loc, "unsupported a variable as the index in the")
<< slang::ast::toString(expr.getSelectionKind()) << "kind";
return {};
}
} else
lowBit = context.convertExpression(expr.left());
if (!value || !lowBit)
return {};
return builder.create<moore::ExtractOp>(loc, type, value, lowBit);
}
/// Emit an error for all other expressions.
template <typename T>
Value visit(T &&node) {

View File

@ -209,6 +209,10 @@ module Expressions;
integer d, e, f;
bit x;
logic y;
logic [31:0] vec_1;
logic [0:31] vec_2;
bit [4:1] arr [1:3][2:7];
bit [3:2] s;
initial begin
// CHECK: moore.constant 0 : !moore.packed<range<bit, 31:0>>
@ -225,6 +229,43 @@ module Expressions;
a = {a, b, c};
// CHECK: moore.concat %d, %e : (!moore.integer, !moore.integer) -> !moore.packed<range<logic, 63:0>>
d = {d, e};
// CHECK: %[[VAL_1:.*]] = moore.constant false : !moore.packed<range<bit, 0:0>>
// CHECK: %[[VAL_2:.*]] = moore.concat %[[VAL_1]] : (!moore.packed<range<bit, 0:0>>) -> !moore.packed<range<bit, 0:0>>
// CHECK: %[[VAL_3:.*]] = moore.replicate %[[VAL_2]] : (!moore.packed<range<bit, 0:0>>) -> !moore.packed<range<bit, 31:0>>
a = {32{1'b0}};
// CHECK: %[[VAL:.*]] = moore.constant 1 : !moore.int
// CHECK: moore.extract %vec_1 from %[[VAL]] : !moore.packed<range<logic, 31:0>>, !moore.int -> !moore.packed<range<logic, 3:1>>
y = vec_1[3:1];
// CHECK: %[[VAL:.*]] = moore.constant 2 : !moore.int
// CHECK: moore.extract %vec_2 from %[[VAL]] : !moore.packed<range<logic, 0:31>>, !moore.int -> !moore.packed<range<logic, 2:3>>
y = vec_2[2:3];
// CHECK: moore.extract %d from %x : !moore.integer, !moore.bit -> !moore.logic
y = d[x];
// CHECK: moore.extract %a from %x : !moore.int, !moore.bit -> !moore.bit
y = a[x];
// CHECK: %[[VAL:.*]] = moore.constant 15 : !moore.int
// CHECK: moore.extract %vec_1 from %[[VAL]] : !moore.packed<range<logic, 31:0>>, !moore.int -> !moore.logic
y = vec_1[15];
// CHECK: %[[VAL:.*]] = moore.constant 15 : !moore.int
// CHECK: moore.extract %vec_1 from %[[VAL]] : !moore.packed<range<logic, 31:0>>, !moore.int -> !moore.packed<range<logic, 15:15>>
y = vec_1[15+:1];
// CHECK: %[[VAL:.*]] = moore.constant 0 : !moore.int
// CHECK: moore.extract %vec_2 from %[[VAL]] : !moore.packed<range<logic, 0:31>>, !moore.int -> !moore.packed<range<logic, 0:0>>
y = vec_2[0+:1];
// CHECK: %[[VAL_1:.*]] = moore.constant 1 : !moore.int
// CHECK: %[[VAL_2:.*]] = moore.mul %[[VAL_1]], %a : !moore.int
// CHECK: moore.extract %vec_1 from %[[VAL_2]] : !moore.packed<range<logic, 31:0>>, !moore.int -> !moore.packed<range<logic, 31:31>>
y = vec_1[1*a-:1];
// CHECK: %[[VAL_1:.*]] = moore.constant 3 : !moore.int
// CHECK: %[[VAL_2:.*]] = moore.extract %arr from %[[VAL_1]] : !moore.unpacked<range<range<packed<range<bit, 4:1>>, 2:7>, 1:3>>, !moore.int -> !moore.unpacked<range<packed<range<bit, 4:1>>, 2:7>>
// CHECK: %[[VAL_3:.*]] = moore.constant 7 : !moore.int
// CHECK: %[[VAL_4:.*]] = moore.extract %[[VAL_2]] from %[[VAL_3]] : !moore.unpacked<range<packed<range<bit, 4:1>>, 2:7>>, !moore.int -> !moore.packed<range<bit, 4:1>>
// CHECK: %[[VAL_5:.*]] = moore.constant 3 : !moore.int
// CHECK: moore.extract %[[VAL_4]] from %[[VAL_5]] : !moore.packed<range<bit, 4:1>>, !moore.int -> !moore.packed<range<bit, 4:3>>
s = arr[3][7][4:3];
// CHECK: moore.extract %vec_1 from %s : !moore.packed<range<logic, 31:0>>, !moore.packed<range<bit, 3:2>> -> !moore.logic
y = vec_1[s];
//===------------------------------------------------------------------===//
// Unary operators

View File

@ -102,3 +102,49 @@ module Foo;
// expected-error @below {{literals with X or Z bits not supported}}
initial x = 'z;
endmodule
// -----
module Foo;
// expected-remark @below {{declared here}}
int a, b;
initial begin
// expected-error @below {{replication constant can only be zero inside of a concatenation}}
a = {0{32'd5}};
// expected-error @below {{value must be positive}}
a = {-1{32'd5}};
// expected-error @below {{value must not have any unknown bits}}
a = {32'bx{1'b0}};
// expected-error @below {{value must not have any unknown bits}}
a = {32'bz{1'b0}};
// expected-error @below {{reference to non-constant variable 'b' is not allowed in a constant expression}}
a = {b{32'd5}};
end
endmodule
// -----
module Foo;
bit [3:0] a;
bit [1:0] b;
// expected-remark @below {{declared here}}
bit c;
initial begin
// expected-error @below {{cannot refer to element 1'bx of 'bit[3:0]' [-Windex-oob]}}
c = a[1'bx];
// expected-error @below {{endianness of selection must match declared range (type is 'bit[3:0]')}}
b = a[0:1];
// expected-error @below {{reference to non-constant variable 'c' is not allowed in a constant expression}}
b = a[c:1];
// expected-error @below {{reference to non-constant variable 'c' is not allowed in a constant expression}}
b = a[2-:c];
// expected-error @below {{value must not have any unknown bits}}
b = a[1'bz:0];
// expected-error @below {{value must not have any unknown bits}}
b = a[1-:'x];
// expected-error @below {{value must be positive}}
b = a[1-:0];
// expected-error @below {{value must be positive}}
b = a[1-:-1];
end
endmodule

View File

@ -47,6 +47,7 @@ moore.module @Expressions {
%int2 = moore.variable : !moore.int
%integer = moore.variable : !moore.integer
%integer2 = moore.variable : !moore.integer
%arr = moore.variable : !moore.unpacked<range<range<packed<range<bit, 7:0>>, 0:3>, 0:1>>
// CHECK: moore.constant 0 : !moore.int
moore.constant 0 : !moore.int
@ -136,4 +137,23 @@ moore.module @Expressions {
moore.concat %b5, %b1 : (!moore.packed<range<bit, 4:0>>, !moore.bit) -> !moore.packed<range<bit, 5:0>>
// CHECK: moore.concat %l1, %l1, %l1 : (!moore.logic, !moore.logic, !moore.logic) -> !moore.packed<range<logic, 2:0>>
moore.concat %l1, %l1, %l1 : (!moore.logic, !moore.logic, !moore.logic) -> !moore.packed<range<logic, 2:0>>
// CHECK: [[VAL:%.*]] = moore.concat %b1 : (!moore.bit) -> !moore.packed<range<bit, 0:0>>
// CHECK: moore.replicate [[VAL]] : (!moore.packed<range<bit, 0:0>>) -> !moore.packed<range<bit, 3:0>>
%0 = moore.concat %b1 : (!moore.bit) -> !moore.packed<range<bit, 0:0>>
moore.replicate %0 : (!moore.packed<range<bit, 0:0>>) -> !moore.packed<range<bit, 3:0>>
// CHECK: moore.extract %b5 from %b1 : !moore.packed<range<bit, 4:0>>, !moore.bit -> !moore.bit
moore.extract %b5 from %b1 : !moore.packed<range<bit, 4:0>>, !moore.bit -> !moore.bit
// CHECK: [[VAL1:%.*]] = moore.constant 0 : !moore.int
// CHECK: [[VAL2:%.*]] = moore.extract %arr from [[VAL1]] : !moore.unpacked<range<range<packed<range<bit, 7:0>>, 0:3>, 0:1>>, !moore.int -> !moore.unpacked<range<packed<range<bit, 7:0>>, 0:3>>
%1 = moore.constant 0 : !moore.int
%2 = moore.extract %arr from %1 : !moore.unpacked<range<range<packed<range<bit, 7:0>>, 0:3>, 0:1>>, !moore.int -> !moore.unpacked<range<packed<range<bit, 7:0>>, 0:3>>
// CHECK: [[VAL3:%.*]] = moore.constant 3 : !moore.int
// CHECK: [[VAL4:%.*]] = moore.extract [[VAL2]] from [[VAL3]] : !moore.unpacked<range<packed<range<bit, 7:0>>, 0:3>>, !moore.int -> !moore.packed<range<bit, 7:0>>
%3 = moore.constant 3 : !moore.int
%4 = moore.extract %2 from %3 : !moore.unpacked<range<packed<range<bit, 7:0>>, 0:3>>, !moore.int -> !moore.packed<range<bit, 7:0>>
// CHECK: [[VAL5:%.*]] = moore.constant 2 : !moore.int
// CHECK: moore.extract [[VAL4]] from [[VAL5]] : !moore.packed<range<bit, 7:0>>, !moore.int -> !moore.packed<range<bit, 6:2>>
%5 = moore.constant 2 : !moore.int
moore.extract %4 from %5 : !moore.packed<range<bit, 7:0>>, !moore.int -> !moore.packed<range<bit, 6:2>>
}