Skip to content

Commit

Permalink
[OM] Add C API and Python bindings for EvaluatorValue::Reference. (#6785
Browse files Browse the repository at this point in the history
)

In some OM dialect constructs, it is possible to receive
EvaluatorValue::Reference values. In the Python bindings, where we are
converting an EvaluatorValue to a Python value, we need to dereference
the Reference, to get at the underlying EvaluatorValue that was set
during evaluation.

This adds the necessary C APIs, and updates the Python bindings to use
them. If we encounter a Reference, we dereference it and recursively
call the converter function.

A Python test was added using an example IR from the Evaluator unit
tests, which delays evaluation and introduces references.
  • Loading branch information
mikeurbach authored Mar 5, 2024
1 parent 23eb8c3 commit 675716b
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 0 deletions.
9 changes: 9 additions & 0 deletions include/circt-c/Dialect/OM.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,15 @@ omEvaluatorValueIsAPath(OMEvaluatorValue evaluatorValue);
MLIR_CAPI_EXPORTED MlirAttribute
omEvaluatorPathGetAsString(OMEvaluatorValue evaluatorValue);

/// Query if the EvaluatorValue is a Reference.
MLIR_CAPI_EXPORTED bool
omEvaluatorValueIsAReference(OMEvaluatorValue evaluatorValue);

/// Dereference a Reference EvaluatorValue. Emits an error and returns null if
/// the Reference cannot be dereferenced.
MLIR_CAPI_EXPORTED OMEvaluatorValue
omEvaluatorValueGetReferenceValue(OMEvaluatorValue evaluatorValue);

//===----------------------------------------------------------------------===//
// ReferenceAttr API
//===----------------------------------------------------------------------===//
Expand Down
27 changes: 27 additions & 0 deletions integration_test/Bindings/Python/dialects/om.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,28 @@
%3 = om.frozenpath_empty
om.class.field @deleted, %3 : !om.frozenpath
}
om.class @Class1(%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 @Class2() {
%0 = om.constant #om.integer<2 : si3> : !om.integer
om.class.field @value, %0 : !om.integer
}
om.class @IntegerBinaryArithmeticObjectsDelayed() {
%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
}
}
""")

Expand Down Expand Up @@ -232,3 +254,8 @@
]
for paths_field in paths_fields:
assert isinstance(paths_field.value.type, om.PathType)

delayed = evaluator.instantiate("IntegerBinaryArithmeticObjectsDelayed")

# CHECK: 3
print(delayed.result)
4 changes: 4 additions & 0 deletions lib/Bindings/Python/OMModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,10 @@ PythonValue omEvaluatorValueToPythonValue(OMEvaluatorValue result) {
if (omEvaluatorValueIsAPath(result))
return Path(result);

if (omEvaluatorValueIsAReference(result))
return omEvaluatorValueToPythonValue(
omEvaluatorValueGetReferenceValue(result));

// If the field was a primitive, return the Attribute.
assert(omEvaluatorValueIsAPrimitive(result));
return omEvaluatorValueGetPrimitive(result);
Expand Down
25 changes: 25 additions & 0 deletions lib/CAPI/Dialect/OM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,31 @@ MlirAttribute omEvaluatorPathGetAsString(OMEvaluatorValue evaluatorValue) {
return wrap((Attribute)path->getAsString());
}

/// Query if the EvaluatorValue is a Reference.
bool omEvaluatorValueIsAReference(OMEvaluatorValue evaluatorValue) {
return isa<evaluator::ReferenceValue>(unwrap(evaluatorValue).get());
}

/// Dereference a Reference EvaluatorValue. Emits an error and returns null if
/// the Reference cannot be dereferenced.
OMEvaluatorValue
omEvaluatorValueGetReferenceValue(OMEvaluatorValue evaluatorValue) {
// Assert the EvaluatorValue is a Reference.
assert(omEvaluatorValueIsAReference(evaluatorValue));

// Attempt to get the final EvaluatorValue from the Reference.
auto result =
llvm::cast<evaluator::ReferenceValue>(unwrap(evaluatorValue).get())
->getStrippedValue();

// If this failed, an error diagnostic has been emitted, and we return null.
if (failed(result))
return {};

// If this succeeded, wrap the EvaluatorValue and return it.
return wrap(result.value());
}

//===----------------------------------------------------------------------===//
// ReferenceAttr API.
//===----------------------------------------------------------------------===//
Expand Down

0 comments on commit 675716b

Please sign in to comment.