Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[OM] Rework ClassOp to use fields terminator #7537

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/circt/Dialect/OM/OMOpInterfaces.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
25 changes: 9 additions & 16 deletions include/circt/Dialect/OM/OMOpInterfaces.td
Original file line number Diff line number Diff line change
Expand Up @@ -33,26 +33,19 @@ def ClassLike : OpInterface<"ClassLike"> {
"mlir::ArrayAttr", "getFormalParamNames", (ins)>,
InterfaceMethod<"Get the class-like formal parameter names attribute name",
leonardt marked this conversation as resolved.
Show resolved Hide resolved
"mlir::StringAttr", "getFormalParamNamesAttrName", (ins)>,
InterfaceMethod<"Get the class-like dictionary mapping field names to type",
"mlir::DictionaryAttr", "getFieldTypes", (ins)>,
InterfaceMethod<"Get the class-like body region",
"mlir::Region &", "getBody", (ins)>,
InterfaceMethod<"Get the class-like body block",
"mlir::Block *", "getBodyBlock", (ins),
/*methodBody=*/[{ return $_op.getBodyBlock(); }]>
];
}

def ClassFieldLike : OpInterface<"ClassFieldLike"> {
let cppNamespace = "circt::om";

let description = [{
Common functionality for class-like field operations.
}];

let methods = [
InterfaceMethod<"Get the class-like field's type",
"mlir::Type", "getType", (ins)>,
InterfaceMethod<"Get the class-like field's name attribute",
"mlir::StringAttr", "getNameAttr", (ins)>
/*methodBody=*/[{ return $_op.getBodyBlock(); }]>,
InterfaceMethod<"Get the class-like field type",
"std::optional<mlir::Type>", "getFieldType", (ins "mlir::StringAttr":$field)>,
InterfaceMethod<"Get the class-like field names",
"mlir::ArrayAttr", "getFieldNames", (ins)>,
InterfaceMethod<"Replace field types dictionary attr",
"void", "replaceFieldTypes", (ins "mlir::AttrTypeReplacer":$replacer)>,
];
}

Expand Down
1 change: 1 addition & 0 deletions include/circt/Dialect/OM/OMOps.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
78 changes: 45 additions & 33 deletions include/circt/Dialect/OM/OMOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -33,40 +34,65 @@ class OMOp<string mnemonic, list<Trait> traits = []> :

class OMClassLike<string mnemonic, list<Trait> traits = []> :
OMOp<mnemonic, traits # [
SingleBlock, NoTerminator, Symbol, RegionKindInterface, IsolatedFromAbove,
Symbol, RegionKindInterface, IsolatedFromAbove,
DeclareOpInterfaceMethods<OpAsmOpInterface, ["getAsmBlockArgumentNames"]>,
DeclareOpInterfaceMethods<ClassLike>]> {

let arguments = (ins
SymbolNameAttr:$sym_name,
StrArrayAttr:$formalParamNames
StrArrayAttr:$formalParamNames,
ArrayAttr:$fieldNames,
DictionaryAttr:$fieldTypes
);

let regions = (region
SizedRegion<1>:$body
);

let builders = [
OpBuilder<(ins "::mlir::Twine":$name)>,
OpBuilder<(ins "::mlir::Twine":$name,
"::mlir::ArrayRef<::mlir::StringRef>":$formalParamNames)>,
"::mlir::ArrayRef<::mlir::StringRef>":$formalParamNames,
"::mlir::DictionaryAttr":$fieldTypes)>,
OpBuilder<(ins "::mlir::Twine":$name,
"::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::DictionaryAttr":$fieldTypes), [{
build(odsBuilder, odsState, name, {}, fieldTypes);
}]>,
OpBuilder<(ins "::mlir::StringAttr":$name,
"::mlir::ArrayAttr":$formalParamNames), [{
build(odsBuilder, odsState, name, formalParamNames,
odsBuilder.getArrayAttr({}), odsBuilder.getDictionaryAttr({}));

}]>
];

let hasCustomAssemblyFormat = 1;

let hasVerifier = 1;
}

class OMClassFieldLike<string mnemonic, list<Trait> traits = []> :
OMOp<mnemonic, traits # [
DeclareOpInterfaceMethods<ClassFieldLike>]> {
}

//===----------------------------------------------------------------------===//
// Class definitions
//===----------------------------------------------------------------------===//

