diff --git a/include/circt/Dialect/OM/OMOpInterfaces.h b/include/circt/Dialect/OM/OMOpInterfaces.h index e09ff6aca3..5ca35de594 100644 --- a/include/circt/Dialect/OM/OMOpInterfaces.h +++ b/include/circt/Dialect/OM/OMOpInterfaces.h @@ -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" diff --git a/include/circt/Dialect/OM/OMOpInterfaces.td b/include/circt/Dialect/OM/OMOpInterfaces.td index 1934142a5a..4b5aa72c04 100644 --- a/include/circt/Dialect/OM/OMOpInterfaces.td +++ b/include/circt/Dialect/OM/OMOpInterfaces.td @@ -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", "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)>, ]; } diff --git a/include/circt/Dialect/OM/OMOps.h b/include/circt/Dialect/OM/OMOps.h index 7e766637e6..63e56a019b 100644 --- a/include/circt/Dialect/OM/OMOps.h +++ b/include/circt/Dialect/OM/OMOps.h @@ -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 diff --git a/include/circt/Dialect/OM/OMOps.td b/include/circt/Dialect/OM/OMOps.td index 9155d821b2..9e53f1a784 100644 --- a/include/circt/Dialect/OM/OMOps.td +++ b/include/circt/Dialect/OM/OMOps.td @@ -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 traits = []> : class OMClassLike traits = []> : OMOp, DeclareOpInterfaceMethods]> { let arguments = (ins SymbolNameAttr:$sym_name, - StrArrayAttr:$formalParamNames + StrArrayAttr:$formalParamNames, + ArrayAttr:$fieldNames, + DictionaryAttr:$fieldTypes ); let regions = (region @@ -47,9 +50,44 @@ class OMClassLike 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 traits = []> : let hasVerifier = 1; } -class OMClassFieldLike traits = []> : - OMOp]> { -} - //===----------------------------------------------------------------------===// // 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(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 + locs, mlir::ArrayRef 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:$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 //===----------------------------------------------------------------------===// diff --git a/integration_test/Bindings/Python/dialects/om.py b/integration_test/Bindings/Python/dialects/om.py index 2e2bce8a48..e7fa4ed4ec 100644 --- a/integration_test/Bindings/Python/dialects/om.py +++ b/integration_test/Bindings/Python/dialects/om.py @@ -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.list %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, tuple: tuple, !om.integer>, nest: !om.class.type<@Nest>, map: !om.map, map_create: !om.map, 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.list - om.class.field @list, %list : !om.list %tuple = om.tuple_create %list, %c_14: !om.list, !om.integer - om.class.field @tuple, %tuple : tuple, !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<@Nest> - om.class.field @nest, %2 : !om.class.type<@Nest> %3 = om.constant #om.map, b = #om.integer<32>}> : !om.map - om.class.field @map, %3 : !om.map %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 %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, tuple, !om.integer>, !om.class.type<@Nest>, !om.map, !om.map, 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.field @list_child, %0 : !om.list> + om.class @Nest(%0: !om.list>) -> (list_child: !om.list>) { + om.class.fields %0 : !om.list> } hw.module @Root(in %clock: i1) { %0 = sv.wire sym @x : !hw.inout } - 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: &fieldNames, + SmallVector &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 formalParamNames, + bool hasContainingModule) { + SmallVector fieldNames; + SmallVector fieldTypes; + for (unsigned i = 0, e = moduleLike.getNumPorts(); i < e; ++i) { + auto type = moduleLike.getPortType(i); + if (!isa(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( + moduleLike.getLoc(), name, formalParamNames, fieldNames, fieldTypes); +} + +static om::ClassLike convertClass(FModuleLike moduleLike, OpBuilder builder, + Twine name, + ArrayRef formalParamNames, + bool hasContainingModule) { + // Collect output property assignments to get field names and types. + SmallVector fieldNames; + SmallVector fieldTypes; + for (auto op : llvm::make_early_inc_range( + moduleLike->getRegion(0).getOps())) { + auto outputPort = dyn_cast(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(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(moduleLike.getOperation())) - loweredClassOp = builder.create( - moduleLike.getLoc(), className + suffix, formalParamNames); - else - loweredClassOp = builder.create( - moduleLike.getLoc(), className + suffix, formalParamNames); + if (isa( + 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 opsToErase; OpBuilder builder = OpBuilder::atBlockBegin(classOp.getBodyBlock()); + llvm::SmallVector fieldLocs; + llvm::SmallVector 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(op)) { + if (isa(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())) { - // Property assignments will currently be pointing back to the original - // FIRRTL Class for output ports. - auto outputPort = dyn_cast(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(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(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(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(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 &classTypeTable; }; -struct ClassFieldOpConversion : public OpConversionPattern { +struct ClassFieldsOpConversion : public OpConversionPattern { using OpConversionPattern::OpConversionPattern; LogicalResult - matchAndRewrite(ClassFieldOp op, OpAdaptor adaptor, + matchAndRewrite(ClassFieldsOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override { - rewriter.replaceOpWithNewOp(op, adaptor.getNameAttr(), - adaptor.getValue()); - return success(); - } -}; - -struct ClassExternFieldOpConversion - : public OpConversionPattern { - 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(op, adaptor.getNameAttr(), - type); + rewriter.replaceOpWithNewOp(op, adaptor.getOperands()); return success(); } }; @@ -1899,28 +1940,41 @@ struct ObjectOpConversion : public OpConversionPattern { } }; +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 { 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 op) { return !isa(op.getType()); }); - // OM Class ops are legal if they don't use FIRRTL types for block arguments. target.addDynamicallyLegalOp( [](Operation *op) -> std::optional { auto classLike = dyn_cast(op); if (!classLike) return std::nullopt; + auto fieldNames = classLike.getFieldNames(); + if (!llvm::all_of(fieldNames, [&](auto field) { + std::optional type = + classLike.getFieldType(cast(field)); + return type.has_value() && !isa(type.value()); + })) + return false; return llvm::none_of( classLike.getBodyBlock()->getArgumentTypes(), @@ -2115,8 +2156,7 @@ static void populateRewritePatterns( patterns.add(converter, patterns.getContext()); patterns.add(converter, patterns.getContext(), classTypeTable); - patterns.add(converter, patterns.getContext()); - patterns.add(converter, patterns.getContext()); + patterns.add(converter, patterns.getContext()); patterns.add(converter, patterns.getContext()); patterns.add(converter, patterns.getContext()); diff --git a/lib/Dialect/OM/Evaluator/Evaluator.cpp b/lib/Dialect/OM/Evaluator/Evaluator.cpp index e100a0e8d0..9eab2d736f 100644 --- a/lib/Dialect/OM/Evaluator/Evaluator.cpp +++ b/lib/Dialect/OM/Evaluator/Evaluator.cpp @@ -257,15 +257,18 @@ circt::om::Evaluator::evaluateObjectInstance(StringAttr className, worklist.push({result, actualParams}); } - for (auto field : cls.getOps()) { - 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 result = - evaluateValue(value, actualParams, field.getLoc()); + evaluateValue(value, actualParams, fieldLoc); if (failed(result)) return result; - fields[name] = result.value(); + fields[cast(name)] = result.value(); } // If the there is an instance, we must update the object value. diff --git a/lib/Dialect/OM/OMOps.cpp b/lib/Dialect/OM/OMOps.cpp index e635a37a9f..f10dc3072c 100644 --- a/lib/Dialect/OM/OMOps.cpp +++ b/lib/Dialect/OM/OMOps.cpp @@ -77,6 +77,37 @@ static void printPathString(OpAsmPrinter &p, Operation *op, PathAttr path, //===----------------------------------------------------------------------===// // Shared definitions //===----------------------------------------------------------------------===// +static ParseResult parseClassFieldsList(OpAsmParser &parser, + SmallVectorImpl &fieldNames, + SmallVectorImpl &fieldTypes) { + + llvm::StringMap 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 fieldTypes; + SmallVector fieldNames; + if (succeeded(parser.parseOptionalArrow())) + if (failed(parseClassFieldsList(parser, fieldNames, fieldTypes))) + return failure(); + + SmallVector fieldTypesMap; + if (!fieldNames.empty()) { + for (auto [name, type] : zip(fieldNames, fieldTypes)) + fieldTypesMap.push_back( + NamedAttribute(cast(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 fieldNames = + cast(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(fieldNames[i]); + printer.printKeywordOrString(name.getValue()); + printer << ": "; + Type type = classLike.getFieldType(name).value(); + printer.printType(type); + } + printer << ") "; + } + // Print the optional attribute dictionary. SmallVector elidedAttrs{classLike.getSymNameAttrName(), - classLike.getFormalParamNamesAttrName()}; + classLike.getFormalParamNamesAttrName(), + "fieldTypes", "fieldNames"}; printer.printOptionalAttrDictWithKeyword(classLike.getOperation()->getAttrs(), elidedAttrs); @@ -174,6 +240,32 @@ void getClassLikeAsmBlockArgumentNames(ClassLike classLike, Region ®ion, setNameFn(args[i], argNames[i]); } +NamedAttribute makeFieldType(StringAttr name, Type type) { + return NamedAttribute(name, TypeAttr::get(type)); +} + +NamedAttribute makeFieldIdx(MLIRContext *ctx, mlir::StringAttr name, + unsigned i) { + return NamedAttribute(StringAttr(name), + mlir::IntegerAttr::get(mlir::IndexType::get(ctx), i)); +} + +std::optional getClassLikeFieldType(ClassLike classLike, + StringAttr name) { + DictionaryAttr fieldTypes = mlir::cast( + classLike.getOperation()->getAttr("fieldTypes")); + Attribute type = fieldTypes.get(name); + if (!type) + return std::nullopt; + return cast(type).getValue(); +} + +void replaceClassLikeFieldTypes(ClassLike classLike, + AttrTypeReplacer &replacer) { + classLike->setAttr("fieldTypes", cast(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 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 formalParamNames, ArrayRef fieldNames, ArrayRef fieldTypes) { circt::om::ClassOp classOp = odsBuilder.create( 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(loc, name, - body->addArgument(type, loc)); + odsBuilder.create( + 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 +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 locs, + mlir::ArrayRef 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 locAttrs; + for (auto loc : locs) { + locAttrs.push_back(cast(LocationAttr(loc))); + } + // Also store the locations incase there's some other analysis that might + // be able to use the default FusedLoc representation. + builder.create( + 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(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(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(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 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(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 +circt::om::ClassExternOp::getFieldType(mlir::StringAttr field) { + return getClassLikeFieldType(*this, field); +} + +void circt::om::ClassExternOp::replaceFieldTypes(AttrTypeReplacer replacer) { + replaceClassLikeFieldTypes(*this, replacer); +} + //===----------------------------------------------------------------------===// // ObjectOp //===----------------------------------------------------------------------===// diff --git a/lib/Dialect/OM/Transforms/FreezePaths.cpp b/lib/Dialect/OM/Transforms/FreezePaths.cpp index 3156a445cb..90580cce3f 100644 --- a/lib/Dialect/OM/Transforms/FreezePaths.cpp +++ b/lib/Dialect/OM/Transforms/FreezePaths.cpp @@ -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(); } diff --git a/lib/Dialect/OM/Transforms/LinkModules.cpp b/lib/Dialect/OM/Transforms/LinkModules.cpp index aad9565602..76d8c17a84 100644 --- a/lib/Dialect/OM/Transforms/LinkModules.cpp +++ b/lib/Dialect/OM/Transforms/LinkModules.cpp @@ -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(op)) { // Update its class name if changed.. auto it = symMapping.find({module, objectOp.getClassNameAttr()}); @@ -170,10 +171,6 @@ static FailureOr resolveClasses(StringAttr name, return diag; }; - llvm::MapVector classFields; - for (auto fieldOp : classOp.getOps()) - classFields.insert({fieldOp.getNameAttr(), fieldOp.getType()}); - for (auto op : classes) { if (op == classOp) continue; @@ -193,25 +190,32 @@ static FailureOr resolveClasses(StringAttr name, } // Check declared fields. llvm::DenseSet declaredFields; - for (auto fieldOp : op.getBodyBlock()->getOps()) { - auto it = classFields.find(fieldOp.getNameAttr()); + + for (auto nameAttr : op.getFieldNames()) { + StringAttr name = cast(nameAttr); + std::optional opTypeOpt = op.getFieldType(name); + + if (!opTypeOpt.has_value()) + return emitError(op) << " no type for field " << name; + Type opType = opTypeOpt.value(); + + std::optional 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(fieldName))) return emitError(op) << "definition has a field " << fieldName << " but not found in this declaration"; } diff --git a/lib/Dialect/OM/Transforms/VerifyObjectFields.cpp b/lib/Dialect/OM/Transforms/VerifyObjectFields.cpp index 1377de5a48..7d912d28ff 100644 --- a/lib/Dialect/OM/Transforms/VerifyObjectFields.cpp +++ b/lib/Dialect/OM/Transforms/VerifyObjectFields.cpp @@ -49,36 +49,10 @@ void VerifyObjectFieldsPass::runOnOperation() { "op must have a single region and symbol table trait"); auto &symbolTable = getAnalysis(); - /// A map from a class and field name to a field. - llvm::MapVector> tables; - for (auto op : module->getRegion(0).getOps()) - tables.insert({op, llvm::DenseMap()}); - - // 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(), + [&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( objectField.getFieldPath().getAsRange()); 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 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(fieldDef.getType()); + auto classType = dyn_cast(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( + classDef = symbolTable.lookupNearestSymbolFrom( 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(); } diff --git a/test/CAPI/om.c b/test/CAPI/om.c index 2e78323826..c09d4e21bd 100644 --- a/test/CAPI/om.c +++ b/test/CAPI/om.c @@ -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, baz: " + "tuple, 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" - " om.class.field @foo, %0 : i64" - " om.class.field @bar, %2 : !om.list" - " om.class.field @baz, %3 : tuple, i64>" + " om.class.fields %0, %2, %3 : i64, !om.list, " + "tuple, i64>" " }" "}"; diff --git a/test/Dialect/FIRRTL/SFCTests/directories.fir b/test/Dialect/FIRRTL/SFCTests/directories.fir index 1c4c13fcd4..c5dab282fd 100644 --- a/test/Dialect/FIRRTL/SFCTests/directories.fir +++ b/test/Dialect/FIRRTL/SFCTests/directories.fir @@ -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, %inDut_in: i1, %extraPorts_in: !om.list> -; 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 -; MLIR_OUT: om.class.field @extraPorts, %extraPorts_in : !om.list> -; 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, %inDut_in: i1, %extraPorts_in: !om.list>, %preExtInstName_in: !om.list) -> (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, inDut: i1, extraPorts: !om.list>, preExtInstName: !om.list) +; 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, i1, !om.list>, !om.list +; 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 diff --git a/test/Dialect/FIRRTL/lower-classes.mlir b/test/Dialect/FIRRTL/lower-classes.mlir index 70dfce9a25..234438f924 100644 --- a/test/Dialect/FIRRTL/lower-classes.mlir +++ b/test/Dialect/FIRRTL/lower-classes.mlir @@ -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, + // CHECK-SAME: out_empty: !om.list, + // CHECK-SAME: out_nested: !om.list>, + // CHECK-SAME: out_objs: !om.list> + // 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> firrtl.propassign %out_objs, %objs : !firrtl.list> - // CHECK-NEXT: om.class.field @out_strings, %[[STRINGS]] : !om.list - // CHECK-NEXT: om.class.field @out_empty, %[[EMPTY]] : !om.list - // CHECK-NEXT: om.class.field @out_nested, %[[NESTED]] : !om.list> - // CHECK-NEXT: om.class.field @out_objs, %[[OBJS]] : !om.list + // CHECK-NEXT: om.class.fields %[[STRINGS]], %[[EMPTY]], %[[NESTED]], %[[OBJS]] : !om.list, !om.list, !om.list>, !om.list> } // 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) firrtl.module @ListCreate(in %propIn: !firrtl.integer, out %propOut: !firrtl.list) attributes {convention = #firrtl} { %0 = firrtl.integer 123 %1 = firrtl.list.create %propIn, %0 : !firrtl.list firrtl.propassign %propOut, %1 : !firrtl.list // 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 + // CHECK: om.class.fields %[[c1]] : !om.list } + // CHECK: -> (propOut: firrtl.module @ListConcat(in %propIn0: !firrtl.list, in %propIn1: !firrtl.list, out %propOut: !firrtl.list) { // CHECK: [[CONCAT:%.+]] = om.list_concat %propIn0, %propIn1 %1 = firrtl.list.concat %propIn0, %propIn1 : !firrtl.list - // CHECK: om.class.field @propOut, [[CONCAT]] + // CHECK: om.class.fields [[CONCAT]] firrtl.propassign %propOut, %1 : !firrtl.list } } @@ -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} { // 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>) + // CHECK-SAME: -> (containingModule: !om.path, ports: !om.list>) firrtl.class @NeedsRTLPorts(in %containingModule_in: !firrtl.path, out %containingModule: !firrtl.path) { + // CHECK: om.class.fields %containingModule_in, %ports : !om.path, !om.list> 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 + } diff --git a/test/Dialect/OM/errors.mlir b/test/Dialect/OM/errors.mlir index ac7cb79ebc..be83112130 100644 --- a/test/Dialect/OM/errors.mlir +++ b/test/Dialect/OM/errors.mlir @@ -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){ // 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 - om.class.field @list, %0 : !om.list + om.class.fields %0 : !om.list } // ----- @@ -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.class @Map(%map: !om.map, !om.string>) { + om.class.fields } // ----- @@ -108,6 +122,7 @@ om.class @Map(%map: !om.map, !om.string>) { om.class @Tuple(%tuple: tuple) { // expected-error @+1 {{tuple index out-of-bounds, must be less than 2 but got 2}} %val = om.tuple_get %tuple[2] : tuple + om.class.fields } // ----- @@ -115,24 +130,28 @@ om.class @Tuple(%tuple: tuple) { om.class @MapConstant() { // expected-error @+1 {{a value of a map attribute must have a type 'i64' but field "b" has '!om.list'}} %0 = om.constant #om.map}> : !om.map + 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 } diff --git a/test/Dialect/OM/freeze-paths-errors.mlir b/test/Dialect/OM/freeze-paths-errors.mlir index 5425127fea..c5e090e75c 100644 --- a/test/Dialect/OM/freeze-paths-errors.mlir +++ b/test/Dialect/OM/freeze-paths-errors.mlir @@ -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 } diff --git a/test/Dialect/OM/freeze-paths.mlir b/test/Dialect/OM/freeze-paths.mlir index bc9733a35f..a27a676b49 100644 --- a/test/Dialect/OM/freeze-paths.mlir +++ b/test/Dialect/OM/freeze-paths.mlir @@ -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, basepath: !om.list, path: !om.list, nestedpath: !om.list>) +om.class @ListCreateTest(%notpath: i1, %basepath : !om.basepath, %path : !om.path) -> (notpath: !om.list, basepath: !om.list, path: !om.list, nestedpath: !om.list>) { // 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 %3 = om.list_create %2 : !om.list - // CHECK: om.class.field @notpath, [[NOT_PATH_LIST]] : !om.list - om.class.field @notpath, %0 : !om.list - - // CHECK: om.class.field @basepath, [[BASE_PATH_LIST]] : !om.list - om.class.field @basepath, %1 : !om.list - - // CHECK: om.class.field @path, [[PATH_LIST]] : !om.list - om.class.field @path, %2 : !om.list - - // CHECK: om.class.field @nestedpath, [[NESTED_PATH_LIST]] : !om.list> - om.class.field @nestedpath, %3 : !om.list> + // CHECK: om.class.fields [[NOT_PATH_LIST]], [[BASE_PATH_LIST]], [[PATH_LIST]], [[NESTED_PATH_LIST]] : !om.list, !om.list, !om.list, !om.list> + om.class.fields %0, %1, %2, %3 : !om.list, !om.list, !om.list, !om.list> } -// CHECK-LABEL om.class @PathListClass(%pathList: !om.list) -om.class @PathListClass(%pathList : !om.list) { - om.class.field @pathList, %pathList : !om.list +// CHECK-LABEL om.class @PathListClass(%pathList: !om.list) -> (pathList: !om.list +om.class @PathListClass(%pathList : !om.list) -> (pathList: !om.list) { + om.class.fields %pathList : !om.list } // CHECK-LABEL om.class @PathListTest(%arg: !om.list) @@ -111,16 +105,18 @@ om.class @PathListTest(%arg : !om.list) { %0 = om.list_create : !om.path // CHECK: om.object @PathListClass([[RES]]) : (!om.list) om.object @PathListClass(%0) : (!om.list) -> !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>) { // 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> %1 = om.object.field %0, [@nestedpath] : (!om.class.type<@PathTest>) -> !om.list> - // CHECK: om.class.field @subfield, [[SUBFIELD]] : !om.list> - om.class.field @subfield, %1 : !om.list> + // CHECK: om.class.fields [[SUBFIELD]] : !om.list> + om.class.fields %1 : !om.list> } diff --git a/test/Dialect/OM/link-modules-error.mlir b/test/Dialect/OM/link-modules-error.mlir index 3543bfc418..e322381320 100644 --- a/test/Dialect/OM/link-modules-error.mlir +++ b/test/Dialect/OM/link-modules-error.mlir @@ -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 } } } diff --git a/test/Dialect/OM/link-modules.mlir b/test/Dialect/OM/link-modules.mlir index 6d83a00c8e..75811ebdc6 100644 --- a/test/Dialect/OM/link-modules.mlir +++ b/test/Dialect/OM/link-modules.mlir @@ -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 + } } } diff --git a/test/Dialect/OM/round-trip.mlir b/test/Dialect/OM/round-trip.mlir index 575774c93f..ef4210dc33 100644 --- a/test/Dialect/OM/round-trip.mlir +++ b/test/Dialect/OM/round-trip.mlir @@ -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, list_i32: !om.list) +om.class @ListConstant() -> (list_i64: !om.list, list_i32: !om.list) { // CHECK: %[[const1:.+]] = om.constant #om.list : !om.list %0 = om.constant #om.list : !om.list - // CHECK: om.class.field @list_i64, %[[const1]] : !om.list - om.class.field @list_i64, %0 : !om.list // CHECK: %[[const2:.+]] = om.constant #om.list : !om.list %1 = om.constant #om.list : !om.list - // CHECK: om.class.field @list_i32, %[[const2]] : !om.list - om.class.field @list_i32, %1 : !om.list + + // CHECK: om.class.fields %[[const1]], %[[const2]] : !om.list, !om.list + om.class.fields %0, %1 : !om.list, !om.list } // CHECK-LABEL: @ListCreate -om.class @ListCreate() { +// CHECK-SAME: -> (list_field: !om.list>) +om.class @ListCreate() -> (list_field: !om.list>) { // 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.field @list_field, %list : !om.list> + // CHECK: om.class.fields [[list]] : !om.list> + om.class.fields %list : !om.list> } // 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.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.class @Map(%map: !om.map) { - om.class.field @field, %map : !om.map +// CHECK-SAME: -> (field: !om.map) +om.class @Map(%map: !om.map) -> (field: !om.map) { + // CHECK: om.class.fields %map : !om.map + om.class.fields %map : !om.map } // CHECK-LABEL: @Tuple -om.class @Tuple(%int: i1, %str: !om.string) { +// CHECK-SAME: -> (tuple: tuple, val: !om.string) +om.class @Tuple(%int: i1, %str: !om.string) -> (tuple: tuple, 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 - om.class.field @tuple, %tuple : tuple // CHECK-NEXT: %[[tuple_get:.+]] = om.tuple_get %[[tuple]][1] : tuple %val = om.tuple_get %tuple[1] : tuple - // 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, !om.string + om.class.fields %tuple, %val : tuple, !om.string } // CHECK-LABEL: @MapConstant -om.class @MapConstant() { +// CHECK-SAME: -> (map_i64: !om.map) +om.class @MapConstant() -> (map_i64: !om.map) { // CHECK: %[[const1:.+]] = om.constant #om.map : !om.map %0 = om.constant #om.map : !om.map - // CHECK: om.class.field @map_i64, %[[const1]] : !om.map - om.class.field @map_i64, %0 : !om.map + // CHECK: om.class.fields %[[const1]] : !om.map + om.class.fields %0 : !om.map } // CHECK-LABEL: @MapCreate -om.class @MapCreate(%e1: tuple>, %e2: tuple>) { +// CHECK-SAME: -> (map_field: !om.map>) +om.class @MapCreate(%e1: tuple>, %e2: tuple>) -> (map_field: !om.map>) { // 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.class.field @map_field, %map : !om.map> + // CHECK-NEXT: om.class.fields %[[map]] : !om.map> + om.class.fields %map : !om.map> } 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} // 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 } diff --git a/test/firtool/classes-dedupe.fir b/test/firtool/classes-dedupe.fir index 396c064dac..9a9341fa8e 100644 --- a/test/firtool/classes-dedupe.fir +++ b/test/firtool/classes-dedupe.fir @@ -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 output out_foo_4 : Inst + ; 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 : diff --git a/test/om-linker/Inputs/a.mlir b/test/om-linker/Inputs/a.mlir index ad6f2dd1d4..2f3cda74bc 100644 --- a/test/om-linker/Inputs/a.mlir +++ b/test/om-linker/Inputs/a.mlir @@ -1,5 +1,8 @@ module { om.class @A(%arg: i1) { + om.class.fields + } + om.class @Conflict(){ + om.class.fields } - om.class @Conflict(){} } diff --git a/test/om-linker/Inputs/b.mlir b/test/om-linker/Inputs/b.mlir index 7718987f03..009c3e495d 100644 --- a/test/om-linker/Inputs/b.mlir +++ b/test/om-linker/Inputs/b.mlir @@ -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(){} } diff --git a/test/om-linker/link.mlir b/test/om-linker/link.mlir index 2256c613cb..14e5b55e81 100644 --- a/test/om-linker/link.mlir +++ b/test/om-linker/link.mlir @@ -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: } diff --git a/unittests/Dialect/OM/Evaluator/EvaluatorTests.cpp b/unittests/Dialect/OM/Evaluator/EvaluatorTests.cpp index 18920b0cf4..a7576f2fa5 100644 --- a/unittests/Dialect/OM/Evaluator/EvaluatorTests.cpp +++ b/unittests/Dialect/OM/Evaluator/EvaluatorTests.cpp @@ -166,7 +166,9 @@ TEST(EvaluatorTests, GetFieldInvalidName) { builder.setInsertionPointToStart(&mod.getBodyRegion().front()); auto cls = builder.create("MyClass"); - cls.getBody().emplaceBlock(); + auto &body = cls.getBody().emplaceBlock(); + builder.setInsertionPointToStart(&body); + builder.create(loc, llvm::ArrayRef()); Evaluator evaluator(mod); @@ -240,12 +242,18 @@ TEST(EvaluatorTests, InstantiateObjectWithConstantField) { auto mod = builder.create(loc); builder.setInsertionPointToStart(&mod.getBodyRegion().front()); - auto cls = builder.create("MyClass"); + auto constantType = builder.getI32IntegerAttr(42); + auto cls = builder.create( + "MyClass", builder.getStrArrayAttr({"field"}), + builder.getDictionaryAttr({ + NamedAttribute(builder.getStringAttr("field"), constantType), + + })); auto &body = cls.getBody().emplaceBlock(); builder.setInsertionPointToStart(&body); auto constant = builder.create( - circt::om::IntegerAttr::get(&context, builder.getI32IntegerAttr(42))); - builder.create("field", constant); + circt::om::IntegerAttr::get(&context, constantType)); + builder.create(loc, SmallVector({constant})); Evaluator evaluator(mod); @@ -284,12 +292,19 @@ TEST(EvaluatorTests, InstantiateObjectWithChildObject) { params, fields, types); builder.setInsertionPointToStart(&mod.getBodyRegion().front()); - auto cls = builder.create("MyClass", params); + auto innerType = TypeAttr::get(ClassType::get( + builder.getContext(), mlir::FlatSymbolRefAttr::get(innerCls))); + auto cls = builder.create( + "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(innerCls, body.getArguments()); - builder.create("field", object); + builder.create(loc, SmallVector({object})); Evaluator evaluator(mod); @@ -337,7 +352,14 @@ TEST(EvaluatorTests, InstantiateObjectWithFieldAccess) { params, fields, types); builder.setInsertionPointToStart(&mod.getBodyRegion().front()); - auto cls = builder.create("MyClass", params); + auto innerType = TypeAttr::get(ClassType::get( + builder.getContext(), mlir::FlatSymbolRefAttr::get(innerCls))); + auto cls = builder.create( + "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(builder.getI32Type(), object, builder.getArrayAttr(FlatSymbolRefAttr::get( builder.getStringAttr("field")))); - builder.create("field", field); + builder.create(loc, SmallVector({field})); Evaluator evaluator(mod); @@ -383,15 +405,24 @@ TEST(EvaluatorTests, InstantiateObjectWithChildObjectMemoized) { builder.setInsertionPointToStart(&mod.getBodyRegion().front()); auto innerCls = builder.create("MyInnerClass"); - innerCls.getBody().emplaceBlock(); + auto &innerBody = innerCls.getBody().emplaceBlock(); + builder.setInsertionPointToStart(&innerBody); + builder.create(loc, llvm::ArrayRef()); builder.setInsertionPointToStart(&mod.getBodyRegion().front()); - auto cls = builder.create("MyClass"); + auto innerType = TypeAttr::get(ClassType::get( + builder.getContext(), mlir::FlatSymbolRefAttr::get(innerCls))); + auto cls = builder.create( + "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(innerCls, body.getArguments()); - builder.create("field1", object); - builder.create("field2", object); + builder.create(loc, SmallVector({object, object})); Evaluator evaluator(mod); @@ -443,15 +474,24 @@ TEST(EvaluatorTests, AnyCastObject) { builder.setInsertionPointToStart(&mod.getBodyRegion().front()); auto innerCls = builder.create("MyInnerClass"); - innerCls.getBody().emplaceBlock(); + auto &innerBody = innerCls.getBody().emplaceBlock(); + builder.setInsertionPointToStart(&innerBody); + builder.create(loc, llvm::ArrayRef()); builder.setInsertionPointToStart(&mod.getBodyRegion().front()); - auto cls = builder.create("MyClass"); + auto innerType = TypeAttr::get(ClassType::get( + builder.getContext(), mlir::FlatSymbolRefAttr::get(innerCls))); + auto cls = builder.create( + "MyClass", builder.getStrArrayAttr({"field"}), + builder.getDictionaryAttr({ + NamedAttribute(builder.getStringAttr("field"), innerType), + + })); auto &body = cls.getBody().emplaceBlock(); builder.setInsertionPointToStart(&body); auto object = builder.create(innerCls, body.getArguments()); auto cast = builder.create(object); - builder.create("field", cast); + builder.create(loc, SmallVector({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("MyClass", params); + auto innerType = TypeAttr::get(ClassType::get( + builder.getContext(), mlir::FlatSymbolRefAttr::get(innerCls))); + auto cls = builder.create( + "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(body.getArgument(0)); SmallVector objectParams = {cast}; auto object = builder.create(innerCls, objectParams); - builder.create("field", object); + builder.create(loc, SmallVector({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(); @@ -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(); @@ -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(); @@ -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(); @@ -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(); @@ -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(); @@ -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(); @@ -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) {" " %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.class.field @result, %concat : !om.list" + " om.class.fields %concat : !om.list" "}"; DialectRegistry registry; @@ -1075,12 +1132,12 @@ TEST(EvaluatorTests, ListConcat) { TEST(EvaluatorTests, ListConcatField) { StringRef mod = - "om.class @ListField() {" + "om.class @ListField() -> (value: !om.list) {" " %0 = om.constant #om.integer<2 : i8> : !om.integer" " %1 = om.list_create %0 : !om.integer" - " om.class.field @value, %1 : !om.list" + " om.class.fields %1 : !om.list" "}" - "om.class @ListConcatField() {" + "om.class @ListConcatField() -> (result: !om.list){" " %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" " %concat = om.list_concat %l0, %l1 : !om.list" - " om.class.field @result, %concat : !om.list" + " om.class.fields %concat : !om.list" "}"; DialectRegistry registry;