Skip to content

Commit de851dc

Browse files
authored
[OM] Clean up ObjectOfieldOp: Move away from symbols, remove a field path and VerifyObjectFields pass (#10303)
Replace FlatSymbolRefArrayAttr with StringAttr for field names, changing syntax from 'object, [@field]' to 'object["field"]'. Nested field access now requires chaining ObjectFieldOp instead of using an array path. This moves verification from the VerifyObjectFields pass into the ObjectFieldOp verifier itself by adding SymbolUserOpInterface, eliminating the need for a separate pass. The Evaluator is updated to handle StringAttr and dereference ReferenceValue.
1 parent 37dbfd0 commit de851dc

18 files changed

Lines changed: 131 additions & 270 deletions

File tree

include/circt/Dialect/OM/OMOps.td

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -238,18 +238,21 @@ def ElaboratedObjectOp : OMOp<"elaborated_object", [
238238
}];
239239
}
240240

241-
def ObjectFieldOp : OMOp<"object.field", [Pure]> {
241+
def ObjectFieldOp : OMOp<"object.field", [
242+
Pure,
243+
DeclareOpInterfaceMethods<SymbolUserOpInterface>
244+
]> {
242245
let arguments = (ins
243246
ClassType:$object,
244-
FlatSymbolRefArrayAttr:$fieldPath
247+
StrAttr:$field
245248
);
246249

247250
let results = (outs
248251
AnyType:$result
249252
);
250253

251254
let assemblyFormat = [{
252-
$object `,` $fieldPath attr-dict `:` functional-type($object, $result)
255+
$object `[` $field `]` attr-dict `:` functional-type($object, $result)
253256
}];
254257
}
255258

include/circt/Dialect/OM/OMPasses.td

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,6 @@ def LinkModules: Pass<"om-link-modules", "mlir::ModuleOp"> {
2525
}];
2626
}
2727

28-
def VerifyObjectFields: Pass<"om-verify-object-fields"> {
29-
let summary = "Verify fields of ObjectOp are valid";
30-
let description = [{
31-
Verify object fields are valid.
32-
}];
33-
}
34-
3528
def StripOMPass : Pass<"strip-om", "mlir::ModuleOp"> {
3629
let summary = "Remove OM information";
3730
let description = [{

integration_test/Bindings/Python/dialects/om.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,10 @@
8888
8989
om.class @IntegerBinaryArithmeticObjectsDelayed() -> (result: !om.integer) {
9090
%0 = om.object @Class1(%5) : (!om.integer) -> !om.class.type<@Class1>
91-
%1 = om.object.field %0, [@value] : (!om.class.type<@Class1>) -> !om.integer
91+
%1 = om.object.field %0["value"] : (!om.class.type<@Class1>) -> !om.integer
9292
9393
%2 = om.object @Class2() : () -> !om.class.type<@Class2>
94-
%3 = om.object.field %2, [@value] : (!om.class.type<@Class2>) -> !om.integer
94+
%3 = om.object.field %2["value"] : (!om.class.type<@Class2>) -> !om.integer
9595
9696
%5 = om.integer.add %1, %3 : !om.integer
9797
om.class.fields %5 : !om.integer
@@ -152,13 +152,13 @@
152152
print(obj.reference)
153153

154154
for (name, field) in obj:
155-
# location from om.class.field @child, %0 : !om.class.type<@Child>
155+
# location from om.class.field "child"
156156
# CHECK: name: child, field: <circt.dialects.om.Object object
157157
# CHECK-SAME: loc: loc("-":{{.*}}:{{.*}})
158-
# location from om.class.field @field, %param : !om.integer
158+
# location from om.class.field "field"
159159
# CHECK: name: field, field: 42
160160
# CHECK-SAME: loc: loc("-":{{.*}}:{{.*}})
161-
# location from om.class.field @reference, %sym : !om.ref
161+
# location from om.class.field "reference"
162162
# CHECK: name: reference, field: ('Root', 'x')
163163
# CHECK-SAME: loc: loc("-":{{.*}}:{{.*}})
164164
loc = obj.get_field_loc(name)

lib/Dialect/FIRRTL/Transforms/LowerClasses.cpp

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1463,13 +1463,10 @@ updateInstanceInClass(InstanceOp firrtlInstance, hw::HierPathOp hierPath,
14631463
if (!isa<PropertyType>(result.getType()))
14641464
continue;
14651465

1466-
// The path to the field is just this output's name.
1467-
auto objectFieldPath = builder.getArrayAttr({FlatSymbolRefAttr::get(
1468-
firrtlInstance.getPortNameAttr(result.getResultNumber()))});
1469-
14701466
// Create the field access.
14711467
auto objectField = om::ObjectFieldOp::create(
1472-
builder, object.getLoc(), result.getType(), object, objectFieldPath);
1468+
builder, object.getLoc(), result.getType(), object,
1469+
firrtlInstance.getPortNameAttr(result.getResultNumber()));
14731470

14741471
result.replaceAllUsesWith(objectField);
14751472
}
@@ -1967,11 +1964,9 @@ struct ObjectSubfieldOpConversion
19671964
if (element.direction == Direction::In)
19681965
return failure();
19691966

1970-
auto field = FlatSymbolRefAttr::get(element.name);
1971-
auto path = rewriter.getArrayAttr({field});
19721967
auto type = typeConverter->convertType(element.type);
19731968
rewriter.replaceOpWithNewOp<om::ObjectFieldOp>(op, type, adaptor.getInput(),
1974-
path);
1969+
element.name);
19751970
return success();
19761971
}
19771972

@@ -2067,7 +2062,7 @@ struct ObjectFieldOpConversion : public OpConversionPattern<om::ObjectFieldOp> {
20672062
return failure();
20682063

20692064
rewriter.replaceOpWithNewOp<om::ObjectFieldOp>(
2070-
op, type, adaptor.getObject(), adaptor.getFieldPathAttr());
2065+
op, type, adaptor.getObject(), adaptor.getFieldAttr());
20712066

20722067
return success();
20732068
}

