diff --git a/include/circt-c/Dialect/OM.h b/include/circt-c/Dialect/OM.h index cb1b148428b3..dd49b5825963 100644 --- a/include/circt-c/Dialect/OM.h +++ b/include/circt-c/Dialect/OM.h @@ -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); diff --git a/include/circt/Dialect/OM/Evaluator/Evaluator.h b/include/circt/Dialect/OM/Evaluator/Evaluator.h index 3a84c572b153..4de0e46790dd 100644 --- a/include/circt/Dialect/OM/Evaluator/Evaluator.h +++ b/include/circt/Dialect/OM/Evaluator/Evaluator.h @@ -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 #include namespace circt { @@ -49,7 +47,7 @@ using ObjectFields = SmallDenseMap; class EvaluatorValue : public std::enable_shared_from_this { 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; } @@ -61,14 +59,6 @@ class EvaluatorValue : public std::enable_shared_from_this { 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). @@ -92,9 +82,6 @@ class EvaluatorValue : public std::enable_shared_from_this { // 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. @@ -110,51 +97,7 @@ class EvaluatorValue : public std::enable_shared_from_this { 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 getStrippedValue() const { - llvm::SmallPtrSet visited; - auto currentValue = value; - while (auto *v = dyn_cast(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. @@ -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 @@ -205,19 +145,6 @@ class AttributeValue : public EvaluatorValue { friend std::shared_ptr 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(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: @@ -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) {} @@ -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 fields; @@ -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; @@ -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; @@ -397,130 +312,43 @@ class Evaluator { FailureOr getPartiallyEvaluatedValue(Type type, Location loc); - using ActualParameters = - SmallVectorImpl> *; - - using ObjectKey = std::pair; - - /// 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 instantiateImpl(StringAttr className, ArrayRef actualParams); - FailureOr - getOrCreateValue(Value value, ActualParameters actualParams, Location loc); - FailureOr - allocateObjectInstance(StringAttr clasName, ActualParameters actualParams); + FailureOr 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 - evaluateValue(Value value, ActualParameters actualParams, Location loc); + /// described in the rationale document. + FailureOr evaluateValue(Value value, Location loc); - /// Evaluator dispatch functions for the small expression grammar. - FailureOr evaluateParameter(BlockArgument formalParam, - ActualParameters actualParams, - Location loc); - - FailureOr - evaluateConstant(ConstantOp op, ActualParameters actualParams, Location loc); - - /// Instantiate an Object with its class name and actual parameters. - FailureOr - evaluateObjectInstance(StringAttr className, ActualParameters actualParams, - Location loc, ObjectKey instanceKey = {}); - FailureOr - evaluateObjectInstance(ObjectOp op, ActualParameters actualParams); + /// Evaluate a class body with actual parameters. FailureOr - evaluateElaboratedObject(ElaboratedObjectOp op, ActualParameters actualParams, - Location loc); - FailureOr - evaluateObjectField(ObjectFieldOp op, ActualParameters actualParams, - Location loc); - FailureOr evaluateListCreate(ListCreateOp op, - ActualParameters actualParams, - Location loc); - FailureOr evaluateListConcat(ListConcatOp op, - ActualParameters actualParams, - Location loc); - FailureOr - evaluateIntegerBinary(IntegerBinaryOp op, ActualParameters actualParams, - Location loc); - FailureOr - evaluateStringConcat(StringConcatOp op, ActualParameters actualParams, - Location loc); - FailureOr - evaluateBinaryEquality(BinaryEqualityOp op, ActualParameters actualParams, + evaluateObjectInstance(StringAttr className, + ArrayRef actualParams, Location loc); - FailureOr - evaluateBasePathCreate(FrozenBasePathCreateOp op, - ActualParameters actualParams, Location loc); - FailureOr - evaluatePathCreate(FrozenPathCreateOp op, ActualParameters actualParams, - Location loc); - FailureOr - evaluateEmptyPath(FrozenEmptyPathOp op, ActualParameters actualParams, - Location loc); - FailureOr - evaluateUnknownValue(UnknownValueOp op, Location loc); - LogicalResult evaluatePropertyAssert(PropertyAssertOp op, - ActualParameters actualParams); + /// Evaluator dispatch functions for the small expression grammar. + FailureOr evaluateOp(ConstantOp op, Location loc); + FailureOr evaluateOp(ElaboratedObjectOp op, Location loc); + FailureOr evaluateOp(ListCreateOp op, Location loc); + FailureOr evaluateOp(ListConcatOp op, Location loc); + FailureOr evaluateOp(FrozenBasePathCreateOp op, + Location loc); + FailureOr evaluateOp(FrozenPathCreateOp op, Location loc); + FailureOr evaluateOp(FrozenEmptyPathOp op, Location loc); + FailureOr evaluateOp(UnknownValueOp op, Location loc); FailureOr createUnknownValue(Type type, Location loc); - FailureOr - 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>>> - 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 worklist; - std::vector 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> pendingAsserts; - - /// Evaluator value storage. Return an evaluator value for the given - /// instantiation context (a pair of Value and parameters). - DenseMap> objects; - - /// Counter for fully evaluated nodes. - uint64_t fullyEvaluatedCount = 0; + /// Evaluator value storage for the current instantiation. + DenseMap> objects; #ifndef NDEBUG /// Current nesting depth for debug output indentation. @@ -554,9 +382,6 @@ operator<<(mlir::Diagnostic &diag, diag << "Object(" << object->getType() << ")"; else if (auto *list = llvm::dyn_cast(&evaluatorValue)) diag << "List(" << list->getType() << ")"; - else if (auto *ref = - llvm::dyn_cast(&evaluatorValue)) - diag << "Reference(" << ref->getValueType() << ")"; else if (llvm::isa(&evaluatorValue)) diag << "BasePath()"; else if (llvm::isa(&evaluatorValue)) diff --git a/integration_test/Bindings/Python/dialects/om.py b/integration_test/Bindings/Python/dialects/om.py index ce7fa5fa6adf..d865ba325d42 100644 --- a/integration_test/Bindings/Python/dialects/om.py +++ b/integration_test/Bindings/Python/dialects/om.py @@ -141,12 +141,12 @@ 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) @@ -154,13 +154,13 @@ for (name, field) in obj: # location from om.class.field "child" # CHECK: name: child, field: getAsString()); } -/// Query if the EvaluatorValue is a Reference. -bool omEvaluatorValueIsAReference(OMEvaluatorValue evaluatorValue) { - return isa(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(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()); -} - /// Query if the EvaluatorValue is an Unknown value. bool omEvaluatorValueIsUnknown(OMEvaluatorValue evaluatorValue) { return unwrap(evaluatorValue)->isUnknown(); diff --git a/lib/Dialect/OM/Evaluator/CMakeLists.txt b/lib/Dialect/OM/Evaluator/CMakeLists.txt index 6576782ba383..a833a29e2f5f 100644 --- a/lib/Dialect/OM/Evaluator/CMakeLists.txt +++ b/lib/Dialect/OM/Evaluator/CMakeLists.txt @@ -4,7 +4,6 @@ add_circt_library(CIRCTOMEvaluator DEPENDS MLIROMIncGen MLIROMAttrIncGen - MLIROMOpInterfacesIncGen LINK_LIBS CIRCTOM diff --git a/lib/Dialect/OM/Evaluator/Evaluator.cpp b/lib/Dialect/OM/Evaluator/Evaluator.cpp index 9f635baa7c69..ad11d85ebdd0 100644 --- a/lib/Dialect/OM/Evaluator/Evaluator.cpp +++ b/lib/Dialect/OM/Evaluator/Evaluator.cpp @@ -31,9 +31,6 @@ using namespace circt::om; namespace { -constexpr StringLiteral skipElaborationTransformAttr = - "om.skip_elaboration_transform"; - LogicalResult verifyActualParameters(ClassLike classLike, ArrayRef actualParams) { auto formalParamNames = @@ -82,6 +79,11 @@ LogicalResult verifyActualParameters(ClassLike classLike, return success(); } +bool requiresCompleteEvaluation(const evaluator::EvaluatorValuePtr &value) { + return !value->isFullyEvaluated() && + !isa(value.get()); +} + /// A helper class that builds the scratch IR for evaluating an object. This is /// used to convert from the evaluator's API (which uses opaque pointers to /// evaluator values) into actual MLIR IR. @@ -104,7 +106,7 @@ class ScratchIRBuilder { ClassOp createWrapperClass(ClassLike rootClass); /// Convert an API input value into scratch IR, preserving opaque any-typed - /// inputs and rejecting runtime references/cycles. + /// inputs and rejecting object cycles. FailureOr materializeInput(const EvaluatorValuePtr &value, Location loc, Type expectedType); /// Convert a fully evaluated list value into scratch IR. @@ -200,8 +202,6 @@ ScratchIRBuilder::materializeInput(const EvaluatorValuePtr &value, Location loc, return emitError(loc, "cannot materialize null OM evaluator value"); loc = value->getLoc(); - if (isa(value.get())) - return emitError(loc, "cannot import OM reference value"); if (!expectedType) return emitError(loc, "cannot import OM evaluator value without an " "expected type"); @@ -336,25 +336,11 @@ circt::om::getEvaluatorValuesFromAttributes(MLIRContext *context, return values; } -LogicalResult circt::om::evaluator::EvaluatorValue::finalize() { - using namespace evaluator; - // Early return if already finalized. - if (finalized) - return success(); - // Enable the flag to avoid infinite recursions. - finalized = true; - assert(isFullyEvaluated()); - return llvm::TypeSwitch(this) - .Case([](auto v) { return v->finalizeImpl(); }); -} - Type circt::om::evaluator::EvaluatorValue::getType() const { return llvm::TypeSwitch(this) .Case([](auto *attr) -> Type { return attr->getType(); }) .Case([](auto *object) { return object->getObjectType(); }) .Case([](auto *list) { return list->getListType(); }) - .Case([](auto *ref) { return ref->getValueType(); }) .Case( [this](auto *tuple) { return FrozenBasePathType::get(ctx); }) .Case( @@ -393,17 +379,14 @@ circt::om::Evaluator::getPartiallyEvaluatedValue(Type type, Location loc) { }) .Default([&](auto type) { return failure(); }); - if (succeeded(result)) - attachCounter(result.value()); - return result; } -FailureOr circt::om::Evaluator::getOrCreateValue( - Value value, ActualParameters actualParams, Location loc) { +FailureOr +circt::om::Evaluator::getOrCreateValue(Value value, Location loc) { LLVM_DEBUG(dbgs() << "- get: " << value << "\n"); - auto it = objects.find({value, actualParams}); + auto it = objects.find(value); if (it != objects.end()) { auto evalVal = it->second; evalVal->setLocIfUnknown(loc); @@ -413,35 +396,19 @@ FailureOr circt::om::Evaluator::getOrCreateValue( FailureOr result = TypeSwitch>(value) .Case([&](BlockArgument arg) { - auto val = (*actualParams)[arg.getArgNumber()]; - val->setLoc(loc); - return val; + auto error = arg.getOwner()->getParentOp()->emitError( + "unable to evaluate unbound parameter"); + error.attachNote() << "value: " << value; + return failure(); }) .Case([&](OpResult result) { return TypeSwitch>( result.getDefiningOp()) - .Case([&](ConstantOp op) { - return evaluateConstant(op, actualParams, loc); - }) - .Case([&](IntegerBinaryOp op) { - // Create a partially evaluated AttributeValue in case we need - // to delay evaluation. - evaluator::EvaluatorValuePtr result = - evaluator::AttributeValue::get(op.getResult().getType(), - loc); - return success(result); - }) - .Case([&](auto op) { - // Create a reference value since the value pointed by object - // field op is not created yet. - evaluator::EvaluatorValuePtr result = - std::make_shared( - value.getType(), loc); - return success(result); - }) + .Case( + [&](auto op) { return evaluateOp(op, loc); }) .Case([&](AnyCastOp op) { - return getOrCreateValue(op.getInput(), actualParams, loc); + return getOrCreateValue(op.getInput(), loc); }) .Case([&](FrozenBasePathCreateOp op) { evaluator::EvaluatorValuePtr result = @@ -463,24 +430,12 @@ FailureOr circt::om::Evaluator::getOrCreateValue( evaluator::PathValue::getEmptyPath(loc)); return success(result); }) - .Case([&](BinaryEqualityOp op) { - evaluator::EvaluatorValuePtr result = - evaluator::AttributeValue::get(op.getResult().getType(), - loc); - return success(result); - }) - .Case([&](auto op) { + .Case([&](auto op) { return getPartiallyEvaluatedValue(op.getType(), loc); }) - .Case([&](auto op) { - return getPartiallyEvaluatedValue(op.getType(), op.getLoc()); - }) .Case([&](auto op) { return getPartiallyEvaluatedValue(op.getType(), op.getLoc()); }) - .Case( - [&](auto op) { return evaluateUnknownValue(op, loc); }) .Default([&](Operation *op) { auto error = op->emitError("unable to evaluate value"); error.attachNote() << "value: " << value; @@ -490,17 +445,14 @@ FailureOr circt::om::Evaluator::getOrCreateValue( if (failed(result)) return result; - // Attach listener to newly created values - attachCounter(result.value()); - objects[{value, actualParams}] = result.value(); + objects[value] = result.value(); return result; } FailureOr -circt::om::Evaluator::evaluateObjectInstance(StringAttr className, - ActualParameters actualParams, - Location loc, - ObjectKey instanceKey) { +circt::om::Evaluator::evaluateObjectInstance( + StringAttr className, ArrayRef actualParams, + Location loc) { #ifndef NDEBUG DebugNesting nestOne(debugNesting); #endif @@ -518,7 +470,6 @@ circt::om::Evaluator::evaluateObjectInstance(StringAttr className, if (isa(classDef)) { evaluator::EvaluatorValuePtr result = std::make_shared(classDef, loc); - attachCounter(result); result->markUnknown(); LLVM_DEBUG(dbgs(1) << "extern: \n"); return result; @@ -527,28 +478,41 @@ circt::om::Evaluator::evaluateObjectInstance(StringAttr className, // Otherwise, it's a regular class, proceed normally ClassOp cls = cast(classDef); - if (failed(verifyActualParameters(cls, *actualParams))) + if (failed(verifyActualParameters(cls, actualParams))) return failure(); - // Instantiate the fields. - evaluator::ObjectFields fields; + for (auto [arg, actual] : + llvm::zip(cls.getBodyBlock()->getArguments(), actualParams)) { + actual->setLoc(arg.getLoc()); + objects.try_emplace(arg, actual); + } + evaluator::ObjectFields fields; auto *context = cls.getContext(); { LLVM_DEBUG(dbgs() << "ops:\n"); #ifndef NDEBUG DebugNesting nestOne(debugNesting); #endif + // Allocate placeholders for all class-body results before evaluating any + // fields. for (auto &op : cls.getOps()) + for (auto result : op.getResults()) + if (failed(getOrCreateValue(result, UnknownLoc::get(context)))) + return failure(); + + // A later field evaluation can then connect object valued cycles by + // pointing at these placeholders, and the placeholders are filled + // below. + for (auto &op : cls.getOps()) { for (auto result : op.getResults()) { - // Allocate the value, with unknown loc. It will be later set when - // evaluating the fields. - if (failed(getOrCreateValue(result, actualParams, - UnknownLoc::get(context)))) + auto evaluated = evaluateValue(result, op.getLoc()); + if (failed(evaluated)) return failure(); - // Add to the worklist. - worklist.push_back({result, actualParams}); + if (requiresCompleteEvaluation(evaluated.value())) + return op.emitError("failed to evaluate value"); } + } } LLVM_DEBUG(dbgs() << "fields:\n"); @@ -564,36 +528,18 @@ circt::om::Evaluator::evaluateObjectInstance(StringAttr className, DebugNesting nestOne(debugNesting); #endif FailureOr result = - evaluateValue(value, actualParams, fieldLoc); + evaluateValue(value, fieldLoc); if (failed(result)) return result; + if (requiresCompleteEvaluation(result.value())) + return emitError(fieldLoc, "failed to evaluate field ") << name; LLVM_DEBUG(dbgs() << "value: " << result.value() << "\n"); fields[cast(name)] = result.value(); } - // Defer property assertions until after the worklist is drained, so that - // all ReferenceValues are fully resolved before we try to inspect them. - LLVM_DEBUG(dbgs() << "queuing asserts:\n"); - for (auto assertOp : cls.getOps()) { - LLVM_DEBUG(dbgs(1) << "- " << assertOp << "\n"); - pendingAsserts.push({assertOp, actualParams}); - } - - // If the there is an instance, we must update the object value. - LLVM_DEBUG(dbgs() << "object value:\n"); - if (instanceKey.first) { - auto result = - getOrCreateValue(instanceKey.first, instanceKey.second, loc).value(); - auto *object = llvm::cast(result.get()); - object->setFields(std::move(fields)); - return result; - } - - // If it's external call, just allocate new ObjectValue. evaluator::EvaluatorValuePtr result = std::make_shared(cls, fields, loc); - // Object is already fully evaluated when created with fields. assert(result->isFullyEvaluated() && "object with fields should be fully evaluated"); return result; @@ -613,13 +559,6 @@ circt::om::Evaluator::instantiate( dbgs() << "- " << param << "\n"; }); - // Skip the elaboration transform and directly instantiate the class if the - // caller explicitly requests so. - // TODO: Remove this after fully migrating to the new evaluator-based - // implementation. - if (getModule()->hasAttr(skipElaborationTransformAttr)) - return instantiateImpl(className, actualParams); - auto rootClass = symbolTable.lookup(className); if (!rootClass) return symbolTable.getOp()->emitError("unknown class name ") << className; @@ -655,7 +594,6 @@ circt::om::Evaluator::instantiateImpl( evaluator::EvaluatorValuePtr result = std::make_shared( classDef, UnknownLoc::get(classDef.getContext())); - attachCounter(result); result->markUnknown(); LLVM_DEBUG(dbgs(1) << "result: \n"); return result; @@ -664,150 +602,44 @@ circt::om::Evaluator::instantiateImpl( // Otherwise, it's a regular class, proceed normally ClassOp cls = cast(classDef); - auto parameters = - std::make_unique>>( - actualParams); - - actualParametersBuffers.push_back(std::move(parameters)); + objects.clear(); auto loc = cls.getLoc(); LLVM_DEBUG(dbgs() << "evaluate object:\n"); - auto result = evaluateObjectInstance( - className, actualParametersBuffers.back().get(), loc); + auto result = evaluateObjectInstance(className, actualParams, loc); if (failed(result)) return failure(); - // `evaluateObjectInstance` has populated the worklist. Continue evaluations - // unless there is a partially evaluated value. - LLVM_DEBUG(dbgs() << "worklist:\n"); - - // Use two-worklist approach: process all items from current worklist, and if - // at least one becomes fully evaluated, swap and continue. If a full pass - // completes with no progress, we have a cycle. - while (!worklist.empty()) { - uint64_t countBeforePass = fullyEvaluatedCount; - LLVM_DEBUG(dbgs() << "- processing " << worklist.size() - << " items (fully evaluated count: " - << fullyEvaluatedCount << ")\n"); - - // Process all items in the current worklist. - while (!worklist.empty()) { - auto [value, args] = worklist.back(); - worklist.pop_back(); - auto result = evaluateValue(value, args, loc); - - if (failed(result)) - return failure(); - - // If not fully evaluated, add to next worklist for retry. - if (!result.value()->isFullyEvaluated()) - nextWorklist.push_back({value, args}); - } - - // Check if we made progress. - uint64_t evaluatedThisPass = fullyEvaluatedCount - countBeforePass; - LLVM_DEBUG(dbgs() << "- evaluated " << evaluatedThisPass - << " nodes this pass\n"); - - // If nothing became fully evaluated in this pass, we have a cycle. - if (evaluatedThisPass == 0 && !nextWorklist.empty()) - return cls.emitError() - << "cycle detected: " << nextWorklist.size() - << " values remain partially evaluated after full pass with no " - "progress (total fully evaluated: " - << fullyEvaluatedCount << ")"; - - // Swap worklists for next iteration. - worklist = std::move(nextWorklist); - nextWorklist.clear(); - } - - // Now that all values are fully resolved, evaluate the deferred property - // assertions. - LLVM_DEBUG(dbgs() << "asserts:\n"); - bool assertFailed = false; - while (!pendingAsserts.empty()) { - auto [assertOp, assertParams] = pendingAsserts.front(); - pendingAsserts.pop(); - assertFailed |= failed(evaluatePropertyAssert(assertOp, assertParams)); - } - if (assertFailed) - return failure(); - - auto &object = result.value(); - // Finalize the value. This will eliminate intermidiate ReferenceValue used as - // a placeholder in the initialization. - LLVM_DEBUG(dbgs() << "finalizing\n"); - if (failed(object->finalize())) - return cls.emitError() << "failed to finalize evaluation. Probably the " - "class contains a dataflow cycle"; - LLVM_DEBUG(dbgs() << "result: " << object << "\n"); - return object; + LLVM_DEBUG(dbgs() << "result: " << result.value() << "\n"); + return result; } FailureOr -circt::om::Evaluator::evaluateValue(Value value, ActualParameters actualParams, - Location loc) { - auto evaluatorValue = getOrCreateValue(value, actualParams, loc).value(); +circt::om::Evaluator::evaluateValue(Value value, Location loc) { + auto evaluatorValue = getOrCreateValue(value, loc); + if (failed(evaluatorValue)) + return failure(); LLVM_DEBUG(dbgs() << "- eval: " << value << "\n"); // Return if the value is already evaluated. - if (evaluatorValue->isFullyEvaluated()) { - LLVM_DEBUG(dbgs(1) << "fully evaluated: " << evaluatorValue << "\n"); + if (evaluatorValue.value()->isFullyEvaluated()) { + LLVM_DEBUG(dbgs(1) << "fully evaluated: " << evaluatorValue.value() + << "\n"); return evaluatorValue; } return llvm::TypeSwitch>(value) - .Case([&](BlockArgument arg) { - return evaluateParameter(arg, actualParams, loc); - }) + .Case([&](BlockArgument arg) { return evaluatorValue; }) .Case([&](OpResult result) { return TypeSwitch>( result.getDefiningOp()) - .Case([&](ConstantOp op) { - return evaluateConstant(op, actualParams, loc); - }) - .Case([&](IntegerBinaryOp op) { - return evaluateIntegerBinary(op, actualParams, loc); - }) - .Case([&](ObjectOp op) { - return evaluateObjectInstance(op, actualParams); - }) - .Case([&](ElaboratedObjectOp op) { - return evaluateElaboratedObject(op, actualParams, loc); - }) - .Case([&](ObjectFieldOp op) { - return evaluateObjectField(op, actualParams, loc); - }) - .Case([&](ListCreateOp op) { - return evaluateListCreate(op, actualParams, loc); - }) - .Case([&](ListConcatOp op) { - return evaluateListConcat(op, actualParams, loc); - }) - .Case([&](StringConcatOp op) { - return evaluateStringConcat(op, actualParams, loc); - }) - .Case([&](BinaryEqualityOp op) { - return evaluateBinaryEquality(op, actualParams, loc); - }) - .Case([&](AnyCastOp op) { - return evaluateValue(op.getInput(), actualParams, loc); - }) - .Case([&](FrozenBasePathCreateOp op) { - return evaluateBasePathCreate(op, actualParams, loc); - }) - .Case([&](FrozenPathCreateOp op) { - return evaluatePathCreate(op, actualParams, loc); - }) - .Case([&](FrozenEmptyPathOp op) { - return evaluateEmptyPath(op, actualParams, loc); - }) - .Case([&](UnknownValueOp op) { - return evaluateUnknownValue(op, loc); - }) + .Case([&](auto op) { return evaluateOp(op, loc); }) + .Case( + [&](AnyCastOp op) { return evaluateValue(op.getInput(), loc); }) .Default([&](Operation *op) { auto error = op->emitError("unable to evaluate value"); error.attachNote() << "value: " << value; @@ -816,195 +648,16 @@ circt::om::Evaluator::evaluateValue(Value value, ActualParameters actualParams, }); } -/// Evaluator dispatch function for parameters. -FailureOr circt::om::Evaluator::evaluateParameter( - BlockArgument formalParam, ActualParameters actualParams, Location loc) { - auto val = (*actualParams)[formalParam.getArgNumber()]; - val->setLoc(loc); - return success(val); -} - /// Evaluator dispatch function for constants. FailureOr -circt::om::Evaluator::evaluateConstant(ConstantOp op, - ActualParameters actualParams, - Location loc) { +circt::om::Evaluator::evaluateOp(ConstantOp op, Location loc) { // For list constants, create ListValue. return success(om::evaluator::AttributeValue::get(op.getValue(), loc)); } -// Evaluator dispatch function for integer binary operations. -FailureOr circt::om::Evaluator::evaluateIntegerBinary( - IntegerBinaryOp op, ActualParameters actualParams, Location loc) { - // Get the op's EvaluatorValue handle, in case it hasn't been evaluated yet. - auto handle = getOrCreateValue(op.getResult(), actualParams, loc); - - // If it's fully evaluated, we can return it. - if (handle.value()->isFullyEvaluated()) - return handle; - - // Evaluate operands if necessary, and return the partially evaluated value if - // they aren't ready. - auto lhsResult = evaluateValue(op.getLhs(), actualParams, loc); - if (failed(lhsResult)) - return lhsResult; - if (!lhsResult.value()->isFullyEvaluated()) - return handle; - - auto rhsResult = evaluateValue(op.getRhs(), actualParams, loc); - if (failed(rhsResult)) - return rhsResult; - if (!rhsResult.value()->isFullyEvaluated()) - return handle; - - // Check if any operand is unknown and propagate the unknown flag. - if (lhsResult.value()->isUnknown() || rhsResult.value()->isUnknown()) { - handle.value()->markUnknown(); - return handle; - } - - // Extract the attribute from an EvaluatorValue (handles both om::IntegerAttr - // and mlir::IntegerAttr). - auto extractAttr = [](evaluator::EvaluatorValue *value) -> Attribute { - return llvm::TypeSwitch(value) - .Case([](evaluator::AttributeValue *val) { return val->getAttr(); }) - .Case([](evaluator::ReferenceValue *val) { - return cast(val->getStrippedValue()->get()) - ->getAttr(); - }); - }; - - mlir::Attribute lhsAttr = extractAttr(lhsResult.value().get()); - mlir::Attribute rhsAttr = extractAttr(rhsResult.value().get()); - assert(lhsAttr && rhsAttr && - "expected attribute for IntegerBinaryOp operands"); - - std::array operandAttrs = {lhsAttr, rhsAttr}; - SmallVector results; - mlir::Attribute resultAttr; - // Even with fully constant operands, folders may decline to fold or may - // produce a non-attribute result. - if (failed(op->fold(operandAttrs, results)) || results.size() != 1 || - !(resultAttr = results[0].dyn_cast())) - return op->emitError("failed to evaluate integer operation"); - - // Finalize the op result value. - auto *handleValue = cast(handle.value().get()); - auto resultStatus = handleValue->setAttr(resultAttr); - if (failed(resultStatus)) - return resultStatus; - - auto finalizeStatus = handleValue->finalize(); - if (failed(finalizeStatus)) - return finalizeStatus; - - return handle; -} - -/// Evaluator dispatch function for property assertions. -LogicalResult -circt::om::Evaluator::evaluatePropertyAssert(PropertyAssertOp op, - ActualParameters actualParams) { -#ifndef NDEBUG - DebugNesting nest(debugNesting); -#endif - - auto loc = op.getLoc(); - - // Evaluate the condition, returning early if it isn't ready yet. - LLVM_DEBUG(dbgs() << "op: " << op << "\n" - << indent() << "evaluate condition: \n"); - auto condResult = evaluateValue(op.getCondition(), actualParams, loc); - if (failed(condResult)) - return failure(); - if (!condResult.value()->isFullyEvaluated()) { - LLVM_DEBUG(dbgs() << "evaluate condition: \n"); - return success(); - } - - // If the condition is unknown, skip silently (best-effort). - if (condResult.value()->isUnknown()) - return success(); - - LLVM_DEBUG(dbgs() << "condition: " << condResult.value() << "\n"); - - // Extract the attribute from the condition value, handling the case where - // the condition resolves through a ReferenceValue (e.g. an ObjectFieldOp or - // a parameter that participates in cycle resolution). - auto extractAttr = [](evaluator::EvaluatorValue *value) -> mlir::Attribute { - return llvm::TypeSwitch(value) - .Case([](evaluator::AttributeValue *val) { return val->getAttr(); }) - .Case([](evaluator::ReferenceValue *val) -> mlir::Attribute { - auto stripped = val->getStrippedValue(); - if (failed(stripped)) - return {}; - if (auto *attr = - dyn_cast(stripped.value().get())) - return attr->getAttr(); - return {}; - }) - .Default([](auto *) -> mlir::Attribute { return {}; }); - }; - - auto condAttr = extractAttr(condResult.value().get()); - if (!condAttr) - return success(); - - bool isFalse = false; - if (auto boolAttr = dyn_cast(condAttr)) - isFalse = !boolAttr.getValue(); - else if (auto intAttr = dyn_cast(condAttr)) - isFalse = intAttr.getValue().isZero(); - else - return op.emitError("expected BoolAttr or mlir::IntegerAttr"); - - if (isFalse) - return op.emitError("OM property assertion failed: ") << op.getMessage(); - - return success(); -} - -/// Evaluator dispatch function for Object instances. -FailureOr -circt::om::Evaluator::createParametersFromOperands( - ValueRange range, ActualParameters actualParams, Location loc) { - // Create an unique storage to store parameters. - auto parameters = std::make_unique< - SmallVector>>(); - - // Collect operands' evaluator values in the current instantiation context. - for (auto input : range) { - auto inputResult = getOrCreateValue(input, actualParams, loc); - if (failed(inputResult)) - return failure(); - parameters->push_back(inputResult.value()); - } - - actualParametersBuffers.push_back(std::move(parameters)); - return actualParametersBuffers.back().get(); -} - -/// Evaluator dispatch function for Object instances. FailureOr -circt::om::Evaluator::evaluateObjectInstance(ObjectOp op, - ActualParameters actualParams) { - auto loc = op.getLoc(); - if (isFullyEvaluated({op, actualParams})) - return getOrCreateValue(op, actualParams, loc); - - auto params = - createParametersFromOperands(op.getOperands(), actualParams, loc); - if (failed(params)) - return failure(); - return evaluateObjectInstance(op.getClassNameAttr().getAttr(), params.value(), - loc, {op, actualParams}); -} - -FailureOr -circt::om::Evaluator::evaluateElaboratedObject(ElaboratedObjectOp op, - ActualParameters actualParams, - Location loc) { - auto objectValue = getOrCreateValue(op, actualParams, loc); +circt::om::Evaluator::evaluateOp(ElaboratedObjectOp op, Location loc) { + auto objectValue = getOrCreateValue(op, loc); if (failed(objectValue)) return failure(); auto object = cast(objectValue.value().get()); @@ -1030,12 +683,16 @@ circt::om::Evaluator::evaluateElaboratedObject(ElaboratedObjectOp op, llvm::enumerate(llvm::zip(fieldNames, fieldValues))) { auto [fieldName, fieldValue] = fieldNameAndValue; auto fieldLoc = classOp ? classOp.getFieldLocByIndex(index) : loc; - auto fieldResult = getOrCreateValue(fieldValue, actualParams, fieldLoc); + auto fieldResult = getOrCreateValue(fieldValue, fieldLoc); + if (failed(fieldResult)) + return failure(); + if (!isa(fieldResult.value().get())) + fieldResult = evaluateValue(fieldValue, fieldLoc); if (failed(fieldResult)) return failure(); - if (!fieldResult.value()->isFullyEvaluated()) - worklist.push_back({fieldValue, actualParams}); + if (requiresCompleteEvaluation(fieldResult.value())) + return emitError(fieldLoc, "failed to evaluate field ") << fieldName; fields[cast(fieldName)] = fieldResult.value(); } @@ -1044,81 +701,20 @@ circt::om::Evaluator::evaluateElaboratedObject(ElaboratedObjectOp op, return objectValue; } -/// Evaluator dispatch function for Object fields. -FailureOr -circt::om::Evaluator::evaluateObjectField(ObjectFieldOp op, - ActualParameters actualParams, - Location loc) { - // Evaluate the Object itself, in case it hasn't been evaluated yet. - FailureOr currentObjectResult = - evaluateValue(op.getObject(), actualParams, loc); - if (failed(currentObjectResult)) - return currentObjectResult; - - auto result = currentObjectResult.value(); - - auto objectFieldValue = getOrCreateValue(op, actualParams, loc).value(); - - if (result->isUnknown()) { - // If objectFieldValue is a ReferenceValue, set its value to a unknown value - // of the proper type - if (auto *ref = - llvm::dyn_cast(objectFieldValue.get())) { - auto unknownField = createUnknownValue(op.getResult().getType(), loc); - if (failed(unknownField)) - return unknownField; - ref->setValue(unknownField.value()); - } - // markUnknown() also marks the value as fully evaluated - objectFieldValue->markUnknown(); - return objectFieldValue; - } - - // If the result is a ReferenceValue, dereference it to get the actual object. - if (auto *ref = llvm::dyn_cast(result.get())) { - auto stripped = ref->getStrippedValue(); - if (failed(stripped)) - return failure(); - result = stripped.value(); - } - - auto *currentObject = llvm::cast(result.get()); - - auto field = op.getFieldAttr(); - - // `currentObject` might not be fully evaluated. - if (!currentObject->getFields().contains(field)) - return objectFieldValue; - - auto currentField = currentObject->getField(field); - auto finalField = currentField.value(); - - if (!finalField->isFullyEvaluated()) - return objectFieldValue; - - // Update the reference. - llvm::cast(objectFieldValue.get()) - ->setValue(finalField); - - // Return the field being accessed. - return objectFieldValue; -} - /// Evaluator dispatch function for List creation. FailureOr -circt::om::Evaluator::evaluateListCreate(ListCreateOp op, - ActualParameters actualParams, - Location loc) { +circt::om::Evaluator::evaluateOp(ListCreateOp op, Location loc) { // Evaluate the Object itself, in case it hasn't been evaluated yet. SmallVector values; - auto list = getOrCreateValue(op, actualParams, loc); + auto list = getOrCreateValue(op, loc); bool hasUnknown = false; for (auto operand : op.getOperands()) { - auto result = evaluateValue(operand, actualParams, loc); + auto result = evaluateValue(operand, loc); if (failed(result)) return result; - if (!result.value()->isFullyEvaluated()) - return list; + if (requiresCompleteEvaluation(result.value())) + return op.emitError() + << "failed to evaluate list element operand: " << operand; // Check if any operand is unknown. if (result.value()->isUnknown()) hasUnknown = true; @@ -1140,27 +736,22 @@ circt::om::Evaluator::evaluateListCreate(ListCreateOp op, /// Evaluator dispatch function for List concatenation. FailureOr -circt::om::Evaluator::evaluateListConcat(ListConcatOp op, - ActualParameters actualParams, - Location loc) { +circt::om::Evaluator::evaluateOp(ListConcatOp op, Location loc) { // Evaluate the List concat op itself, in case it hasn't been evaluated yet. SmallVector values; - auto list = getOrCreateValue(op, actualParams, loc); + auto list = getOrCreateValue(op, loc); - // Extract the ListValue, either directly or through an object reference. + // Extract the ListValue. auto extractList = [](evaluator::EvaluatorValue *value) { return std::move( llvm::TypeSwitch( value) - .Case([](evaluator::ListValue *val) { return val; }) - .Case([](evaluator::ReferenceValue *val) { - return cast(val->getStrippedValue()->get()); - })); + .Case([](evaluator::ListValue *val) { return val; })); }; bool hasUnknown = false; for (auto operand : op.getOperands()) { - auto result = evaluateValue(operand, actualParams, loc); + auto result = evaluateValue(operand, loc); if (failed(result)) return result; if (!result.value()->isFullyEvaluated()) @@ -1192,138 +783,12 @@ circt::om::Evaluator::evaluateListConcat(ListConcatOp op, return list; } -/// Evaluator dispatch function for String concatenation. -FailureOr -circt::om::Evaluator::evaluateStringConcat(StringConcatOp op, - ActualParameters actualParams, - Location loc) { - // Get the op's EvaluatorValue handle, in case it hasn't been evaluated yet. - auto handle = getOrCreateValue(op.getResult(), actualParams, loc); - if (failed(handle)) - return handle; - - // If it's fully evaluated, we can return it. - if (handle.value()->isFullyEvaluated()) - return handle; - - // Extract the string attributes, handling both AttributeValue and - // ReferenceValue cases. - auto extractAttr = [](evaluator::EvaluatorValue *value) -> StringAttr { - return llvm::TypeSwitch(value) - .Case([](evaluator::AttributeValue *val) { - return val->getAs(); - }) - .Case([](evaluator::ReferenceValue *val) { - return cast(val->getStrippedValue()->get()) - ->getAs(); - }); - }; - - // Evaluate all operands and concatenate them. - std::string result; - for (auto operand : op.getOperands()) { - auto operandResult = evaluateValue(operand, actualParams, loc); - if (failed(operandResult)) - return operandResult; - if (!operandResult.value()->isFullyEvaluated()) - return handle; - - StringAttr str = extractAttr(operandResult.value().get()); - assert(str && "expected StringAttr for StringConcatOp operand"); - result += str.getValue().str(); - } - - // Create the concatenated string attribute. - auto resultStr = StringAttr::get(result, op.getResult().getType()); - - // Finalize the op result value. - auto *handleValue = cast(handle.value().get()); - auto resultStatus = handleValue->setAttr(resultStr); - if (failed(resultStatus)) - return resultStatus; - - auto finalizeStatus = handleValue->finalize(); - if (failed(finalizeStatus)) - return finalizeStatus; - - return handle; -} - -// Evaluator dispatch function for binary property equality operations. -FailureOr -circt::om::Evaluator::evaluateBinaryEquality(BinaryEqualityOp op, - ActualParameters actualParams, - Location loc) { - // Get the op's EvaluatorValue handle, in case it hasn't been evaluated yet. - auto handle = getOrCreateValue(op.getResult(), actualParams, loc); - if (failed(handle)) - return handle; - - // If it's fully evaluated, we can return it. - if (handle.value()->isFullyEvaluated()) - return handle; - - // Evaluate both operands, returning the partially evaluated handle if either - // isn't ready yet. - auto lhsResult = evaluateValue(op.getLhs(), actualParams, loc); - if (failed(lhsResult)) - return lhsResult; - if (!lhsResult.value()->isFullyEvaluated()) - return handle; - - auto rhsResult = evaluateValue(op.getRhs(), actualParams, loc); - if (failed(rhsResult)) - return rhsResult; - if (!rhsResult.value()->isFullyEvaluated()) - return handle; - - // Check if any operand is unknown and propagate the unknown flag. - if (lhsResult.value()->isUnknown() || rhsResult.value()->isUnknown()) { - handle.value()->markUnknown(); - return handle; - } - - // Extract the underlying attribute, handling both AttributeValue and - // ReferenceValue cases. - auto extractAttr = [](evaluator::EvaluatorValue *value) -> mlir::Attribute { - return llvm::TypeSwitch(value) - .Case([](evaluator::AttributeValue *val) { return val->getAttr(); }) - .Case([](evaluator::ReferenceValue *val) -> mlir::Attribute { - return cast(val->getStrippedValue()->get()) - ->getAttr(); - }); - }; - - mlir::Attribute lhs = extractAttr(lhsResult.value().get()); - mlir::Attribute rhs = extractAttr(rhsResult.value().get()); - assert(lhs && rhs && "expected attribute for BinaryEqualityOp operands"); - - // Perform the binary equality operation. - FailureOr result = op.evaluateBinaryEquality(lhs, rhs); - if (failed(result)) - return op->emitError("failed to evaluate binary equality operation"); - - // Finalize the op result value. - auto *handleValue = cast(handle.value().get()); - auto resultStatus = handleValue->setAttr(*result); - if (failed(resultStatus)) - return resultStatus; - - auto finalizeStatus = handleValue->finalize(); - if (failed(finalizeStatus)) - return finalizeStatus; - - return handle; -} - FailureOr -circt::om::Evaluator::evaluateBasePathCreate(FrozenBasePathCreateOp op, - ActualParameters actualParams, - Location loc) { +circt::om::Evaluator::evaluateOp(FrozenBasePathCreateOp op, Location loc) { // Evaluate the Object itself, in case it hasn't been evaluated yet. - auto valueResult = getOrCreateValue(op, actualParams, loc).value(); + auto valueResult = getOrCreateValue(op, loc).value(); auto *path = llvm::cast(valueResult.get()); - auto result = evaluateValue(op.getBasePath(), actualParams, loc); + auto result = evaluateValue(op.getBasePath(), loc); if (failed(result)) return result; auto &value = result.value(); @@ -1341,13 +806,11 @@ circt::om::Evaluator::evaluateBasePathCreate(FrozenBasePathCreateOp op, } FailureOr -circt::om::Evaluator::evaluatePathCreate(FrozenPathCreateOp op, - ActualParameters actualParams, - Location loc) { +circt::om::Evaluator::evaluateOp(FrozenPathCreateOp op, Location loc) { // Evaluate the Object itself, in case it hasn't been evaluated yet. - auto valueResult = getOrCreateValue(op, actualParams, loc).value(); + auto valueResult = getOrCreateValue(op, loc).value(); auto *path = llvm::cast(valueResult.get()); - auto result = evaluateValue(op.getBasePath(), actualParams, loc); + auto result = evaluateValue(op.getBasePath(), loc); if (failed(result)) return result; auto &value = result.value(); @@ -1364,9 +827,9 @@ circt::om::Evaluator::evaluatePathCreate(FrozenPathCreateOp op, return valueResult; } -FailureOr circt::om::Evaluator::evaluateEmptyPath( - FrozenEmptyPathOp op, ActualParameters actualParams, Location loc) { - auto valueResult = getOrCreateValue(op, actualParams, loc).value(); +FailureOr +circt::om::Evaluator::evaluateOp(FrozenEmptyPathOp op, Location loc) { + auto valueResult = getOrCreateValue(op, loc).value(); return valueResult; } @@ -1417,7 +880,7 @@ circt::om::Evaluator::createUnknownValue(Type type, Location loc) { /// Evaluate an unknown value FailureOr -circt::om::Evaluator::evaluateUnknownValue(UnknownValueOp op, Location loc) { +circt::om::Evaluator::evaluateOp(UnknownValueOp op, Location loc) { return createUnknownValue(op.getType(), loc); } @@ -1448,42 +911,6 @@ ArrayAttr circt::om::Object::getFieldNames() { return ArrayAttr::get(cls.getContext(), fieldNames); } -LogicalResult circt::om::evaluator::ObjectValue::finalizeImpl() { - for (auto &&[e, value] : fields) - if (failed(finalizeEvaluatorValue(value))) - return failure(); - - return success(); -} - -//===----------------------------------------------------------------------===// -// ReferenceValue -//===----------------------------------------------------------------------===// - -LogicalResult circt::om::evaluator::ReferenceValue::finalizeImpl() { - auto result = getStrippedValue(); - if (failed(result)) - return result; - value = std::move(result.value()); - // the stripped value also needs to be finalized - if (failed(finalizeEvaluatorValue(value))) - return failure(); - - return success(); -} - -//===----------------------------------------------------------------------===// -// ListValue -//===----------------------------------------------------------------------===// - -LogicalResult circt::om::evaluator::ListValue::finalizeImpl() { - for (auto &value : elements) { - if (failed(finalizeEvaluatorValue(value))) - return failure(); - } - return success(); -} - //===----------------------------------------------------------------------===// // BasePathValue //===----------------------------------------------------------------------===// @@ -1598,13 +1025,6 @@ LogicalResult circt::om::evaluator::AttributeValue::setAttr(Attribute attr) { return success(); } -LogicalResult circt::om::evaluator::AttributeValue::finalizeImpl() { - if (!isFullyEvaluated()) - return mlir::emitError( - getLoc(), "cannot finalize AttributeValue that is not fully evaluated"); - return success(); -} - std::shared_ptr circt::om::evaluator::AttributeValue::get(Attribute attr, LocationAttr loc) { auto type = cast(attr).getType(); diff --git a/unittests/Dialect/OM/Evaluator/EvaluatorTests.cpp b/unittests/Dialect/OM/Evaluator/EvaluatorTests.cpp index bed727ce4d9e..a1f1de03d55d 100644 --- a/unittests/Dialect/OM/Evaluator/EvaluatorTests.cpp +++ b/unittests/Dialect/OM/Evaluator/EvaluatorTests.cpp @@ -38,13 +38,9 @@ struct EvaluatorTestContext { context.getOrLoadDialect(); } - OwningOpRef parseModule(StringRef moduleText, - bool skipElaborationTransform = false) { + OwningOpRef parseModule(StringRef moduleText) { OwningOpRef owning = parseSourceString(moduleText, ParserConfig(&context)); - if (owning && skipElaborationTransform) - owning.get()->setAttr("om.skip_elaboration_transform", - UnitAttr::get(&context)); return owning; } @@ -104,29 +100,19 @@ getListElements(const evaluator::EvaluatorValuePtr &value) { return llvm::cast(value.get())->getElements(); } -class EvaluatorTests : public ::testing::TestWithParam { +class EvaluatorTests : public ::testing::Test { protected: OwningOpRef parseModule(StringRef moduleText) { - return test.parseModule(moduleText, GetParam()); - } - - OwningOpRef parseModule(StringRef moduleText, - bool skipElaborationTransform) { - return test.parseModule(moduleText, skipElaborationTransform); + return test.parseModule(moduleText); } EvaluatorTestContext test; MLIRContext &context = test.context; }; -std::string getEvaluatorFlowName(const ::testing::TestParamInfo &info) { - return info.param ? "WithoutElaborationTransform" - : "WithElaborationTransform"; -} - /// Failure scenarios. -TEST_P(EvaluatorTests, InstantiateInvalidClassName) { +TEST_F(EvaluatorTests, InstantiateInvalidClassName) { StringRef mod = R"MLIR( module { } @@ -145,7 +131,7 @@ module { ASSERT_FALSE(succeeded(result)); } -TEST_P(EvaluatorTests, InstantiateInvalidParamSize) { +TEST_F(EvaluatorTests, InstantiateInvalidParamSize) { StringRef mod = R"MLIR( module { om.class @MyClass(%param: !om.integer) { @@ -170,7 +156,7 @@ module { ASSERT_FALSE(succeeded(result)); } -TEST_P(EvaluatorTests, InstantiateNullParam) { +TEST_F(EvaluatorTests, InstantiateNullParam) { StringRef mod = R"MLIR( module { om.class @MyClass(%param: !om.integer) { @@ -193,7 +179,7 @@ module { ASSERT_FALSE(succeeded(result)); } -TEST_P(EvaluatorTests, InstantiateInvalidParamType) { +TEST_F(EvaluatorTests, InstantiateInvalidParamType) { StringRef mod = R"MLIR( module { om.class @MyClass(%param: !om.integer) { @@ -218,7 +204,7 @@ module { ASSERT_FALSE(succeeded(result)); } -TEST_P(EvaluatorTests, GetFieldInvalidName) { +TEST_F(EvaluatorTests, GetFieldInvalidName) { StringRef mod = R"MLIR( module { om.class @MyClass() { @@ -247,7 +233,7 @@ module { /// Success scenarios. -TEST_P(EvaluatorTests, InstantiateObjectWithParamField) { +TEST_F(EvaluatorTests, InstantiateObjectWithParamField) { StringRef mod = R"MLIR( module { om.class @MyClass(%param: !om.integer) -> (field: !om.integer) { @@ -267,7 +253,7 @@ module { ASSERT_EQ(42, getInteger(getField(result.value(), "field"))); } -TEST_P(EvaluatorTests, InstantiateWithStructuredInputs) { +TEST_F(EvaluatorTests, InstantiateWithStructuredInputs) { StringRef mod = R"MLIR( module { om.class @Leaf(%value: !om.integer) -> (value: !om.integer) { @@ -328,10 +314,7 @@ module { ASSERT_EQ(anyFieldValue->getClassOp().getSymNameAttr().getValue(), "Leaf"); } -TEST_P(EvaluatorTests, InstantiateWithPartiallyEvaluatedInputs) { - if (GetParam()) - return; - +TEST_F(EvaluatorTests, InstantiateWithPartiallyEvaluatedInputs) { auto runFailure = [&](StringRef mod, StringRef className, evaluator::EvaluatorValuePtr value, StringRef expectedError) { @@ -378,7 +361,7 @@ module { "cannot import partially evaluated OM list value"); } -TEST_P(EvaluatorTests, InstantiateObjectWithConstantField) { +TEST_F(EvaluatorTests, InstantiateObjectWithConstantField) { StringRef mod = R"MLIR( module { om.class @MyClass() -> (field: !om.integer) { @@ -398,7 +381,7 @@ module { ASSERT_EQ(42, getInteger(getField(result.value(), "field"))); } -TEST_P(EvaluatorTests, InstantiateObjectWithChildObject) { +TEST_F(EvaluatorTests, InstantiateObjectWithChildObject) { StringRef mod = R"MLIR( module { om.class @MyInnerClass(%param: !om.integer) -> (field: !om.integer) { @@ -424,7 +407,7 @@ module { ASSERT_EQ(42, getInteger(getField(fieldValue, "field"))); } -TEST_P(EvaluatorTests, InstantiateObjectWithFieldAccess) { +TEST_F(EvaluatorTests, InstantiateObjectWithFieldAccess) { StringRef mod = R"MLIR( module { om.class @MyInnerClass(%param: !om.integer) -> (field: !om.integer) { @@ -450,7 +433,7 @@ module { ASSERT_EQ(42, getInteger(getField(result.value(), "field"))); } -TEST_P(EvaluatorTests, InstantiateObjectWithChildObjectMemoized) { +TEST_F(EvaluatorTests, InstantiateObjectWithChildObjectMemoized) { StringRef mod = R"MLIR( module { om.class @MyInnerClass() { @@ -489,7 +472,7 @@ module { ASSERT_EQ(field1Value, field2Value); } -TEST_P(EvaluatorTests, AnyCastObject) { +TEST_F(EvaluatorTests, AnyCastObject) { StringRef mod = R"MLIR( module { om.class @MyInnerClass() { @@ -515,7 +498,7 @@ module { ASSERT_EQ(fieldValue->getClassOp().getSymName(), "MyInnerClass"); } -TEST_P(EvaluatorTests, AnyCastParam) { +TEST_F(EvaluatorTests, AnyCastParam) { StringRef mod = R"MLIR( module { om.class @MyInnerClass(%param: !om.any) -> (field: !om.any) { @@ -545,7 +528,7 @@ module { ASSERT_EQ(42u, getBuiltinInteger(getField(fieldValue, "field"))); } -TEST_P(EvaluatorTests, InstantiateGraphRegion) { +TEST_F(EvaluatorTests, InstantiateGraphRegion) { StringRef mod = R"MLIR( !ty = !om.class.type<@LinkedList> om.class @LinkedList(%n: !ty, %val: !om.string) -> (n: !ty, val: @@ -586,24 +569,15 @@ om.class @UseNode(%node: !ty) -> (node: !ty) { auto node = getField(result.value(), "field1"); - if (!GetParam()) { - context.getDiagEngine().registerHandler([&](Diagnostic &diag) { - ASSERT_EQ(diag.str(), "cannot import mutually referential OM objects"); - }); - auto useNodeResult = - evaluator.instantiate(StringAttr::get(&context, "UseNode"), {node}); - ASSERT_TRUE(failed(useNodeResult)); - return; - } - + context.getDiagEngine().registerHandler([&](Diagnostic &diag) { + ASSERT_EQ(diag.str(), "cannot import mutually referential OM objects"); + }); auto useNodeResult = evaluator.instantiate(StringAttr::get(&context, "UseNode"), {node}); - ASSERT_TRUE(succeeded(useNodeResult)); - auto resultNode = getField(useNodeResult.value(), "node"); - ASSERT_EQ(resultNode.get(), node.get()); + ASSERT_TRUE(failed(useNodeResult)); } -TEST_P(EvaluatorTests, InstantiateCycle) { +TEST_F(EvaluatorTests, InstantiateCycle) { StringRef mod = R"MLIR( !ty = !om.class.type<@LinkedList> om.class @LinkedList(%n: !ty) -> (n: !ty){ @@ -617,11 +591,7 @@ om.class @ReferenceEachOther() -> (field: !ty){ )MLIR"; context.getDiagEngine().registerHandler([&](Diagnostic &diag) { - ASSERT_EQ(diag.str(), - GetParam() - ? "cycle detected: 1 values remain partially evaluated after " - "full pass with no progress (total fully evaluated: 1)" - : "failed to evaluate om.object.field"); + ASSERT_EQ(diag.str(), "failed to evaluate om.object.field"); }); OwningOpRef owning = parseModule(mod); @@ -637,7 +607,7 @@ om.class @ReferenceEachOther() -> (field: !ty){ // Test nested object field references. // https://github.com/llvm/circt/issues/10264 -TEST_P(EvaluatorTests, Issue10264NestedFieldReferences) { +TEST_F(EvaluatorTests, Issue10264NestedFieldReferences) { StringRef mod = R"MLIR( om.class @Domain(%in: !om.string) -> (out: !om.string) { om.class.fields %in : !om.string @@ -666,7 +636,7 @@ om.class @Top() -> (test: i1) { ASSERT_FALSE(getBool(getField(result.value(), "test"))); } -TEST_P(EvaluatorTests, IntegerBinaryArithmeticAdd) { +TEST_F(EvaluatorTests, IntegerBinaryArithmeticAdd) { StringRef mod = R"MLIR( om.class @IntegerBinaryArithmeticAdd() -> (result: !om.integer) { %0 = om.constant #om.integer<1 : si3> : !om.integer @@ -688,7 +658,7 @@ om.class @IntegerBinaryArithmeticAdd() -> (result: !om.integer) { ASSERT_EQ(getInteger(getField(result.value(), "result")), 3); } -TEST_P(EvaluatorTests, IntegerBinaryArithmeticMul) { +TEST_F(EvaluatorTests, IntegerBinaryArithmeticMul) { StringRef mod = R"MLIR( om.class @IntegerBinaryArithmeticMul() -> (result: !om.integer) { %0 = om.constant #om.integer<2 : si3> : !om.integer @@ -710,7 +680,7 @@ om.class @IntegerBinaryArithmeticMul() -> (result: !om.integer) { ASSERT_EQ(6, getInteger(getField(result.value(), "result"))); } -TEST_P(EvaluatorTests, IntegerBinaryArithmeticShr) { +TEST_F(EvaluatorTests, IntegerBinaryArithmeticShr) { StringRef mod = R"MLIR( om.class @IntegerBinaryArithmeticShr() -> (result: !om.integer){ %0 = om.constant #om.integer<8 : si5> : !om.integer @@ -732,7 +702,7 @@ om.class @IntegerBinaryArithmeticShr() -> (result: !om.integer){ ASSERT_EQ(2, getInteger(getField(result.value(), "result"))); } -TEST_P(EvaluatorTests, IntegerBinaryArithmeticShrNegative) { +TEST_F(EvaluatorTests, IntegerBinaryArithmeticShrNegative) { StringRef mod = R"MLIR( om.class @IntegerBinaryArithmeticShrNegative() -> (result: !om.integer){ %0 = om.constant #om.integer<8 : si5> : !om.integer @@ -747,8 +717,7 @@ om.class @IntegerBinaryArithmeticShrNegative() -> (result: !om.integer){ ASSERT_EQ(diag.str(), "'om.integer.shr' op shift amount must be non-negative"); if (StringRef(diag.str()).starts_with("failed")) - ASSERT_EQ(diag.str(), GetParam() ? "failed to evaluate integer operation" - : "failed to evaluate om.integer.shr"); + ASSERT_EQ(diag.str(), "failed to evaluate om.integer.shr"); }); OwningOpRef owning = parseModule(mod); @@ -762,7 +731,7 @@ om.class @IntegerBinaryArithmeticShrNegative() -> (result: !om.integer){ ASSERT_TRUE(failed(result)); } -TEST_P(EvaluatorTests, IntegerBinaryArithmeticShrTooLarge) { +TEST_F(EvaluatorTests, IntegerBinaryArithmeticShrTooLarge) { StringRef mod = R"MLIR( om.class @IntegerBinaryArithmeticShrTooLarge() -> (result: !om.integer){ %0 = om.constant #om.integer<8 : si5> : !om.integer @@ -778,8 +747,7 @@ om.class @IntegerBinaryArithmeticShrTooLarge() -> (result: !om.integer){ diag.str(), "'om.integer.shr' op shift amount must be representable in 64 bits"); if (StringRef(diag.str()).starts_with("failed")) - ASSERT_EQ(diag.str(), GetParam() ? "failed to evaluate integer operation" - : "failed to evaluate om.integer.shr"); + ASSERT_EQ(diag.str(), "failed to evaluate om.integer.shr"); }); OwningOpRef owning = parseModule(mod); @@ -793,7 +761,7 @@ om.class @IntegerBinaryArithmeticShrTooLarge() -> (result: !om.integer){ ASSERT_TRUE(failed(result)); } -TEST_P(EvaluatorTests, IntegerBinaryArithmeticShl) { +TEST_F(EvaluatorTests, IntegerBinaryArithmeticShl) { StringRef mod = R"MLIR( om.class @IntegerBinaryArithmeticShl() -> (result: !om.integer){ %0 = om.constant #om.integer<8 : si7> : !om.integer @@ -815,7 +783,7 @@ om.class @IntegerBinaryArithmeticShl() -> (result: !om.integer){ ASSERT_EQ(32, getInteger(getField(result.value(), "result"))); } -TEST_P(EvaluatorTests, IntegerBinaryArithmeticShlNegative) { +TEST_F(EvaluatorTests, IntegerBinaryArithmeticShlNegative) { StringRef mod = R"MLIR( om.class @IntegerBinaryArithmeticShlNegative() -> (result: !om.integer) { %0 = om.constant #om.integer<8 : si5> : !om.integer @@ -830,8 +798,7 @@ om.class @IntegerBinaryArithmeticShlNegative() -> (result: !om.integer) { ASSERT_EQ(diag.str(), "'om.integer.shl' op shift amount must be non-negative"); if (StringRef(diag.str()).starts_with("failed")) - ASSERT_EQ(diag.str(), GetParam() ? "failed to evaluate integer operation" - : "failed to evaluate om.integer.shl"); + ASSERT_EQ(diag.str(), "failed to evaluate om.integer.shl"); }); OwningOpRef owning = parseModule(mod); @@ -845,7 +812,7 @@ om.class @IntegerBinaryArithmeticShlNegative() -> (result: !om.integer) { ASSERT_TRUE(failed(result)); } -TEST_P(EvaluatorTests, IntegerBinaryArithmeticShlTooLarge) { +TEST_F(EvaluatorTests, IntegerBinaryArithmeticShlTooLarge) { StringRef mod = R"MLIR( om.class @IntegerBinaryArithmeticShlTooLarge() -> (result: !om.integer) { %0 = om.constant #om.integer<8 : si5> : !om.integer @@ -861,8 +828,7 @@ om.class @IntegerBinaryArithmeticShlTooLarge() -> (result: !om.integer) { diag.str(), "'om.integer.shl' op shift amount must be representable in 64 bits"); if (StringRef(diag.str()).starts_with("failed")) - ASSERT_EQ(diag.str(), GetParam() ? "failed to evaluate integer operation" - : "failed to evaluate om.integer.shl"); + ASSERT_EQ(diag.str(), "failed to evaluate om.integer.shl"); }); OwningOpRef owning = parseModule(mod); @@ -876,7 +842,7 @@ om.class @IntegerBinaryArithmeticShlTooLarge() -> (result: !om.integer) { ASSERT_TRUE(failed(result)); } -TEST_P(EvaluatorTests, IntegerBinaryArithmeticObjects) { +TEST_F(EvaluatorTests, IntegerBinaryArithmeticObjects) { StringRef mod = R"MLIR( om.class @Class1() -> (value: !om.integer){ %0 = om.constant #om.integer<1 : si3> : !om.integer @@ -912,7 +878,7 @@ om.class @IntegerBinaryArithmeticObjects() -> (result: !om.integer) { ASSERT_EQ(3, getInteger(getField(result.value(), "result"))); } -TEST_P(EvaluatorTests, IntegerBinaryArithmeticObjectsDelayed) { +TEST_F(EvaluatorTests, IntegerBinaryArithmeticObjectsDelayed) { StringRef mod = R"MLIR( om.class @Class1(%input: !om.integer) -> (value: !om.integer, input: !om.integer) { %0 = om.constant #om.integer<1 : si3> : !om.integer @@ -948,7 +914,7 @@ om.class @IntegerBinaryArithmeticObjectsDelayed() -> (result: !om.integer){ ASSERT_EQ(3, getInteger(getField(result.value(), "result"))); } -TEST_P(EvaluatorTests, IntegerBinaryArithmeticWidthMismatch) { +TEST_F(EvaluatorTests, IntegerBinaryArithmeticWidthMismatch) { StringRef mod = R"MLIR( om.class @IntegerBinaryArithmeticWidthMismatch() -> (result: !om.integer) { %0 = om.constant #om.integer<1 : si3> : !om.integer @@ -970,7 +936,7 @@ om.class @IntegerBinaryArithmeticWidthMismatch() -> (result: !om.integer) { ASSERT_EQ(3, getInteger(getField(result.value(), "result"))); } -TEST_P(EvaluatorTests, ListConcat) { +TEST_F(EvaluatorTests, ListConcat) { StringRef mod = R"MLIR( om.class @ListConcat() -> (result: !om.list) { %0 = om.constant #om.integer<0 : i8> : !om.integer @@ -1000,7 +966,7 @@ om.class @ListConcat() -> (result: !om.list) { ASSERT_EQ(2, getInteger(finalList[2])); } -TEST_P(EvaluatorTests, ListConcatField) { +TEST_F(EvaluatorTests, ListConcatField) { StringRef mod = R"MLIR( om.class @ListField() -> (value: !om.list) { %0 = om.constant #om.integer<2 : i8> : !om.integer @@ -1035,7 +1001,7 @@ om.class @ListConcatField() -> (result: !om.list){ ASSERT_EQ(2, getInteger(finalList[2])); } -TEST_P(EvaluatorTests, ListOfListConcat) { +TEST_F(EvaluatorTests, ListOfListConcat) { StringRef mod = R"MLIR( om.class @ListOfListConcat() -> (result: !om.list>) { %0 = om.constant "foo" : !om.string @@ -1073,7 +1039,7 @@ om.class @ListOfListConcat() -> (result: !om.list>) { ASSERT_EQ("qux", getString(sublist1[1])); } -TEST_P(EvaluatorTests, ListConcatPartialCycle) { +TEST_F(EvaluatorTests, ListConcatPartialCycle) { StringRef mod = R"MLIR( om.class @Child(%field_in: !om.any) -> (field: !om.list) { %1 = om.list_create %field_in : !om.any @@ -1115,7 +1081,7 @@ om.class @ListConcatPartialCycle() -> (result: !om.list){ ASSERT_EQ(2, getInteger(getField(finalList[1], "id"))); } -TEST_P(EvaluatorTests, NestedReferenceValue) { +TEST_F(EvaluatorTests, NestedFieldValues) { StringRef mod = R"MLIR( om.class @Empty() { om.class.fields @@ -1172,7 +1138,7 @@ om.class @OuterClass1() -> (om: !om.any) { ASSERT_TRUE(isa(anyList2[0].get())); } -TEST_P(EvaluatorTests, ListAttrConcat) { +TEST_F(EvaluatorTests, ListAttrConcat) { StringRef mod = R"MLIR( om.class @ConcatListAttribute() -> (result: !om.list) { %0 = om.constant #om.list : !om.list @@ -1203,7 +1169,7 @@ om.class @ConcatListAttribute() -> (result: !om.list) { checkEq(listVal[3], "Y"); } -TEST_P(EvaluatorTests, UnknownValuesBasic) { +TEST_F(EvaluatorTests, UnknownValuesBasic) { StringRef mod = R"MLIR( om.class.extern @Baz() -> (a: !om.integer) {} @@ -1338,7 +1304,7 @@ om.class @Foo( checkFieldValueType("q", Kind::Object); // external class -> ObjectValue } -TEST_P(EvaluatorTests, UnknownValuesNested) { +TEST_F(EvaluatorTests, UnknownValuesNested) { StringRef mod = R"MLIR( om.class @Bar( %known_in: !om.integer, @@ -1386,7 +1352,7 @@ om.class @Foo( ASSERT_TRUE(getField(result.value(), "b")->isUnknown()); } -TEST_P(EvaluatorTests, StringConcat) { +TEST_F(EvaluatorTests, StringConcat) { const char *mod = R"MLIR( module { om.class @Test() -> (result: !om.string) { @@ -1413,7 +1379,7 @@ module { ASSERT_EQ("Hello, World!", getString(getField(result.value(), "result"))); } -TEST_P(EvaluatorTests, UnknownObjectFieldTest) { +TEST_F(EvaluatorTests, UnknownObjectFieldTest) { StringRef mod = R"MLIR( om.class.extern @Dut_Class(%basepath: !om.frozenbasepath) -> (omirOut: !om.list) { } @@ -1442,7 +1408,7 @@ om.class @TestHarness_Class(%basepath: !om.frozenbasepath) -> (result: !om.list< EXPECT_TRUE(getField(result.value(), "result")->isUnknown()); } -TEST_P(EvaluatorTests, PropertyAssertTests) { +TEST_F(EvaluatorTests, PropertyAssertTests) { StringRef mod = R"MLIR( // Test 1: A true assert passes. om.class @True() -> () { @@ -1598,8 +1564,7 @@ om.class @ChainedDomainAssert(%basepath: !om.frozenbasepath) -> () { evaluator.instantiate(StringAttr::get(&context, "SubfieldFalse"), {}))); // Test 11: Two asserts on a value flowing through chained object instances. - // Both assertions fail; the evaluator must drain the worklist before - // evaluating either assert (i.e. the fix for the null-ReferenceValue crash). + // Both assertions fail. auto basepath = std::make_shared(&context); ASSERT_TRUE(failed(evaluator.instantiate( StringAttr::get(&context, "ChainedDomainAssert"), {basepath}))); @@ -1616,7 +1581,7 @@ om.class @ChainedDomainAssert(%basepath: !om.frozenbasepath) -> () { EXPECT_EQ(actual, expected); } -TEST_P(EvaluatorTests, PropEqTests) { +TEST_F(EvaluatorTests, PropEqTests) { StringRef mod = R"MLIR( om.class @PropEqString(%s: !om.string) -> (equal: i1, not_equal: i1, unknown: i1) { %a = om.constant "hello" : !om.string @@ -1676,7 +1641,7 @@ om.class @PropEqInteger(%n: !om.integer) -> (equal: i1, not_equal: i1, unknown: } } -TEST_P(EvaluatorTests, IntegerBitwiseTests) { +TEST_F(EvaluatorTests, IntegerBitwiseTests) { StringRef mod = R"MLIR( om.class @IntegerBitwiseAnd(%a: i8, %b: i8) -> (result: i8) { %and = om.integer.and %a, %b : i8 @@ -1713,7 +1678,6 @@ om.class @IntegerBitwiseUnknown(%b: i8) -> (unknown: i8) { auto attr = mlir::IntegerAttr::get(i8Type, val); auto v = evaluator::AttributeValue::get(i8Type, unknownLoc); (void)cast(v.get())->setAttr(attr); - (void)cast(v.get())->finalize(); return v; }; @@ -1762,11 +1726,8 @@ om.class @IntegerBitwiseUnknown(%b: i8) -> (unknown: i8) { auto r = evaluator.instantiate( StringAttr::get(&context, "IntegerBitwiseUnknown"), {unknown}); ASSERT_TRUE(succeeded(r)); - ASSERT_EQ(getField(r.value(), "unknown")->isUnknown(), GetParam()); + ASSERT_FALSE(getField(r.value(), "unknown")->isUnknown()); } } -INSTANTIATE_TEST_SUITE_P(EvaluatorFlows, EvaluatorTests, - ::testing::Values(false, true), getEvaluatorFlowName); - } // namespace