[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:
Lenny Truong 2024-10-21 17:15:36 -04:00 committed by GitHub
parent f85865eea9
commit 3a9ccf9583
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 890 additions and 635 deletions

View File

@ -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"

View File

@ -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)>,
];
}

View File

@ -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

View File

@ -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
//===----------------------------------------------------------------------===//

View File

@ -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")

View File

@ -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());

View File

@ -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.

View File

@ -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 &region,
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
//===----------------------------------------------------------------------===//

View File

@ -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();
}

View File

@ -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";
}

View File

@ -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();
}

View File

@ -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>"
" }"
"}";

View File

@ -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

View 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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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>>
}

View File

@ -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
}
}
}

View File

@ -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
}
}
}

View File

@ -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
}

View File

@ -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 :

View File

@ -1,5 +1,8 @@
module {
om.class @A(%arg: i1) {
om.class.fields
}
om.class @Conflict(){
om.class.fields
}
om.class @Conflict(){}
}

View File

@ -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(){}
}

View File

@ -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: }

View File

@ -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;