def ClassOp : OMClassLike<"class"> {
def ClassOp : OMClassLike<"class", [
SingleBlockImplicitTerminator<"ClassFieldsOp">]> {
let extraClassDeclaration = [{
mlir::Block *getBodyBlock() { return &getBody().front(); }
// This builds a ClassOp, and populates it with the CLassFieldOps.
Expand All @@ -82,26 +108,24 @@ def ClassOp : OMClassLike<"class"> {
static mlir::RegionKind getRegionKind(unsigned index) {
return mlir::RegionKind::Graph;
}

circt::om::ClassFieldsOp getFieldsOp() {
return mlir::cast<ClassFieldsOp>(this->getBodyBlock()->getTerminator());
}
}];
}

def ClassFieldOp : OMClassFieldLike<"class.field",
[HasParent<"ClassOp">]> {
let arguments = (ins
SymbolNameAttr:$name,
AnyType:$value
);

let assemblyFormat = [{
$name `,` $value attr-dict `:` type($value)
}];
def ClassFieldsOp : OMOp<"class.fields", [Terminator, ReturnLike, Pure,
HasParent<"ClassOp">]> {
let arguments = (ins Variadic<AnyType>:$fields);
let assemblyFormat = "attr-dict ($fields^ `:` qualified(type($fields)))?";
}

//===----------------------------------------------------------------------===//
// External class definitions
//===----------------------------------------------------------------------===//

def ClassExternOp : OMClassLike<"class.extern"> {
def ClassExternOp : OMClassLike<"class.extern", [NoTerminator]> {
let extraClassDeclaration = [{
mlir::Block *getBodyBlock() { return &getBody().front(); }

Expand All @@ -112,18 +136,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
//===----------------------------------------------------------------------===//
Expand Down
85 changes: 36 additions & 49 deletions integration_test/Bindings/Python/dialects/om.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,108 +14,95 @@

module = Module.parse("""
module {
om.class @node() {
om.class @node() -> (field2: !om.string) {
%0 = om.constant #om.list<!om.string,["MyThing" : !om.string]> : !om.list<!om.string>
%1 = om.constant "Component.inst1.foo" : !om.string
om.class.field @field2, %1 : !om.string
om.class.fields %1 : !om.string
}

om.class @comp(
%inst1_propOut_bore: !om.class.type<@node>,
%inst2_propOut_bore: !om.class.type<@node>) {
om.class.field @field2, %inst1_propOut_bore : !om.class.type<@node>
om.class.field @field3, %inst2_propOut_bore : !om.class.type<@node>
%inst2_propOut_bore: !om.class.type<@node>) -> (field2: !om.class.type<@node>, field3: !om.class.type<@node>) {
om.class.fields %inst1_propOut_bore, %inst2_propOut_bore : !om.class.type<@node>, !om.class.type<@node>
}

om.class @Client() {
om.class @Client() -> (client_omnode_0_OMIROut: !om.class.type<@comp>, node0_OMIROut : !om.class.type<@node>, node1_OMIROut : !om.class.type<@node>) {
%0 = om.object @node() : () -> !om.class.type<@node>
%2 = om.object @comp(%0, %0) : (!om.class.type<@node>, !om.class.type<@node>) -> !om.class.type<@comp>

om.class.field @client_omnode_0_OMIROut, %2 : !om.class.type<@comp>
om.class.field @node0_OMIROut, %0 : !om.class.type<@node>
om.class.field @node1_OMIROut, %0 : !om.class.type<@node>
om.class.fields %2, %0, %0 : !om.class.type<@comp>, !om.class.type<@node>, !om.class.type<@node>
}

om.class @Test(%param: !om.integer) {
om.class @Test(%param: !om.integer) -> (field: !om.integer, child: !om.class.type<@Child>, reference: !om.ref, list: !om.list<!om.string>, tuple: tuple<!om.list<!om.string>, !om.integer>, nest: !om.class.type<@Nest>, map: !om.map<!om.string, !om.integer>, map_create: !om.map<!om.string, !om.integer>, true: i1, false: i1) {
%sym = om.constant #om.ref<<@Root::@x>> : !om.ref
om.class.field @field, %param : !om.integer

%c_14 = om.constant #om.integer<14> : !om.integer
%0 = om.object @Child(%c_14) : (!om.integer) -> !om.class.type<@Child>
om.class.field @child, %0 : !om.class.type<@Child>

om.class.field @reference, %sym : !om.ref

%list = om.constant #om.list<!om.string, ["X" : !om.string, "Y" : !om.string]> : !om.list<!om.string>
om.class.field @list, %list : !om.list<!om.string>

%tuple = om.tuple_create %list, %c_14: !om.list<!om.string>, !om.integer
om.class.field @tuple, %tuple : tuple<!om.list<!om.string>, !om.integer>

%c_15 = om.constant #om.integer<15> : !om.integer
%1 = om.object @Child(%c_15) : (!om.integer) -> !om.class.type<@Child>
%list_child = om.list_create %0, %1: !om.class.type<@Child>
%2 = om.object @Nest(%list_child) : (!om.list<!om.class.type<@Child>>) -> !om.class.type<@Nest>
om.class.field @nest, %2 : !om.class.type<@Nest>

%3 = om.constant #om.map<!om.integer, {a = #om.integer<42>, b = #om.integer<32>}> : !om.map<!om.string, !om.integer>
om.class.field @map, %3 : !om.map<!om.string, !om.integer>

%x = om.constant "X" : !om.string
%y = om.constant "Y" : !om.string
%entry1 = om.tuple_create %x, %c_14: !om.string, !om.integer
%entry2 = om.tuple_create %y, %c_15: !om.string, !om.integer

%map = om.map_create %entry1, %entry2: !om.string, !om.integer
om.class.field @map_create, %map : !om.map<!om.string, !om.integer>

%true = om.constant true
om.class.field @true, %true : i1
%false = om.constant false
om.class.field @false, %false : i1

om.class.fields %param, %0, %sym, %list, %tuple, %2, %3, %map, %true, %false : !om.integer, !om.class.type<@Child>, !om.ref, !om.list<!om.string>, tuple<!om.list<!om.string>, !om.integer>, !om.class.type<@Nest>, !om.map<!om.string, !om.integer>, !om.map<!om.string, !om.integer>, i1, i1
}

om.class @Child(%0: !om.integer) {
om.class.field @foo, %0 : !om.integer
om.class @Child(%0: !om.integer) -> (foo: !om.integer) {
om.class.fields %0 : !om.integer
}

om.class @Nest(%0: !om.list<!om.class.type<@Child>>) {
om.class.field @list_child, %0 : !om.list<!om.class.type<@Child>>
om.class @Nest(%0: !om.list<!om.class.type<@Child>>) -> (list_child: !om.list<!om.class.type<@Child>>) {
om.class.fields %0 : !om.list<!om.class.type<@Child>>
}

hw.module @Root(in %clock: i1) {
%0 = sv.wire sym @x : !hw.inout<i1>
}

om.class @Paths(%basepath: !om.frozenbasepath) {
om.class @Paths(%basepath: !om.frozenbasepath) -> (path: !om.frozenpath, deleted: !om.frozenpath) {
%0 = om.frozenbasepath_create %basepath "Foo/bar"
%1 = om.frozenpath_create reference %0 "Bar/baz:Baz>w"
om.class.field @path, %1 : !om.frozenpath

%3 = om.frozenpath_empty
om.class.field @deleted, %3 : !om.frozenpath
om.class.fields %1, %3 : !om.frozenpath, !om.frozenpath
}

om.class @Class1(%input: !om.integer) {
om.class @Class1(%input: !om.integer) -> (value: !om.integer, input: !om.integer) {
%0 = om.constant #om.integer<1 : si3> : !om.integer
om.class.field @value, %0 : !om.integer
om.class.field @input, %input : !om.integer
om.class.fields %0, %input : !om.integer, !om.integer
}

om.class @Class2() {
om.class @Class2() -> (value: !om.integer) {
%0 = om.constant #om.integer<2 : si3> : !om.integer
om.class.field @value, %0 : !om.integer
om.class.fields %0 : !om.integer
}

om.class @IntegerBinaryArithmeticObjectsDelayed() {
om.class @IntegerBinaryArithmeticObjectsDelayed() -> (result: !om.integer) {
%0 = om.object @Class1(%5) : (!om.integer) -> !om.class.type<@Class1>
%1 = om.object.field %0, [@value] : (!om.class.type<@Class1>) -> !om.integer

%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
om.class.fields %5 : !om.integer
}
}
""")
Expand Down Expand Up @@ -157,23 +144,23 @@
print(obj.field)

# location of the om.class.field @field
# CHECK: loc("-":27:7)
print(obj.get_field_loc("field"))
# CHECK: loc("-":22:20)
print("field:", obj.get_field_loc("field"))

# CHECK: 14
print(obj.child.foo)
# CHECK: loc("-":65:7)
# CHECK: loc("-":53:21)
print(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("-":31:16)
print("tuple", obj.get_field_loc("tuple"))

# CHECK: loc("-":25:5)
# CHECK: loc("-":22:5)
print(obj.loc)

try:
Expand All @@ -185,13 +172,13 @@
for (name, field) in obj:
# location from om.class.field @child, %0 : !om.class.type<@Child>
# CHECK: name: child, field: <circt.dialects.om.Object object
# CHECK-SAME: loc: loc("-":30:12)
# CHECK-SAME: loc: loc("-":26:12)
# location from om.class.field @field, %param : !om.integer
# CHECK: name: field, field: 42
# CHECK-SAME: loc: loc("-":27:7)
# CHECK-SAME: loc: loc("-":22:20)
# location from om.class.field @reference, %sym : !om.ref
# CHECK: name: reference, field: ('Root', 'x')
# CHECK-SAME: loc: loc("-":33:7)
# CHECK-SAME: loc: loc("-":23:14)
loc = obj.get_field_loc(name)
print(f"name: {name}, field: {field}, loc: {loc}")

Expand Down Expand Up @@ -260,12 +247,12 @@
base_path_type = paths_class.regions[0].blocks[0].arguments[0].type
assert isinstance(base_path_type, om.BasePathType)

paths_fields = [
op for op in paths_class.regions[0].blocks[0]
if isinstance(op, om.ClassFieldOp)
]
for paths_field in paths_fields:
assert isinstance(paths_field.value.type, om.PathType)
paths_ops = paths_class.regions[0].blocks[0].operations
# NOTE: would be nice if this supported [-1] indexing syntax
class_fields_op = paths_ops[len(paths_ops) - 1]
assert len(class_fields_op.operands)
for arg in class_fields_op.operands:
assert isinstance(arg.type, om.PathType)

delayed = evaluator.instantiate("IntegerBinaryArithmeticObjectsDelayed")

Expand Down
Loading
Loading