mirror of https://github.com/llvm/circt.git
[OM] Rework ClassOp to use return style for class fields (#7537)
This changes the OM dialect Class/ExternClass to use a return style field name/type specifier syntax and, for non-extern class, a terminator op in the style of hw.output.
This commit is contained in:
parent
f85865eea9
commit
3a9ccf9583
|
@ -14,6 +14,7 @@
|
|||
#define CIRCT_DIALECT_OM_OMOPINTERFACES_H
|
||||
|
||||
#include "mlir/IR/OpDefinition.h"
|
||||
#include "mlir/IR/OpImplementation.h"
|
||||
#include "llvm/ADT/APSInt.h"
|
||||
|
||||
#include "circt/Dialect/OM/OMOpInterfaces.h.inc"
|
||||
|
|
|
@ -33,26 +33,19 @@ def ClassLike : OpInterface<"ClassLike"> {
|
|||
"mlir::ArrayAttr", "getFormalParamNames", (ins)>,
|
||||
InterfaceMethod<"Get the class-like formal parameter names attribute name",
|
||||
"mlir::StringAttr", "getFormalParamNamesAttrName", (ins)>,
|
||||
InterfaceMethod<"Get the class-like dictionary mapping field names to type",
|
||||
"mlir::DictionaryAttr", "getFieldTypes", (ins)>,
|
||||
InterfaceMethod<"Get the class-like body region",
|
||||
"mlir::Region &", "getBody", (ins)>,
|
||||
InterfaceMethod<"Get the class-like body block",
|
||||
"mlir::Block *", "getBodyBlock", (ins),
|
||||
/*methodBody=*/[{ return $_op.getBodyBlock(); }]>
|
||||
];
|
||||
}
|
||||
|
||||
def ClassFieldLike : OpInterface<"ClassFieldLike"> {
|
||||
let cppNamespace = "circt::om";
|
||||
|
||||
let description = [{
|
||||
Common functionality for class-like field operations.
|
||||
}];
|
||||
|
||||
let methods = [
|
||||
InterfaceMethod<"Get the class-like field's type",
|
||||
"mlir::Type", "getType", (ins)>,
|
||||
InterfaceMethod<"Get the class-like field's name attribute",
|
||||
"mlir::StringAttr", "getNameAttr", (ins)>
|
||||
/*methodBody=*/[{ return $_op.getBodyBlock(); }]>,
|
||||
InterfaceMethod<"Get the class-like field type",
|
||||
"std::optional<mlir::Type>", "getFieldType", (ins "mlir::StringAttr":$field)>,
|
||||
InterfaceMethod<"Get the class-like field names",
|
||||
"mlir::ArrayAttr", "getFieldNames", (ins)>,
|
||||
InterfaceMethod<"Replace field types dictionary attr",
|
||||
"void", "replaceFieldTypes", (ins "mlir::AttrTypeReplacer":$replacer)>,
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "mlir/IR/BuiltinOps.h"
|
||||
#include "mlir/IR/OpDefinition.h"
|
||||
#include "mlir/Interfaces/ControlFlowInterfaces.h"
|
||||
#include "mlir/Interfaces/InferTypeOpInterface.h"
|
||||
|
||||
#define GET_OP_CLASSES
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#ifndef CIRCT_DIALECT_OM_OMOPS_TD
|
||||
#define CIRCT_DIALECT_OM_OMOPS_TD
|
||||
|
||||
include "mlir/Interfaces/ControlFlowInterfaces.td"
|
||||
include "circt/Dialect/OM/OMDialect.td"
|
||||
include "circt/Dialect/OM/OMEnums.td"
|
||||
include "circt/Dialect/OM/OMOpInterfaces.td"
|
||||
|
@ -33,13 +34,15 @@ class OMOp<string mnemonic, list<Trait> traits = []> :
|
|||
|
||||
class OMClassLike<string mnemonic, list<Trait> traits = []> :
|
||||
OMOp<mnemonic, traits # [
|
||||
SingleBlock, NoTerminator, Symbol, RegionKindInterface, IsolatedFromAbove,
|
||||
Symbol, RegionKindInterface, IsolatedFromAbove,
|
||||
DeclareOpInterfaceMethods<OpAsmOpInterface, ["getAsmBlockArgumentNames"]>,
|
||||
DeclareOpInterfaceMethods<ClassLike>]> {
|
||||
|
||||
let arguments = (ins
|
||||
SymbolNameAttr:$sym_name,
|
||||
StrArrayAttr:$formalParamNames
|
||||
StrArrayAttr:$formalParamNames,
|
||||
ArrayAttr:$fieldNames,
|
||||
DictionaryAttr:$fieldTypes
|
||||
);
|
||||
|
||||
let regions = (region
|
||||
|
@ -47,9 +50,44 @@ class OMClassLike<string mnemonic, list<Trait> traits = []> :
|
|||
);
|
||||
|
||||
let builders = [
|
||||
OpBuilder<(ins "::mlir::Twine":$name)>,
|
||||
OpBuilder<(ins "::mlir::Twine":$name,
|
||||
"::mlir::ArrayRef<::mlir::StringRef>":$formalParamNames)>,
|
||||
"::mlir::ArrayRef<::mlir::StringRef>":$formalParamNames,
|
||||
"::mlir::ArrayRef<::mlir::Attribute>":$fieldNames,
|
||||
"::mlir::ArrayRef<::mlir::NamedAttribute>":$fieldTypes), [{
|
||||
build(odsBuilder, odsState, odsBuilder.getStringAttr(name),
|
||||
odsBuilder.getStrArrayAttr(formalParamNames),
|
||||
odsBuilder.getArrayAttr(fieldNames),
|
||||
odsBuilder.getDictionaryAttr(fieldTypes));
|
||||
}]>,
|
||||
OpBuilder<(ins "::mlir::Twine":$name,
|
||||
"::mlir::ArrayRef<::mlir::StringRef>":$formalParamNames), [{
|
||||
build(odsBuilder, odsState, odsBuilder.getStringAttr(name),
|
||||
odsBuilder.getStrArrayAttr(formalParamNames));
|
||||
}]>,
|
||||
OpBuilder<(ins "::mlir::Twine":$name), [{
|
||||
build(odsBuilder, odsState, odsBuilder.getStringAttr(name),
|
||||
odsBuilder.getStrArrayAttr({}));
|
||||
}]>,
|
||||
OpBuilder<(ins "::mlir::Twine":$name,
|
||||
"::mlir::ArrayAttr":$fieldNames,
|
||||
"::mlir::DictionaryAttr":$fieldTypes), [{
|
||||
build(odsBuilder, odsState, odsBuilder.getStringAttr(name),
|
||||
odsBuilder.getStrArrayAttr({}), fieldNames, fieldTypes);
|
||||
}]>,
|
||||
OpBuilder<(ins "::mlir::Twine":$name,
|
||||
"::mlir::ArrayRef<::mlir::StringRef>":$formalParamNames,
|
||||
"::mlir::ArrayAttr":$fieldNames,
|
||||
"::mlir::DictionaryAttr":$fieldTypes), [{
|
||||
build(odsBuilder, odsState, odsBuilder.getStringAttr(name),
|
||||
odsBuilder.getStrArrayAttr(formalParamNames), fieldNames,
|
||||
fieldTypes);
|
||||
}]>,
|
||||
OpBuilder<(ins "::mlir::StringAttr":$name,
|
||||
"::mlir::ArrayAttr":$formalParamNames), [{
|
||||
build(odsBuilder, odsState, name, formalParamNames,
|
||||
odsBuilder.getArrayAttr({}), odsBuilder.getDictionaryAttr({}));
|
||||
|
||||
}]>
|
||||
];
|
||||
|
||||
let hasCustomAssemblyFormat = 1;
|
||||
|
@ -57,16 +95,12 @@ class OMClassLike<string mnemonic, list<Trait> traits = []> :
|
|||
let hasVerifier = 1;
|
||||
}
|
||||
|
||||
class OMClassFieldLike<string mnemonic, list<Trait> traits = []> :
|
||||
OMOp<mnemonic, traits # [
|
||||
DeclareOpInterfaceMethods<ClassFieldLike>]> {
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Class definitions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def ClassOp : OMClassLike<"class"> {
|
||||
def ClassOp : OMClassLike<"class", [
|
||||
SingleBlockImplicitTerminator<"ClassFieldsOp">]> {
|
||||
let extraClassDeclaration = [{
|
||||
mlir::Block *getBodyBlock() { return &getBody().front(); }
|
||||
// This builds a ClassOp, and populates it with the CLassFieldOps.
|
||||
|
@ -82,26 +116,46 @@ def ClassOp : OMClassLike<"class"> {
|
|||
static mlir::RegionKind getRegionKind(unsigned index) {
|
||||
return mlir::RegionKind::Graph;
|
||||
}
|
||||
|
||||
circt::om::ClassFieldsOp getFieldsOp() {
|
||||
return mlir::cast<ClassFieldsOp>(this->getBodyBlock()->getTerminator());
|
||||
}
|
||||
|
||||
// The addFields API encapsulates the logic used to represent field
|
||||
// locations under the hood. Users should invoke this method rather
|
||||
// than construct the operation directly, otherwise logic to retrieve
|
||||
// the field location will break.
|
||||
// This is required because MLIR's FusedLoc uses a "set" semantics where a
|
||||
// single location is used to represent multiple fields with the same
|
||||
// location. The OM implementation uses the metadata attribute on FusedLoc
|
||||
// to store the original array of locations, so that the specific location
|
||||
// of a field may be easily retrieved by index using the
|
||||
// `getFieldLocByIndex` API.
|
||||
void addFields(mlir::OpBuilder &builder, mlir::ArrayRef<mlir::Location>
|
||||
locs, mlir::ArrayRef<mlir::Value> values);
|
||||
|
||||
// Return the location for a field referenced by index in the fieldNames
|
||||
// array attribute. If the field has a location added by addFields API,
|
||||
// its location will be retrieved from the array of per field locations.
|
||||
// Otherwise, it will inherit the location of the class op Using this with
|
||||
// a ClassFieldsOp that has been constructed with a FusedLoc but not
|
||||
// following the internal storage format of `addFields` will result in an
|
||||
// assertion error
|
||||
mlir::Location getFieldLocByIndex(size_t i);
|
||||
}];
|
||||
}
|
||||
|
||||
def ClassFieldOp : OMClassFieldLike<"class.field",
|
||||
[HasParent<"ClassOp">]> {
|
||||
let arguments = (ins
|
||||
SymbolNameAttr:$name,
|
||||
AnyType:$value
|
||||
);
|
||||
|
||||
let assemblyFormat = [{
|
||||
$name `,` $value attr-dict `:` type($value)
|
||||
}];
|
||||
def ClassFieldsOp : OMOp<"class.fields", [Terminator, ReturnLike, Pure,
|
||||
HasParent<"ClassOp">]> {
|
||||
let arguments = (ins Variadic<AnyType>:$fields);
|
||||
let assemblyFormat = "attr-dict ($fields^ `:` qualified(type($fields)))?";
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// External class definitions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def ClassExternOp : OMClassLike<"class.extern"> {
|
||||
def ClassExternOp : OMClassLike<"class.extern", [NoTerminator]> {
|
||||
let extraClassDeclaration = [{
|
||||
mlir::Block *getBodyBlock() { return &getBody().front(); }
|
||||
|
||||
|
@ -112,18 +166,6 @@ def ClassExternOp : OMClassLike<"class.extern"> {
|
|||
}];
|
||||
}
|
||||
|
||||
def ClassExternFieldOp : OMClassFieldLike<"class.extern.field",
|
||||
[HasParent<"ClassExternOp">]> {
|
||||
let arguments = (ins
|
||||
SymbolNameAttr:$name,
|
||||
TypeAttr:$type
|
||||
);
|
||||
|
||||
let assemblyFormat = [{
|
||||
$name attr-dict `:` $type
|
||||
}];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Object instantiations and fields
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -14,52 +14,42 @@ with Context() as ctx, Location.unknown():
|
|||
|
||||
module = Module.parse("""
|
||||
module {
|
||||
om.class @node() {
|
||||
om.class @node() -> (field2: !om.string) {
|
||||
%0 = om.constant #om.list<!om.string,["MyThing" : !om.string]> : !om.list<!om.string>
|
||||
%1 = om.constant "Component.inst1.foo" : !om.string
|
||||
om.class.field @field2, %1 : !om.string
|
||||
om.class.fields %1 : !om.string
|
||||
}
|
||||
|
||||
om.class @comp(
|
||||
%inst1_propOut_bore: !om.class.type<@node>,
|
||||
%inst2_propOut_bore: !om.class.type<@node>) {
|
||||
om.class.field @field2, %inst1_propOut_bore : !om.class.type<@node>
|
||||
om.class.field @field3, %inst2_propOut_bore : !om.class.type<@node>
|
||||
%inst2_propOut_bore: !om.class.type<@node>) -> (field2: !om.class.type<@node>, field3: !om.class.type<@node>) {
|
||||
om.class.fields %inst1_propOut_bore, %inst2_propOut_bore : !om.class.type<@node>, !om.class.type<@node>
|
||||
}
|
||||
|
||||
om.class @Client() {
|
||||
om.class @Client() -> (client_omnode_0_OMIROut: !om.class.type<@comp>, node0_OMIROut : !om.class.type<@node>, node1_OMIROut : !om.class.type<@node>) {
|
||||
%0 = om.object @node() : () -> !om.class.type<@node>
|
||||
%2 = om.object @comp(%0, %0) : (!om.class.type<@node>, !om.class.type<@node>) -> !om.class.type<@comp>
|
||||
|
||||
om.class.field @client_omnode_0_OMIROut, %2 : !om.class.type<@comp>
|
||||
om.class.field @node0_OMIROut, %0 : !om.class.type<@node>
|
||||
om.class.field @node1_OMIROut, %0 : !om.class.type<@node>
|
||||
om.class.fields %2, %0, %0 : !om.class.type<@comp>, !om.class.type<@node>, !om.class.type<@node>
|
||||
}
|
||||
|
||||
om.class @Test(%param: !om.integer) {
|
||||
om.class @Test(%param: !om.integer) -> (field: !om.integer, child: !om.class.type<@Child>, reference: !om.ref, list: !om.list<!om.string>, tuple: tuple<!om.list<!om.string>, !om.integer>, nest: !om.class.type<@Nest>, map: !om.map<!om.string, !om.integer>, map_create: !om.map<!om.string, !om.integer>, true: i1, false: i1) {
|
||||
%sym = om.constant #om.ref<<@Root::@x>> : !om.ref
|
||||
om.class.field @field, %param : !om.integer
|
||||
|
||||
%c_14 = om.constant #om.integer<14> : !om.integer
|
||||
%0 = om.object @Child(%c_14) : (!om.integer) -> !om.class.type<@Child>
|
||||
om.class.field @child, %0 : !om.class.type<@Child>
|
||||
|
||||
om.class.field @reference, %sym : !om.ref
|
||||
|
||||
%list = om.constant #om.list<!om.string, ["X" : !om.string, "Y" : !om.string]> : !om.list<!om.string>
|
||||
om.class.field @list, %list : !om.list<!om.string>
|
||||
|
||||
%tuple = om.tuple_create %list, %c_14: !om.list<!om.string>, !om.integer
|
||||
om.class.field @tuple, %tuple : tuple<!om.list<!om.string>, !om.integer>
|
||||
|
||||
%c_15 = om.constant #om.integer<15> : !om.integer
|
||||
%1 = om.object @Child(%c_15) : (!om.integer) -> !om.class.type<@Child>
|
||||
%list_child = om.list_create %0, %1: !om.class.type<@Child>
|
||||
%2 = om.object @Nest(%list_child) : (!om.list<!om.class.type<@Child>>) -> !om.class.type<@Nest>
|
||||
om.class.field @nest, %2 : !om.class.type<@Nest>
|
||||
|
||||
%3 = om.constant #om.map<!om.integer, {a = #om.integer<42>, b = #om.integer<32>}> : !om.map<!om.string, !om.integer>
|
||||
om.class.field @map, %3 : !om.map<!om.string, !om.integer>
|
||||
|
||||
%x = om.constant "X" : !om.string
|
||||
%y = om.constant "Y" : !om.string
|
||||
|
@ -67,47 +57,44 @@ with Context() as ctx, Location.unknown():
|
|||
%entry2 = om.tuple_create %y, %c_15: !om.string, !om.integer
|
||||
|
||||
%map = om.map_create %entry1, %entry2: !om.string, !om.integer
|
||||
om.class.field @map_create, %map : !om.map<!om.string, !om.integer>
|
||||
|
||||
%true = om.constant true
|
||||
om.class.field @true, %true : i1
|
||||
%false = om.constant false
|
||||
om.class.field @false, %false : i1
|
||||
|
||||
om.class.fields %param, %0, %sym, %list, %tuple, %2, %3, %map, %true, %false : !om.integer, !om.class.type<@Child>, !om.ref, !om.list<!om.string>, tuple<!om.list<!om.string>, !om.integer>, !om.class.type<@Nest>, !om.map<!om.string, !om.integer>, !om.map<!om.string, !om.integer>, i1, i1
|
||||
}
|
||||
|
||||
om.class @Child(%0: !om.integer) {
|
||||
om.class.field @foo, %0 : !om.integer
|
||||
om.class @Child(%0: !om.integer) -> (foo: !om.integer) {
|
||||
om.class.fields %0 : !om.integer
|
||||
}
|
||||
|
||||
om.class @Nest(%0: !om.list<!om.class.type<@Child>>) {
|
||||
om.class.field @list_child, %0 : !om.list<!om.class.type<@Child>>
|
||||
om.class @Nest(%0: !om.list<!om.class.type<@Child>>) -> (list_child: !om.list<!om.class.type<@Child>>) {
|
||||
om.class.fields %0 : !om.list<!om.class.type<@Child>>
|
||||
}
|
||||
|
||||
hw.module @Root(in %clock: i1) {
|
||||
%0 = sv.wire sym @x : !hw.inout<i1>
|
||||
}
|
||||
|
||||
om.class @Paths(%basepath: !om.frozenbasepath) {
|
||||
om.class @Paths(%basepath: !om.frozenbasepath) -> (path: !om.frozenpath, deleted: !om.frozenpath) {
|
||||
%0 = om.frozenbasepath_create %basepath "Foo/bar"
|
||||
%1 = om.frozenpath_create reference %0 "Bar/baz:Baz>w"
|
||||
om.class.field @path, %1 : !om.frozenpath
|
||||
|
||||
%3 = om.frozenpath_empty
|
||||
om.class.field @deleted, %3 : !om.frozenpath
|
||||
om.class.fields %1, %3 : !om.frozenpath, !om.frozenpath
|
||||
}
|
||||
|
||||
om.class @Class1(%input: !om.integer) {
|
||||
om.class @Class1(%input: !om.integer) -> (value: !om.integer, input: !om.integer) {
|
||||
%0 = om.constant #om.integer<1 : si3> : !om.integer
|
||||
om.class.field @value, %0 : !om.integer
|
||||
om.class.field @input, %input : !om.integer
|
||||
om.class.fields %0, %input : !om.integer, !om.integer
|
||||
}
|
||||
|
||||
om.class @Class2() {
|
||||
om.class @Class2() -> (value: !om.integer) {
|
||||
%0 = om.constant #om.integer<2 : si3> : !om.integer
|
||||
om.class.field @value, %0 : !om.integer
|
||||
om.class.fields %0 : !om.integer
|
||||
}
|
||||
|
||||
om.class @IntegerBinaryArithmeticObjectsDelayed() {
|
||||
om.class @IntegerBinaryArithmeticObjectsDelayed() -> (result: !om.integer) {
|
||||
%0 = om.object @Class1(%5) : (!om.integer) -> !om.class.type<@Class1>
|
||||
%1 = om.object.field %0, [@value] : (!om.class.type<@Class1>) -> !om.integer
|
||||
|
||||
|
@ -115,7 +102,7 @@ with Context() as ctx, Location.unknown():
|
|||
%3 = om.object.field %2, [@value] : (!om.class.type<@Class2>) -> !om.integer
|
||||
|
||||
%5 = om.integer.add %1, %3 : !om.integer
|
||||
om.class.field @result, %5 : !om.integer
|
||||
om.class.fields %5 : !om.integer
|
||||
}
|
||||
}
|
||||
""")
|
||||
|
@ -157,23 +144,23 @@ print(obj.type.name)
|
|||
print(obj.field)
|
||||
|
||||
# location of the om.class.field @field
|
||||
# CHECK: loc("-":27:7)
|
||||
print(obj.get_field_loc("field"))
|
||||
# CHECK: field: loc("-":50:7)
|
||||
print("field:", obj.get_field_loc("field"))
|
||||
|
||||
# CHECK: 14
|
||||
print(obj.child.foo)
|
||||
# CHECK: loc("-":65:7)
|
||||
print(obj.child.get_field_loc("foo"))
|
||||
# CHECK: child.foo: 14
|
||||
print("child.foo: ", obj.child.foo)
|
||||
# CHECK: child.foo.loc loc("-":54:7)
|
||||
print("child.foo.loc", obj.child.get_field_loc("foo"))
|
||||
# CHECK: ('Root', 'x')
|
||||
print(obj.reference)
|
||||
(fst, snd) = obj.tuple
|
||||
# CHECK: 14
|
||||
print(snd)
|
||||
|
||||
# CHECK: loc("-":39:7)
|
||||
print(obj.get_field_loc("tuple"))
|
||||
# CHECK: loc("-":50:7)
|
||||
print("tuple", obj.get_field_loc("tuple"))
|
||||
|
||||
# CHECK: loc("-":25:5)
|
||||
# CHECK: loc("-":22:5)
|
||||
print(obj.loc)
|
||||
|
||||
try:
|
||||
|
@ -185,13 +172,13 @@ except IndexError as e:
|
|||
for (name, field) in obj:
|
||||
# location from om.class.field @child, %0 : !om.class.type<@Child>
|
||||
# CHECK: name: child, field: <circt.dialects.om.Object object
|
||||
# CHECK-SAME: loc: loc("-":30:12)
|
||||
# CHECK-SAME: loc: loc("-":26:12)
|
||||
# location from om.class.field @field, %param : !om.integer
|
||||
# CHECK: name: field, field: 42
|
||||
# CHECK-SAME: loc: loc("-":27:7)
|
||||
# CHECK-SAME: loc: loc("-":50:7)
|
||||
# location from om.class.field @reference, %sym : !om.ref
|
||||
# CHECK: name: reference, field: ('Root', 'x')
|
||||
# CHECK-SAME: loc: loc("-":33:7)
|
||||
# CHECK-SAME: loc: loc("-":50:7)
|
||||
loc = obj.get_field_loc(name)
|
||||
print(f"name: {name}, field: {field}, loc: {loc}")
|
||||
|
||||
|
@ -260,12 +247,12 @@ paths_class = [
|
|||
base_path_type = paths_class.regions[0].blocks[0].arguments[0].type
|
||||
assert isinstance(base_path_type, om.BasePathType)
|
||||
|
||||
paths_fields = [
|
||||
op for op in paths_class.regions[0].blocks[0]
|
||||
if isinstance(op, om.ClassFieldOp)
|
||||
]
|
||||
for paths_field in paths_fields:
|
||||
assert isinstance(paths_field.value.type, om.PathType)
|
||||
paths_ops = paths_class.regions[0].blocks[0].operations
|
||||
# NOTE: would be nice if this supported [-1] indexing syntax
|
||||
class_fields_op = paths_ops[len(paths_ops) - 1]
|
||||
assert len(class_fields_op.operands)
|
||||
for arg in class_fields_op.operands:
|
||||
assert isinstance(arg.type, om.PathType)
|
||||
|
||||
delayed = evaluator.instantiate("IntegerBinaryArithmeticObjectsDelayed")
|
||||
|
||||
|
|
|
@ -966,6 +966,66 @@ bool LowerClassesPass::shouldCreateClass(StringAttr modName) {
|
|||
return shouldCreateClassMemo.at(modName);
|
||||
}
|
||||
|
||||
void checkAddContainingModulePorts(bool hasContainingModule, OpBuilder builder,
|
||||
SmallVector<Attribute> &fieldNames,
|
||||
SmallVector<NamedAttribute> &fieldTypes) {
|
||||
if (hasContainingModule) {
|
||||
auto name = builder.getStringAttr(kPortsName);
|
||||
fieldNames.push_back(name);
|
||||
fieldTypes.push_back(NamedAttribute(
|
||||
name, TypeAttr::get(getRtlPortsType(builder.getContext()))));
|
||||
}
|
||||
}
|
||||
|
||||
static om::ClassLike convertExtClass(FModuleLike moduleLike, OpBuilder builder,
|
||||
Twine name,
|
||||
ArrayRef<StringRef> formalParamNames,
|
||||
bool hasContainingModule) {
|
||||
SmallVector<Attribute> fieldNames;
|
||||
SmallVector<NamedAttribute> fieldTypes;
|
||||
for (unsigned i = 0, e = moduleLike.getNumPorts(); i < e; ++i) {
|
||||
auto type = moduleLike.getPortType(i);
|
||||
if (!isa<PropertyType>(type))
|
||||
continue;
|
||||
|
||||
auto direction = moduleLike.getPortDirection(i);
|
||||
if (direction != Direction::In) {
|
||||
auto name = moduleLike.getPortNameAttr(i);
|
||||
fieldNames.push_back(name);
|
||||
fieldTypes.push_back(NamedAttribute(name, TypeAttr::get(type)));
|
||||
}
|
||||
}
|
||||
checkAddContainingModulePorts(hasContainingModule, builder, fieldNames,
|
||||
fieldTypes);
|
||||
return builder.create<om::ClassExternOp>(
|
||||
moduleLike.getLoc(), name, formalParamNames, fieldNames, fieldTypes);
|
||||
}
|
||||
|
||||
static om::ClassLike convertClass(FModuleLike moduleLike, OpBuilder builder,
|
||||
Twine name,
|
||||
ArrayRef<StringRef> formalParamNames,
|
||||
bool hasContainingModule) {
|
||||
// Collect output property assignments to get field names and types.
|
||||
SmallVector<Attribute> fieldNames;
|
||||
SmallVector<NamedAttribute> fieldTypes;
|
||||
for (auto op : llvm::make_early_inc_range(
|
||||
moduleLike->getRegion(0).getOps<PropAssignOp>())) {
|
||||
auto outputPort = dyn_cast<BlockArgument>(op.getDest());
|
||||
if (!outputPort)
|
||||
continue;
|
||||
|
||||
StringAttr name = moduleLike.getPortNameAttr(outputPort.getArgNumber());
|
||||
|
||||
fieldNames.push_back(name);
|
||||
fieldTypes.push_back(
|
||||
NamedAttribute(name, TypeAttr::get(op.getSrc().getType())));
|
||||
}
|
||||
checkAddContainingModulePorts(hasContainingModule, builder, fieldNames,
|
||||
fieldTypes);
|
||||
return builder.create<om::ClassOp>(moduleLike.getLoc(), name,
|
||||
formalParamNames, fieldNames, fieldTypes);
|
||||
}
|
||||
|
||||
// Create an OM Class op from a FIRRTL Class op or Module op with properties.
|
||||
om::ClassLike LowerClassesPass::createClass(FModuleLike moduleLike,
|
||||
const PathInfoTable &pathInfoTable,
|
||||
|
@ -1015,12 +1075,14 @@ om::ClassLike LowerClassesPass::createClass(FModuleLike moduleLike,
|
|||
|
||||
// Construct the OM Class with the FIRRTL Class name and parameter names.
|
||||
om::ClassLike loweredClassOp;
|
||||
if (isa<firrtl::ExtClassOp, firrtl::FExtModuleOp>(moduleLike.getOperation()))
|
||||
loweredClassOp = builder.create<om::ClassExternOp>(
|
||||
moduleLike.getLoc(), className + suffix, formalParamNames);
|
||||
else
|
||||
loweredClassOp = builder.create<om::ClassOp>(
|
||||
moduleLike.getLoc(), className + suffix, formalParamNames);
|
||||
if (isa<firrtl::ExtClassOp, firrtl::FExtModuleOp>(
|
||||
moduleLike.getOperation())) {
|
||||
loweredClassOp = convertExtClass(moduleLike, builder, className + suffix,
|
||||
formalParamNames, hasContainingModule);
|
||||
} else {
|
||||
loweredClassOp = convertClass(moduleLike, builder, className + suffix,
|
||||
formalParamNames, hasContainingModule);
|
||||
}
|
||||
|
||||
return loweredClassOp;
|
||||
}
|
||||
|
@ -1091,6 +1153,8 @@ void LowerClassesPass::lowerClass(om::ClassOp classOp, FModuleLike moduleLike,
|
|||
// Clone the property ops from the FIRRTL Class or Module to the OM Class.
|
||||
SmallVector<Operation *> opsToErase;
|
||||
OpBuilder builder = OpBuilder::atBlockBegin(classOp.getBodyBlock());
|
||||
llvm::SmallVector<mlir::Location> fieldLocs;
|
||||
llvm::SmallVector<mlir::Value> fieldValues;
|
||||
for (auto &op : moduleLike->getRegion(0).getOps()) {
|
||||
// Check if any operand is a property.
|
||||
auto propertyOperands = llvm::any_of(op.getOperandTypes(), [](Type type) {
|
||||
|
@ -1108,8 +1172,19 @@ void LowerClassesPass::lowerClass(om::ClassOp classOp, FModuleLike moduleLike,
|
|||
if (!needsClone && !propertyOperands && !propertyResults)
|
||||
continue;
|
||||
|
||||
// Actually clone the op over to the OM Class.
|
||||
builder.clone(op, mapping);
|
||||
bool isField = false;
|
||||
if (auto propAssign = dyn_cast<PropAssignOp>(op)) {
|
||||
if (isa<BlockArgument>(propAssign.getDest())) {
|
||||
// Store any output property assignments into fields op inputs.
|
||||
fieldLocs.push_back(op.getLoc());
|
||||
fieldValues.push_back(mapping.lookup(propAssign.getSrc()));
|
||||
isField = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isField)
|
||||
// Clone the op over to the OM Class.
|
||||
builder.clone(op, mapping);
|
||||
|
||||
// In case this is a Module, remember to erase this op, unless it is an
|
||||
// instance. Instances are handled later in updateInstances.
|
||||
|
@ -1117,28 +1192,16 @@ void LowerClassesPass::lowerClass(om::ClassOp classOp, FModuleLike moduleLike,
|
|||
opsToErase.push_back(&op);
|
||||
}
|
||||
|
||||
// Convert any output property assignments to Field ops.
|
||||
for (auto op : llvm::make_early_inc_range(classOp.getOps<PropAssignOp>())) {
|
||||
// Property assignments will currently be pointing back to the original
|
||||
// FIRRTL Class for output ports.
|
||||
auto outputPort = dyn_cast<BlockArgument>(op.getDest());
|
||||
if (!outputPort)
|
||||
continue;
|
||||
|
||||
// Get the original port name, create a Field, and erase the propassign.
|
||||
auto name = moduleLike.getPortName(outputPort.getArgNumber());
|
||||
builder.create<ClassFieldOp>(op.getLoc(), name, op.getSrc());
|
||||
op.erase();
|
||||
}
|
||||
|
||||
// If there is a 'containingModule', add an argument for 'ports', and a field.
|
||||
if (hasContainingModule) {
|
||||
BlockArgument argumentValue = classBody->addArgument(
|
||||
getRtlPortsType(&getContext()), UnknownLoc::get(&getContext()));
|
||||
builder.create<ClassFieldOp>(argumentValue.getLoc(), kPortsName,
|
||||
argumentValue);
|
||||
fieldLocs.push_back(argumentValue.getLoc());
|
||||
fieldValues.push_back(argumentValue);
|
||||
}
|
||||
|
||||
classOp.addFields(builder, fieldLocs, fieldValues);
|
||||
|
||||
// If the module-like is a Class, it will be completely erased later.
|
||||
// Otherwise, erase just the property ports and ops.
|
||||
if (!isa<firrtl::ClassLike>(moduleLike.getOperation())) {
|
||||
|
@ -1158,7 +1221,6 @@ void LowerClassesPass::lowerClassExtern(ClassExternOp classExternOp,
|
|||
// Add a class.extern.field op for each output.
|
||||
BitVector portsToErase(moduleLike.getNumPorts());
|
||||
Block *classBody = &classExternOp.getRegion().emplaceBlock();
|
||||
OpBuilder builder = OpBuilder::atBlockBegin(classBody);
|
||||
|
||||
// Every class gets a base path as its first parameter.
|
||||
classBody->addArgument(BasePathType::get(&getContext()),
|
||||
|
@ -1173,10 +1235,6 @@ void LowerClassesPass::lowerClassExtern(ClassExternOp classExternOp,
|
|||
auto direction = moduleLike.getPortDirection(i);
|
||||
if (direction == Direction::In)
|
||||
classBody->addArgument(type, loc);
|
||||
else {
|
||||
auto name = moduleLike.getPortNameAttr(i);
|
||||
builder.create<om::ClassExternFieldOp>(loc, name, type);
|
||||
}
|
||||
|
||||
// In case this is a Module, remember to erase this port.
|
||||
portsToErase.set(i);
|
||||
|
@ -1856,30 +1914,13 @@ struct ObjectSubfieldOpConversion
|
|||
const DenseMap<StringAttr, firrtl::ClassType> &classTypeTable;
|
||||
};
|
||||
|
||||
struct ClassFieldOpConversion : public OpConversionPattern<ClassFieldOp> {
|
||||
struct ClassFieldsOpConversion : public OpConversionPattern<ClassFieldsOp> {
|
||||
using OpConversionPattern::OpConversionPattern;
|
||||
|
||||
LogicalResult
|
||||
matchAndRewrite(ClassFieldOp op, OpAdaptor adaptor,
|
||||
matchAndRewrite(ClassFieldsOp op, OpAdaptor adaptor,
|
||||
ConversionPatternRewriter &rewriter) const override {
|
||||
rewriter.replaceOpWithNewOp<ClassFieldOp>(op, adaptor.getNameAttr(),
|
||||
adaptor.getValue());
|
||||
return success();
|
||||
}
|
||||
};
|
||||
|
||||
struct ClassExternFieldOpConversion
|
||||
: public OpConversionPattern<ClassExternFieldOp> {
|
||||
using OpConversionPattern::OpConversionPattern;
|
||||
|
||||
LogicalResult
|
||||
matchAndRewrite(ClassExternFieldOp op, OpAdaptor adaptor,
|
||||
ConversionPatternRewriter &rewriter) const override {
|
||||
auto type = typeConverter->convertType(adaptor.getType());
|
||||
if (!type)
|
||||
return failure();
|
||||
rewriter.replaceOpWithNewOp<ClassExternFieldOp>(op, adaptor.getNameAttr(),
|
||||
type);
|
||||
rewriter.replaceOpWithNewOp<ClassFieldsOp>(op, adaptor.getOperands());
|
||||
return success();
|
||||
}
|
||||
};
|
||||
|
@ -1899,28 +1940,41 @@ struct ObjectOpConversion : public OpConversionPattern<om::ObjectOp> {
|
|||
}
|
||||
};
|
||||
|
||||
static LogicalResult convertClassLike(om::ClassLike classOp,
|
||||
TypeConverter typeConverter,
|
||||
ConversionPatternRewriter &rewriter) {
|
||||
Block *body = classOp.getBodyBlock();
|
||||
TypeConverter::SignatureConversion result(body->getNumArguments());
|
||||
|
||||
// Convert block argument types.
|
||||
if (failed(
|
||||
typeConverter.convertSignatureArgs(body->getArgumentTypes(), result)))
|
||||
return failure();
|
||||
|
||||
// Convert the body.
|
||||
if (failed(rewriter.convertRegionTypes(body->getParent(), typeConverter,
|
||||
&result)))
|
||||
return failure();
|
||||
|
||||
rewriter.modifyOpInPlace(classOp, [&]() {
|
||||
mlir::AttrTypeReplacer replacer;
|
||||
replacer.addReplacement([&](TypeAttr typeAttr) {
|
||||
return mlir::TypeAttr::get(
|
||||
typeConverter.convertType(typeAttr.getValue()));
|
||||
});
|
||||
classOp.replaceFieldTypes(replacer);
|
||||
});
|
||||
|
||||
return success();
|
||||
}
|
||||
|
||||
struct ClassOpSignatureConversion : public OpConversionPattern<om::ClassOp> {
|
||||
using OpConversionPattern::OpConversionPattern;
|
||||
|
||||
LogicalResult
|
||||
matchAndRewrite(om::ClassOp classOp, OpAdaptor adaptor,
|
||||
ConversionPatternRewriter &rewriter) const override {
|
||||
Block *body = classOp.getBodyBlock();
|
||||
TypeConverter::SignatureConversion result(body->getNumArguments());
|
||||
|
||||
// Convert block argument types.
|
||||
if (failed(typeConverter->convertSignatureArgs(body->getArgumentTypes(),
|
||||
result)))
|
||||
return failure();
|
||||
|
||||
// Convert the body.
|
||||
if (failed(rewriter.convertRegionTypes(body->getParent(), *typeConverter,
|
||||
&result)))
|
||||
return failure();
|
||||
|
||||
rewriter.modifyOpInPlace(classOp, []() {});
|
||||
|
||||
return success();
|
||||
return convertClassLike(classOp, *typeConverter, rewriter);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1931,22 +1985,7 @@ struct ClassExternOpSignatureConversion
|
|||
LogicalResult
|
||||
matchAndRewrite(om::ClassExternOp classOp, OpAdaptor adaptor,
|
||||
ConversionPatternRewriter &rewriter) const override {
|
||||
Block *body = classOp.getBodyBlock();
|
||||
TypeConverter::SignatureConversion result(body->getNumArguments());
|
||||
|
||||
// Convert block argument types.
|
||||
if (failed(typeConverter->convertSignatureArgs(body->getArgumentTypes(),
|
||||
result)))
|
||||
return failure();
|
||||
|
||||
// Convert the body.
|
||||
if (failed(rewriter.convertRegionTypes(body->getParent(), *typeConverter,
|
||||
&result)))
|
||||
return failure();
|
||||
|
||||
rewriter.modifyOpInPlace(classOp, []() {});
|
||||
|
||||
return success();
|
||||
return convertClassLike(classOp, *typeConverter, rewriter);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1997,17 +2036,19 @@ static void populateConversionTarget(ConversionTarget &target) {
|
|||
return noFIRRTLOperands && noFIRRTLResults;
|
||||
});
|
||||
|
||||
// the OM op class.extern.field doesn't have operands or results, so we must
|
||||
// check it's type for a firrtl dialect.
|
||||
target.addDynamicallyLegalOp<ClassExternFieldOp>(
|
||||
[](ClassExternFieldOp op) { return !isa<FIRRTLType>(op.getType()); });
|
||||
|
||||
// OM Class ops are legal if they don't use FIRRTL types for block arguments.
|
||||
target.addDynamicallyLegalOp<om::ClassOp, om::ClassExternOp>(
|
||||
[](Operation *op) -> std::optional<bool> {
|
||||
auto classLike = dyn_cast<om::ClassLike>(op);
|
||||
if (!classLike)
|
||||
return std::nullopt;
|
||||
auto fieldNames = classLike.getFieldNames();
|
||||
if (!llvm::all_of(fieldNames, [&](auto field) {
|
||||
std::optional<Type> type =
|
||||
classLike.getFieldType(cast<StringAttr>(field));
|
||||
return type.has_value() && !isa<FIRRTLType>(type.value());
|
||||
}))
|
||||
return false;
|
||||
|
||||
return llvm::none_of(
|
||||
classLike.getBodyBlock()->getArgumentTypes(),
|
||||
|
@ -2115,8 +2156,7 @@ static void populateRewritePatterns(
|
|||
patterns.add<AnyCastOpConversion>(converter, patterns.getContext());
|
||||
patterns.add<ObjectSubfieldOpConversion>(converter, patterns.getContext(),
|
||||
classTypeTable);
|
||||
patterns.add<ClassFieldOpConversion>(converter, patterns.getContext());
|
||||
patterns.add<ClassExternFieldOpConversion>(converter, patterns.getContext());
|
||||
patterns.add<ClassFieldsOpConversion>(converter, patterns.getContext());
|
||||
patterns.add<ClassOpSignatureConversion>(converter, patterns.getContext());
|
||||
patterns.add<ClassExternOpSignatureConversion>(converter,
|
||||
patterns.getContext());
|
||||
|
|
|
@ -257,15 +257,18 @@ circt::om::Evaluator::evaluateObjectInstance(StringAttr className,
|
|||
worklist.push({result, actualParams});
|
||||
}
|
||||
|
||||
for (auto field : cls.getOps<ClassFieldOp>()) {
|
||||
StringAttr name = field.getNameAttr();
|
||||
Value value = field.getValue();
|
||||
auto fieldNames = cls.getFieldNames();
|
||||
auto operands = cls.getFieldsOp()->getOperands();
|
||||
for (size_t i = 0; i < fieldNames.size(); ++i) {
|
||||
auto name = fieldNames[i];
|
||||
auto value = operands[i];
|
||||
auto fieldLoc = cls.getFieldLocByIndex(i);
|
||||
FailureOr<evaluator::EvaluatorValuePtr> result =
|
||||
evaluateValue(value, actualParams, field.getLoc());
|
||||
evaluateValue(value, actualParams, fieldLoc);
|
||||
if (failed(result))
|
||||
return result;
|
||||
|
||||
fields[name] = result.value();
|
||||
fields[cast<StringAttr>(name)] = result.value();
|
||||
}
|
||||
|
||||
// If the there is an instance, we must update the object value.
|
||||
|
|
|
@ -77,6 +77,37 @@ static void printPathString(OpAsmPrinter &p, Operation *op, PathAttr path,
|
|||
//===----------------------------------------------------------------------===//
|
||||
// Shared definitions
|
||||
//===----------------------------------------------------------------------===//
|
||||
static ParseResult parseClassFieldsList(OpAsmParser &parser,
|
||||
SmallVectorImpl<Attribute> &fieldNames,
|
||||
SmallVectorImpl<Type> &fieldTypes) {
|
||||
|
||||
llvm::StringMap<SMLoc> nameLocMap;
|
||||
auto parseElt = [&]() -> ParseResult {
|
||||
// Parse the field name.
|
||||
std::string fieldName;
|
||||
if (parser.parseKeywordOrString(&fieldName))
|
||||
return failure();
|
||||
SMLoc currLoc = parser.getCurrentLocation();
|
||||
if (nameLocMap.count(fieldName)) {
|
||||
parser.emitError(currLoc, "field \"")
|
||||
<< fieldName << "\" is defined twice";
|
||||
parser.emitError(nameLocMap[fieldName]) << "previous definition is here";
|
||||
return failure();
|
||||
}
|
||||
nameLocMap[fieldName] = currLoc;
|
||||
fieldNames.push_back(StringAttr::get(parser.getContext(), fieldName));
|
||||
|
||||
// Parse the field type.
|
||||
fieldTypes.emplace_back();
|
||||
if (parser.parseColonType(fieldTypes.back()))
|
||||
return failure();
|
||||
|
||||
return success();
|
||||
};
|
||||
|
||||
return parser.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren,
|
||||
parseElt);
|
||||
}
|
||||
|
||||
static ParseResult parseClassLike(OpAsmParser &parser, OperationState &state) {
|
||||
// Parse the Class symbol name.
|
||||
|
@ -91,6 +122,23 @@ static ParseResult parseClassLike(OpAsmParser &parser, OperationState &state) {
|
|||
/*allowType=*/true, /*allowAttrs=*/false))
|
||||
return failure();
|
||||
|
||||
SmallVector<Type> fieldTypes;
|
||||
SmallVector<Attribute> fieldNames;
|
||||
if (succeeded(parser.parseOptionalArrow()))
|
||||
if (failed(parseClassFieldsList(parser, fieldNames, fieldTypes)))
|
||||
return failure();
|
||||
|
||||
SmallVector<NamedAttribute> fieldTypesMap;
|
||||
if (!fieldNames.empty()) {
|
||||
for (auto [name, type] : zip(fieldNames, fieldTypes))
|
||||
fieldTypesMap.push_back(
|
||||
NamedAttribute(cast<StringAttr>(name), TypeAttr::get(type)));
|
||||
}
|
||||
auto *ctx = parser.getContext();
|
||||
state.addAttribute("fieldNames", mlir::ArrayAttr::get(ctx, fieldNames));
|
||||
state.addAttribute("fieldTypes",
|
||||
mlir::DictionaryAttr::get(ctx, fieldTypesMap));
|
||||
|
||||
// Parse the optional attribute dictionary.
|
||||
if (failed(parser.parseOptionalAttrDictWithKeyword(state.attributes)))
|
||||
return failure();
|
||||
|
@ -134,9 +182,27 @@ static void printClassLike(ClassLike classLike, OpAsmPrinter &printer) {
|
|||
}
|
||||
printer << ") ";
|
||||
|
||||
ArrayRef<Attribute> fieldNames =
|
||||
cast<ArrayAttr>(classLike->getAttr("fieldNames")).getValue();
|
||||
|
||||
if (!fieldNames.empty()) {
|
||||
printer << " -> (";
|
||||
for (size_t i = 0, e = fieldNames.size(); i < e; ++i) {
|
||||
if (i != 0)
|
||||
printer << ", ";
|
||||
StringAttr name = cast<StringAttr>(fieldNames[i]);
|
||||
printer.printKeywordOrString(name.getValue());
|
||||
printer << ": ";
|
||||
Type type = classLike.getFieldType(name).value();
|
||||
printer.printType(type);
|
||||
}
|
||||
printer << ") ";
|
||||
}
|
||||
|
||||
// Print the optional attribute dictionary.
|
||||
SmallVector<StringRef> elidedAttrs{classLike.getSymNameAttrName(),
|
||||
classLike.getFormalParamNamesAttrName()};
|
||||
classLike.getFormalParamNamesAttrName(),
|
||||
"fieldTypes", "fieldNames"};
|
||||
printer.printOptionalAttrDictWithKeyword(classLike.getOperation()->getAttrs(),
|
||||
elidedAttrs);
|
||||
|
||||
|
@ -174,6 +240,32 @@ void getClassLikeAsmBlockArgumentNames(ClassLike classLike, Region ®ion,
|
|||
setNameFn(args[i], argNames[i]);
|
||||
}
|
||||
|
||||
NamedAttribute makeFieldType(StringAttr name, Type type) {
|
||||
return NamedAttribute(name, TypeAttr::get(type));
|
||||
}
|
||||
|
||||
NamedAttribute makeFieldIdx(MLIRContext *ctx, mlir::StringAttr name,
|
||||
unsigned i) {
|
||||
return NamedAttribute(StringAttr(name),
|
||||
mlir::IntegerAttr::get(mlir::IndexType::get(ctx), i));
|
||||
}
|
||||
|
||||
std::optional<Type> getClassLikeFieldType(ClassLike classLike,
|
||||
StringAttr name) {
|
||||
DictionaryAttr fieldTypes = mlir::cast<DictionaryAttr>(
|
||||
classLike.getOperation()->getAttr("fieldTypes"));
|
||||
Attribute type = fieldTypes.get(name);
|
||||
if (!type)
|
||||
return std::nullopt;
|
||||
return cast<TypeAttr>(type).getValue();
|
||||
}
|
||||
|
||||
void replaceClassLikeFieldTypes(ClassLike classLike,
|
||||
AttrTypeReplacer &replacer) {
|
||||
classLike->setAttr("fieldTypes", cast<DictionaryAttr>(replacer.replace(
|
||||
classLike.getFieldTypes())));
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ClassOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -183,37 +275,31 @@ ParseResult circt::om::ClassOp::parse(OpAsmParser &parser,
|
|||
return parseClassLike(parser, state);
|
||||
}
|
||||
|
||||
void circt::om::ClassOp::build(OpBuilder &odsBuilder, OperationState &odsState,
|
||||
Twine name,
|
||||
ArrayRef<StringRef> formalParamNames) {
|
||||
return build(odsBuilder, odsState, odsBuilder.getStringAttr(name),
|
||||
odsBuilder.getStrArrayAttr(formalParamNames));
|
||||
}
|
||||
|
||||
circt::om::ClassOp circt::om::ClassOp::buildSimpleClassOp(
|
||||
OpBuilder &odsBuilder, Location loc, Twine name,
|
||||
ArrayRef<StringRef> formalParamNames, ArrayRef<StringRef> fieldNames,
|
||||
ArrayRef<Type> fieldTypes) {
|
||||
circt::om::ClassOp classOp = odsBuilder.create<circt::om::ClassOp>(
|
||||
loc, odsBuilder.getStringAttr(name),
|
||||
odsBuilder.getStrArrayAttr(formalParamNames));
|
||||
odsBuilder.getStrArrayAttr(formalParamNames),
|
||||
odsBuilder.getStrArrayAttr(fieldNames),
|
||||
odsBuilder.getDictionaryAttr(llvm::map_to_vector(
|
||||
llvm::zip(fieldNames, fieldTypes), [&](auto field) -> NamedAttribute {
|
||||
return NamedAttribute(odsBuilder.getStringAttr(std::get<0>(field)),
|
||||
TypeAttr::get(std::get<1>(field)));
|
||||
})));
|
||||
Block *body = &classOp.getRegion().emplaceBlock();
|
||||
auto prevLoc = odsBuilder.saveInsertionPoint();
|
||||
odsBuilder.setInsertionPointToEnd(body);
|
||||
for (auto [name, type] : llvm::zip(fieldNames, fieldTypes))
|
||||
odsBuilder.create<circt::om::ClassFieldOp>(loc, name,
|
||||
body->addArgument(type, loc));
|
||||
odsBuilder.create<ClassFieldsOp>(
|
||||
loc, llvm::map_to_vector(fieldTypes, [&](Type type) -> Value {
|
||||
return body->addArgument(type, loc);
|
||||
}));
|
||||
odsBuilder.restoreInsertionPoint(prevLoc);
|
||||
|
||||
return classOp;
|
||||
}
|
||||
|
||||
void circt::om::ClassOp::build(OpBuilder &odsBuilder, OperationState &odsState,
|
||||
Twine name) {
|
||||
return build(odsBuilder, odsState, odsBuilder.getStringAttr(name),
|
||||
odsBuilder.getStrArrayAttr({}));
|
||||
}
|
||||
|
||||
void circt::om::ClassOp::print(OpAsmPrinter &printer) {
|
||||
printClassLike(*this, printer);
|
||||
}
|
||||
|
@ -225,11 +311,46 @@ void circt::om::ClassOp::getAsmBlockArgumentNames(
|
|||
getClassLikeAsmBlockArgumentNames(*this, region, setNameFn);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ClassFieldOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
std::optional<mlir::Type>
|
||||
circt::om::ClassOp::getFieldType(mlir::StringAttr field) {
|
||||
return getClassLikeFieldType(*this, field);
|
||||
}
|
||||
|
||||
Type circt::om::ClassFieldOp::getType() { return getValue().getType(); }
|
||||
void circt::om::ClassOp::replaceFieldTypes(AttrTypeReplacer replacer) {
|
||||
replaceClassLikeFieldTypes(*this, replacer);
|
||||
}
|
||||
|
||||
void circt::om::ClassOp::addFields(mlir::OpBuilder &builder,
|
||||
mlir::ArrayRef<Location> locs,
|
||||
mlir::ArrayRef<Value> values) {
|
||||
// Store the original locations as a metadata array so that unique locations
|
||||
// are preserved as a mapping from field index to location
|
||||
mlir::SmallVector<Attribute> locAttrs;
|
||||
for (auto loc : locs) {
|
||||
locAttrs.push_back(cast<Attribute>(LocationAttr(loc)));
|
||||
}
|
||||
// Also store the locations incase there's some other analysis that might
|
||||
// be able to use the default FusedLoc representation.
|
||||
builder.create<ClassFieldsOp>(
|
||||
builder.getFusedLoc(locs, builder.getArrayAttr(locAttrs)), values);
|
||||
}
|
||||
|
||||
mlir::Location circt::om::ClassOp::getFieldLocByIndex(size_t i) {
|
||||
Location loc = this->getFieldsOp()->getLoc();
|
||||
if (auto locs = dyn_cast<FusedLoc>(loc)) {
|
||||
// Because it's possible for a user to construct a fields op directly and
|
||||
// place a FusedLoc that doersn't follow the storage format of addFields, we
|
||||
// assert the information has been stored appropriately
|
||||
ArrayAttr metadataArr = dyn_cast<ArrayAttr>(locs.getMetadata());
|
||||
assert(metadataArr && "Expected fused loc to store metadata array");
|
||||
assert(i < metadataArr.size() &&
|
||||
"expected index to be less than array size");
|
||||
LocationAttr locAttr = dyn_cast<LocationAttr>(metadataArr[i]);
|
||||
assert(locAttr && "expected metadataArr entry to be location attribute");
|
||||
loc = Location(locAttr);
|
||||
}
|
||||
return loc;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ClassExternOp
|
||||
|
@ -240,19 +361,6 @@ ParseResult circt::om::ClassExternOp::parse(OpAsmParser &parser,
|
|||
return parseClassLike(parser, state);
|
||||
}
|
||||
|
||||
void circt::om::ClassExternOp::build(OpBuilder &odsBuilder,
|
||||
OperationState &odsState, Twine name) {
|
||||
return build(odsBuilder, odsState, odsBuilder.getStringAttr(name),
|
||||
odsBuilder.getStrArrayAttr({}));
|
||||
}
|
||||
|
||||
void circt::om::ClassExternOp::build(OpBuilder &odsBuilder,
|
||||
OperationState &odsState, Twine name,
|
||||
ArrayRef<StringRef> formalParamNames) {
|
||||
return build(odsBuilder, odsState, odsBuilder.getStringAttr(name),
|
||||
odsBuilder.getStrArrayAttr(formalParamNames));
|
||||
}
|
||||
|
||||
void circt::om::ClassExternOp::print(OpAsmPrinter &printer) {
|
||||
printClassLike(*this, printer);
|
||||
}
|
||||
|
@ -261,11 +369,10 @@ LogicalResult circt::om::ClassExternOp::verify() {
|
|||
if (failed(verifyClassLike(*this))) {
|
||||
return failure();
|
||||
}
|
||||
|
||||
// Verify that only external class field declarations are present in the body.
|
||||
for (auto &op : getOps())
|
||||
if (!isa<ClassExternFieldOp>(op))
|
||||
return op.emitOpError("not allowed in external class");
|
||||
// Verify body is empty
|
||||
if (!this->getBodyBlock()->getOperations().empty()) {
|
||||
return this->emitOpError("external class body should be empty");
|
||||
}
|
||||
|
||||
return success();
|
||||
}
|
||||
|
@ -275,6 +382,15 @@ void circt::om::ClassExternOp::getAsmBlockArgumentNames(
|
|||
getClassLikeAsmBlockArgumentNames(*this, region, setNameFn);
|
||||
}
|
||||
|
||||
std::optional<mlir::Type>
|
||||
circt::om::ClassExternOp::getFieldType(mlir::StringAttr field) {
|
||||
return getClassLikeFieldType(*this, field);
|
||||
}
|
||||
|
||||
void circt::om::ClassExternOp::replaceFieldTypes(AttrTypeReplacer replacer) {
|
||||
replaceClassLikeFieldTypes(*this, replacer);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ObjectOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -90,8 +90,7 @@ static bool hasPathType(Type type) {
|
|||
return isPathType;
|
||||
}
|
||||
|
||||
// Convert potentially nested lists of PathType or BasePathType to frozen lists.
|
||||
static Type processType(Type type) {
|
||||
mlir::AttrTypeReplacer makeReplacer() {
|
||||
mlir::AttrTypeReplacer replacer;
|
||||
replacer.addReplacement([](BasePathType innerType) {
|
||||
return FrozenBasePathType::get(innerType.getContext());
|
||||
|
@ -99,7 +98,12 @@ static Type processType(Type type) {
|
|||
replacer.addReplacement([](PathType innerType) {
|
||||
return FrozenPathType::get(innerType.getContext());
|
||||
});
|
||||
return replacer;
|
||||
}
|
||||
|
||||
// Convert potentially nested lists of PathType or BasePathType to frozen lists.
|
||||
static Type processType(Type type) {
|
||||
mlir::AttrTypeReplacer replacer = makeReplacer();
|
||||
return replacer.replace(type);
|
||||
}
|
||||
|
||||
|
@ -323,6 +327,9 @@ LogicalResult PathVisitor::run(ModuleOp module) {
|
|||
});
|
||||
if (result.wasInterrupted())
|
||||
return failure();
|
||||
|
||||
// Transform field types
|
||||
classLike.replaceFieldTypes(makeReplacer());
|
||||
}
|
||||
return success();
|
||||
}
|
||||
|
|
|
@ -98,6 +98,7 @@ void ModuleInfo::postProcess(const SymMappingTy &symMapping) {
|
|||
auto it = symMapping.find({module, classOp.getNameAttr()});
|
||||
if (it != symMapping.end())
|
||||
classOp.setSymNameAttr(it->second);
|
||||
classOp.replaceFieldTypes(replacer);
|
||||
} else if (auto objectOp = dyn_cast<ObjectOp>(op)) {
|
||||
// Update its class name if changed..
|
||||
auto it = symMapping.find({module, objectOp.getClassNameAttr()});
|
||||
|
@ -170,10 +171,6 @@ static FailureOr<bool> resolveClasses(StringAttr name,
|
|||
return diag;
|
||||
};
|
||||
|
||||
llvm::MapVector<StringAttr, Type> classFields;
|
||||
for (auto fieldOp : classOp.getOps<om::ClassFieldOp>())
|
||||
classFields.insert({fieldOp.getNameAttr(), fieldOp.getType()});
|
||||
|
||||
for (auto op : classes) {
|
||||
if (op == classOp)
|
||||
continue;
|
||||
|
@ -193,25 +190,32 @@ static FailureOr<bool> resolveClasses(StringAttr name,
|
|||
}
|
||||
// Check declared fields.
|
||||
llvm::DenseSet<StringAttr> declaredFields;
|
||||
for (auto fieldOp : op.getBodyBlock()->getOps<om::ClassExternFieldOp>()) {
|
||||
auto it = classFields.find(fieldOp.getNameAttr());
|
||||
|
||||
for (auto nameAttr : op.getFieldNames()) {
|
||||
StringAttr name = cast<StringAttr>(nameAttr);
|
||||
std::optional<Type> opTypeOpt = op.getFieldType(name);
|
||||
|
||||
if (!opTypeOpt.has_value())
|
||||
return emitError(op) << " no type for field " << name;
|
||||
Type opType = opTypeOpt.value();
|
||||
|
||||
std::optional<Type> classTypeOpt = classOp.getFieldType(name);
|
||||
|
||||
// Field not found in its definition.
|
||||
if (it == classFields.end())
|
||||
return emitError(op)
|
||||
<< "declaration has a field " << fieldOp.getNameAttr()
|
||||
<< " but not found in its definition";
|
||||
if (!classTypeOpt.has_value())
|
||||
return emitError(op) << "declaration has a field " << name
|
||||
<< " but not found in its definition";
|
||||
Type classType = classTypeOpt.value();
|
||||
|
||||
if (it->second != fieldOp.getType())
|
||||
if (classType != opType)
|
||||
return emitError(op)
|
||||
<< "declaration has a field " << fieldOp.getNameAttr()
|
||||
<< " but types don't match, " << it->second << " vs "
|
||||
<< fieldOp.getType();
|
||||
declaredFields.insert(fieldOp.getNameAttr());
|
||||
<< "declaration has a field " << name
|
||||
<< " but types don't match, " << classType << " vs " << opType;
|
||||
declaredFields.insert(name);
|
||||
}
|
||||
|
||||
for (auto [fieldName, _] : classFields)
|
||||
if (!declaredFields.count(fieldName))
|
||||
for (auto fieldName : classOp.getFieldNames())
|
||||
if (!declaredFields.count(cast<StringAttr>(fieldName)))
|
||||
return emitError(op) << "definition has a field " << fieldName
|
||||
<< " but not found in this declaration";
|
||||
}
|
||||
|
|
|
@ -49,36 +49,10 @@ void VerifyObjectFieldsPass::runOnOperation() {
|
|||
"op must have a single region and symbol table trait");
|
||||
auto &symbolTable = getAnalysis<SymbolTable>();
|
||||
|
||||
/// A map from a class and field name to a field.
|
||||
llvm::MapVector<ClassLike, llvm::DenseMap<StringAttr, ClassFieldLike>> tables;
|
||||
for (auto op : module->getRegion(0).getOps<om::ClassLike>())
|
||||
tables.insert({op, llvm::DenseMap<StringAttr, ClassFieldLike>()});
|
||||
|
||||
// Peel tables parallelly.
|
||||
if (failed(
|
||||
mlir::failableParallelForEach(&getContext(), tables, [](auto &entry) {
|
||||
ClassLike classLike = entry.first;
|
||||
auto &table = entry.second;
|
||||
auto result = classLike.walk([&](ClassFieldLike fieldLike)
|
||||
-> WalkResult {
|
||||
if (table.insert({fieldLike.getNameAttr(), fieldLike}).second)
|
||||
return WalkResult::advance();
|
||||
|
||||
auto emit = fieldLike.emitOpError()
|
||||
<< "field " << fieldLike.getNameAttr()
|
||||
<< " is defined twice";
|
||||
emit.attachNote(table.lookup(fieldLike.getNameAttr()).getLoc())
|
||||
<< "previous definition is here";
|
||||
return WalkResult::interrupt();
|
||||
});
|
||||
return LogicalResult::failure(result.wasInterrupted());
|
||||
})))
|
||||
return signalPassFailure();
|
||||
|
||||
// Run actual verification. Make sure not to mutate `tables`.
|
||||
auto result = mlir::failableParallelForEach(
|
||||
&getContext(), tables, [&tables, &symbolTable](const auto &entry) {
|
||||
ClassLike classLike = entry.first;
|
||||
&getContext(), module->getRegion(0).getOps<om::ClassLike>(),
|
||||
[&symbolTable](ClassLike classLike) {
|
||||
auto result =
|
||||
classLike.walk([&](ObjectFieldOp objectField) -> WalkResult {
|
||||
auto objectInstType =
|
||||
|
@ -94,40 +68,39 @@ void VerifyObjectFieldsPass::runOnOperation() {
|
|||
}
|
||||
|
||||
// Traverse the field path, verifying each field exists.
|
||||
ClassFieldLike finalField;
|
||||
Type finalFieldType;
|
||||
auto fields = SmallVector<FlatSymbolRefAttr>(
|
||||
objectField.getFieldPath().getAsRange<FlatSymbolRefAttr>());
|
||||
for (size_t i = 0, e = fields.size(); i < e; ++i) {
|
||||
// Verify the field exists on the ClassOp.
|
||||
auto field = fields[i];
|
||||
ClassFieldLike fieldDef;
|
||||
auto *it = tables.find(classDef);
|
||||
assert(it != tables.end() && "must be visited");
|
||||
fieldDef = it->second.lookup(field.getAttr());
|
||||
std::optional<Type> fieldTypeOpt =
|
||||
classDef.getFieldType(field.getAttr());
|
||||
|
||||
if (!fieldDef) {
|
||||
if (!fieldTypeOpt.has_value()) {
|
||||
auto error =
|
||||
objectField.emitOpError("referenced non-existent field ")
|
||||
<< field;
|
||||
error.attachNote(classDef.getLoc()) << "class defined here";
|
||||
return WalkResult::interrupt();
|
||||
}
|
||||
Type fieldType = fieldTypeOpt.value();
|
||||
|
||||
// If there are more fields, verify the current field is of
|
||||
// ClassType, and look up the ClassOp for that field.
|
||||
if (i < e - 1) {
|
||||
auto classType = dyn_cast<ClassType>(fieldDef.getType());
|
||||
auto classType = dyn_cast<ClassType>(fieldType);
|
||||
if (!classType) {
|
||||
objectField.emitOpError("nested field access into ")
|
||||
<< field << " requires a ClassType, but found "
|
||||
<< fieldDef.getType();
|
||||
<< fieldType;
|
||||
return WalkResult::interrupt();
|
||||
}
|
||||
|
||||
// Check if the nested ClassOp exists. ObjectInstOp verifier
|
||||
// already checked the class exits but it's not verified yet
|
||||
// if the object is an input argument.
|
||||
classDef = symbolTable.lookupNearestSymbolFrom<ClassLike>(
|
||||
classDef = symbolTable.lookupNearestSymbolFrom<ClassOp>(
|
||||
objectField, classType.getClassName());
|
||||
|
||||
if (!classDef) {
|
||||
|
@ -143,14 +116,14 @@ void VerifyObjectFieldsPass::runOnOperation() {
|
|||
|
||||
// On the last iteration down the path, save the final field
|
||||
// being accessed.
|
||||
finalField = fieldDef;
|
||||
finalFieldType = fieldType;
|
||||
}
|
||||
|
||||
// Verify the accessed field type matches the result type.
|
||||
if (finalField.getType() != objectField.getResult().getType()) {
|
||||
if (finalFieldType != objectField.getResult().getType()) {
|
||||
objectField.emitOpError("expected type ")
|
||||
<< objectField.getResult().getType()
|
||||
<< ", but accessed field has type " << finalField.getType();
|
||||
<< ", but accessed field has type " << finalFieldType;
|
||||
|
||||
return WalkResult::interrupt();
|
||||
}
|
||||
|
|
|
@ -20,19 +20,19 @@
|
|||
void testEvaluator(MlirContext ctx) {
|
||||
const char *testIR =
|
||||
"module {"
|
||||
" om.class @Test(%param: !om.integer) {"
|
||||
" om.class.field @field, %param : !om.integer"
|
||||
" om.class @Test(%param: !om.integer) -> (field: !om.integer, child: "
|
||||
"!om.class.type<@Child>) {"
|
||||
" %0 = om.object @Child() : () -> !om.class.type<@Child>"
|
||||
" om.class.field @child, %0 : !om.class.type<@Child>"
|
||||
" om.class.fields %param, %0 : !om.integer, !om.class.type<@Child>"
|
||||
" }"
|
||||
" om.class @Child() {"
|
||||
" om.class @Child() -> (foo: i64, bar: !om.list<i64>, baz: "
|
||||
"tuple<!om.list<i64>, i64>){"
|
||||
" %0 = om.constant 14 : i64"
|
||||
" %1 = om.constant 15 : i64"
|
||||
" %2 = om.list_create %0, %1 : i64"
|
||||
" %3 = om.tuple_create %2, %0 : !om.list<i64>, i64"
|
||||
" om.class.field @foo, %0 : i64"
|
||||
" om.class.field @bar, %2 : !om.list<i64>"
|
||||
" om.class.field @baz, %3 : tuple<!om.list<i64>, i64>"
|
||||
" om.class.fields %0, %2, %3 : i64, !om.list<i64>, "
|
||||
"tuple<!om.list<i64>, i64>"
|
||||
" }"
|
||||
"}";
|
||||
|
||||
|
|
|
@ -135,35 +135,23 @@ circuit TestHarness:
|
|||
; SITEST_NODUT: FILE "testbench.sitest.json"
|
||||
; SITEST_NODUT-NOT: FILE
|
||||
|
||||
; MLIR_OUT: om.class @SitestBlackBoxModulesSchema(%basepath: !om.basepath, %moduleName_in: !om.string) {
|
||||
; MLIR_OUT: om.class.field @moduleName, %moduleName_in : !om.string
|
||||
; MLIR_OUT: om.class @SitestBlackBoxModulesSchema(%basepath: !om.basepath, %moduleName_in: !om.string) -> (moduleName: !om.string) {
|
||||
; MLIR_OUT: om.class.fields %moduleName_in : !om.string
|
||||
; MLIR_OUT: }
|
||||
|
||||
; MLIR_OUT: om.class @SitestBlackBoxMetadata(%basepath: !om.basepath)
|
||||
; MLIR_OUT: om.class @SitestBlackBoxMetadata(%basepath: !om.basepath) -> [[V1:.+]]: !om.class.type<@SitestBlackBoxModulesSchema>, [[V2:.+]]: !om.class.type<@SitestBlackBoxModulesSchema>, [[V3:.+]]: !om.class.type<@SitestBlackBoxModulesSchema>
|
||||
; MLIR_OUT: %0 = om.constant "Foo_BlackBox" : !om.string
|
||||
; MLIR_OUT: %1 = om.object @SitestBlackBoxModulesSchema(%basepath, %0) : (!om.basepath, !om.string) -> !om.class.type<@SitestBlackBoxModulesSchema>
|
||||
; MLIR_OUT: %2 = om.constant "Bar_BlackBox" : !om.string
|
||||
; MLIR_OUT: %3 = om.object @SitestBlackBoxModulesSchema(%basepath, %2) : (!om.basepath, !om.string) -> !om.class.type<@SitestBlackBoxModulesSchema>
|
||||
; MLIR_OUT: %4 = om.constant "Baz_BlackBox" : !om.string
|
||||
; MLIR_OUT: %5 = om.object @SitestBlackBoxModulesSchema(%basepath, %4) : (!om.basepath, !om.string) -> !om.class.type<@SitestBlackBoxModulesSchema>
|
||||
; MLIR_OUT: om.class.field @[[V1:.+]], %1 : !om.class.type<@SitestBlackBoxModulesSchema>
|
||||
; MLIR_OUT: om.class.field @[[V2:.+]], %3 : !om.class.type<@SitestBlackBoxModulesSchema>
|
||||
; MLIR_OUT: om.class.field @[[V3:.+]], %5 : !om.class.type<@SitestBlackBoxModulesSchema>
|
||||
; MLIR_OUT: om.class.fields %1, %3, %5 : !om.class.type<@SitestBlackBoxModulesSchema>, !om.class.type<@SitestBlackBoxModulesSchema>, !om.class.type<@SitestBlackBoxModulesSchema>
|
||||
; MLIR_OUT: }
|
||||
|
||||
; MLIR_OUT: om.class @MemorySchema(%basepath: !om.basepath, %name_in: !om.string, %depth_in: !om.integer, %width_in: !om.integer, %maskBits_in: !om.integer, %readPorts_in: !om.integer, %writePorts_in: !om.integer, %readwritePorts_in: !om.integer, %writeLatency_in: !om.integer, %readLatency_in: !om.integer, %hierarchy_in: !om.list<!om.path>, %inDut_in: i1, %extraPorts_in: !om.list<!om.class.type<@ExtraPortsMemorySchema>>
|
||||
; MLIR_OUT: om.class.field @name, %name_in : !om.string
|
||||
; MLIR_OUT: om.class.field @depth, %depth_in : !om.integer
|
||||
; MLIR_OUT: om.class.field @width, %width_in : !om.integer
|
||||
; MLIR_OUT: om.class.field @maskBits, %maskBits_in : !om.integer
|
||||
; MLIR_OUT: om.class.field @readPorts, %readPorts_in : !om.integer
|
||||
; MLIR_OUT: om.class.field @writePorts, %writePorts_in : !om.integer
|
||||
; MLIR_OUT: om.class.field @readwritePorts, %readwritePorts_in : !om.integer
|
||||
; MLIR_OUT: om.class.field @writeLatency, %writeLatency_in : !om.integer
|
||||
; MLIR_OUT: om.class.field @readLatency, %readLatency_in : !om.integer
|
||||
; MLIR_OUT: om.class.field @hierarchy, %hierarchy_in : !om.list<!om.path>
|
||||
; MLIR_OUT: om.class.field @extraPorts, %extraPorts_in : !om.list<!om.class.type<@ExtraPortsMemorySchema>>
|
||||
; MLIR_OUT: om.class @MemoryMetadata(%basepath: !om.basepath)
|
||||
; MLIR_OUT: om.class @MemorySchema(%basepath: !om.basepath, %name_in: !om.string, %depth_in: !om.integer, %width_in: !om.integer, %maskBits_in: !om.integer, %readPorts_in: !om.integer, %writePorts_in: !om.integer, %readwritePorts_in: !om.integer, %writeLatency_in: !om.integer, %readLatency_in: !om.integer, %hierarchy_in: !om.list<!om.path>, %inDut_in: i1, %extraPorts_in: !om.list<!om.class.type<@ExtraPortsMemorySchema>>, %preExtInstName_in: !om.list<!om.string>) -> (name: !om.string, depth: !om.integer, width: !om.integer, maskBits: !om.integer, readPorts: !om.integer, writePorts: !om.integer, readwritePorts: !om.integer, writeLatency: !om.integer, readLatency: !om.integer, hierarchy: !om.list<!om.path>, inDut: i1, extraPorts: !om.list<!om.class.type<@ExtraPortsMemorySchema>>, preExtInstName: !om.list<!om.string>)
|
||||
; MLIR_OUT: om.class.fields %name_in, %depth_in, %width_in, %maskBits_in, %readPorts_in, %writePorts_in, %readwritePorts_in, %writeLatency_in, %readLatency_in, %hierarchy_in, %inDut_in, %extraPorts_in, %preExtInstName_in : !om.string, !om.integer, !om.integer, !om.integer, !om.integer, !om.integer, !om.integer, !om.integer, !om.integer, !om.list<!om.path>, i1, !om.list<!om.class.type<@ExtraPortsMemorySchema>>, !om.list<!om.string>
|
||||
; MLIR_OUT: om.class @MemoryMetadata(%basepath: !om.basepath) -> (foo_m_ext_field: !om.class.type<@MemorySchema>, bar_m_ext_field: !om.class.type<@MemorySchema>, baz_m_ext_field: !om.class.type<@MemorySchema>)
|
||||
; MLIR_OUT: om.path_create instance %basepath @memNLA
|
||||
; MLIR_OUT: om.list_create
|
||||
; MLIR_OUT: om.object @MemorySchema
|
||||
|
@ -201,9 +189,7 @@ circuit TestHarness:
|
|||
; MLIR_OUT: om.constant #om.integer<0 : ui32> : !om.integer
|
||||
; MLIR_OUT: om.constant #om.integer<1 : ui32> : !om.integer
|
||||
; MLIR_OUT: om.constant #om.integer<1 : ui32> : !om.integer
|
||||
; MLIR_OUT: om.class.field @foo_m_ext_field
|
||||
; MLIR_OUT: om.class.field @bar_m_ext_field
|
||||
; MLIR_OUT: om.class.field @baz_m_ext_field
|
||||
; MLIR_OUT: om.class.fields %4, %20, %38 : !om.class.type<@MemorySchema>, !om.class.type<@MemorySchema>, !om.class.type<@MemorySchema>
|
||||
|
||||
; SITEST_NODUT: FILE "design.sitest.json"
|
||||
; SITEST_NODUT-NOT: FILE
|
||||
|
|
|
@ -3,33 +3,35 @@
|
|||
firrtl.circuit "Component" {
|
||||
// CHECK-LABEL: om.class @Class_0
|
||||
// CHECK-SAME: %[[REF1:[^ ]+]]: !om.class.type<@Class_1>
|
||||
// CHECK-SAME: -> (someReference: !om.class.type<@Class_1>)
|
||||
firrtl.class private @Class_0(in %someReference_in: !firrtl.class<@Class_1(out someInt: !firrtl.integer)>, out %someReference: !firrtl.class<@Class_1(out someInt: !firrtl.integer)>) {
|
||||
// CHECK: om.class.field @someReference, %[[REF1]]
|
||||
// CHECK: om.class.fields %[[REF1]] : !om.class.type<@Class_1>
|
||||
firrtl.propassign %someReference, %someReference_in : !firrtl.class<@Class_1(out someInt: !firrtl.integer)>
|
||||
}
|
||||
|
||||
// CHECK-LABEL: om.class @Class_1
|
||||
// CHECK-SAME: -> (someInt: !om.integer)
|
||||
firrtl.class private @Class_1(out %someInt: !firrtl.integer) {
|
||||
// CHECK: %[[C1:.+]] = om.constant #om.integer<1 : si4> : !om.integer
|
||||
%0 = firrtl.integer 1
|
||||
// CHECK: om.class.field @someInt, %[[C1]]
|
||||
// CHECK: om.class.fields %[[C1]] : !om.integer
|
||||
firrtl.propassign %someInt, %0 : !firrtl.integer
|
||||
}
|
||||
|
||||
// CHECK-LABEL: om.class @Class_2
|
||||
// CHECK-SAME: -> (someString: !om.string)
|
||||
firrtl.class private @Class_2(out %someString: !firrtl.string) {
|
||||
// CHECK: %[[C2:.+]] = om.constant "fubar" : !om.string
|
||||
%0 = firrtl.string "fubar"
|
||||
// CHECK: om.class.field @someString, %[[C2]]
|
||||
// CHECK: om.class.fields %[[C2]] : !om.string
|
||||
firrtl.propassign %someString, %0 : !firrtl.string
|
||||
}
|
||||
|
||||
// CHECK-LABEL: om.class.extern @ExtClass(%basepath: !om.basepath, %input: !om.string) {
|
||||
// CHECK-NEXT: om.class.extern.field @field : !om.string
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-LABEL: om.class.extern @ExtClass(%basepath: !om.basepath, %input: !om.string) -> (field: !om.string)
|
||||
firrtl.extclass private @ExtClass(in input: !firrtl.string, out field: !firrtl.string)
|
||||
|
||||
// CHECK-LABEL: om.class @ClassEntrypoint
|
||||
// CHECK-SAME: -> (obj_0_out: !om.class.type<@Class_1>)
|
||||
firrtl.class private @ClassEntrypoint(out %obj_0_out: !firrtl.class<@Class_1(out someInt: !firrtl.integer)>) {
|
||||
// CHECK: %[[OBJ1:.+]] = om.object @Class_1(%basepath) : (!om.basepath) -> !om.class.type<@Class_1>
|
||||
%obj1 = firrtl.object @Class_1(out someInt: !firrtl.integer)
|
||||
|
@ -40,16 +42,17 @@ firrtl.circuit "Component" {
|
|||
firrtl.propassign %obj0_someReference_in, %obj1 : !firrtl.class<@Class_1(out someInt: !firrtl.integer)>
|
||||
|
||||
// CHECK: %[[REF:.+]] = om.object.field %[[OBJ0]], [@someReference] : (!om.class.type<@Class_0>) -> !om.class.type<@Class_1>
|
||||
// CHECK: om.class.field @obj_0_out, %[[REF]] : !om.class.type<@Class_1>
|
||||
// CHECK: om.class.fields %[[REF]] : !om.class.type<@Class_1>
|
||||
%obj0_someReference = firrtl.object.subfield %obj0[someReference] : !firrtl.class<@Class_0(in someReference_in: !firrtl.class<@Class_1(out someInt: !firrtl.integer)>, out someReference: !firrtl.class<@Class_1(out someInt: !firrtl.integer)>)>
|
||||
firrtl.propassign %obj_0_out, %obj0_someReference: !firrtl.class<@Class_1(out someInt: !firrtl.integer)>
|
||||
}
|
||||
|
||||
// CHECK-LABEL: om.class @ReadOutputPort(%basepath: !om.basepath)
|
||||
// CHECK-SAME: -> (output: !om.integer)
|
||||
firrtl.class @ReadOutputPort(out %output : !firrtl.integer) {
|
||||
// CHECK: %[[OBJ:.+]] = om.object @Class_1(%basepath) : (!om.basepath) -> !om.class.type<@Class_1>
|
||||
// CHECK: %[[FIELD:.+]] = om.object.field %[[OBJ]], [@someInt] : (!om.class.type<@Class_1>) -> !om.integer
|
||||
// CHECK: om.class.field @output, %[[FIELD]] : !om.integer
|
||||
// CHECK: om.class.fields %[[FIELD]] : !om.integer
|
||||
%obj = firrtl.object @Class_1(out someInt: !firrtl.integer)
|
||||
%0 = firrtl.object.subfield %obj[someInt] : !firrtl.class<@Class_1(out someInt: !firrtl.integer)>
|
||||
firrtl.propassign %output, %0 : !firrtl.integer
|
||||
|
@ -100,7 +103,13 @@ firrtl.circuit "Component" {
|
|||
// CHECK-SAME: %s1: !om.string
|
||||
// CHECK-SAME: %s2: !om.string
|
||||
// CHECK-SAME: %c1: !om.class.type<@ClassTest>
|
||||
// CHECK-SAME: %c2: !om.class.type<@ClassTest>) {
|
||||
// CHECK-SAME: %c2: !om.class.type<@ClassTest>)
|
||||
// CHECK-SAME: -> (
|
||||
// CHECK-SAME: out_strings: !om.list<!om.string>,
|
||||
// CHECK-SAME: out_empty: !om.list<!om.string>,
|
||||
// CHECK-SAME: out_nested: !om.list<!om.list<!om.string>>,
|
||||
// CHECK-SAME: out_objs: !om.list<!om.class.type<@ClassTest>>
|
||||
// CHECK-SAME: ) {
|
||||
firrtl.class @ListTest(in %s1: !firrtl.string,
|
||||
in %s2: !firrtl.string,
|
||||
in %c1: !firrtl.class<@ClassTest()>,
|
||||
|
@ -129,24 +138,23 @@ firrtl.circuit "Component" {
|
|||
%objs = firrtl.list.create %c1, %c2 : !firrtl.list<class<@ClassTest()>>
|
||||
firrtl.propassign %out_objs, %objs : !firrtl.list<class<@ClassTest()>>
|
||||
|
||||
// CHECK-NEXT: om.class.field @out_strings, %[[STRINGS]] : !om.list<!om.string>
|
||||
// CHECK-NEXT: om.class.field @out_empty, %[[EMPTY]] : !om.list<!om.string>
|
||||
// CHECK-NEXT: om.class.field @out_nested, %[[NESTED]] : !om.list<!om.list<!om.string>>
|
||||
// CHECK-NEXT: om.class.field @out_objs, %[[OBJS]] : !om.list<!om.class.type<@ClassTest>
|
||||
// CHECK-NEXT: om.class.fields %[[STRINGS]], %[[EMPTY]], %[[NESTED]], %[[OBJS]] : !om.list<!om.string>, !om.list<!om.string>, !om.list<!om.list<!om.string>>, !om.list<!om.class.type<@ClassTest>>
|
||||
}
|
||||
|
||||
// CHECK-LABEL: om.class @BoolTest
|
||||
// CHECK-SAME: -> (b: i1)
|
||||
firrtl.class @BoolTest(out %b : !firrtl.bool) {
|
||||
// CHECK-NEXT: %[[TRUE:.+]] = om.constant true
|
||||
// CHECK-NEXT: om.class.field @b, %[[TRUE]] : i1
|
||||
// CHECK-NEXT: om.class.fields %[[TRUE]] : i1
|
||||
%true = firrtl.bool true
|
||||
firrtl.propassign %b, %true : !firrtl.bool
|
||||
}
|
||||
|
||||
// CHECK-LABEL: om.class @DoubleTest
|
||||
// CHECK-SAME: -> (d: f64)
|
||||
firrtl.class @DoubleTest(out %d : !firrtl.double) {
|
||||
// CHECK-NEXT: %[[DBL:.+]] = om.constant 4.0{{0*[eE]}}-01 : f64
|
||||
// CHECK-NEXT: om.class.field @d, %[[DBL]] : f64
|
||||
// CHECK-NEXT: om.class.fields %[[DBL]] : f64
|
||||
%dbl = firrtl.double 0.4
|
||||
firrtl.propassign %d, %dbl: !firrtl.double
|
||||
}
|
||||
|
@ -217,19 +225,21 @@ firrtl.circuit "PathModule" {
|
|||
|
||||
%module_path = firrtl.path reference distinct[5]<>
|
||||
}
|
||||
// CHECK: -> (propOut: !om.list<!om.integer>)
|
||||
firrtl.module @ListCreate(in %propIn: !firrtl.integer, out %propOut: !firrtl.list<integer>) attributes {convention = #firrtl<convention scalarized>} {
|
||||
%0 = firrtl.integer 123
|
||||
%1 = firrtl.list.create %propIn, %0 : !firrtl.list<integer>
|
||||
firrtl.propassign %propOut, %1 : !firrtl.list<integer>
|
||||
// CHECK: %[[c0:.+]] = om.constant #om.integer<123 : si12> : !om.integer
|
||||
// CHECK: %[[c1:.+]] = om.list_create %propIn, %[[c0]] : !om.integer
|
||||
// CHECK: om.class.field @propOut, %[[c1]] : !om.list<!om.integer>
|
||||
// CHECK: om.class.fields %[[c1]] : !om.list<!om.integer>
|
||||
}
|
||||
|
||||
// CHECK: -> (propOut:
|
||||
firrtl.module @ListConcat(in %propIn0: !firrtl.list<integer>, in %propIn1: !firrtl.list<integer>, out %propOut: !firrtl.list<integer>) {
|
||||
// CHECK: [[CONCAT:%.+]] = om.list_concat %propIn0, %propIn1
|
||||
%1 = firrtl.list.concat %propIn0, %propIn1 : !firrtl.list<integer>
|
||||
// CHECK: om.class.field @propOut, [[CONCAT]]
|
||||
// CHECK: om.class.fields [[CONCAT]]
|
||||
firrtl.propassign %propOut, %1 : !firrtl.list<integer>
|
||||
}
|
||||
}
|
||||
|
@ -238,10 +248,11 @@ firrtl.circuit "PathModule" {
|
|||
firrtl.circuit "WireProp" {
|
||||
// CHECK: om.class @WireProp
|
||||
// CHECK-SAME: %[[IN:[^ ]+]]: !om.string
|
||||
// CHECK-SAME: -> (out: !om.string)
|
||||
firrtl.module @WireProp(in %in: !firrtl.string, out %out: !firrtl.string) attributes {convention = #firrtl<convention scalarized>} {
|
||||
// CHECK-NOT: firrtl.wire
|
||||
// CHECK-NOT: firrtl.propassign
|
||||
// CHECK: om.class.field @out, %[[IN]] : !om.string
|
||||
// CHECK: om.class.fields %[[IN]] : !om.string
|
||||
%s = firrtl.wire : !firrtl.string
|
||||
firrtl.propassign %s, %in : !firrtl.string
|
||||
firrtl.propassign %out, %s : !firrtl.string
|
||||
|
@ -305,16 +316,14 @@ firrtl.circuit "ModuleInstances" {
|
|||
firrtl.propassign %outputProp, %mod.outputProp : !firrtl.string
|
||||
}
|
||||
|
||||
// CHECK: om.class.extern @ExtModule_Class(%basepath: !om.basepath, %inputProp: !om.string)
|
||||
// CHECK: om.class.extern.field @outputProp : !om.string
|
||||
// CHECK: om.class.extern @ExtModule_Class(%basepath: !om.basepath, %inputProp: !om.string) -> (outputProp: !om.string)
|
||||
|
||||
// CHECK: om.class.extern @TheRealName_Class(%basepath: !om.basepath, %inputProp: !om.string)
|
||||
// CHECK: om.class.extern.field @outputProp : !om.string
|
||||
// CHECK: om.class.extern @TheRealName_Class(%basepath: !om.basepath, %inputProp: !om.string) -> (outputProp: !om.string)
|
||||
|
||||
// CHECK: om.class @Module_Class(%basepath: !om.basepath, %[[IN_PROP0:.+]]: !om.string)
|
||||
// CHECK: om.class.field @outputProp, %[[IN_PROP0]] : !om.string
|
||||
// CHECK: om.class @Module_Class(%basepath: !om.basepath, %[[IN_PROP0:.+]]: !om.string) -> (outputProp: !om.string)
|
||||
// CHECK: om.class.fields %[[IN_PROP0]] : !om.string
|
||||
|
||||
// CHECK: om.class @ModuleInstances_Class(%basepath: !om.basepath, %[[IN_PROP1:.+]]: !om.string)
|
||||
// CHECK: om.class @ModuleInstances_Class(%basepath: !om.basepath, %[[IN_PROP1:.+]]: !om.string) -> (outputProp: !om.string)
|
||||
// CHECK: %[[BASEPATH:.+]] = om.basepath_create %basepath @[[EXT_NLA]]
|
||||
// CHECK: %[[O0:.+]] = om.object @ExtModule_Class(%[[BASEPATH]], %[[IN_PROP1]])
|
||||
// CHECK: %[[F0:.+]] = om.object.field %[[O0]], [@outputProp]
|
||||
|
@ -323,19 +332,20 @@ firrtl.circuit "ModuleInstances" {
|
|||
// CHECK: %[[BASEPATH:.+]] = om.basepath_create %basepath @[[MOD_NLA]]
|
||||
// CHECK: %[[O1:.+]] = om.object @Module_Class(%[[BASEPATH]], %[[F0]])
|
||||
// CHECK: %[[F1:.+]] = om.object.field %[[O1]], [@outputProp]
|
||||
// CHECK: om.class.field @outputProp, %[[F1]]
|
||||
// CHECK: om.class.fields %[[F1]] : !om.string
|
||||
}
|
||||
|
||||
// CHECK-LABEL: firrtl.circuit "AnyCast"
|
||||
firrtl.circuit "AnyCast" {
|
||||
firrtl.class private @Foo() {}
|
||||
|
||||
// CHECK: -> (foo: !om.any)
|
||||
firrtl.module @AnyCast(out %foo: !firrtl.anyref) {
|
||||
// CHECK: %[[OBJ:.+]] = om.object @Foo
|
||||
%fooObject = firrtl.object @Foo()
|
||||
// CHECK: %[[CAST:.+]] = om.any_cast %[[OBJ]]
|
||||
%0 = firrtl.object.anyref_cast %fooObject : !firrtl.class<@Foo()>
|
||||
// CHECK: om.class.field @foo, %[[CAST]]
|
||||
// CHECK: om.class.fields %[[CAST]] : !om.any
|
||||
firrtl.propassign %foo, %0 : !firrtl.anyref
|
||||
}
|
||||
}
|
||||
|
@ -542,12 +552,14 @@ firrtl.circuit "RTLPorts" {
|
|||
firrtl.propassign %field2, %path : !firrtl.path
|
||||
}
|
||||
|
||||
// CHECK: om.class @NeedsRTLPorts
|
||||
// CHECK-NEXT: om.class.field @containingModule
|
||||
// CHECK-NEXT: om.class.field @ports
|
||||
// CHECK: om.class @NeedsRTLPorts(%basepath: !om.basepath, %containingModule_in: !om.path, %ports: !om.list<!om.class.type<@RtlPort>>)
|
||||
// CHECK-SAME: -> (containingModule: !om.path, ports: !om.list<!om.class.type<@RtlPort>>)
|
||||
firrtl.class @NeedsRTLPorts(in %containingModule_in: !firrtl.path, out %containingModule: !firrtl.path) {
|
||||
// CHECK: om.class.fields %containingModule_in, %ports : !om.path, !om.list<!om.class.type<@RtlPort>>
|
||||
firrtl.propassign %containingModule, %containingModule_in : !firrtl.path
|
||||
}
|
||||
|
||||
// CHECK-COUNT-1: om.class @RtlPort
|
||||
// CHECK: om.class @RtlPort(%ref: !om.path, %direction: !om.string, %width: !om.integer) -> (ref: !om.path, direction: !om.string, width: !om.integer)
|
||||
// CHECK-NEXT: om.class.fields %ref, %direction, %width : !om.path, !om.string, !om.integer
|
||||
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
om.class @Class() {
|
||||
// expected-error @+1 {{'om.object' op result type ("Bar") does not match referred to class ("Foo")}}
|
||||
%0 = om.object @Foo() : () -> !om.class.type<@Bar>
|
||||
om.class.fields
|
||||
}
|
||||
|
||||
// -----
|
||||
|
@ -10,80 +11,91 @@ om.class @Class() {
|
|||
om.class @Class() {
|
||||
// expected-error @+1 {{'om.object' op refers to non-existant class ("NonExistant")}}
|
||||
%0 = om.object @NonExistant() : () -> !om.class.type<@NonExistant>
|
||||
om.class.fields
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// expected-note @+1 {{formal parameters:}}
|
||||
om.class @Class1(%param : i1) {}
|
||||
om.class @Class1(%param : i1) {
|
||||
om.class.fields
|
||||
}
|
||||
|
||||
om.class @Class2() {
|
||||
// expected-error @+2 {{'om.object' op actual parameter list doesn't match formal parameter list}}
|
||||
// expected-note @+1 {{actual parameters:}}
|
||||
%0 = om.object @Class1() : () -> !om.class.type<@Class1>
|
||||
om.class.fields
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
om.class @Class1(%param : i1) {}
|
||||
om.class @Class1(%param : i1) {
|
||||
om.class.fields
|
||||
}
|
||||
|
||||
om.class @Class2(%param : i2) {
|
||||
// expected-error @+1 {{'om.object' op actual parameter type ('i2') doesn't match formal parameter type ('i1')}}
|
||||
%1 = om.object @Class1(%param) : (i2) -> !om.class.type<@Class1>
|
||||
om.class.fields
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// expected-note @+1 {{class defined here}}
|
||||
om.class @Class1() {}
|
||||
om.class @Class1() {
|
||||
om.class.fields
|
||||
}
|
||||
|
||||
om.class @Class2() {
|
||||
%0 = om.object @Class1() : () -> !om.class.type<@Class1>
|
||||
// expected-error @+1 {{'om.object.field' op referenced non-existent field @foo}}
|
||||
om.object.field %0, [@foo] : (!om.class.type<@Class1>) -> i1
|
||||
om.class.fields
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
om.class @Class1() {
|
||||
om.class @Class1() -> (foo: i1) {
|
||||
%0 = om.constant 1 : i1
|
||||
om.class.field @foo, %0 : i1
|
||||
om.class.fields %0 : i1
|
||||
}
|
||||
|
||||
om.class @Class2() {
|
||||
%0 = om.object @Class1() : () -> !om.class.type<@Class1>
|
||||
// expected-error @+1 {{'om.object.field' op nested field access into @foo requires a ClassType, but found 'i1'}}
|
||||
om.object.field %0, [@foo, @bar] : (!om.class.type<@Class1>) -> i1
|
||||
om.class.fields
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
om.class @Class1() {
|
||||
om.class @Class1() -> (foo: i1) {
|
||||
%0 = om.constant 1 : i1
|
||||
om.class.field @foo, %0 : i1
|
||||
om.class.fields %0 : i1
|
||||
}
|
||||
|
||||
om.class @Class2(%arg0: i1) {
|
||||
%0 = om.object @Class1() : () -> !om.class.type<@Class1>
|
||||
// expected-error @+1 {{'om.object.field' op expected type 'i2', but accessed field has type 'i1'}}
|
||||
om.object.field %0, [@foo] : (!om.class.type<@Class1>) -> i2
|
||||
om.class.fields
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
om.class.extern @Extern(%param1: i1) {
|
||||
// expected-error @+1 {{'om.constant' op not allowed in external class}}
|
||||
// expected-error @+1 {{'om.class.extern' op external class body should be empty}}
|
||||
om.class.extern @Extern(%param1: i1) -> (field1: i1) {
|
||||
%0 = om.constant 0 : i1
|
||||
om.class.extern.field @field1 : i1
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// CHECK-LABEL: @List
|
||||
om.class @List() {
|
||||
om.class @List() -> (list: !om.list<i32>){
|
||||
// expected-error @+1 {{an element of a list attribute must have a type 'i32' but got 'i64'}}
|
||||
%0 = om.constant #om.list< i32, [42 : i64]> : !om.list<i32>
|
||||
om.class.field @list, %0 : !om.list<i32>
|
||||
om.class.fields %0 : !om.list<i32>
|
||||
}
|
||||
|
||||
// -----
|
||||
|
@ -95,12 +107,14 @@ om.class @ListCreate() {
|
|||
// expected-error @+2 {{use of value '%1' expects different type than prior uses: 'i64' vs 'i32'}}
|
||||
// expected-note @-2 {{prior use here}}
|
||||
%lst = om.list_create %0, %1 : i64
|
||||
om.class.fields
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// expected-error @+1 {{map key type must be either string or integer but got '!om.list<!om.string>'}}
|
||||
om.class @Map(%map: !om.map<!om.list<!om.string>, !om.string>) {
|
||||
om.class.fields
|
||||
}
|
||||
|
||||
// -----
|
||||
|
@ -108,6 +122,7 @@ om.class @Map(%map: !om.map<!om.list<!om.string>, !om.string>) {
|
|||
om.class @Tuple(%tuple: tuple<i1, !om.string>) {
|
||||
// expected-error @+1 {{tuple index out-of-bounds, must be less than 2 but got 2}}
|
||||
%val = om.tuple_get %tuple[2] : tuple<i1, !om.string>
|
||||
om.class.fields
|
||||
}
|
||||
|
||||
// -----
|
||||
|
@ -115,24 +130,28 @@ om.class @Tuple(%tuple: tuple<i1, !om.string>) {
|
|||
om.class @MapConstant() {
|
||||
// expected-error @+1 {{a value of a map attribute must have a type 'i64' but field "b" has '!om.list<i32>'}}
|
||||
%0 = om.constant #om.map<i64, {a = 42, b = #om.list<i32, []>}> : !om.map<!om.string, i64>
|
||||
om.class.fields
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
om.class @Thing() { }
|
||||
om.class @Thing() {
|
||||
om.class.fields
|
||||
}
|
||||
|
||||
om.class @BadPath(%basepath: !om.basepath) {
|
||||
// expected-error @below {{invalid symbol reference}}
|
||||
%0 = om.path_create reference %basepath @Thing
|
||||
om.class.fields
|
||||
}
|
||||
|
||||
|
||||
// -----
|
||||
|
||||
om.class @DupField(%0: i1) {
|
||||
// expected-note @+1 {{previous definition is here}}
|
||||
om.class.field @foo, %0 : i1
|
||||
// expected-error @+1 {{'om.class.field' op field "foo" is defined twice}}
|
||||
om.class.field @foo, %0 : i1
|
||||
// expected-error @+2 {{custom op 'om.class' previous definition is here}}
|
||||
// expected-error @+1 {{custom op 'om.class' field "foo" is defined twice}}
|
||||
om.class @DupField(%0: i1) -> (foo: i1, foo: i1){
|
||||
om.class.fields %0, %0 : i1, i1
|
||||
}
|
||||
|
||||
// -----
|
||||
|
@ -140,4 +159,5 @@ om.class @DupField(%0: i1) {
|
|||
om.class @UnknownClass(%arg: !om.class.type<@Unknwon>) {
|
||||
// expected-error @+1 {{class @Unknwon was not found}}
|
||||
om.object.field %arg, [@unknown]: (!om.class.type<@Unknwon>) -> i1
|
||||
om.class.fields
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ hw.module @Top() {
|
|||
om.class @OM(%basepath: !om.basepath) {
|
||||
// expected-error @below {{component does not have verilog name}}
|
||||
%path = om.path_create reference %basepath @nla
|
||||
om.class.fields
|
||||
}
|
||||
|
||||
// -----
|
||||
|
@ -21,4 +22,5 @@ hw.module @Top() {
|
|||
om.class @OM(%basepath: !om.basepath) {
|
||||
// expected-error @below {{basepath must target an instance}}
|
||||
%path = om.basepath_create %basepath @nla
|
||||
om.class.fields
|
||||
}
|
||||
|
|
|
@ -68,10 +68,13 @@ om.class @PathTest(%basepath : !om.basepath, %path : !om.path) {
|
|||
|
||||
// CHECK: om.frozenbasepath_create %basepath "PathModule/child"
|
||||
%13 = om.basepath_create %basepath @nla_3
|
||||
|
||||
om.class.fields
|
||||
}
|
||||
|
||||
// CHECK-LABEL om.class @ListCreateTest()
|
||||
om.class @ListCreateTest(%notpath: i1, %basepath : !om.basepath, %path : !om.path) {
|
||||
// CHECK-LABEL: om.class @ListCreateTest
|
||||
// CHECK-SAME: -> (notpath: !om.list<i1>, basepath: !om.list<!om.frozenbasepath>, path: !om.list<!om.frozenpath>, nestedpath: !om.list<!om.list<!om.frozenpath>>)
|
||||
om.class @ListCreateTest(%notpath: i1, %basepath : !om.basepath, %path : !om.path) -> (notpath: !om.list<i1>, basepath: !om.list<!om.basepath>, path: !om.list<!om.path>, nestedpath: !om.list<!om.list<!om.path>>) {
|
||||
// CHECK: [[NOT_PATH_LIST:%.+]] = om.list_create %notpath : i1
|
||||
%0 = om.list_create %notpath : i1
|
||||
|
||||
|
@ -84,22 +87,13 @@ om.class @ListCreateTest(%notpath: i1, %basepath : !om.basepath, %path : !om.pat
|
|||
// CHECK: [[NESTED_PATH_LIST:%.+]] = om.list_create [[PATH_LIST]] : !om.list<!om.frozenpath>
|
||||
%3 = om.list_create %2 : !om.list<!om.path>
|
||||
|
||||
// CHECK: om.class.field @notpath, [[NOT_PATH_LIST]] : !om.list<i1>
|
||||
om.class.field @notpath, %0 : !om.list<i1>
|
||||
|
||||
// CHECK: om.class.field @basepath, [[BASE_PATH_LIST]] : !om.list<!om.frozenbasepath>
|
||||
om.class.field @basepath, %1 : !om.list<!om.basepath>
|
||||
|
||||
// CHECK: om.class.field @path, [[PATH_LIST]] : !om.list<!om.frozenpath>
|
||||
om.class.field @path, %2 : !om.list<!om.path>
|
||||
|
||||
// CHECK: om.class.field @nestedpath, [[NESTED_PATH_LIST]] : !om.list<!om.list<!om.frozenpath>>
|
||||
om.class.field @nestedpath, %3 : !om.list<!om.list<!om.path>>
|
||||
// CHECK: om.class.fields [[NOT_PATH_LIST]], [[BASE_PATH_LIST]], [[PATH_LIST]], [[NESTED_PATH_LIST]] : !om.list<i1>, !om.list<!om.frozenbasepath>, !om.list<!om.frozenpath>, !om.list<!om.list<!om.frozenpath>>
|
||||
om.class.fields %0, %1, %2, %3 : !om.list<i1>, !om.list<!om.basepath>, !om.list<!om.path>, !om.list<!om.list<!om.path>>
|
||||
}
|
||||
|
||||
// CHECK-LABEL om.class @PathListClass(%pathList: !om.list<!om.frozenpath>)
|
||||
om.class @PathListClass(%pathList : !om.list<!om.path>) {
|
||||
om.class.field @pathList, %pathList : !om.list<!om.path>
|
||||
// CHECK-LABEL om.class @PathListClass(%pathList: !om.list<!om.frozenpath>) -> (pathList: !om.list<!om.path>
|
||||
om.class @PathListClass(%pathList : !om.list<!om.path>) -> (pathList: !om.list<!om.path>) {
|
||||
om.class.fields %pathList : !om.list<!om.path>
|
||||
}
|
||||
|
||||
// CHECK-LABEL om.class @PathListTest(%arg: !om.list<!om.frozenpath>)
|
||||
|
@ -111,16 +105,18 @@ om.class @PathListTest(%arg : !om.list<!om.path>) {
|
|||
%0 = om.list_create : !om.path
|
||||
// CHECK: om.object @PathListClass([[RES]]) : (!om.list<!om.frozenpath>)
|
||||
om.object @PathListClass(%0) : (!om.list<!om.path>) -> !om.class.type<@PathListClass>
|
||||
|
||||
om.class.fields
|
||||
}
|
||||
|
||||
// CHECK-LABEL: om.class @ObjectFieldTest
|
||||
om.class @ObjectFieldTest(%basepath : !om.basepath, %path : !om.path) {
|
||||
om.class @ObjectFieldTest(%basepath : !om.basepath, %path : !om.path) -> (subfield: !om.list<!om.list<!om.path>>) {
|
||||
// CHECK: [[OBJ:%.+]] = om.object @PathTest
|
||||
%0 = om.object @PathTest(%basepath, %path) : (!om.basepath, !om.path) -> !om.class.type<@PathTest>
|
||||
|
||||
// CHECK: [[SUBFIELD:%.+]] = om.object.field [[OBJ]], [@nestedpath] : (!om.class.type<@PathTest>) -> !om.list<!om.list<!om.frozenpath>>
|
||||
%1 = om.object.field %0, [@nestedpath] : (!om.class.type<@PathTest>) -> !om.list<!om.list<!om.path>>
|
||||
|
||||
// CHECK: om.class.field @subfield, [[SUBFIELD]] : !om.list<!om.list<!om.frozenpath>>
|
||||
om.class.field @subfield, %1 : !om.list<!om.list<!om.path>>
|
||||
// CHECK: om.class.fields [[SUBFIELD]] : !om.list<!om.list<!om.frozenpath>>
|
||||
om.class.fields %1 : !om.list<!om.list<!om.path>>
|
||||
}
|
||||
|
|
|
@ -26,11 +26,15 @@ module {
|
|||
}
|
||||
module {
|
||||
// expected-note @+1 {{class "A" is defined here}}
|
||||
om.class @A() {}
|
||||
om.class @A() {
|
||||
om.class.fields
|
||||
}
|
||||
}
|
||||
module {
|
||||
// expected-note @+1 {{class "A" is defined here}}
|
||||
om.class @A() {}
|
||||
om.class @A() {
|
||||
om.class.fields
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,17 +44,16 @@ module {
|
|||
// Check types mismatch.
|
||||
module {
|
||||
// expected-error @+1 {{failed to link class "A" since declaration doesn't match the definition: 0-th argument type is not equal, 'i2' vs 'i1'}}
|
||||
om.class.extern @A(%arg: i1) {
|
||||
om.class.extern.field @a: i1
|
||||
}
|
||||
om.class.extern @A(%arg: i1) -> (a: i1) {}
|
||||
om.class @UseA(%arg: i1) {
|
||||
%0 = om.object @A(%arg) : (i1) -> !om.class.type<@A>
|
||||
om.class.fields
|
||||
}
|
||||
}
|
||||
module {
|
||||
// expected-note @+1 {{definition is here}}
|
||||
om.class @A(%arg: i2) {
|
||||
om.class.field @a, %arg: i2
|
||||
om.class @A(%arg: i2) -> (a: i2) {
|
||||
om.class.fields %arg: i2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -60,13 +63,12 @@ module {
|
|||
module {
|
||||
module {
|
||||
// expected-error @+1 {{failed to link class "A" since declaration doesn't match the definition: declaration has a field "a" but not found in its definition}}
|
||||
om.class.extern @A() {
|
||||
om.class.extern.field @a : i1
|
||||
}
|
||||
om.class.extern @A() -> (a: i1) {}
|
||||
}
|
||||
module {
|
||||
// expected-note @+1 {{definition is here}}
|
||||
om.class @A() {
|
||||
om.class.fields
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -76,14 +78,13 @@ module {
|
|||
module {
|
||||
module {
|
||||
// expected-error @+1 {{failed to link class "A" since declaration doesn't match the definition: definition has a field "a" but not found in this declaration}}
|
||||
om.class.extern @A() {
|
||||
}
|
||||
om.class.extern @A() {}
|
||||
}
|
||||
module {
|
||||
// expected-note @+1 {{definition is here}}
|
||||
om.class @A() {
|
||||
om.class @A() -> (a: i1) {
|
||||
%0 = om.constant false
|
||||
om.class.field @a, %0 : i1
|
||||
om.class.fields %0 : i1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -93,15 +94,13 @@ module {
|
|||
module {
|
||||
module {
|
||||
// expected-error @+1 {{failed to link class "A" since declaration doesn't match the definition: declaration has a field "a" but types don't match, 'i1' vs 'i2'}}
|
||||
om.class.extern @A() {
|
||||
om.class.extern.field @a : i2
|
||||
}
|
||||
om.class.extern @A() -> (a: i2) {}
|
||||
}
|
||||
module {
|
||||
// expected-note @+1 {{definition is here}}
|
||||
om.class @A() {
|
||||
om.class @A() -> (a: i1) {
|
||||
%0 = om.constant false
|
||||
om.class.field @a, %0 : i1
|
||||
om.class.fields %0 : i1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,9 @@ module {
|
|||
// CHECK-LABEL: om.class @A
|
||||
// CHECK-LABEL: om.class @Conflict_A
|
||||
// CHECK-LABEL: om.class @UseConflict_A
|
||||
// CHECK-SAME: -> (c: !om.class.type<@Conflict_A>)
|
||||
// CHECK-NEXT: om.object @Conflict_A() : () -> !om.class.type<@Conflict_A>
|
||||
// CHECK-NEXT: om.class.field @c, %{{.+}} : !om.class.type<@Conflict_A>
|
||||
// CHECK-NEXT: om.class.fields %{{.+}} : !om.class.type<@Conflict_A>
|
||||
|
||||
// CHECK-LABEL: om.class @Conflict_B
|
||||
// CHECK-LABEL: om.class @UseConflict_B()
|
||||
|
@ -21,40 +22,39 @@ module {
|
|||
// CHECK-NEXT: om.object.field %{{.+}}, [@c] : (!om.class.type<@Conflict_module_0>) -> i1
|
||||
|
||||
module attributes {om.namespace = "A"} {
|
||||
om.class @A(%arg: i1) {
|
||||
om.class.field @a, %arg: i1
|
||||
om.class @A(%arg: i1) -> (a: i1) {
|
||||
om.class.fields %arg : i1
|
||||
}
|
||||
om.class @Conflict() {
|
||||
om.class @Conflict() -> (c: i1) {
|
||||
%0 = om.constant 0 : i1
|
||||
om.class.field @c, %0: i1
|
||||
om.class.fields %0 : i1
|
||||
}
|
||||
om.class @UseConflict() {
|
||||
om.class @UseConflict() -> (c: !om.class.type<@Conflict>){
|
||||
%0 = om.object @Conflict() : () -> !om.class.type<@Conflict>
|
||||
om.class.field @c, %0: !om.class.type<@Conflict>
|
||||
om.class.fields %0 : !om.class.type<@Conflict>
|
||||
}
|
||||
}
|
||||
module attributes {om.namespace = "B"} {
|
||||
om.class.extern @A(%arg: i1) {
|
||||
om.class.extern.field @a: i1
|
||||
}
|
||||
om.class @Conflict() {
|
||||
om.class.extern @A(%arg: i1) -> (a: i1) {}
|
||||
om.class @Conflict() -> (c: i1) {
|
||||
%0 = om.constant 0 : i1
|
||||
om.class.field @c, %0: i1
|
||||
om.class.fields %0 : i1
|
||||
}
|
||||
om.class @UseConflict() {
|
||||
%0 = om.object @Conflict() : () -> !om.class.type<@Conflict>
|
||||
%1 = om.object.field %0, [@c] : (!om.class.type<@Conflict>) -> i1
|
||||
om.class.field @c, %1: i1
|
||||
om.class @UseConflict() -> (c: i1) {
|
||||
%0 = om.object @Conflict() : () -> !om.class.type<@Conflict>
|
||||
%1 = om.object.field %0, [@c] : (!om.class.type<@Conflict>) -> i1
|
||||
om.class.fields %1 : i1
|
||||
}
|
||||
}
|
||||
module {
|
||||
om.class @Conflict() {
|
||||
om.class @Conflict() -> (c: i1) {
|
||||
%0 = om.constant 0 : i1
|
||||
om.class.field @c, %0: i1
|
||||
om.class.fields %0 : i1
|
||||
}
|
||||
om.class @UseConflict() {
|
||||
%0 = om.object @Conflict() : () -> !om.class.type<@Conflict>
|
||||
%1 = om.object.field %0, [@c] : (!om.class.type<@Conflict>) -> i1
|
||||
om.class.fields
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -68,10 +68,12 @@ module {
|
|||
// CHECK-NOT: delete-me
|
||||
"delete-me"() {sym_name = "Bar"} : () -> ()
|
||||
om.class @Foo() {
|
||||
}
|
||||
om.class.fields
|
||||
}
|
||||
}
|
||||
module {
|
||||
om.class @Bar() {
|
||||
}
|
||||
om.class.fields
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
// RUN: circt-opt %s -verify-diagnostics | circt-opt -verify-diagnostics | FileCheck %s
|
||||
// RUN: circt-opt %s -verify-diagnostics --mlir-print-local-scope --mlir-print-debuginfo | circt-opt --mlir-print-local-scope --mlir-print-debuginfo -verify-diagnostics | FileCheck %s
|
||||
|
||||
// CHECK-LABEL: om.class @Thingy
|
||||
// CHECK-SAME: (%blue_1: i8, %blue_2: i32)
|
||||
om.class @Thingy(%blue_1: i8, %blue_2: i32) {
|
||||
// CHECK-SAME: (%blue_1: i8, %blue_2: i32) -> (widget: !om.class.type<@Widget>, gadget: !om.class.type<@Gadget>, blue_1: i8, blue_2: i8)
|
||||
om.class @Thingy(%blue_1: i8, %blue_2: i32) -> (widget: !om.class.type<@Widget>, gadget: !om.class.type<@Gadget>, blue_1: i8, blue_2: i8) {
|
||||
// CHECK: %[[c5:.+]] = om.constant 5 : i8
|
||||
%0 = om.constant 5 : i8
|
||||
// CHECK: %[[c6:.+]] = om.constant 6 : i32
|
||||
%1 = om.constant 6 : i32
|
||||
// CHECK: %[[widget:.+]] = om.object @Widget(%[[c5]], %[[c6]]) : (i8, i32) -> !om.class.type<@Widget>
|
||||
%2 = om.object @Widget(%0, %1) : (i8, i32) -> !om.class.type<@Widget>
|
||||
// CHECK: om.class.field @widget, %[[widget]] : !om.class.type<@Widget>
|
||||
om.class.field @widget, %2 : !om.class.type<@Widget>
|
||||
|
||||
// CHECK: %[[c7:.+]] = om.constant 7 : i8
|
||||
%3 = om.constant 7 : i8
|
||||
|
@ -18,52 +16,42 @@ om.class @Thingy(%blue_1: i8, %blue_2: i32) {
|
|||
%4 = om.constant 8 : i32
|
||||
// CHECK: %[[gadget:.+]] = om.object @Gadget(%[[c7]], %[[c8]]) : (i8, i32) -> !om.class.type<@Gadget>
|
||||
%5 = om.object @Gadget(%3, %4) : (i8, i32) -> !om.class.type<@Gadget>
|
||||
// CHECK: om.class.field @gadget, %[[gadget]] : !om.class.type<@Gadget>
|
||||
om.class.field @gadget, %5 : !om.class.type<@Gadget>
|
||||
|
||||
// CHECK: om.class.field @blue_1, %blue_1 : i8
|
||||
om.class.field @blue_1, %blue_1 : i8
|
||||
|
||||
// CHECK: %[[widget_field:.+]] = om.object.field %[[widget]], [@blue_1] : (!om.class.type<@Widget>) -> i8
|
||||
%6 = om.object.field %2, [@blue_1] : (!om.class.type<@Widget>) -> i8
|
||||
// CHECK: om.class.field @blue_2, %[[widget_field]] : i8
|
||||
om.class.field @blue_2, %6 : i8
|
||||
|
||||
// CHECK: om.class.fields {test = "fieldsAttr"} %2, %5, %blue_1, %6 : !om.class.type<@Widget>, !om.class.type<@Gadget>, i8, i8 loc("test")
|
||||
om.class.fields {test = "fieldsAttr"} %2, %5, %blue_1, %6 : !om.class.type<@Widget>, !om.class.type<@Gadget>, i8, i8 loc("test")
|
||||
}
|
||||
|
||||
// CHECK-LABEL: om.class @Widget
|
||||
// CHECK-SAME: (%blue_1: i8, %green_1: i32)
|
||||
om.class @Widget(%blue_1: i8, %green_1: i32) {
|
||||
// CHECK: om.class.field @blue_1, %blue_1 : i8
|
||||
om.class.field @blue_1, %blue_1 : i8
|
||||
// CHECK: om.class.field @green_1, %green_1 : i32
|
||||
om.class.field @green_1, %green_1 : i32
|
||||
// CHECK-SAME: (%blue_1: i8, %green_1: i32) -> (blue_1: i8, green_1: i32)
|
||||
om.class @Widget(%blue_1: i8, %green_1: i32) -> (blue_1: i8, green_1: i32) {
|
||||
// CHECK: om.class.fields %blue_1, %green_1 : i8, i32
|
||||
om.class.fields %blue_1, %green_1 : i8, i32
|
||||
}
|
||||
|
||||
// CHECK-LABEL: om.class @Gadget
|
||||
// CHECK-SAME: (%green_1: i8, %green_2: i32)
|
||||
om.class @Gadget(%green_1: i8, %green_2: i32) {
|
||||
// CHECK: om.class.field @green_1, %green_1 : i8
|
||||
om.class.field @green_1, %green_1 : i8
|
||||
// CHECK: om.class.field @green_2, %green_2 : i32
|
||||
om.class.field @green_2, %green_2 : i32
|
||||
// CHECK-SAME: (%green_1: i8, %green_2: i32) -> (green_1: i8, green_2: i32)
|
||||
om.class @Gadget(%green_1: i8, %green_2: i32) -> (green_1: i8, green_2: i32) {
|
||||
// CHECK: om.class.fields %green_1, %green_2 : i8, i32
|
||||
om.class.fields %green_1, %green_2 : i8, i32
|
||||
}
|
||||
|
||||
// CHECK-LABEL: om.class @Empty
|
||||
om.class @Empty() {}
|
||||
om.class @Empty() {
|
||||
om.class.fields
|
||||
}
|
||||
|
||||
// CHECK-LABEL: om.class @DiscardableAttrs
|
||||
// CHECK-SAME: attributes {foo.bar = "baz"}
|
||||
om.class @DiscardableAttrs() attributes {foo.bar="baz"} {}
|
||||
om.class @DiscardableAttrs() attributes {foo.bar="baz"} {
|
||||
om.class.fields
|
||||
}
|
||||
|
||||
// CHECK-LABEL: om.class.extern @Extern
|
||||
// CHECK-SAME: (%param1: i1, %param2: i2)
|
||||
om.class.extern @Extern(%param1: i1, %param2: i2) {
|
||||
// CHECK: om.class.extern.field @field1 : i3
|
||||
om.class.extern.field @field1 : i3
|
||||
|
||||
// CHECK: om.class.extern.field @field2 : i4
|
||||
om.class.extern.field @field2 : i4
|
||||
}
|
||||
// CHECK-SAME: (%param1: i1, %param2: i2) -> (field1: i3, field2: i4)
|
||||
om.class.extern @Extern(%param1: i1, %param2: i2) -> (field1 : i3, field2 : i4) {}
|
||||
|
||||
// CHECK-LABEL: om.class @ExternObject
|
||||
// CHECK-SAME: (%[[P0:.+]]: i1, %[[P1:.+]]: i2)
|
||||
|
@ -73,21 +61,22 @@ om.class @ExternObject(%param1: i1, %param2: i2) {
|
|||
|
||||
// CHECK: om.object.field %[[O0]], [@field1]
|
||||
%1 = om.object.field %0, [@field1] : (!om.class.type<@Extern>) -> i3
|
||||
om.class.fields
|
||||
}
|
||||
|
||||
om.class @NestedField1() {
|
||||
om.class @NestedField1() -> (baz: i1) {
|
||||
%0 = om.constant 1 : i1
|
||||
om.class.field @baz, %0 : i1
|
||||
om.class.fields %0 : i1
|
||||
}
|
||||
|
||||
om.class @NestedField2() {
|
||||
om.class @NestedField2() -> (bar: !om.class.type<@NestedField1>) {
|
||||
%0 = om.object @NestedField1() : () -> !om.class.type<@NestedField1>
|
||||
om.class.field @bar, %0 : !om.class.type<@NestedField1>
|
||||
om.class.fields %0 : !om.class.type<@NestedField1>
|
||||
}
|
||||
|
||||
om.class @NestedField3() {
|
||||
om.class @NestedField3() -> (foo: !om.class.type<@NestedField2>) {
|
||||
%0 = om.object @NestedField2() : () -> !om.class.type<@NestedField2>
|
||||
om.class.field @foo, %0 : !om.class.type<@NestedField2>
|
||||
om.class.fields %0 : !om.class.type<@NestedField2>
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @NestedField4
|
||||
|
@ -96,46 +85,47 @@ om.class @NestedField4() {
|
|||
%0 = om.object @NestedField3() : () -> !om.class.type<@NestedField3>
|
||||
// CHECK: %{{.+}} = om.object.field %[[nested]], [@foo, @bar, @baz] : (!om.class.type<@NestedField3>) -> i1
|
||||
%1 = om.object.field %0, [@foo, @bar, @baz] : (!om.class.type<@NestedField3>) -> i1
|
||||
om.class.fields
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @ReferenceParameter
|
||||
// CHECK-SAME: !om.ref
|
||||
// CHECK-SAME: !om.sym_ref
|
||||
om.class @ReferenceParameter(%arg0: !om.ref, %arg1: !om.sym_ref) {
|
||||
// CHECK: om.class.field @myref
|
||||
om.class.field @myref, %arg0 : !om.ref
|
||||
// CHECK: om.class.field @sym
|
||||
om.class.field @sym, %arg1 : !om.sym_ref
|
||||
// CHECK-SAME: -> (myref: !om.ref, sym: !om.sym_ref)
|
||||
om.class @ReferenceParameter(%arg0: !om.ref, %arg1: !om.sym_ref) -> (myref: !om.ref, sym: !om.sym_ref) {
|
||||
// CHECK: om.class.fields %arg0, %arg1 : !om.ref, !om.sym_ref
|
||||
om.class.fields %arg0, %arg1 : !om.ref, !om.sym_ref
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @ReferenceConstant
|
||||
om.class @ReferenceConstant() {
|
||||
// CHECK-SAME: -> (myref: !om.ref, sym: !om.sym_ref)
|
||||
om.class @ReferenceConstant() -> (myref: !om.ref, sym: !om.sym_ref) {
|
||||
// CHECK: %[[const1:.+]] = om.constant #om.ref<<@A::@inst_1>> : !om.ref
|
||||
%0 = om.constant #om.ref<#hw.innerNameRef<@A::@inst_1>> : !om.ref
|
||||
// CHECK: om.class.field @myref, %[[const1]] : !om.ref
|
||||
om.class.field @myref, %0 : !om.ref
|
||||
|
||||
// CHECK: %[[const2:.+]] = om.constant #om.sym_ref<@A> : !om.sym_ref
|
||||
%1 = om.constant #om.sym_ref<@A> : !om.sym_ref
|
||||
// CHECK: om.class.field @sym, %[[const2]] : !om.sym_ref
|
||||
om.class.field @sym, %1 : !om.sym_ref
|
||||
|
||||
// CHECK: om.class.fields %[[const1]], %[[const2]] : !om.ref, !om.sym_ref
|
||||
om.class.fields %0, %1 : !om.ref, !om.sym_ref
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @ListConstant
|
||||
om.class @ListConstant() {
|
||||
// CHECK-SAME: -> (list_i64: !om.list<i64>, list_i32: !om.list<i32>)
|
||||
om.class @ListConstant() -> (list_i64: !om.list<i64>, list_i32: !om.list<i32>) {
|
||||
// CHECK: %[[const1:.+]] = om.constant #om.list<i64, [42]> : !om.list<i64>
|
||||
%0 = om.constant #om.list<i64, [42]> : !om.list<i64>
|
||||
// CHECK: om.class.field @list_i64, %[[const1]] : !om.list<i64>
|
||||
om.class.field @list_i64, %0 : !om.list<i64>
|
||||
|
||||
// CHECK: %[[const2:.+]] = om.constant #om.list<i32, []> : !om.list<i32>
|
||||
%1 = om.constant #om.list<i32, []> : !om.list<i32>
|
||||
// CHECK: om.class.field @list_i32, %[[const2]] : !om.list<i32>
|
||||
om.class.field @list_i32, %1 : !om.list<i32>
|
||||
|
||||
// CHECK: om.class.fields %[[const1]], %[[const2]] : !om.list<i64>, !om.list<i32>
|
||||
om.class.fields %0, %1 : !om.list<i64>, !om.list<i32>
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @ListCreate
|
||||
om.class @ListCreate() {
|
||||
// CHECK-SAME: -> (list_field: !om.list<!om.class.type<@Widget>>)
|
||||
om.class @ListCreate() -> (list_field: !om.list<!om.class.type<@Widget>>) {
|
||||
// CHECK: [[cst5_i8:%.+]] = om.constant 5 : i8
|
||||
%cst5_i8 = om.constant 5 : i8
|
||||
// CHECK: [[cst6_i8:%.+]] = om.constant 6 : i8
|
||||
|
@ -154,8 +144,8 @@ om.class @ListCreate() {
|
|||
// CHECK: [[list:%.+]] = om.list_create [[obj0]], [[obj1]] : !om.class.type<@Widget>
|
||||
%list = om.list_create %obj0, %obj1 : !om.class.type<@Widget>
|
||||
|
||||
// CHECK: om.class.field @list_field, [[list]] : !om.list<!om.class.type<@Widget>>
|
||||
om.class.field @list_field, %list : !om.list<!om.class.type<@Widget>>
|
||||
// CHECK: om.class.fields [[list]] : !om.list<!om.class.type<@Widget>>
|
||||
om.class.fields %list : !om.list<!om.class.type<@Widget>>
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @ListConcat
|
||||
|
@ -172,27 +162,32 @@ om.class @ListConcat() {
|
|||
|
||||
// CHECK: om.list_concat [[L0]], [[L1]]
|
||||
%concat = om.list_concat %l0, %l1 : !om.list<!om.integer>
|
||||
|
||||
om.class.fields
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @Integer
|
||||
om.class @IntegerConstant() {
|
||||
// CHECK-SAME: -> (int: !om.integer)
|
||||
om.class @IntegerConstant() -> (int: !om.integer) {
|
||||
// CHECK: %[[const1:.+]] = om.constant #om.integer<36755551979133953793 : i67> : !om.integer
|
||||
%0 = om.constant #om.integer<36755551979133953793 : i67> : !om.integer
|
||||
// CHECK: om.class.field @int, %[[const1]] : !om.integer
|
||||
om.class.field @int, %0 : !om.integer
|
||||
// CHECK: om.class.fields %[[const1]] : !om.integer
|
||||
om.class.fields %0 : !om.integer
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @String
|
||||
om.class @StringConstant() {
|
||||
// CHECK-SAME: -> (string: !om.string)
|
||||
om.class @StringConstant() -> (string: !om.string) {
|
||||
// CHECK: %[[const1:.+]] = om.constant "foo" : !om.string
|
||||
%0 = om.constant "foo" : !om.string
|
||||
// CHECK: om.class.field @string, %[[const1]] : !om.string
|
||||
om.class.field @string, %0 : !om.string
|
||||
// CHECK: om.class.fields %[[const1]] : !om.string
|
||||
om.class.fields %0 : !om.string
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @LinkedList
|
||||
om.class @LinkedList(%prev: !om.class.type<@LinkedList>) {
|
||||
om.class.field @prev, %prev : !om.class.type<@LinkedList>
|
||||
// CHECK-SAME: -> (prev: !om.class.type<@LinkedList>)
|
||||
om.class @LinkedList(%prev: !om.class.type<@LinkedList>) -> (prev: !om.class.type<@LinkedList>) {
|
||||
om.class.fields %prev : !om.class.type<@LinkedList>
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @ReferenceEachOther
|
||||
|
@ -201,6 +196,7 @@ om.class @ReferenceEachOther() {
|
|||
// CHECK-NEXT: %[[obj2]] = om.object @LinkedList(%[[obj1]]) : (!om.class.type<@LinkedList>) -> !om.class.type<@LinkedList>
|
||||
%0 = om.object @LinkedList(%1) : (!om.class.type<@LinkedList>) -> !om.class.type<@LinkedList>
|
||||
%1 = om.object @LinkedList(%0) : (!om.class.type<@LinkedList>) -> !om.class.type<@LinkedList>
|
||||
om.class.fields
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @RefecenceEachOthersField
|
||||
|
@ -214,61 +210,65 @@ om.class @RefecenceEachOthersField(%blue_1: i8, %green_1: i32) {
|
|||
%2 = om.object @Widget(%1, %green_1) : (i8, i32) -> !om.class.type<@Widget>
|
||||
// CHECK-NEXT: %[[field2]] = om.object.field %[[obj2]], [@green_1] : (!om.class.type<@Widget>) -> i32
|
||||
%3 = om.object.field %2, [@green_1] : (!om.class.type<@Widget>) -> i32
|
||||
om.class.fields
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @Bool
|
||||
om.class @BoolConstant(%b0 : i1) {
|
||||
// CHECK-SAME: -> (bool: i1, bool2: i1, bool3: i1)
|
||||
om.class @BoolConstant(%b0 : i1) -> (bool: i1, bool2: i1, bool3: i1) {
|
||||
// CHECK: %[[const1:.+]] = om.constant true
|
||||
%1 = om.constant true
|
||||
// CHECK: %[[const2:.+]] = om.constant false
|
||||
%2 = om.constant false
|
||||
// CHECK: om.class.field @bool, %b0
|
||||
om.class.field @bool, %b0 : i1
|
||||
// CHECK: om.class.field @bool2, %[[const1]]
|
||||
om.class.field @bool2, %1 : i1
|
||||
// CHECK: om.class.field @bool3, %[[const2]]
|
||||
om.class.field @bool3, %2 : i1
|
||||
// CHECK: om.class.fields %b0, %[[const1]], %[[const2]] : i1, i1, i1
|
||||
om.class.fields %b0, %1, %2 : i1, i1, i1
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @Map
|
||||
// CHECK-SAME: !om.map<!om.string, !om.string>
|
||||
om.class @Map(%map: !om.map<!om.string, !om.string>) {
|
||||
om.class.field @field, %map : !om.map<!om.string, !om.string>
|
||||
// CHECK-SAME: -> (field: !om.map<!om.string, !om.string>)
|
||||
om.class @Map(%map: !om.map<!om.string, !om.string>) -> (field: !om.map<!om.string, !om.string>) {
|
||||
// CHECK: om.class.fields %map : !om.map<!om.string, !om.string>
|
||||
om.class.fields %map : !om.map<!om.string, !om.string>
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @Tuple
|
||||
om.class @Tuple(%int: i1, %str: !om.string) {
|
||||
// CHECK-SAME: -> (tuple: tuple<i1, !om.string>, val: !om.string)
|
||||
om.class @Tuple(%int: i1, %str: !om.string) -> (tuple: tuple<i1, !om.string>, val: !om.string) {
|
||||
// CHECK: %[[tuple:.+]] = om.tuple_create %int, %str : i1, !om.string
|
||||
%tuple = om.tuple_create %int, %str : i1, !om.string
|
||||
// CHECK-NEXT: om.class.field @tuple, %[[tuple]] : tuple<i1, !om.string>
|
||||
om.class.field @tuple, %tuple : tuple<i1, !om.string>
|
||||
// CHECK-NEXT: %[[tuple_get:.+]] = om.tuple_get %[[tuple]][1] : tuple<i1, !om.string>
|
||||
%val = om.tuple_get %tuple[1] : tuple<i1, !om.string>
|
||||
// CHECK-NEXT: om.class.field @val, %[[tuple_get]] : !om.string
|
||||
om.class.field @val, %val : !om.string
|
||||
// CHECK-NEXT: om.class.fields %[[tuple]], %[[tuple_get]] : tuple<i1, !om.string>, !om.string
|
||||
om.class.fields %tuple, %val : tuple<i1, !om.string>, !om.string
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @MapConstant
|
||||
om.class @MapConstant() {
|
||||
// CHECK-SAME: -> (map_i64: !om.map<!om.string, i64>)
|
||||
om.class @MapConstant() -> (map_i64: !om.map<!om.string, i64>) {
|
||||
// CHECK: %[[const1:.+]] = om.constant #om.map<i64, {a = 42 : i64, b = 32 : i64}> : !om.map<!om.string, i64>
|
||||
%0 = om.constant #om.map<i64, {a = 42, b = 32}> : !om.map<!om.string, i64>
|
||||
// CHECK: om.class.field @map_i64, %[[const1]] : !om.map<!om.string, i64>
|
||||
om.class.field @map_i64, %0 : !om.map<!om.string, i64>
|
||||
// CHECK: om.class.fields %[[const1]] : !om.map<!om.string, i64>
|
||||
om.class.fields %0 : !om.map<!om.string, i64>
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @MapCreate
|
||||
om.class @MapCreate(%e1: tuple<!om.string, !om.class.type<@Empty>>, %e2: tuple<!om.string, !om.class.type<@Empty>>) {
|
||||
// CHECK-SAME: -> (map_field: !om.map<!om.string, !om.class.type<@Empty>>)
|
||||
om.class @MapCreate(%e1: tuple<!om.string, !om.class.type<@Empty>>, %e2: tuple<!om.string, !om.class.type<@Empty>>) -> (map_field: !om.map<!om.string, !om.class.type<@Empty>>) {
|
||||
// CHECK: %[[map:.+]] = om.map_create %e1, %e2 : !om.string, !om.class.type<@Empty>
|
||||
%map = om.map_create %e1, %e2 : !om.string, !om.class.type<@Empty>
|
||||
// CHECK-NEXT: om.class.field @map_field, %[[map]] : !om.map<!om.string, !om.class.type<@Empty>>
|
||||
om.class.field @map_field, %map : !om.map<!om.string, !om.class.type<@Empty>>
|
||||
// CHECK-NEXT: om.class.fields %[[map]] : !om.map<!om.string, !om.class.type<@Empty>>
|
||||
om.class.fields %map : !om.map<!om.string, !om.class.type<@Empty>>
|
||||
}
|
||||
|
||||
hw.hierpath @HierPath [@PathModule::@wire]
|
||||
hw.module @PathModule() {
|
||||
%wire = hw.wire %wire sym @wire : i1
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @Path
|
||||
om.class @Path(%basepath: !om.basepath) {
|
||||
// CHECK: -> (path_empty: !om.path)
|
||||
om.class @Path(%basepath: !om.basepath) -> (path_empty: !om.path) {
|
||||
// CHECK: %[[v0:.+]] = om.basepath_create %basepath @HierPath
|
||||
%0 = om.basepath_create %basepath @HierPath
|
||||
// CHECK: %[[v1:.+]] = om.path_create reference %basepath @HierPath
|
||||
|
@ -277,8 +277,8 @@ om.class @Path(%basepath: !om.basepath) {
|
|||
%2 = om.constant 1 : i1 { foo = #om<path[Foo:foo, Bar:bar]>}
|
||||
// CHECK: %[[v3:.+]] = om.path_empty
|
||||
%3 = om.path_empty
|
||||
// CHECK: om.class.field @path_empty, %[[v3]] : !om.path
|
||||
om.class.field @path_empty, %3 : !om.path
|
||||
// CHECK: om.class.fields %[[v3]] : !om.path
|
||||
om.class.fields %3 : !om.path
|
||||
}
|
||||
|
||||
om.class @FrozenPath(%basepath: !om.frozenbasepath) {
|
||||
|
@ -286,15 +286,17 @@ om.class @FrozenPath(%basepath: !om.frozenbasepath) {
|
|||
%0 = om.frozenbasepath_create %basepath "Foo/bar"
|
||||
// CHECK: %[[v1:.+]] = om.frozenpath_create reference %basepath "Foo/bar:Bar>w.a"
|
||||
%1 = om.frozenpath_create reference %basepath "Foo/bar:Bar>w.a"
|
||||
om.class.fields
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @Any
|
||||
// CHECK-SAME: %[[IN:.+]]: !om.class.type
|
||||
om.class @Any(%in: !om.class.type<@Empty>) {
|
||||
// CHECK-SAME: -> (field: !om.any)
|
||||
om.class @Any(%in: !om.class.type<@Empty>) -> (field: !om.any) {
|
||||
// CHECK: %[[CAST:.+]] = om.any_cast %[[IN]]
|
||||
%0 = om.any_cast %in : (!om.class.type<@Empty>) -> !om.any
|
||||
// CHECK: om.class.field @field, %[[CAST]]
|
||||
om.class.field @field, %0 : !om.any
|
||||
// CHECK: om.class.fields %[[CAST]] : !om.any
|
||||
om.class.fields %0 : !om.any
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @IntegerArithmetic
|
||||
|
@ -313,4 +315,6 @@ om.class @IntegerArithmetic() {
|
|||
|
||||
// CHECK: om.integer.shl %0, %1 : !om.integer
|
||||
%5 = om.integer.shl %0, %1 : !om.integer
|
||||
|
||||
om.class.fields
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ circuit Test : %[[
|
|||
output out_baz : Integer
|
||||
propassign out_baz, Integer(1)
|
||||
|
||||
; CHECK-LABEL: om.class @OM_1(%basepath: !om.basepath)
|
||||
; CHECK-LABEL: om.class @OM_1(%basepath: !om.basepath) -> (out_foo_1: !om.class.type<@Foo_1>, out_foo_2: !om.class.type<@Foo_2>, out_foo_3: !om.class.type<@Foo_3>, out_foo_4: !om.class.type<@Foo_3>, out_1: !om.path, out_2: !om.path)
|
||||
class OM_1 :
|
||||
output out_1 : Path
|
||||
output out_2 : Path
|
||||
|
@ -98,9 +98,11 @@ circuit Test : %[[
|
|||
output out_foo_3 : Inst<Foo_3>
|
||||
output out_foo_4 : Inst<Foo_4>
|
||||
|
||||
; CHECK: [[FOO_1:%.+]] = om.object @Foo_1
|
||||
object foo_1 of Foo_1
|
||||
propassign out_foo_1, foo_1
|
||||
|
||||
; CHECK: [[FOO_2:%.+]] = om.object @Foo_2
|
||||
object foo_2 of Foo_2
|
||||
propassign out_foo_2, foo_2
|
||||
|
||||
|
@ -117,8 +119,7 @@ circuit Test : %[[
|
|||
; CHECK: om.path_create reference %basepath [[NLA2]]
|
||||
propassign out_2, path("OMReferenceTarget:~Test|CPU_1/fetch_1:Fetch_1>foo")
|
||||
|
||||
; CHECK: om.class.field @out_foo_3, [[FOO_3]]
|
||||
; CHECK: om.class.field @out_foo_4, [[FOO_4]]
|
||||
; CHECK: om.class.fields [[FOO_1]], [[FOO_2]], [[FOO_3]], [[FOO_4]], %4, %5 : !om.class.type<@Foo_1>, !om.class.type<@Foo_2>, !om.class.type<@Foo_3>, !om.class.type<@Foo_3>, !om.path, !om.path
|
||||
|
||||
; CHECK-NOT: OM_2
|
||||
class OM_2 :
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
module {
|
||||
om.class @A(%arg: i1) {
|
||||
om.class.fields
|
||||
}
|
||||
om.class @Conflict(){
|
||||
om.class.fields
|
||||
}
|
||||
om.class @Conflict(){}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
module {
|
||||
om.class.extern @A(%arg: i1) {
|
||||
}
|
||||
om.class.extern @A(%arg: i1) {}
|
||||
om.class @B(%arg: i2) {
|
||||
om.class.fields
|
||||
}
|
||||
om.class @Conflict(){
|
||||
om.class.fields
|
||||
}
|
||||
om.class @Conflict(){}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
// RUN: om-linker %S/Inputs/a.mlir %S/Inputs/b.mlir %S/Inputs/other.mlir | FileCheck %s
|
||||
// CHECK: module {
|
||||
// CHECK-NEXT: om.class @A(%arg: i1) {
|
||||
// CHECK-NEXT: om.class.fields
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: om.class @Conflict_a() {
|
||||
// CHECK-NEXT: om.class.fields
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: om.class @B(%arg: i2) {
|
||||
// CHECK-NEXT: om.class.fields
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: om.class @Conflict_b() {
|
||||
// CHECK-NEXT: om.class.fields
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: }
|
||||
|
|
|
@ -166,7 +166,9 @@ TEST(EvaluatorTests, GetFieldInvalidName) {
|
|||
|
||||
builder.setInsertionPointToStart(&mod.getBodyRegion().front());
|
||||
auto cls = builder.create<ClassOp>("MyClass");
|
||||
cls.getBody().emplaceBlock();
|
||||
auto &body = cls.getBody().emplaceBlock();
|
||||
builder.setInsertionPointToStart(&body);
|
||||
builder.create<ClassFieldsOp>(loc, llvm::ArrayRef<mlir::Value>());
|
||||
|
||||
Evaluator evaluator(mod);
|
||||
|
||||
|
@ -240,12 +242,18 @@ TEST(EvaluatorTests, InstantiateObjectWithConstantField) {
|
|||
auto mod = builder.create<ModuleOp>(loc);
|
||||
|
||||
builder.setInsertionPointToStart(&mod.getBodyRegion().front());
|
||||
auto cls = builder.create<ClassOp>("MyClass");
|
||||
auto constantType = builder.getI32IntegerAttr(42);
|
||||
auto cls = builder.create<ClassOp>(
|
||||
"MyClass", builder.getStrArrayAttr({"field"}),
|
||||
builder.getDictionaryAttr({
|
||||
NamedAttribute(builder.getStringAttr("field"), constantType),
|
||||
|
||||
}));
|
||||
auto &body = cls.getBody().emplaceBlock();
|
||||
builder.setInsertionPointToStart(&body);
|
||||
auto constant = builder.create<ConstantOp>(
|
||||
circt::om::IntegerAttr::get(&context, builder.getI32IntegerAttr(42)));
|
||||
builder.create<ClassFieldOp>("field", constant);
|
||||
circt::om::IntegerAttr::get(&context, constantType));
|
||||
builder.create<ClassFieldsOp>(loc, SmallVector<Value>({constant}));
|
||||
|
||||
Evaluator evaluator(mod);
|
||||
|
||||
|
@ -284,12 +292,19 @@ TEST(EvaluatorTests, InstantiateObjectWithChildObject) {
|
|||
params, fields, types);
|
||||
|
||||
builder.setInsertionPointToStart(&mod.getBodyRegion().front());
|
||||
auto cls = builder.create<ClassOp>("MyClass", params);
|
||||
auto innerType = TypeAttr::get(ClassType::get(
|
||||
builder.getContext(), mlir::FlatSymbolRefAttr::get(innerCls)));
|
||||
auto cls = builder.create<ClassOp>(
|
||||
"MyClass", params, builder.getStrArrayAttr({"field"}),
|
||||
builder.getDictionaryAttr({
|
||||
NamedAttribute(builder.getStringAttr("field"), innerType),
|
||||
|
||||
}));
|
||||
auto &body = cls.getBody().emplaceBlock();
|
||||
body.addArgument(circt::om::OMIntegerType::get(&context), cls.getLoc());
|
||||
builder.setInsertionPointToStart(&body);
|
||||
auto object = builder.create<ObjectOp>(innerCls, body.getArguments());
|
||||
builder.create<ClassFieldOp>("field", object);
|
||||
builder.create<ClassFieldsOp>(loc, SmallVector<Value>({object}));
|
||||
|
||||
Evaluator evaluator(mod);
|
||||
|
||||
|
@ -337,7 +352,14 @@ TEST(EvaluatorTests, InstantiateObjectWithFieldAccess) {
|
|||
params, fields, types);
|
||||
|
||||
builder.setInsertionPointToStart(&mod.getBodyRegion().front());
|
||||
auto cls = builder.create<ClassOp>("MyClass", params);
|
||||
auto innerType = TypeAttr::get(ClassType::get(
|
||||
builder.getContext(), mlir::FlatSymbolRefAttr::get(innerCls)));
|
||||
auto cls = builder.create<ClassOp>(
|
||||
"MyClass", params, builder.getStrArrayAttr({"field"}),
|
||||
builder.getDictionaryAttr({
|
||||
NamedAttribute(builder.getStringAttr("field"), innerType),
|
||||
|
||||
}));
|
||||
auto &body = cls.getBody().emplaceBlock();
|
||||
body.addArgument(circt::om::OMIntegerType::get(&context), cls.getLoc());
|
||||
builder.setInsertionPointToStart(&body);
|
||||
|
@ -346,7 +368,7 @@ TEST(EvaluatorTests, InstantiateObjectWithFieldAccess) {
|
|||
builder.create<ObjectFieldOp>(builder.getI32Type(), object,
|
||||
builder.getArrayAttr(FlatSymbolRefAttr::get(
|
||||
builder.getStringAttr("field"))));
|
||||
builder.create<ClassFieldOp>("field", field);
|
||||
builder.create<ClassFieldsOp>(loc, SmallVector<Value>({field}));
|
||||
|
||||
Evaluator evaluator(mod);
|
||||
|
||||
|
@ -383,15 +405,24 @@ TEST(EvaluatorTests, InstantiateObjectWithChildObjectMemoized) {
|
|||
|
||||
builder.setInsertionPointToStart(&mod.getBodyRegion().front());
|
||||
auto innerCls = builder.create<ClassOp>("MyInnerClass");
|
||||
innerCls.getBody().emplaceBlock();
|
||||
auto &innerBody = innerCls.getBody().emplaceBlock();
|
||||
builder.setInsertionPointToStart(&innerBody);
|
||||
builder.create<ClassFieldsOp>(loc, llvm::ArrayRef<mlir::Value>());
|
||||
|
||||
builder.setInsertionPointToStart(&mod.getBodyRegion().front());
|
||||
auto cls = builder.create<ClassOp>("MyClass");
|
||||
auto innerType = TypeAttr::get(ClassType::get(
|
||||
builder.getContext(), mlir::FlatSymbolRefAttr::get(innerCls)));
|
||||
auto cls = builder.create<ClassOp>(
|
||||
"MyClass", builder.getStrArrayAttr({"field1", "field2"}),
|
||||
builder.getDictionaryAttr({
|
||||
NamedAttribute(builder.getStringAttr("field1"), innerType),
|
||||
NamedAttribute(builder.getStringAttr("field2"), innerType),
|
||||
|
||||
}));
|
||||
auto &body = cls.getBody().emplaceBlock();
|
||||
builder.setInsertionPointToStart(&body);
|
||||
auto object = builder.create<ObjectOp>(innerCls, body.getArguments());
|
||||
builder.create<ClassFieldOp>("field1", object);
|
||||
builder.create<ClassFieldOp>("field2", object);
|
||||
builder.create<ClassFieldsOp>(loc, SmallVector<Value>({object, object}));
|
||||
|
||||
Evaluator evaluator(mod);
|
||||
|
||||
|
@ -443,15 +474,24 @@ TEST(EvaluatorTests, AnyCastObject) {
|
|||
|
||||
builder.setInsertionPointToStart(&mod.getBodyRegion().front());
|
||||
auto innerCls = builder.create<ClassOp>("MyInnerClass");
|
||||
innerCls.getBody().emplaceBlock();
|
||||
auto &innerBody = innerCls.getBody().emplaceBlock();
|
||||
builder.setInsertionPointToStart(&innerBody);
|
||||
builder.create<ClassFieldsOp>(loc, llvm::ArrayRef<mlir::Value>());
|
||||
|
||||
builder.setInsertionPointToStart(&mod.getBodyRegion().front());
|
||||
auto cls = builder.create<ClassOp>("MyClass");
|
||||
auto innerType = TypeAttr::get(ClassType::get(
|
||||
builder.getContext(), mlir::FlatSymbolRefAttr::get(innerCls)));
|
||||
auto cls = builder.create<ClassOp>(
|
||||
"MyClass", builder.getStrArrayAttr({"field"}),
|
||||
builder.getDictionaryAttr({
|
||||
NamedAttribute(builder.getStringAttr("field"), innerType),
|
||||
|
||||
}));
|
||||
auto &body = cls.getBody().emplaceBlock();
|
||||
builder.setInsertionPointToStart(&body);
|
||||
auto object = builder.create<ObjectOp>(innerCls, body.getArguments());
|
||||
auto cast = builder.create<AnyCastOp>(object);
|
||||
builder.create<ClassFieldOp>("field", cast);
|
||||
builder.create<ClassFieldsOp>(loc, SmallVector<Value>({cast}));
|
||||
|
||||
Evaluator evaluator(mod);
|
||||
|
||||
|
@ -491,14 +531,21 @@ TEST(EvaluatorTests, AnyCastParam) {
|
|||
auto i64 = builder.getIntegerType(64);
|
||||
builder.setInsertionPointToStart(&mod.getBodyRegion().front());
|
||||
StringRef params[] = {"param"};
|
||||
auto cls = builder.create<ClassOp>("MyClass", params);
|
||||
auto innerType = TypeAttr::get(ClassType::get(
|
||||
builder.getContext(), mlir::FlatSymbolRefAttr::get(innerCls)));
|
||||
auto cls = builder.create<ClassOp>(
|
||||
"MyClass", params, builder.getStrArrayAttr({"field"}),
|
||||
builder.getDictionaryAttr({
|
||||
NamedAttribute(builder.getStringAttr("field"), innerType),
|
||||
|
||||
}));
|
||||
auto &body = cls.getBody().emplaceBlock();
|
||||
body.addArguments({i64}, {builder.getLoc()});
|
||||
builder.setInsertionPointToStart(&body);
|
||||
auto cast = builder.create<AnyCastOp>(body.getArgument(0));
|
||||
SmallVector<Value> objectParams = {cast};
|
||||
auto object = builder.create<ObjectOp>(innerCls, objectParams);
|
||||
builder.create<ClassFieldOp>("field", object);
|
||||
builder.create<ClassFieldsOp>(loc, SmallVector<Value>({object}));
|
||||
|
||||
Evaluator evaluator(mod);
|
||||
|
||||
|
@ -526,17 +573,16 @@ TEST(EvaluatorTests, AnyCastParam) {
|
|||
TEST(EvaluatorTests, InstantiateGraphRegion) {
|
||||
StringRef module =
|
||||
"!ty = !om.class.type<@LinkedList>"
|
||||
"om.class @LinkedList(%n: !ty, %val: !om.string) {"
|
||||
" om.class.field @n, %n : !ty"
|
||||
" om.class.field @val, %val : !om.string"
|
||||
"om.class @LinkedList(%n: !ty, %val: !om.string) -> (n: !ty, val: "
|
||||
"!om.string){"
|
||||
" om.class.fields %n, %val : !ty, !om.string"
|
||||
"}"
|
||||
"om.class @ReferenceEachOther() {"
|
||||
"om.class @ReferenceEachOther() -> (field1: !ty, field2: !ty) {"
|
||||
" %str = om.constant \"foo\" : !om.string"
|
||||
" %val = om.object.field %1, [@n, @n, @val] : (!ty) -> !om.string"
|
||||
" %0 = om.object @LinkedList(%1, %val) : (!ty, !om.string) -> !ty"
|
||||
" %1 = om.object @LinkedList(%0, %str) : (!ty, !om.string) -> !ty"
|
||||
" om.class.field @field1, %0 : !ty"
|
||||
" om.class.field @field2, %1 : !ty"
|
||||
" om.class.fields %0, %1 : !ty, !ty"
|
||||
"}";
|
||||
|
||||
DialectRegistry registry;
|
||||
|
@ -582,13 +628,13 @@ TEST(EvaluatorTests, InstantiateGraphRegion) {
|
|||
|
||||
TEST(EvaluatorTests, InstantiateCycle) {
|
||||
StringRef module = "!ty = !om.class.type<@LinkedList>"
|
||||
"om.class @LinkedList(%n: !ty) {"
|
||||
" om.class.field @n, %n : !ty"
|
||||
"om.class @LinkedList(%n: !ty) -> (n: !ty){"
|
||||
" om.class.fields %n : !ty"
|
||||
"}"
|
||||
"om.class @ReferenceEachOther() {"
|
||||
"om.class @ReferenceEachOther() -> (field: !ty){"
|
||||
" %val = om.object.field %0, [@n] : (!ty) -> !ty"
|
||||
" %0 = om.object @LinkedList(%val) : (!ty) -> !ty"
|
||||
" om.class.field @field, %0 : !ty"
|
||||
" om.class.fields %0 : !ty"
|
||||
"}";
|
||||
|
||||
DialectRegistry registry;
|
||||
|
@ -614,12 +660,13 @@ TEST(EvaluatorTests, InstantiateCycle) {
|
|||
}
|
||||
|
||||
TEST(EvaluatorTests, IntegerBinaryArithmeticAdd) {
|
||||
StringRef mod = "om.class @IntegerBinaryArithmeticAdd() {"
|
||||
" %0 = om.constant #om.integer<1 : si3> : !om.integer"
|
||||
" %1 = om.constant #om.integer<2 : si3> : !om.integer"
|
||||
" %2 = om.integer.add %0, %1 : !om.integer"
|
||||
" om.class.field @result, %2 : !om.integer"
|
||||
"}";
|
||||
StringRef mod =
|
||||
"om.class @IntegerBinaryArithmeticAdd() -> (result: !om.integer) {"
|
||||
" %0 = om.constant #om.integer<1 : si3> : !om.integer"
|
||||
" %1 = om.constant #om.integer<2 : si3> : !om.integer"
|
||||
" %2 = om.integer.add %0, %1 : !om.integer"
|
||||
" om.class.fields %2 : !om.integer"
|
||||
"}";
|
||||
|
||||
DialectRegistry registry;
|
||||
registry.insert<OMDialect>();
|
||||
|
@ -648,12 +695,13 @@ TEST(EvaluatorTests, IntegerBinaryArithmeticAdd) {
|
|||
}
|
||||
|
||||
TEST(EvaluatorTests, IntegerBinaryArithmeticMul) {
|
||||
StringRef mod = "om.class @IntegerBinaryArithmeticMul() {"
|
||||
" %0 = om.constant #om.integer<2 : si3> : !om.integer"
|
||||
" %1 = om.constant #om.integer<3 : si3> : !om.integer"
|
||||
" %2 = om.integer.mul %0, %1 : !om.integer"
|
||||
" om.class.field @result, %2 : !om.integer"
|
||||
"}";
|
||||
StringRef mod =
|
||||
"om.class @IntegerBinaryArithmeticMul() -> (result: !om.integer) {"
|
||||
" %0 = om.constant #om.integer<2 : si3> : !om.integer"
|
||||
" %1 = om.constant #om.integer<3 : si3> : !om.integer"
|
||||
" %2 = om.integer.mul %0, %1 : !om.integer"
|
||||
" om.class.fields %2 : !om.integer"
|
||||
"}";
|
||||
|
||||
DialectRegistry registry;
|
||||
registry.insert<OMDialect>();
|
||||
|
@ -682,12 +730,13 @@ TEST(EvaluatorTests, IntegerBinaryArithmeticMul) {
|
|||
}
|
||||
|
||||
TEST(EvaluatorTests, IntegerBinaryArithmeticShr) {
|
||||
StringRef mod = "om.class @IntegerBinaryArithmeticShr() {"
|
||||
" %0 = om.constant #om.integer<8 : si5> : !om.integer"
|
||||
" %1 = om.constant #om.integer<2 : si3> : !om.integer"
|
||||
" %2 = om.integer.shr %0, %1 : !om.integer"
|
||||
" om.class.field @result, %2 : !om.integer"
|
||||
"}";
|
||||
StringRef mod =
|
||||
"om.class @IntegerBinaryArithmeticShr() -> (result: !om.integer){"
|
||||
" %0 = om.constant #om.integer<8 : si5> : !om.integer"
|
||||
" %1 = om.constant #om.integer<2 : si3> : !om.integer"
|
||||
" %2 = om.integer.shr %0, %1 : !om.integer"
|
||||
" om.class.fields %2 : !om.integer"
|
||||
"}";
|
||||
|
||||
DialectRegistry registry;
|
||||
registry.insert<OMDialect>();
|
||||
|
@ -716,12 +765,13 @@ TEST(EvaluatorTests, IntegerBinaryArithmeticShr) {
|
|||
}
|
||||
|
||||
TEST(EvaluatorTests, IntegerBinaryArithmeticShrNegative) {
|
||||
StringRef mod = "om.class @IntegerBinaryArithmeticShrNegative() {"
|
||||
" %0 = om.constant #om.integer<8 : si5> : !om.integer"
|
||||
" %1 = om.constant #om.integer<-2 : si3> : !om.integer"
|
||||
" %2 = om.integer.shr %0, %1 : !om.integer"
|
||||
" om.class.field @result, %2 : !om.integer"
|
||||
"}";
|
||||
StringRef mod =
|
||||
"om.class @IntegerBinaryArithmeticShrNegative() -> (result: !om.integer){"
|
||||
" %0 = om.constant #om.integer<8 : si5> : !om.integer"
|
||||
" %1 = om.constant #om.integer<-2 : si3> : !om.integer"
|
||||
" %2 = om.integer.shr %0, %1 : !om.integer"
|
||||
" om.class.fields %2 : !om.integer"
|
||||
"}";
|
||||
|
||||
DialectRegistry registry;
|
||||
registry.insert<OMDialect>();
|
||||
|
@ -749,13 +799,14 @@ TEST(EvaluatorTests, IntegerBinaryArithmeticShrNegative) {
|
|||
}
|
||||
|
||||
TEST(EvaluatorTests, IntegerBinaryArithmeticShrTooLarge) {
|
||||
StringRef mod = "om.class @IntegerBinaryArithmeticShrTooLarge() {"
|
||||
" %0 = om.constant #om.integer<8 : si5> : !om.integer"
|
||||
" %1 = om.constant #om.integer<36893488147419100000 : si66> "
|
||||
": !om.integer"
|
||||
" %2 = om.integer.shr %0, %1 : !om.integer"
|
||||
" om.class.field @result, %2 : !om.integer"
|
||||
"}";
|
||||
StringRef mod =
|
||||
"om.class @IntegerBinaryArithmeticShrTooLarge() -> (result: !om.integer){"
|
||||
" %0 = om.constant #om.integer<8 : si5> : !om.integer"
|
||||
" %1 = om.constant #om.integer<36893488147419100000 : si66> "
|
||||
": !om.integer"
|
||||
" %2 = om.integer.shr %0, %1 : !om.integer"
|
||||
" om.class.fields %2 : !om.integer"
|
||||
"}";
|
||||
|
||||
DialectRegistry registry;
|
||||
registry.insert<OMDialect>();
|
||||
|
@ -784,12 +835,13 @@ TEST(EvaluatorTests, IntegerBinaryArithmeticShrTooLarge) {
|
|||
}
|
||||
|
||||
TEST(EvaluatorTests, IntegerBinaryArithmeticShl) {
|
||||
StringRef mod = "om.class @IntegerBinaryArithmeticShl() {"
|
||||
" %0 = om.constant #om.integer<8 : si7> : !om.integer"
|
||||
" %1 = om.constant #om.integer<2 : si3> : !om.integer"
|
||||
" %2 = om.integer.shl %0, %1 : !om.integer"
|
||||
" om.class.field @result, %2 : !om.integer"
|
||||
"}";
|
||||
StringRef mod =
|
||||
"om.class @IntegerBinaryArithmeticShl() -> (result: !om.integer){"
|
||||
" %0 = om.constant #om.integer<8 : si7> : !om.integer"
|
||||
" %1 = om.constant #om.integer<2 : si3> : !om.integer"
|
||||
" %2 = om.integer.shl %0, %1 : !om.integer"
|
||||
" om.class.fields %2 : !om.integer"
|
||||
"}";
|
||||
|
||||
DialectRegistry registry;
|
||||
registry.insert<OMDialect>();
|
||||
|
@ -818,11 +870,12 @@ TEST(EvaluatorTests, IntegerBinaryArithmeticShl) {
|
|||
}
|
||||
|
||||
TEST(EvaluatorTests, IntegerBinaryArithmeticShlNegative) {
|
||||
StringRef mod = "om.class @IntegerBinaryArithmeticShlNegative() {"
|
||||
StringRef mod = "om.class @IntegerBinaryArithmeticShlNegative() -> (result: "
|
||||
"!om.integer) {"
|
||||
" %0 = om.constant #om.integer<8 : si5> : !om.integer"
|
||||
" %1 = om.constant #om.integer<-2 : si3> : !om.integer"
|
||||
" %2 = om.integer.shl %0, %1 : !om.integer"
|
||||
" om.class.field @result, %2 : !om.integer"
|
||||
" om.class.fields %2 : !om.integer"
|
||||
"}";
|
||||
|
||||
DialectRegistry registry;
|
||||
|
@ -851,12 +904,13 @@ TEST(EvaluatorTests, IntegerBinaryArithmeticShlNegative) {
|
|||
}
|
||||
|
||||
TEST(EvaluatorTests, IntegerBinaryArithmeticShlTooLarge) {
|
||||
StringRef mod = "om.class @IntegerBinaryArithmeticShlTooLarge() {"
|
||||
StringRef mod = "om.class @IntegerBinaryArithmeticShlTooLarge() -> (result: "
|
||||
"!om.integer) {"
|
||||
" %0 = om.constant #om.integer<8 : si5> : !om.integer"
|
||||
" %1 = om.constant #om.integer<36893488147419100000 : si66> "
|
||||
": !om.integer"
|
||||
" %2 = om.integer.shl %0, %1 : !om.integer"
|
||||
" om.class.field @result, %2 : !om.integer"
|
||||
" om.class.fields %2 : !om.integer"
|
||||
"}";
|
||||
|
||||
DialectRegistry registry;
|
||||
|
@ -886,28 +940,29 @@ TEST(EvaluatorTests, IntegerBinaryArithmeticShlTooLarge) {
|
|||
}
|
||||
|
||||
TEST(EvaluatorTests, IntegerBinaryArithmeticObjects) {
|
||||
StringRef mod = "om.class @Class1() {"
|
||||
" %0 = om.constant #om.integer<1 : si3> : !om.integer"
|
||||
" om.class.field @value, %0 : !om.integer"
|
||||
"}"
|
||||
""
|
||||
"om.class @Class2() {"
|
||||
" %0 = om.constant #om.integer<2 : si3> : !om.integer"
|
||||
" om.class.field @value, %0 : !om.integer"
|
||||
"}"
|
||||
""
|
||||
"om.class @IntegerBinaryArithmeticObjects() {"
|
||||
" %0 = om.object @Class1() : () -> !om.class.type<@Class1>"
|
||||
" %1 = om.object.field %0, [@value] : "
|
||||
"(!om.class.type<@Class1>) -> !om.integer"
|
||||
""
|
||||
" %2 = om.object @Class2() : () -> !om.class.type<@Class2>"
|
||||
" %3 = om.object.field %2, [@value] : "
|
||||
"(!om.class.type<@Class2>) -> !om.integer"
|
||||
""
|
||||
" %5 = om.integer.add %1, %3 : !om.integer"
|
||||
" om.class.field @result, %5 : !om.integer"
|
||||
"}";
|
||||
StringRef mod =
|
||||
"om.class @Class1() -> (value: !om.integer){"
|
||||
" %0 = om.constant #om.integer<1 : si3> : !om.integer"
|
||||
" om.class.fields %0 : !om.integer"
|
||||
"}"
|
||||
""
|
||||
"om.class @Class2() -> (value: !om.integer){"
|
||||
" %0 = om.constant #om.integer<2 : si3> : !om.integer"
|
||||
" om.class.fields %0 : !om.integer"
|
||||
"}"
|
||||
""
|
||||
"om.class @IntegerBinaryArithmeticObjects() -> (result: !om.integer) {"
|
||||
" %0 = om.object @Class1() : () -> !om.class.type<@Class1>"
|
||||
" %1 = om.object.field %0, [@value] : "
|
||||
"(!om.class.type<@Class1>) -> !om.integer"
|
||||
""
|
||||
" %2 = om.object @Class2() : () -> !om.class.type<@Class2>"
|
||||
" %3 = om.object.field %2, [@value] : "
|
||||
"(!om.class.type<@Class2>) -> !om.integer"
|
||||
""
|
||||
" %5 = om.integer.add %1, %3 : !om.integer"
|
||||
" om.class.fields %5 : !om.integer"
|
||||
"}";
|
||||
|
||||
DialectRegistry registry;
|
||||
registry.insert<OMDialect>();
|
||||
|
@ -937,18 +992,19 @@ TEST(EvaluatorTests, IntegerBinaryArithmeticObjects) {
|
|||
|
||||
TEST(EvaluatorTests, IntegerBinaryArithmeticObjectsDelayed) {
|
||||
StringRef mod =
|
||||
"om.class @Class1(%input: !om.integer) {"
|
||||
"om.class @Class1(%input: !om.integer) -> (value: !om.integer, input: "
|
||||
"!om.integer) {"
|
||||
" %0 = om.constant #om.integer<1 : si3> : !om.integer"
|
||||
" om.class.field @value, %0 : !om.integer"
|
||||
" om.class.field @input, %input : !om.integer"
|
||||
" om.class.fields %0, %input : !om.integer, !om.integer"
|
||||
"}"
|
||||
""
|
||||
"om.class @Class2() {"
|
||||
"om.class @Class2() -> (value: !om.integer){"
|
||||
" %0 = om.constant #om.integer<2 : si3> : !om.integer"
|
||||
" om.class.field @value, %0 : !om.integer"
|
||||
" om.class.fields %0 : !om.integer"
|
||||
"}"
|
||||
""
|
||||
"om.class @IntegerBinaryArithmeticObjectsDelayed() {"
|
||||
"om.class @IntegerBinaryArithmeticObjectsDelayed() -> (result: "
|
||||
"!om.integer){"
|
||||
" %0 = om.object @Class1(%5) : (!om.integer) -> !om.class.type<@Class1>"
|
||||
" %1 = om.object.field %0, [@value] : "
|
||||
"(!om.class.type<@Class1>) -> !om.integer"
|
||||
|
@ -958,7 +1014,7 @@ TEST(EvaluatorTests, IntegerBinaryArithmeticObjectsDelayed) {
|
|||
"(!om.class.type<@Class2>) -> !om.integer"
|
||||
""
|
||||
" %5 = om.integer.add %1, %3 : !om.integer"
|
||||
" om.class.field @result, %5 : !om.integer"
|
||||
" om.class.fields %5 : !om.integer"
|
||||
"}";
|
||||
|
||||
DialectRegistry registry;
|
||||
|
@ -988,11 +1044,12 @@ TEST(EvaluatorTests, IntegerBinaryArithmeticObjectsDelayed) {
|
|||
}
|
||||
|
||||
TEST(EvaluatorTests, IntegerBinaryArithmeticWidthMismatch) {
|
||||
StringRef mod = "om.class @IntegerBinaryArithmeticWidthMismatch() {"
|
||||
StringRef mod = "om.class @IntegerBinaryArithmeticWidthMismatch() -> "
|
||||
"(result: !om.integer) {"
|
||||
" %0 = om.constant #om.integer<1 : si3> : !om.integer"
|
||||
" %1 = om.constant #om.integer<2 : si4> : !om.integer"
|
||||
" %2 = om.integer.add %0, %1 : !om.integer"
|
||||
" om.class.field @result, %2 : !om.integer"
|
||||
" om.class.fields %2 : !om.integer"
|
||||
"}";
|
||||
|
||||
DialectRegistry registry;
|
||||
|
@ -1022,14 +1079,14 @@ TEST(EvaluatorTests, IntegerBinaryArithmeticWidthMismatch) {
|
|||
}
|
||||
|
||||
TEST(EvaluatorTests, ListConcat) {
|
||||
StringRef mod = "om.class @ListConcat() {"
|
||||
StringRef mod = "om.class @ListConcat() -> (result: !om.list<!om.integer>) {"
|
||||
" %0 = om.constant #om.integer<0 : i8> : !om.integer"
|
||||
" %1 = om.constant #om.integer<1 : i8> : !om.integer"
|
||||
" %2 = om.constant #om.integer<2 : i8> : !om.integer"
|
||||
" %l0 = om.list_create %0, %1 : !om.integer"
|
||||
" %l1 = om.list_create %2 : !om.integer"
|
||||
" %concat = om.list_concat %l0, %l1 : !om.list<!om.integer>"
|
||||
" om.class.field @result, %concat : !om.list<!om.integer>"
|
||||
" om.class.fields %concat : !om.list<!om.integer>"
|
||||
"}";
|
||||
|
||||
DialectRegistry registry;
|
||||
|
@ -1075,12 +1132,12 @@ TEST(EvaluatorTests, ListConcat) {
|
|||
|
||||
TEST(EvaluatorTests, ListConcatField) {
|
||||
StringRef mod =
|
||||
"om.class @ListField() {"
|
||||
"om.class @ListField() -> (value: !om.list<!om.integer>) {"
|
||||
" %0 = om.constant #om.integer<2 : i8> : !om.integer"
|
||||
" %1 = om.list_create %0 : !om.integer"
|
||||
" om.class.field @value, %1 : !om.list<!om.integer>"
|
||||
" om.class.fields %1 : !om.list<!om.integer>"
|
||||
"}"
|
||||
"om.class @ListConcatField() {"
|
||||
"om.class @ListConcatField() -> (result: !om.list<!om.integer>){"
|
||||
" %listField = om.object @ListField() : () -> !om.class.type<@ListField>"
|
||||
" %0 = om.constant #om.integer<0 : i8> : !om.integer"
|
||||
" %1 = om.constant #om.integer<1 : i8> : !om.integer"
|
||||
|
@ -1088,7 +1145,7 @@ TEST(EvaluatorTests, ListConcatField) {
|
|||
" %l1 = om.object.field %listField, [@value] : "
|
||||
"(!om.class.type<@ListField>) -> !om.list<!om.integer>"
|
||||
" %concat = om.list_concat %l0, %l1 : !om.list<!om.integer>"
|
||||
" om.class.field @result, %concat : !om.list<!om.integer>"
|
||||
" om.class.fields %concat : !om.list<!om.integer>"
|
||||
"}";
|
||||
|
||||
DialectRegistry registry;
|
||||
|
|
Loading…
Reference in New Issue