mirror of https://github.com/llvm/circt.git
[ImportVerilog] Add rvalue assignment pattern support (#7428)
Add support for assignment patterns like `'{42, 9001}` in rvalue position. These are roughly SystemVerilog's equivalent of `struct_create` and `array_create`. This commit also adds an `array_create` op to support assignment patterns for arrays.
This commit is contained in:
parent
17e85f15c7
commit
e95e92dd19
|
@ -1037,6 +1037,20 @@ def DynExtractRefOp : MooreOp<"dyn_extract_ref", [Pure]> {
|
|||
}];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Array Manipulation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def ArrayCreateOp : MooreOp<"array_create", [Pure, SameTypeOperands]> {
|
||||
let summary = "Create an array value from individual elements";
|
||||
let arguments = (ins Variadic<UnpackedType>:$elements);
|
||||
let results = (outs AnyStaticArrayType:$result);
|
||||
let assemblyFormat = [{
|
||||
$elements attr-dict `:` type($elements) `->` type($result)
|
||||
}];
|
||||
let hasVerifier = 1;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Struct Manipulation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -406,6 +406,12 @@ def BitType : MooreType<CPred<[{
|
|||
}];
|
||||
}
|
||||
|
||||
/// A packed or unpacked array type with a fixed size.
|
||||
def AnyStaticArrayType : MooreType<
|
||||
Or<[ArrayType.predicate, UnpackedArrayType.predicate]>,
|
||||
"packed or unpacked static array type",
|
||||
"moore::UnpackedType">;
|
||||
|
||||
/// A packed or unpacked struct type.
|
||||
def AnyStructType : MooreType<
|
||||
Or<[StructType.predicate, UnpackedStructType.predicate]>,
|
||||
|
|
|
@ -727,6 +727,70 @@ struct RvalueExprVisitor {
|
|||
return builder.create<moore::StringConstantOp>(loc, type, expr.getValue());
|
||||
}
|
||||
|
||||
/// Handle assignment patterns.
|
||||
Value visitAssignmentPattern(
|
||||
const slang::ast::AssignmentPatternExpressionBase &expr,
|
||||
unsigned replCount = 1) {
|
||||
auto type = context.convertType(*expr.type);
|
||||
|
||||
// Convert the individual elements first.
|
||||
auto elementCount = expr.elements().size();
|
||||
SmallVector<Value> elements;
|
||||
elements.reserve(replCount * elementCount);
|
||||
for (auto elementExpr : expr.elements()) {
|
||||
auto value = context.convertRvalueExpression(*elementExpr);
|
||||
if (!value)
|
||||
return {};
|
||||
elements.push_back(value);
|
||||
}
|
||||
for (unsigned replIdx = 1; replIdx < replCount; ++replIdx)
|
||||
for (unsigned elementIdx = 0; elementIdx < elementCount; ++elementIdx)
|
||||
elements.push_back(elements[elementIdx]);
|
||||
|
||||
// Handle packed structs.
|
||||
if (auto structType = dyn_cast<moore::StructType>(type)) {
|
||||
assert(structType.getMembers().size() == elements.size());
|
||||
return builder.create<moore::StructCreateOp>(loc, structType, elements);
|
||||
}
|
||||
|
||||
// Handle unpacked structs.
|
||||
if (auto structType = dyn_cast<moore::UnpackedStructType>(type)) {
|
||||
assert(structType.getMembers().size() == elements.size());
|
||||
return builder.create<moore::StructCreateOp>(loc, structType, elements);
|
||||
}
|
||||
|
||||
// Handle packed arrays.
|
||||
if (auto arrayType = dyn_cast<moore::ArrayType>(type)) {
|
||||
assert(arrayType.getSize() == elements.size());
|
||||
return builder.create<moore::ArrayCreateOp>(loc, arrayType, elements);
|
||||
}
|
||||
|
||||
// Handle unpacked arrays.
|
||||
if (auto arrayType = dyn_cast<moore::UnpackedArrayType>(type)) {
|
||||
assert(arrayType.getSize() == elements.size());
|
||||
return builder.create<moore::ArrayCreateOp>(loc, arrayType, elements);
|
||||
}
|
||||
|
||||
mlir::emitError(loc) << "unsupported assignment pattern with type " << type;
|
||||
return {};
|
||||
}
|
||||
|
||||
Value visit(const slang::ast::SimpleAssignmentPatternExpression &expr) {
|
||||
return visitAssignmentPattern(expr);
|
||||
}
|
||||
|
||||
Value visit(const slang::ast::StructuredAssignmentPatternExpression &expr) {
|
||||
return visitAssignmentPattern(expr);
|
||||
}
|
||||
|
||||
Value visit(const slang::ast::ReplicatedAssignmentPatternExpression &expr) {
|
||||
slang::ast::EvalContext evalContext(context.compilation,
|
||||
slang::ast::EvalFlags::CacheResults);
|
||||
auto count = expr.count().eval(evalContext).integer().as<unsigned>();
|
||||
assert(count && "Slang guarantees constant non-zero replication count");
|
||||
return visitAssignmentPattern(expr, *count);
|
||||
}
|
||||
|
||||
/// Emit an error for all other expressions.
|
||||
template <typename T>
|
||||
Value visit(T &&node) {
|
||||
|
|
|
@ -512,6 +512,39 @@ LogicalResult ConcatRefOp::inferReturnTypes(
|
|||
return success();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ArrayCreateOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static std::pair<unsigned, UnpackedType> getArrayElements(Type type) {
|
||||
if (auto arrayType = dyn_cast<ArrayType>(type))
|
||||
return {arrayType.getSize(), arrayType.getElementType()};
|
||||
if (auto arrayType = dyn_cast<UnpackedArrayType>(type))
|
||||
return {arrayType.getSize(), arrayType.getElementType()};
|
||||
assert(0 && "expected ArrayType or UnpackedArrayType");
|
||||
return {};
|
||||
}
|
||||
|
||||
LogicalResult ArrayCreateOp::verify() {
|
||||
auto [size, elementType] = getArrayElements(getType());
|
||||
|
||||
// Check that the number of operands matches the array size.
|
||||
if (getElements().size() != size)
|
||||
return emitOpError() << "has " << getElements().size()
|
||||
<< " operands, but result type requires " << size;
|
||||
|
||||
// Check that the operand types match the array element type. We only need to
|
||||
// check one of the operands, since the `SameTypeOperands` trait ensures all
|
||||
// operands have the same type.
|
||||
if (size > 0) {
|
||||
auto value = getElements()[0];
|
||||
if (value.getType() != elementType)
|
||||
return emitOpError() << "operands have type " << value.getType()
|
||||
<< ", but array requires " << elementType;
|
||||
}
|
||||
return success();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// StructCreateOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -493,6 +493,10 @@ module Expressions;
|
|||
struct packed {
|
||||
int a, b;
|
||||
} struct0;
|
||||
// CHECK: %ustruct0 = moore.variable : <ustruct<{a: i32, b: i32}>>
|
||||
struct {
|
||||
int a, b;
|
||||
} ustruct0;
|
||||
// CHECK: %struct1 = moore.variable : <struct<{c: struct<{a: i32, b: i32}>, d: struct<{a: i32, b: i32}>}>>
|
||||
struct packed {
|
||||
struct packed {
|
||||
|
@ -512,6 +516,10 @@ module Expressions;
|
|||
// CHECK: %r1 = moore.variable : <real>
|
||||
// CHECK: %r2 = moore.variable : <real>
|
||||
real r1,r2;
|
||||
// CHECK: %arrayInt = moore.variable : <array<2 x i32>>
|
||||
bit [1:0][31:0] arrayInt;
|
||||
// CHECK: %uarrayInt = moore.variable : <uarray<2 x i32>>
|
||||
bit [31:0] uarrayInt [2];
|
||||
|
||||
initial begin
|
||||
// CHECK: moore.constant 0 : i32
|
||||
|
@ -1058,6 +1066,64 @@ module Expressions;
|
|||
// CHECK: [[TMP2:%.+]] = moore.struct_extract [[TMP1]], "b" : struct<{a: i32, b: i32}> -> i32
|
||||
// CHECK: moore.blocking_assign %b, [[TMP2]]
|
||||
b = struct0.b;
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// Assignment Patterns
|
||||
|
||||
// CHECK: [[TMP0:%.+]] = moore.constant 17
|
||||
// CHECK: [[TMP1:%.+]] = moore.constant 17
|
||||
// CHECK: moore.struct_create [[TMP0]], [[TMP1]] : !moore.i32, !moore.i32 -> struct<{a: i32, b: i32}>
|
||||
struct0 = '{default: 17};
|
||||
|
||||
// CHECK: [[TMP0:%.+]] = moore.constant 1337
|
||||
// CHECK: [[TMP1:%.+]] = moore.constant 1337
|
||||
// CHECK: moore.struct_create [[TMP0]], [[TMP1]] : !moore.i32, !moore.i32 -> struct<{a: i32, b: i32}>
|
||||
struct0 = '{int: 1337};
|
||||
|
||||
// CHECK: [[TMP0:%.+]] = moore.constant 420
|
||||
// CHECK: moore.struct_create [[TMP0]], [[TMP0]] : !moore.i32, !moore.i32 -> struct<{a: i32, b: i32}>
|
||||
struct0 = '{2{420}};
|
||||
|
||||
// CHECK: [[TMP0:%.+]] = moore.constant 42
|
||||
// CHECK: [[TMP1:%.+]] = moore.constant 9001
|
||||
// CHECK: moore.struct_create [[TMP0]], [[TMP1]] : !moore.i32, !moore.i32 -> struct<{a: i32, b: i32}>
|
||||
struct0 = '{a: 42, b: 9001};
|
||||
|
||||
// CHECK: [[TMP0:%.+]] = moore.constant 43
|
||||
// CHECK: [[TMP1:%.+]] = moore.constant 9002
|
||||
// CHECK: moore.struct_create [[TMP0]], [[TMP1]] : !moore.i32, !moore.i32 -> struct<{a: i32, b: i32}>
|
||||
struct0 = '{43, 9002};
|
||||
|
||||
// CHECK: [[TMP0:%.+]] = moore.constant 44
|
||||
// CHECK: [[TMP1:%.+]] = moore.constant 9003
|
||||
// CHECK: moore.struct_create [[TMP0]], [[TMP1]] : !moore.i32, !moore.i32 -> ustruct<{a: i32, b: i32}>
|
||||
ustruct0 = '{44, 9003};
|
||||
|
||||
// CHECK: [[TMP0:%.+]] = moore.constant 1
|
||||
// CHECK: [[TMP1:%.+]] = moore.constant 2
|
||||
// CHECK: [[TMP2:%.+]] = moore.struct_create [[TMP0]], [[TMP1]] : !moore.i32, !moore.i32 -> struct<{a: i32, b: i32}>
|
||||
// CHECK: [[TMP0:%.+]] = moore.constant 3
|
||||
// CHECK: [[TMP1:%.+]] = moore.constant 4
|
||||
// CHECK: [[TMP3:%.+]] = moore.struct_create [[TMP0]], [[TMP1]] : !moore.i32, !moore.i32 -> struct<{a: i32, b: i32}>
|
||||
// CHECK: moore.struct_create [[TMP2]], [[TMP3]] : !moore.struct<{a: i32, b: i32}>, !moore.struct<{a: i32, b: i32}> -> struct<{c: struct<{a: i32, b: i32}>, d: struct<{a: i32, b: i32}>}>
|
||||
struct1 = '{c: '{a: 1, b: 2}, d: '{a: 3, b: 4}};
|
||||
|
||||
// CHECK: [[TMP0:%.+]] = moore.constant 42
|
||||
// CHECK: [[TMP1:%.+]] = moore.constant 9001
|
||||
// CHECK: moore.array_create [[TMP0]], [[TMP1]] : !moore.i32, !moore.i32 -> array<2 x i32>
|
||||
arrayInt = '{42, 9001};
|
||||
|
||||
// CHECK: [[TMP0:%.+]] = moore.constant 43
|
||||
// CHECK: [[TMP1:%.+]] = moore.constant 9002
|
||||
// CHECK: moore.array_create [[TMP0]], [[TMP1]] : !moore.i32, !moore.i32 -> uarray<2 x i32>
|
||||
uarrayInt = '{43, 9002};
|
||||
|
||||
// CHECK: [[TMP0:%.+]] = moore.constant 1
|
||||
// CHECK: [[TMP1:%.+]] = moore.constant 2
|
||||
// CHECK: [[TMP2:%.+]] = moore.constant 3
|
||||
// CHECK: [[TMP3:%.+]] = moore.array_create [[TMP0]], [[TMP1]], [[TMP2]], [[TMP0]], [[TMP1]], [[TMP2]] : !moore.i4, !moore.i4, !moore.i4, !moore.i4, !moore.i4, !moore.i4 -> uarray<6 x i4>
|
||||
// CHECK: moore.array_create [[TMP3]], [[TMP3]], [[TMP3]] : !moore.uarray<6 x i4>, !moore.uarray<6 x i4>, !moore.uarray<6 x i4> -> uarray<3 x uarray<6 x i4>>
|
||||
arr = '{3{'{2{4'd1, 4'd2, 4'd3}}}};
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// Builtin Functions
|
||||
|
|
|
@ -275,6 +275,9 @@ moore.module @Expressions(
|
|||
moore.yield %b : i32
|
||||
}
|
||||
|
||||
// CHECK: moore.array_create [[A]], [[B]] : !moore.i32, !moore.i32 -> array<2 x i32>
|
||||
moore.array_create %a, %b : !moore.i32, !moore.i32 -> array<2 x i32>
|
||||
|
||||
// CHECK: moore.struct_create [[A]], [[B]] : !moore.i32, !moore.i32 -> struct<{a: i32, b: i32}>
|
||||
moore.struct_create %a, %b : !moore.i32, !moore.i32 -> struct<{a: i32, b: i32}>
|
||||
// CHECK: moore.struct_extract [[STRUCT1]], "a" : struct<{a: i32, b: i32}> -> i32
|
||||
|
|
Loading…
Reference in New Issue