mirror of https://github.com/llvm/circt.git
[ImportVerilog] Support member-access expression (#7039)
* [ImportVerilog] Support member-access expression Support member-access expression. Add container multiSymbolValue for multi-symbols pointing one value. Signed-off-by: mingzheTerapines <mingzhe.zhang@terapines.com> * [ImportVerilog] Support member-access expression Separate two containers and their annotations. * [ImportVerilog] Support member-access expression3 use auto instead of const slang::ast::Expression * declare concatName with expr.member.name * [ImportVerilog] Support member-access expression4 Simplfy string allocation. * [ImportVerilog] Support member-access expression The signing of unpacked structures is not allowed.- IEEE Standard * [ImportVerilog] Support member-access expression6 Add packed unsigned struct occasion for testing. * [ImportVerilog] Support Union Type Support Union Type Modify uniont tyep to event type as error type example. * [ImportVerilog]Add errors example Add error example for unpacked union. * [ImportVerilog] Add strucfield op Define a struct field access op that can represent accesses into struct fields. * [ImportVerilog] Add struct inject and extract op Add struct inject and extract op. Remove union support. * [ImportVerilog] Support memberaccess * Removed some useless include. * fix test error * Fix errors.sv * remove space. --------- Signed-off-by: mingzheTerapines <mingzhe.zhang@terapines.com>
This commit is contained in:
parent
8a8fd29595
commit
9006a44b07
|
@ -17,6 +17,7 @@ include "mlir/IR/RegionKindInterface.td"
|
|||
include "mlir/IR/SymbolInterfaces.td"
|
||||
include "mlir/Interfaces/InferTypeOpInterface.td"
|
||||
include "mlir/Interfaces/SideEffectInterfaces.td"
|
||||
include "mlir/Interfaces/MemorySlotInterfaces.td"
|
||||
|
||||
// Base class for the operations in this dialect.
|
||||
class MooreOp<string mnemonic, list<Trait> traits = []> :
|
||||
|
@ -783,9 +784,111 @@ def ExtractOp : MooreOp<"extract"> {
|
|||
let arguments = (ins UnpackedType:$input, UnpackedType:$lowBit);
|
||||
let results = (outs UnpackedType:$result);
|
||||
let assemblyFormat = [{
|
||||
$input `from` $lowBit attr-dict `:`
|
||||
$input `from` $lowBit attr-dict `:`
|
||||
type($input) `,` type($lowBit) `->` type($result)
|
||||
}];
|
||||
}
|
||||
|
||||
def StructCreateOp : MooreOp<"struct_create", [SameOperandsAndResultType]> {
|
||||
let summary = "Struct Create operation";
|
||||
let description = [{
|
||||
A structure represents a collection of data types
|
||||
that can be referenced as a whole, or the individual data types
|
||||
that make up the structure can be referenced by name.
|
||||
By default, structures are unpacked, meaning that there is
|
||||
an implementation-dependent packing of the data types.
|
||||
Unpacked structures can contain any data type.
|
||||
See IEEE 1800-2017 § 7.2 "Structures"
|
||||
|
||||
Example:
|
||||
```
|
||||
struct { bit [7:0] opcode; bit [23:0] addr; }IR;
|
||||
IR.opcode = 1; // set field in IR.
|
||||
// anonymous structure
|
||||
// defines variable IR
|
||||
typedef struct {
|
||||
bit [7:0] opcode;
|
||||
bit [23:0] addr;
|
||||
} instruction; // named structure type
|
||||
instruction IR; // define variable
|
||||
```
|
||||
See IEEE 1800-2017 § 7.2. "Structures".
|
||||
}];
|
||||
let arguments = (ins UnpackedType:$structName);
|
||||
let results = (outs UnpackedType:$result);
|
||||
let hasCustomAssemblyFormat = 1;
|
||||
let assemblyFormat = [{
|
||||
$structName attr-dict `:` type($structName)
|
||||
}];
|
||||
}
|
||||
|
||||
def StructExtractOp : MooreOp<"struct_extract"> {
|
||||
let summary = "Struct Extract operation";
|
||||
let description = [{
|
||||
Structures can be converted to bits preserving the bit pattern.
|
||||
In other words, they can be converted back to the same value
|
||||
without any loss of information. When unpacked data are converted
|
||||
to the packed representation, the order of the data in the packed
|
||||
representation is such that the first field in the structure
|
||||
occupies the MSBs. The effect is the same as a concatenation of
|
||||
the data items (struct fields or array elements) in order.
|
||||
The type of the elements in an unpacked structure or array
|
||||
shall be valid for a packed representation in order to be
|
||||
cast to any other type, whether packed or unpacked.
|
||||
See IEEE 1800-2017 § 6.24.1 "Cast operator"
|
||||
|
||||
Example:
|
||||
```
|
||||
typedef struct {
|
||||
int addr = 1 + constant;
|
||||
int crc;
|
||||
byte data [4] = '{4{1}};
|
||||
} packet1;
|
||||
|
||||
packet1 p1; // initialization defined by the typedef.
|
||||
// p1.crc will use the default value for an int
|
||||
```
|
||||
See IEEE 1800-2017 § 7.2.1 "Assigning to structures".
|
||||
}];
|
||||
let arguments = (ins StrAttr:$memberName, UnpackedType:$structName);
|
||||
let results = (outs UnpackedType:$result);
|
||||
let assemblyFormat = [{
|
||||
$structName `,` $memberName attr-dict `:`
|
||||
type($structName) `->` type($result)
|
||||
}];
|
||||
}
|
||||
|
||||
def StructInjectOp : MooreOp<"struct_inject"> {
|
||||
let summary = "Struct Field operation";
|
||||
let description = [{
|
||||
A structure can be assigned as a whole and passed to
|
||||
or from a subroutine as a whole. Members of a structure
|
||||
data type can be assigned individual default member
|
||||
values by using an initial assignment with the declaration
|
||||
of each member. The assigned expression shall be
|
||||
a constant expression.
|
||||
See IEEE 1800-2017 § 7.2.2 "Assigning to structures"
|
||||
|
||||
Example:
|
||||
```
|
||||
typedef struct {
|
||||
int addr = 1 + constant;
|
||||
int crc;
|
||||
byte data [4] = '{4{1}};
|
||||
} packet1;
|
||||
|
||||
packet1 p1; // initialization defined by the typedef.
|
||||
// p1.crc will use the default value for an int
|
||||
```
|
||||
See IEEE 1800-2017 § 7.2. "Assigning to structures".
|
||||
}];
|
||||
let arguments = (ins UnpackedType:$LHS, StrAttr:$memberName,
|
||||
UnpackedType:$RHS);
|
||||
let results = (outs UnpackedType:$result);
|
||||
let assemblyFormat = [{
|
||||
$LHS `,` $memberName `,` $RHS
|
||||
attr-dict `:` type($LHS) type($RHS) `->` type($result)
|
||||
}];
|
||||
}
|
||||
|
||||
#endif // CIRCT_DIALECT_MOORE_MOOREOPS
|
||||
|
|
|
@ -428,6 +428,13 @@ struct ExprVisitor {
|
|||
return builder.create<moore::ExtractOp>(loc, type, value, lowBit);
|
||||
}
|
||||
|
||||
Value visit(const slang::ast::MemberAccessExpression &expr) {
|
||||
return builder.create<moore::StructExtractOp>(
|
||||
loc, context.convertType(*expr.type),
|
||||
builder.getStringAttr(expr.member.name),
|
||||
context.convertExpression(expr.value()));
|
||||
}
|
||||
|
||||
/// Emit an error for all other expressions.
|
||||
template <typename T>
|
||||
Value visit(T &&node) {
|
||||
|
|
|
@ -300,6 +300,9 @@ module Expressions;
|
|||
// CHECK: %y = moore.variable : !moore.l1
|
||||
// CHECK: %vec_1 = moore.variable : !moore.l32
|
||||
// CHECK: %vec_2 = moore.variable : !moore.l32
|
||||
// CHECK: %myStruct = moore.variable : !moore.packed<struct<{a: i32, b: i32}>>
|
||||
// CHECK: %myStruct2 = moore.variable : !moore.packed<struct<{c: struct<{a: i32, b: i32}>, d: struct<{a: i32, b: i32}>}>>
|
||||
// CHECK: %myStruct3 = moore.variable : !moore.packed<struct<{a: i32, b: i32}>>
|
||||
int a, b, c;
|
||||
int unsigned u, w;
|
||||
bit [1:0][3:0] v;
|
||||
|
@ -311,6 +314,12 @@ module Expressions;
|
|||
logic [0:31] vec_2;
|
||||
bit [4:1] arr [1:3][2:7];
|
||||
bit [3:2] s;
|
||||
typedef struct packed signed {int a, b;} structTemp;
|
||||
structTemp myStruct;
|
||||
typedef struct packed signed {structTemp c,d;} structTemp2;
|
||||
structTemp2 myStruct2;
|
||||
typedef struct packed unsigned {int a, b;} structTemp3;
|
||||
structTemp3 myStruct3;
|
||||
|
||||
initial begin
|
||||
// CHECK: moore.constant 0 : !moore.i32
|
||||
|
@ -606,6 +615,32 @@ module Expressions;
|
|||
// CHECK: [[TMP2:%.+]] = moore.add [[A_ADD]], [[TMP1]]
|
||||
// CHECK: moore.blocking_assign %a, [[TMP2]]
|
||||
a += (a *= a--);
|
||||
|
||||
// CHECK: [[A_STRUCT:%.+]] = moore.struct_extract %myStruct, "a" : !moore.packed<struct<{a: i32, b: i32}>> -> !moore.i32
|
||||
// CHECK: moore.blocking_assign [[A_STRUCT]], %a : !moore.i32
|
||||
myStruct.a = a;
|
||||
|
||||
// CHECK: [[B_STRUCT:%.+]] = moore.struct_extract %myStruct, "b" : !moore.packed<struct<{a: i32, b: i32}>> -> !moore.i32
|
||||
// CHECK: moore.blocking_assign %b, [[B_STRUCT]] : !moore.i32
|
||||
b = myStruct.b;
|
||||
|
||||
// CHECK: [[C_STRUCT:%.+]] = moore.struct_extract %myStruct2, "c" : !moore.packed<struct<{c: struct<{a: i32, b: i32}>, d: struct<{a: i32, b: i32}>}>> -> !moore.packed<struct<{a: i32, b: i32}>>
|
||||
// CHECK: [[D_STRUCT:%.+]] = moore.struct_extract [[C_STRUCT]], "a" : !moore.packed<struct<{a: i32, b: i32}>> -> !moore.i32
|
||||
// CHECK: moore.blocking_assign [[D_STRUCT]], %a : !moore.i32
|
||||
myStruct2.c.a = a;
|
||||
|
||||
// CHECK: [[E_STRUCT:%.+]] = moore.struct_extract %myStruct2, "d" : !moore.packed<struct<{c: struct<{a: i32, b: i32}>, d: struct<{a: i32, b: i32}>}>> -> !moore.packed<struct<{a: i32, b: i32}>>
|
||||
// CHECK: [[F_STRUCT:%.+]] = moore.struct_extract [[E_STRUCT]], "b" : !moore.packed<struct<{a: i32, b: i32}>> -> !moore.i32
|
||||
// CHECK: moore.blocking_assign %b, [[F_STRUCT]] : !moore.i32
|
||||
b = myStruct2.d.b;
|
||||
|
||||
// CHECK: [[G_STRUCT:%.+]] = moore.struct_extract %myStruct3, "a" : !moore.packed<struct<{a: i32, b: i32}>> -> !moore.i32
|
||||
// CHECK: moore.blocking_assign [[G_STRUCT]], %a : !moore.i3
|
||||
myStruct3.a = a;
|
||||
|
||||
// CHECK: [[H_STRUCT:%.+]] = moore.struct_extract %myStruct3, "b" : !moore.packed<struct<{a: i32, b: i32}>> -> !moore.i32
|
||||
// CHECK: moore.blocking_assign %b, [[H_STRUCT]] : !moore.i32
|
||||
b = myStruct3.b;
|
||||
end
|
||||
endmodule
|
||||
|
||||
|
|
Loading…
Reference in New Issue