lib/Dialect/OM/Evaluator/Evaluator.cpp

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -739,22 +739,24 @@ circt::om::Evaluator::evaluateObjectField(ObjectFieldOp op,
739739
return objectFieldValue;
740740
}
741741

742+
// If the result is a ReferenceValue, dereference it to get the actual object.
743+
if (auto *ref = llvm::dyn_cast<evaluator::ReferenceValue>(result.get())) {
744+
auto stripped = ref->getStrippedValue();
745+
if (failed(stripped))
746+
return failure();
747+
result = stripped.value();
748+
}
749+
742750
auto *currentObject = llvm::cast<evaluator::ObjectValue>(result.get());
743751

744-
// Iteratively access nested fields through the path until we reach the final
745-
// field in the path.
746-
evaluator::EvaluatorValuePtr finalField;
747-
for (auto field : op.getFieldPath().getAsRange<FlatSymbolRefAttr>()) {
748-
// `currentObject` might no be fully evaluated.
749-
if (!currentObject->getFields().contains(field.getAttr()))
750-
return objectFieldValue;
751-
752-
auto currentField = currentObject->getField(field.getAttr());
753-
finalField = currentField.value();
754-
if (auto *nextObject =
755-
llvm::dyn_cast<evaluator::ObjectValue>(finalField.get()))
756-
currentObject = nextObject;
757-
}
752+
auto field = op.getFieldAttr();
753+
754+
// `currentObject` might not be fully evaluated.
755+
if (!currentObject->getFields().contains(field))
756+
return objectFieldValue;
757+
758+
auto currentField = currentObject->getField(field);
759+
auto finalField = currentField.value();
758760

759761
if (!finalField->isFullyEvaluated())
760762
return objectFieldValue;

lib/Dialect/OM/OMOps.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,38 @@ circt::om::ObjectOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
579579
return success();
580580
}
581581

582+
//===----------------------------------------------------------------------===//
583+
// ObjectFieldOp
584+
//===----------------------------------------------------------------------===//
585+
586+
LogicalResult
587+
circt::om::ObjectFieldOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
588+
auto classType = getObject().getType();
589+
auto className = classType.getClassName().getAttr();
590+
591+
// Verify the referred-to class exists.
592+
auto classDef = dyn_cast_or_null<ClassLike>(
593+
symbolTable.lookupNearestSymbolFrom(*this, className));
594+
if (!classDef)
595+
return emitOpError("class ") << className << " was not found";
596+
597+
// Verify the field exists in the class.
598+
auto fieldName = getFieldAttr();
599+
std::optional<Type> fieldType = classDef.getFieldType(fieldName);
600+
if (!fieldType) {
601+
auto diag = emitOpError("referenced non-existent field ") << fieldName;
602+
diag.attachNote(classDef.getLoc()) << "class defined here";
603+
return diag;
604+
}
605+
606+
// Verify the result type matches the field type.
607+
if (getResult().getType() != fieldType.value())
608+
return emitOpError("expected type ")
609+
<< getResult().getType() << ", but accessed field has type "
610+
<< fieldType.value();
611+
return success();
612+
}
613+
582614
//===----------------------------------------------------------------------===//
583615
// ElaboratedObjectOp
584616
//===----------------------------------------------------------------------===//

lib/Dialect/OM/OMReductions.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -156,12 +156,8 @@ struct OMClassFieldPruner : public OpReduction<ClassOp> {
156156
if (!fieldOp)
157157
continue;
158158

159-
auto fieldPath = fieldOp.getFieldPath();
160-
if (fieldPath.empty())
161-
continue;
162-
163159
// Mark the accessed field as used.
164-
usedFields.insert(cast<FlatSymbolRefAttr>(fieldPath[0]).getAttr());
160+
usedFields.insert(fieldOp.getFieldAttr());
165161
}
166162
});
167163

lib/Dialect/OM/Transforms/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ add_circt_dialect_library(CIRCTOMTransforms
22
FreezePaths.cpp
33
LinkModules.cpp
44
StripOM.cpp
5-
VerifyObjectFields.cpp
65

76
DEPENDS
87
CIRCTOMTransformsIncGen

lib/Dialect/OM/Transforms/FreezePaths.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ LogicalResult PathVisitor::process(ObjectFieldOp objectFieldOp) {
292292
OpBuilder builder(objectFieldOp);
293293
auto newObjectFieldOp = ObjectFieldOp::create(
294294
builder, objectFieldOp.getLoc(), newResultType, objectFieldOp.getObject(),
295-
objectFieldOp.getFieldPath());
295+
objectFieldOp.getFieldAttr());
296296
objectFieldOp.replaceAllUsesWith(newObjectFieldOp.getResult());
297297
objectFieldOp->erase();
298298
return success();

lib/Dialect/OM/Transforms/VerifyObjectFields.cpp

Lines changed: 0 additions & 137 deletions
This file was deleted.

0 commit comments

Comments
 (0)