Skip to content
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
9 changes: 0 additions & 9 deletions include/circt-c/Dialect/OM.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,15 +197,6 @@ 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);

/// Query if the EvaluatorValue is Unknown.
MLIR_CAPI_EXPORTED bool
omEvaluatorValueIsUnknown(OMEvaluatorValue evaluatorValue);
Expand Down
213 changes: 19 additions & 194 deletions include/circt/Dialect/OM/Evaluator/Evaluator.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,9 @@
#include "mlir/IR/MLIRContext.h"
#include "mlir/IR/SymbolTable.h"
#include "mlir/Support/LogicalResult.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Debug.h"

#include <queue>
#include <utility>

namespace circt {
Expand All @@ -49,7 +47,7 @@ using ObjectFields = SmallDenseMap<StringAttr, EvaluatorValuePtr>;
class EvaluatorValue : public std::enable_shared_from_this<EvaluatorValue> {
public:
// Implement LLVM RTTI.
enum class Kind { Attr, Object, List, Reference, BasePath, Path };
enum class Kind { Attr, Object, List, BasePath, Path };
EvaluatorValue(MLIRContext *ctx, Kind kind, Location loc)
: kind(kind), ctx(ctx), loc(loc) {}
Kind getKind() const { return kind; }
Expand All @@ -61,14 +59,6 @@ class EvaluatorValue : public std::enable_shared_from_this<EvaluatorValue> {
void markFullyEvaluated() {
assert(!fullyEvaluated && "should not mark twice");
fullyEvaluated = true;
// Increment the counter if one is set.
if (fullyEvaluatedCounter)
++(*fullyEvaluatedCounter);
}

/// Set a counter to increment when this value becomes fully evaluated.
void setFullyEvaluatedCounter(uint64_t *counter) {
fullyEvaluatedCounter = counter;
}

/// Return true if the value is unknown (has unknown in its fan-in).
Expand All @@ -92,9 +82,6 @@ class EvaluatorValue : public std::enable_shared_from_this<EvaluatorValue> {
// Return a MLIR type which the value represents.
Type getType() const;

// Finalize the evaluator value. Strip intermidiate reference values.
LogicalResult finalize();

// Return the Location associated with the Value.
Location getLoc() const { return loc; }
// Set the Location associated with the Value.
Expand All @@ -110,51 +97,7 @@ class EvaluatorValue : public std::enable_shared_from_this<EvaluatorValue> {
MLIRContext *ctx;
Location loc;
bool fullyEvaluated = false;
bool finalized = false;
bool unknown = false;
uint64_t *fullyEvaluatedCounter = nullptr;
};

/// Values which can be used as pointers to different values.
/// ReferenceValue is replaced with its element and erased at the end of
/// evaluation.
class ReferenceValue : public EvaluatorValue {
public:
ReferenceValue(Type type, Location loc)
: EvaluatorValue(type.getContext(), Kind::Reference, loc), value(nullptr),
type(type) {}

// Implement LLVM RTTI.
static bool classof(const EvaluatorValue *e) {
return e->getKind() == Kind::Reference;
}

Type getValueType() const { return type; }
EvaluatorValuePtr getValue() const { return value; }
void setValue(EvaluatorValuePtr newValue) {
value = std::move(newValue);
markFullyEvaluated();
}

// Finalize the value.
LogicalResult finalizeImpl();

// Return the first non-reference value that is reachable from the reference.
FailureOr<EvaluatorValuePtr> getStrippedValue() const {
llvm::SmallPtrSet<ReferenceValue *, 4> visited;
auto currentValue = value;
while (auto *v = dyn_cast<ReferenceValue>(currentValue.get())) {
// Detect a cycle.
if (!visited.insert(v).second)
return failure();
currentValue = v->getValue();
}
return success(currentValue);
}

private:
EvaluatorValuePtr value;
Type type;
};

/// Values which can be directly representable by MLIR attributes.
Expand All @@ -172,9 +115,6 @@ class AttributeValue : public EvaluatorValue {
// Set Attribute for partially evaluated case.
LogicalResult setAttr(Attribute attr);

// Finalize the value.
LogicalResult finalizeImpl();

Type getType() const { return type; }

// Factory methods that create AttributeValue objects
Expand Down Expand Up @@ -205,19 +145,6 @@ class AttributeValue : public EvaluatorValue {
friend std::shared_ptr<EvaluatorValue> get(Type type, LocationAttr loc);
};

// This perform finalization to `value`.
static inline LogicalResult finalizeEvaluatorValue(EvaluatorValuePtr &value) {
if (failed(value->finalize()))
return failure();
if (auto *ref = llvm::dyn_cast<ReferenceValue>(value.get())) {
auto v = ref->getStrippedValue();
if (failed(v))
return v;
value = v.value();
}
return success();
}

/// A List which contains variadic length of elements with the same type.
class ListValue : public EvaluatorValue {
public:
Expand All @@ -233,9 +160,6 @@ class ListValue : public EvaluatorValue {
markFullyEvaluated();
}

// Finalize the value.
LogicalResult finalizeImpl();

// Partially evaluated value.
ListValue(om::ListType type, Location loc)
: EvaluatorValue(type.getContext(), Kind::List, loc), type(type) {}
Expand Down Expand Up @@ -299,9 +223,6 @@ class ObjectValue : public EvaluatorValue {
/// Get all the field names of the Object.
ArrayAttr getFieldNames();

// Finalize the evaluator value.
LogicalResult finalizeImpl();

private:
om::ClassLike cls;
llvm::SmallDenseMap<StringAttr, EvaluatorValuePtr> fields;
Expand All @@ -320,9 +241,6 @@ class BasePathValue : public EvaluatorValue {
/// Set the basepath which this path is relative to.
void setBasepath(const BasePathValue &basepath);

/// Finalize the evaluator value.
LogicalResult finalizeImpl() { return success(); }

/// Implement LLVM RTTI.
static bool classof(const EvaluatorValue *e) {
return e->getKind() == Kind::BasePath;
Expand Down Expand Up @@ -355,9 +273,6 @@ class PathValue : public EvaluatorValue {

void setBasepath(const BasePathValue &basepath);

// Finalize the evaluator value.
LogicalResult finalizeImpl() { return success(); }

/// Implement LLVM RTTI.
static bool classof(const EvaluatorValue *e) {
return e->getKind() == Kind::Path;
Expand Down Expand Up @@ -397,130 +312,43 @@ class Evaluator {
FailureOr<evaluator::EvaluatorValuePtr>
getPartiallyEvaluatedValue(Type type, Location loc);

using ActualParameters =
SmallVectorImpl<std::shared_ptr<evaluator::EvaluatorValue>> *;

using ObjectKey = std::pair<Value, ActualParameters>;

/// Get the number of fully evaluated nodes tracked by this evaluator.
uint64_t getFullyEvaluatedCount() const { return fullyEvaluatedCount; }

private:
bool isFullyEvaluated(Value value, ActualParameters key) {
return isFullyEvaluated({value, key});
}

bool isFullyEvaluated(ObjectKey key) {
auto val = objects.lookup(key);
return val && val->isFullyEvaluated();
}

/// Attach the evaluation counter to a newly created value.
void attachCounter(evaluator::EvaluatorValuePtr &value) {
if (value && !value->isFullyEvaluated())
value->setFullyEvaluatedCounter(&fullyEvaluatedCount);
}

FailureOr<evaluator::EvaluatorValuePtr>
instantiateImpl(StringAttr className,
ArrayRef<EvaluatorValuePtr> actualParams);

FailureOr<EvaluatorValuePtr>
getOrCreateValue(Value value, ActualParameters actualParams, Location loc);
FailureOr<EvaluatorValuePtr>
allocateObjectInstance(StringAttr clasName, ActualParameters actualParams);
FailureOr<EvaluatorValuePtr> getOrCreateValue(Value value, Location loc);

/// Evaluate a Value in a Class body according to the small expression grammar
/// described in the rationale document. The actual parameters are the values
/// supplied at the current instantiation of the Class being evaluated.
FailureOr<EvaluatorValuePtr>
evaluateValue(Value value, ActualParameters actualParams, Location loc);
/// described in the rationale document.
FailureOr<EvaluatorValuePtr> evaluateValue(Value value, Location loc);

/// Evaluator dispatch functions for the small expression grammar.
FailureOr<EvaluatorValuePtr> evaluateParameter(BlockArgument formalParam,
ActualParameters actualParams,
Location loc);

FailureOr<EvaluatorValuePtr>
evaluateConstant(ConstantOp op, ActualParameters actualParams, Location loc);

/// Instantiate an Object with its class name and actual parameters.
FailureOr<EvaluatorValuePtr>
evaluateObjectInstance(StringAttr className, ActualParameters actualParams,
Location loc, ObjectKey instanceKey = {});
FailureOr<EvaluatorValuePtr>
evaluateObjectInstance(ObjectOp op, ActualParameters actualParams);
/// Evaluate a class body with actual parameters.
FailureOr<EvaluatorValuePtr>
evaluateElaboratedObject(ElaboratedObjectOp op, ActualParameters actualParams,
Location loc);
FailureOr<EvaluatorValuePtr>
evaluateObjectField(ObjectFieldOp op, ActualParameters actualParams,
Location loc);
FailureOr<EvaluatorValuePtr> evaluateListCreate(ListCreateOp op,
ActualParameters actualParams,
Location loc);
FailureOr<EvaluatorValuePtr> evaluateListConcat(ListConcatOp op,
ActualParameters actualParams,
Location loc);
FailureOr<EvaluatorValuePtr>
evaluateIntegerBinary(IntegerBinaryOp op, ActualParameters actualParams,
Location loc);
FailureOr<EvaluatorValuePtr>
evaluateStringConcat(StringConcatOp op, ActualParameters actualParams,
Location loc);
FailureOr<EvaluatorValuePtr>
evaluateBinaryEquality(BinaryEqualityOp op, ActualParameters actualParams,
evaluateObjectInstance(StringAttr className,
ArrayRef<EvaluatorValuePtr> actualParams,
Location loc);
FailureOr<evaluator::EvaluatorValuePtr>
evaluateBasePathCreate(FrozenBasePathCreateOp op,
ActualParameters actualParams, Location loc);
FailureOr<evaluator::EvaluatorValuePtr>
evaluatePathCreate(FrozenPathCreateOp op, ActualParameters actualParams,
Location loc);
FailureOr<evaluator::EvaluatorValuePtr>
evaluateEmptyPath(FrozenEmptyPathOp op, ActualParameters actualParams,
Location loc);
FailureOr<evaluator::EvaluatorValuePtr>
evaluateUnknownValue(UnknownValueOp op, Location loc);

LogicalResult evaluatePropertyAssert(PropertyAssertOp op,
ActualParameters actualParams);
/// Evaluator dispatch functions for the small expression grammar.
FailureOr<EvaluatorValuePtr> evaluateOp(ConstantOp op, Location loc);
FailureOr<EvaluatorValuePtr> evaluateOp(ElaboratedObjectOp op, Location loc);
FailureOr<EvaluatorValuePtr> evaluateOp(ListCreateOp op, Location loc);
FailureOr<EvaluatorValuePtr> evaluateOp(ListConcatOp op, Location loc);
FailureOr<EvaluatorValuePtr> evaluateOp(FrozenBasePathCreateOp op,
Location loc);
FailureOr<EvaluatorValuePtr> evaluateOp(FrozenPathCreateOp op, Location loc);
FailureOr<EvaluatorValuePtr> evaluateOp(FrozenEmptyPathOp op, Location loc);
FailureOr<EvaluatorValuePtr> evaluateOp(UnknownValueOp op, Location loc);

FailureOr<evaluator::EvaluatorValuePtr> createUnknownValue(Type type,
Location loc);

FailureOr<ActualParameters>
createParametersFromOperands(ValueRange range, ActualParameters actualParams,
Location loc);

/// The symbol table for the IR module the Evaluator was constructed with.
/// Used to look up class definitions.
SymbolTable symbolTable;

/// This uniquely stores vectors that represent parameters.
SmallVector<
std::unique_ptr<SmallVector<std::shared_ptr<evaluator::EvaluatorValue>>>>
actualParametersBuffers;

/// Worklists that track values which need to be fully evaluated.
/// We use two worklists to detect cycles: process all items from one,
/// and if any become fully evaluated, swap and continue.
std::vector<ObjectKey> worklist;
std::vector<ObjectKey> nextWorklist;

/// A queue of pending property assertions to be evaluated after the worklist
/// is fully drained. Each entry is a (PropertyAssertOp, ActualParameters)
/// pair. Property assertions are deferred because their operands may be
/// ReferenceValues that are not yet resolved when the class body is first
/// processed.
std::queue<std::pair<PropertyAssertOp, ActualParameters>> pendingAsserts;

/// Evaluator value storage. Return an evaluator value for the given
/// instantiation context (a pair of Value and parameters).
DenseMap<ObjectKey, std::shared_ptr<evaluator::EvaluatorValue>> objects;

/// Counter for fully evaluated nodes.
uint64_t fullyEvaluatedCount = 0;
/// Evaluator value storage for the current instantiation.
DenseMap<Value, std::shared_ptr<evaluator::EvaluatorValue>> objects;

#ifndef NDEBUG
/// Current nesting depth for debug output indentation.
Expand Down Expand Up @@ -554,9 +382,6 @@ operator<<(mlir::Diagnostic &diag,
diag << "Object(" << object->getType() << ")";
else if (auto *list = llvm::dyn_cast<evaluator::ListValue>(&evaluatorValue))
diag << "List(" << list->getType() << ")";
else if (auto *ref =
llvm::dyn_cast<evaluator::ReferenceValue>(&evaluatorValue))
diag << "Reference(" << ref->getValueType() << ")";
else if (llvm::isa<evaluator::BasePathValue>(&evaluatorValue))
diag << "BasePath()";
else if (llvm::isa<evaluator::PathValue>(&evaluatorValue))
Expand Down
10 changes: 5 additions & 5 deletions integration_test/Bindings/Python/dialects/om.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,26 +141,26 @@
print(obj.field)

# location of the om.class.field @field
# CHECK: field: loc("-":{{.*}}:{{.*}})
# CHECK: field: loc
print("field:", obj.get_field_loc("field"))

# CHECK: child.foo: 14
print("child.foo: ", obj.child.foo)
# CHECK: child.foo.loc loc("-":{{.*}}:{{.*}})
# CHECK: child.foo.loc loc
print("child.foo.loc", obj.child.get_field_loc("foo"))
# CHECK: ('Root', 'x')
print(obj.reference)

for (name, field) in obj:
# location from om.class.field "child"
# CHECK: name: child, field: <circt.dialects.om.Object object
# CHECK-SAME: loc: loc(fused
# CHECK-SAME: loc: loc
# location from om.class.field "field"
# CHECK: name: field, field: 42
# CHECK-SAME: loc: loc("-":{{.*}}:{{.*}})
# CHECK-SAME: loc: loc
# location from om.class.field "reference"
# CHECK: name: reference, field: ('Root', 'x')
# CHECK-SAME: loc: loc("-":{{.*}}:{{.*}})
# CHECK-SAME: loc: loc
loc = obj.get_field_loc(name)
print(f"name: {name}, field: {field}, loc: {loc}")

Expand Down
4 changes: 0 additions & 4 deletions lib/Bindings/Python/OMModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -376,10 +376,6 @@ PythonValue omEvaluatorValueToPythonValue(OMEvaluatorValue result) {
if (omEvaluatorValueIsUnknown(result))
return Unknown(omEvaluatorValueGetType(result));

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

// If the field was a primitive, return the Attribute.
assert(omEvaluatorValueIsAPrimitive(result));
return omPrimitiveToPythonValue(omEvaluatorValueGetPrimitive(result));
Expand Down
Loading
Loading