14#include "mlir/IR/BuiltinAttributeInterfaces.h"
15#include "mlir/IR/Location.h"
16#include "mlir/IR/SymbolTable.h"
17#include "llvm/ADT/TypeSwitch.h"
18#include "llvm/ADT/iterator_range.h"
19#include "llvm/Support/Debug.h"
21#define DEBUG_TYPE "om-evaluator"
31 return cast<ModuleOp>(symbolTable.getOp());
34SmallVector<evaluator::EvaluatorValuePtr>
36 ArrayRef<Attribute> attributes) {
37 SmallVector<evaluator::EvaluatorValuePtr> values;
38 values.reserve(attributes.size());
39 for (
auto attr : attributes)
45 using namespace evaluator;
51 assert(isFullyEvaluated());
52 return llvm::TypeSwitch<EvaluatorValue *, LogicalResult>(
this)
58 return llvm::TypeSwitch<const EvaluatorValue *, Type>(
this)
59 .Case<
AttributeValue>([](
auto *attr) -> Type {
return attr->getType(); })
60 .Case<ObjectValue>([](
auto *
object) {
return object->getObjectType(); })
61 .Case<ListValue>([](
auto *list) {
return list->getListType(); })
62 .Case<ReferenceValue>([](
auto *ref) {
return ref->getValueType(); })
64 [
this](
auto *tuple) {
return FrozenBasePathType::get(ctx); })
66 [
this](
auto *tuple) {
return FrozenPathType::get(ctx); });
69FailureOr<evaluator::EvaluatorValuePtr>
74 TypeSwitch<mlir::Type, FailureOr<evaluator::EvaluatorValuePtr>>(type)
75 .Case([&](circt::om::ListType type) {
77 std::make_shared<evaluator::ListValue>(type, loc);
78 return success(result);
80 .Case([&](circt::om::ClassType type)
81 -> FailureOr<evaluator::EvaluatorValuePtr> {
83 symbolTable.lookup<ClassLike>(type.getClassName().getValue());
85 return symbolTable.getOp()->emitError(
"unknown class name ")
86 << type.getClassName();
90 std::make_shared<evaluator::ObjectValue>(classDef, loc);
92 return success(result);
94 .Case([&](circt::om::StringType type) {
97 return success(result);
99 .Default([&](
auto type) {
return failure(); });
101 if (succeeded(result))
102 attachCounter(result.value());
109 LLVM_DEBUG(dbgs() <<
"- get: " << value <<
"\n");
111 auto it = objects.find({value, actualParams});
112 if (it != objects.end()) {
113 auto evalVal = it->second;
114 evalVal->setLocIfUnknown(loc);
118 FailureOr<evaluator::EvaluatorValuePtr> result =
119 TypeSwitch<Value, FailureOr<evaluator::EvaluatorValuePtr>>(value)
120 .Case([&](BlockArgument arg) {
121 auto val = (*actualParams)[arg.getArgNumber()];
125 .Case([&](OpResult result) {
126 return TypeSwitch<Operation *,
127 FailureOr<evaluator::EvaluatorValuePtr>>(
128 result.getDefiningOp())
129 .Case([&](ConstantOp op) {
130 return evaluateConstant(op, actualParams, loc);
132 .Case([&](IntegerBinaryOp op) {
138 return success(result);
140 .Case<ObjectFieldOp>([&](
auto op) {
144 std::make_shared<evaluator::ReferenceValue>(
145 value.getType(), loc);
146 return success(result);
148 .Case<AnyCastOp>([&](AnyCastOp op) {
149 return getOrCreateValue(op.getInput(), actualParams, loc);
151 .Case<FrozenBasePathCreateOp>([&](FrozenBasePathCreateOp op) {
153 std::make_shared<evaluator::BasePathValue>(
154 op.getPathAttr(), loc);
155 return success(result);
157 .Case<FrozenPathCreateOp>([&](FrozenPathCreateOp op) {
159 std::make_shared<evaluator::PathValue>(
160 op.getTargetKindAttr(), op.getPathAttr(),
161 op.getModuleAttr(), op.getRefAttr(),
162 op.getFieldAttr(), loc);
163 return success(result);
165 .Case<FrozenEmptyPathOp>([&](FrozenEmptyPathOp op) {
167 std::make_shared<evaluator::PathValue>(
169 return success(result);
171 .Case([&](BinaryEqualityOp op) {
175 return success(result);
177 .Case<ListCreateOp, ListConcatOp, StringConcatOp,
178 ObjectFieldOp>([&](
auto op) {
179 return getPartiallyEvaluatedValue(op.getType(), loc);
181 .Case<ObjectOp>([&](
auto op) {
182 return getPartiallyEvaluatedValue(op.getType(), op.getLoc());
184 .Case<UnknownValueOp>(
185 [&](
auto op) {
return evaluateUnknownValue(op, loc); })
186 .Default([&](Operation *op) {
187 auto error = op->emitError(
"unable to evaluate value");
188 error.attachNote() <<
"value: " << value;
196 attachCounter(result.value());
197 objects[{value, actualParams}] = result.value();
201FailureOr<evaluator::EvaluatorValuePtr>
209 LLVM_DEBUG(dbgs() <<
"object:\n");
213 LLVM_DEBUG(dbgs() <<
"name: " << className <<
"\n");
215 auto classDef = symbolTable.lookup<ClassLike>(className);
217 return symbolTable.getOp()->emitError(
"unknown class name ") << className;
220 if (isa<ClassExternOp>(classDef)) {
222 std::make_shared<evaluator::ObjectValue>(classDef, loc);
223 attachCounter(result);
224 result->markUnknown();
225 LLVM_DEBUG(dbgs(1) <<
"extern: <unknown-value>\n");
230 ClassOp cls = cast<ClassOp>(classDef);
232 auto formalParamNames = cls.getFormalParamNames().getAsRange<StringAttr>();
233 auto formalParamTypes = cls.getBodyBlock()->getArgumentTypes();
236 if (actualParams->size() != formalParamTypes.size()) {
237 auto error = cls.emitError(
"actual parameter list length (")
238 << actualParams->size() <<
") does not match formal "
239 <<
"parameter list length (" << formalParamTypes.size() <<
")";
240 auto &diag = error.attachNote() <<
"actual parameters: ";
243 for (
const auto ¶m : *actualParams) {
250 error.attachNote(cls.getLoc()) <<
"formal parameters: " << formalParamTypes;
255 for (
auto [actualParam, formalParamName, formalParamType] :
256 llvm::zip(*actualParams, formalParamNames, formalParamTypes)) {
257 if (!actualParam || !actualParam.get())
258 return cls.emitError(
"actual parameter for ")
259 << formalParamName <<
" is null";
262 if (isa<AnyType>(formalParamType))
265 Type actualParamType = actualParam->getType();
267 assert(actualParamType &&
"actualParamType must be non-null!");
269 if (actualParamType != formalParamType) {
270 auto error = cls.emitError(
"actual parameter for ")
271 << formalParamName <<
" has invalid type";
272 error.attachNote() <<
"actual parameter: " << *actualParam;
273 error.attachNote() <<
"format parameter type: " << formalParamType;
281 auto *
context = cls.getContext();
283 LLVM_DEBUG(dbgs() <<
"ops:\n");
287 for (
auto &op : cls.getOps())
288 for (
auto result : op.getResults()) {
291 if (failed(getOrCreateValue(result, actualParams,
295 worklist.push_back({result, actualParams});
299 LLVM_DEBUG(dbgs() <<
"fields:\n");
300 auto fieldNames = cls.getFieldNames();
301 auto operands = cls.getFieldsOp()->getOperands();
302 for (
size_t i = 0; i < fieldNames.size(); ++i) {
303 auto name = fieldNames[i];
304 auto value = operands[i];
305 auto fieldLoc = cls.getFieldLocByIndex(i);
306 LLVM_DEBUG(dbgs() <<
"- name: " << name <<
"\n"
307 << indent(1) <<
"evaluate:\n");
311 FailureOr<evaluator::EvaluatorValuePtr> result =
312 evaluateValue(value, actualParams, fieldLoc);
316 LLVM_DEBUG(dbgs() <<
"value: " << result.value() <<
"\n");
317 fields[cast<StringAttr>(name)] = result.value();
322 LLVM_DEBUG(dbgs() <<
"queuing asserts:\n");
323 for (
auto assertOp : cls.getOps<PropertyAssertOp>()) {
324 LLVM_DEBUG(dbgs(1) <<
"- " << assertOp <<
"\n");
325 pendingAsserts.push({assertOp, actualParams});
329 LLVM_DEBUG(dbgs() <<
"object value:\n");
330 if (instanceKey.first) {
332 getOrCreateValue(instanceKey.first, instanceKey.second, loc).value();
333 auto *
object = llvm::cast<evaluator::ObjectValue>(result.get());
334 object->setFields(std::move(fields));
340 std::make_shared<evaluator::ObjectValue>(cls, fields, loc);
342 assert(result->isFullyEvaluated() &&
343 "object with fields should be fully evaluated");
348FailureOr<std::shared_ptr<evaluator::EvaluatorValue>>
350 StringAttr className, ArrayRef<evaluator::EvaluatorValuePtr> actualParams) {
351 LLVM_DEBUG(dbgs() <<
"instantiate:\n");
356 dbgs() <<
"class: " << className <<
"\n" << indent() <<
"params:\n";
357 for (
auto ¶m : actualParams)
358 dbgs() <<
"- " << param <<
"\n";
361 auto classDef = symbolTable.lookup<ClassLike>(className);
363 return symbolTable.getOp()->emitError(
"unknown class name ") << className;
366 if (isa<ClassExternOp>(classDef)) {
368 std::make_shared<evaluator::ObjectValue>(
369 classDef, UnknownLoc::get(classDef.getContext()));
370 attachCounter(result);
371 result->markUnknown();
372 LLVM_DEBUG(dbgs(1) <<
"result: <unknown extern>\n");
377 ClassOp cls = cast<ClassOp>(classDef);
380 std::make_unique<SmallVector<std::shared_ptr<evaluator::EvaluatorValue>>>(
383 actualParametersBuffers.push_back(std::move(parameters));
385 auto loc = cls.getLoc();
386 LLVM_DEBUG(dbgs() <<
"evaluate object:\n");
387 auto result = evaluateObjectInstance(
388 className, actualParametersBuffers.back().get(), loc);
395 LLVM_DEBUG(dbgs() <<
"worklist:\n");
400 while (!worklist.empty()) {
401 uint64_t countBeforePass = fullyEvaluatedCount;
402 LLVM_DEBUG(dbgs() <<
"- processing " << worklist.size()
403 <<
" items (fully evaluated count: "
404 << fullyEvaluatedCount <<
")\n");
407 while (!worklist.empty()) {
408 auto [value, args] = worklist.back();
410 auto result = evaluateValue(value, args, loc);
416 if (!result.value()->isFullyEvaluated())
417 nextWorklist.push_back({value, args});
421 uint64_t evaluatedThisPass = fullyEvaluatedCount - countBeforePass;
422 LLVM_DEBUG(dbgs() <<
"- evaluated " << evaluatedThisPass
423 <<
" nodes this pass\n");
426 if (evaluatedThisPass == 0 && !nextWorklist.empty())
427 return cls.emitError()
428 <<
"cycle detected: " << nextWorklist.size()
429 <<
" values remain partially evaluated after full pass with no "
430 "progress (total fully evaluated: "
431 << fullyEvaluatedCount <<
")";
434 worklist = std::move(nextWorklist);
435 nextWorklist.clear();
440 LLVM_DEBUG(dbgs() <<
"asserts:\n");
441 bool assertFailed =
false;
442 while (!pendingAsserts.empty()) {
443 auto [assertOp, assertParams] = pendingAsserts.front();
444 pendingAsserts.pop();
445 assertFailed |= failed(evaluatePropertyAssert(assertOp, assertParams));
450 auto &
object = result.value();
453 LLVM_DEBUG(dbgs() <<
"finalizing\n");
454 if (failed(object->finalize()))
455 return cls.emitError() <<
"failed to finalize evaluation. Probably the "
456 "class contains a dataflow cycle";
457 LLVM_DEBUG(dbgs() <<
"result: " <<
object <<
"\n");
461FailureOr<evaluator::EvaluatorValuePtr>
464 auto evaluatorValue = getOrCreateValue(value, actualParams, loc).value();
466 LLVM_DEBUG(dbgs() <<
"- eval: " << value <<
"\n");
469 if (evaluatorValue->isFullyEvaluated()) {
470 LLVM_DEBUG(dbgs(1) <<
"fully evaluated: " << evaluatorValue <<
"\n");
471 return evaluatorValue;
474 return llvm::TypeSwitch<Value, FailureOr<evaluator::EvaluatorValuePtr>>(value)
475 .Case([&](BlockArgument arg) {
476 return evaluateParameter(arg, actualParams, loc);
478 .Case([&](OpResult result) {
479 return TypeSwitch<Operation *, FailureOr<evaluator::EvaluatorValuePtr>>(
480 result.getDefiningOp())
481 .Case([&](ConstantOp op) {
482 return evaluateConstant(op, actualParams, loc);
484 .Case([&](IntegerBinaryOp op) {
485 return evaluateIntegerBinary(op, actualParams, loc);
487 .Case([&](ObjectOp op) {
488 return evaluateObjectInstance(op, actualParams);
490 .Case([&](ObjectFieldOp op) {
491 return evaluateObjectField(op, actualParams, loc);
493 .Case([&](ListCreateOp op) {
494 return evaluateListCreate(op, actualParams, loc);
496 .Case([&](ListConcatOp op) {
497 return evaluateListConcat(op, actualParams, loc);
499 .Case([&](StringConcatOp op) {
500 return evaluateStringConcat(op, actualParams, loc);
502 .Case([&](BinaryEqualityOp op) {
503 return evaluateBinaryEquality(op, actualParams, loc);
505 .Case([&](AnyCastOp op) {
506 return evaluateValue(op.getInput(), actualParams, loc);
508 .Case([&](FrozenBasePathCreateOp op) {
509 return evaluateBasePathCreate(op, actualParams, loc);
511 .Case([&](FrozenPathCreateOp op) {
512 return evaluatePathCreate(op, actualParams, loc);
514 .Case([&](FrozenEmptyPathOp op) {
515 return evaluateEmptyPath(op, actualParams, loc);
517 .Case<UnknownValueOp>([&](UnknownValueOp op) {
518 return evaluateUnknownValue(op, loc);
520 .Default([&](Operation *op) {
521 auto error = op->emitError(
"unable to evaluate value");
522 error.attachNote() <<
"value: " << value;
531 auto val = (*actualParams)[formalParam.getArgNumber()];
537FailureOr<circt::om::evaluator::EvaluatorValuePtr>
549 auto handle = getOrCreateValue(op.getResult(), actualParams, loc);
552 if (handle.value()->isFullyEvaluated())
557 auto lhsResult = evaluateValue(op.getLhs(), actualParams, loc);
558 if (failed(lhsResult))
560 if (!lhsResult.value()->isFullyEvaluated())
563 auto rhsResult = evaluateValue(op.getRhs(), actualParams, loc);
564 if (failed(rhsResult))
566 if (!rhsResult.value()->isFullyEvaluated())
570 if (lhsResult.value()->isUnknown() || rhsResult.value()->isUnknown()) {
571 handle.value()->markUnknown();
578 return llvm::TypeSwitch<evaluator::EvaluatorValue *, Attribute>(value)
581 return cast<evaluator::AttributeValue>(val->getStrippedValue()->
get())
586 mlir::Attribute lhsAttr = extractAttr(lhsResult.value().get());
587 mlir::Attribute rhsAttr = extractAttr(rhsResult.value().get());
588 assert(lhsAttr && rhsAttr &&
589 "expected attribute for IntegerBinaryOp operands");
591 std::array<Attribute, 2> operandAttrs = {lhsAttr, rhsAttr};
592 SmallVector<mlir::OpFoldResult, 1> results;
593 mlir::Attribute resultAttr;
596 if (failed(op->fold(operandAttrs, results)) || results.size() != 1 ||
597 !(resultAttr = results[0].dyn_cast<Attribute>()))
598 return op->emitError(
"failed to evaluate integer operation");
601 auto *handleValue = cast<evaluator::AttributeValue>(handle.value().get());
602 auto resultStatus = handleValue->setAttr(resultAttr);
603 if (failed(resultStatus))
606 auto finalizeStatus = handleValue->finalize();
607 if (failed(finalizeStatus))
608 return finalizeStatus;
621 auto loc = op.getLoc();
624 LLVM_DEBUG(dbgs() <<
"op: " << op <<
"\n"
625 << indent() <<
"evaluate condition: \n");
626 auto condResult = evaluateValue(op.getCondition(), actualParams, loc);
627 if (failed(condResult))
629 if (!condResult.value()->isFullyEvaluated()) {
630 LLVM_DEBUG(dbgs() <<
"evaluate condition: <not fully evaluated>\n");
635 if (condResult.value()->isUnknown())
638 LLVM_DEBUG(dbgs() <<
"condition: " << condResult.value() <<
"\n");
644 return llvm::TypeSwitch<evaluator::EvaluatorValue *, mlir::Attribute>(value)
647 auto stripped = val->getStrippedValue();
648 if (failed(stripped))
651 dyn_cast<evaluator::AttributeValue>(stripped.value().get()))
655 .Default([](
auto *) -> mlir::Attribute {
return {}; });
658 auto condAttr = extractAttr(condResult.value().get());
662 bool isFalse =
false;
663 if (
auto boolAttr = dyn_cast<BoolAttr>(condAttr))
664 isFalse = !boolAttr.getValue();
665 else if (
auto intAttr = dyn_cast<mlir::IntegerAttr>(condAttr))
666 isFalse = intAttr.getValue().isZero();
668 return op.emitError(
"expected BoolAttr or mlir::IntegerAttr");
671 return op.emitError(
"OM property assertion failed: ") << op.getMessage();
677FailureOr<circt::om::Evaluator::ActualParameters>
681 auto parameters = std::make_unique<
682 SmallVector<std::shared_ptr<evaluator::EvaluatorValue>>>();
685 for (
auto input : range) {
686 auto inputResult = getOrCreateValue(input, actualParams, loc);
687 if (failed(inputResult))
689 parameters->push_back(inputResult.value());
692 actualParametersBuffers.push_back(std::move(parameters));
693 return actualParametersBuffers.back().get();
697FailureOr<evaluator::EvaluatorValuePtr>
700 auto loc = op.getLoc();
701 if (isFullyEvaluated({op, actualParams}))
702 return getOrCreateValue(op, actualParams, loc);
705 createParametersFromOperands(op.getOperands(), actualParams, loc);
708 return evaluateObjectInstance(op.getClassNameAttr(), params.value(), loc,
713FailureOr<evaluator::EvaluatorValuePtr>
718 FailureOr<evaluator::EvaluatorValuePtr> currentObjectResult =
719 evaluateValue(op.getObject(), actualParams, loc);
720 if (failed(currentObjectResult))
721 return currentObjectResult;
723 auto result = currentObjectResult.value();
725 auto objectFieldValue = getOrCreateValue(op, actualParams, loc).value();
727 if (result->isUnknown()) {
731 llvm::dyn_cast<evaluator::ReferenceValue>(objectFieldValue.get())) {
732 auto unknownField = createUnknownValue(op.getResult().getType(), loc);
733 if (failed(unknownField))
735 ref->setValue(unknownField.value());
738 objectFieldValue->markUnknown();
739 return objectFieldValue;
743 if (
auto *ref = llvm::dyn_cast<evaluator::ReferenceValue>(result.get())) {
744 auto stripped = ref->getStrippedValue();
745 if (failed(stripped))
747 result = stripped.value();
750 auto *currentObject = llvm::cast<evaluator::ObjectValue>(result.get());
752 auto field = op.getFieldAttr();
755 if (!currentObject->getFields().contains(field))
756 return objectFieldValue;
758 auto currentField = currentObject->getField(field);
759 auto finalField = currentField.value();
761 if (!finalField->isFullyEvaluated())
762 return objectFieldValue;
765 llvm::cast<evaluator::ReferenceValue>(objectFieldValue.get())
766 ->setValue(finalField);
769 return objectFieldValue;
773FailureOr<evaluator::EvaluatorValuePtr>
778 SmallVector<evaluator::EvaluatorValuePtr> values;
779 auto list = getOrCreateValue(op, actualParams, loc);
780 bool hasUnknown =
false;
781 for (
auto operand : op.getOperands()) {
782 auto result = evaluateValue(operand, actualParams, loc);
785 if (!result.value()->isFullyEvaluated())
788 if (result.value()->isUnknown())
790 values.push_back(result.value());
794 llvm::cast<evaluator::ListValue>(list.value().get())
795 ->setElements(std::move(values));
801 list.value()->markUnknown();
807FailureOr<evaluator::EvaluatorValuePtr>
812 SmallVector<evaluator::EvaluatorValuePtr> values;
813 auto list = getOrCreateValue(op, actualParams, loc);
818 llvm::TypeSwitch<evaluator::EvaluatorValue *, evaluator::ListValue *>(
822 return cast<evaluator::ListValue>(val->getStrippedValue()->get());
826 bool hasUnknown =
false;
827 for (
auto operand : op.getOperands()) {
828 auto result = evaluateValue(operand, actualParams, loc);
831 if (!result.value()->isFullyEvaluated())
834 if (result.value()->isUnknown())
843 for (
const auto &subValue : subList->
getElements())
844 values.push_back(subValue);
848 llvm::cast<evaluator::ListValue>(list.value().get())
849 ->setElements(std::move(values));
855 list.value()->markUnknown();
861FailureOr<evaluator::EvaluatorValuePtr>
866 auto handle = getOrCreateValue(op.getResult(), actualParams, loc);
871 if (handle.value()->isFullyEvaluated())
877 return llvm::TypeSwitch<evaluator::EvaluatorValue *, StringAttr>(value)
879 return val->
getAs<StringAttr>();
882 return cast<evaluator::AttributeValue>(val->getStrippedValue()->
get())
883 ->getAs<StringAttr>();
889 for (
auto operand : op.getOperands()) {
890 auto operandResult = evaluateValue(operand, actualParams, loc);
891 if (failed(operandResult))
892 return operandResult;
893 if (!operandResult.value()->isFullyEvaluated())
896 StringAttr str = extractAttr(operandResult.value().get());
897 assert(str &&
"expected StringAttr for StringConcatOp operand");
898 result += str.getValue().str();
902 auto resultStr = StringAttr::get(result, op.getResult().getType());
905 auto *handleValue = cast<evaluator::AttributeValue>(handle.value().get());
906 auto resultStatus = handleValue->setAttr(resultStr);
907 if (failed(resultStatus))
910 auto finalizeStatus = handleValue->finalize();
911 if (failed(finalizeStatus))
912 return finalizeStatus;
918FailureOr<evaluator::EvaluatorValuePtr>
923 auto handle = getOrCreateValue(op.getResult(), actualParams, loc);
928 if (handle.value()->isFullyEvaluated())
933 auto lhsResult = evaluateValue(op.getLhs(), actualParams, loc);
934 if (failed(lhsResult))
936 if (!lhsResult.value()->isFullyEvaluated())
939 auto rhsResult = evaluateValue(op.getRhs(), actualParams, loc);
940 if (failed(rhsResult))
942 if (!rhsResult.value()->isFullyEvaluated())
946 if (lhsResult.value()->isUnknown() || rhsResult.value()->isUnknown()) {
947 handle.value()->markUnknown();
954 return llvm::TypeSwitch<evaluator::EvaluatorValue *, mlir::Attribute>(value)
957 return cast<evaluator::AttributeValue>(val->getStrippedValue()->
get())
962 mlir::Attribute lhs = extractAttr(lhsResult.value().get());
963 mlir::Attribute rhs = extractAttr(rhsResult.value().get());
964 assert(lhs && rhs &&
"expected attribute for BinaryEqualityOp operands");
967 FailureOr<mlir::Attribute> result = op.evaluateBinaryEquality(lhs, rhs);
969 return op->emitError(
"failed to evaluate binary equality operation");
972 auto *handleValue = cast<evaluator::AttributeValue>(handle.value().get());
973 auto resultStatus = handleValue->setAttr(*result);
974 if (failed(resultStatus))
977 auto finalizeStatus = handleValue->finalize();
978 if (failed(finalizeStatus))
979 return finalizeStatus;
984FailureOr<evaluator::EvaluatorValuePtr>
989 auto valueResult = getOrCreateValue(op, actualParams, loc).value();
990 auto *path = llvm::cast<evaluator::BasePathValue>(valueResult.get());
991 auto result = evaluateValue(op.getBasePath(), actualParams, loc);
994 auto &value = result.value();
995 if (!value->isFullyEvaluated())
999 if (result.value()->isUnknown()) {
1000 valueResult->markUnknown();
1004 path->setBasepath(*llvm::cast<evaluator::BasePathValue>(value.get()));
1008FailureOr<evaluator::EvaluatorValuePtr>
1013 auto valueResult = getOrCreateValue(op, actualParams, loc).value();
1014 auto *path = llvm::cast<evaluator::PathValue>(valueResult.get());
1015 auto result = evaluateValue(op.getBasePath(), actualParams, loc);
1018 auto &value = result.value();
1019 if (!value->isFullyEvaluated())
1023 if (result.value()->isUnknown()) {
1024 valueResult->markUnknown();
1028 path->setBasepath(*llvm::cast<evaluator::BasePathValue>(value.get()));
1034 auto valueResult = getOrCreateValue(op, actualParams, loc).value();
1039FailureOr<evaluator::EvaluatorValuePtr>
1045 TypeSwitch<Type, FailureOr<EvaluatorValuePtr>>(type)
1046 .Case([&](ListType type) -> FailureOr<EvaluatorValuePtr> {
1048 return success(std::make_shared<ListValue>(type, loc));
1050 .Case([&](ClassType type) -> FailureOr<EvaluatorValuePtr> {
1053 symbolTable.lookup<ClassLike>(type.getClassName().getValue());
1055 return symbolTable.getOp()->emitError(
"unknown class name ")
1056 << type.getClassName();
1059 return success(std::make_shared<ObjectValue>(classDef, loc));
1061 .Case([&](FrozenBasePathType type) -> FailureOr<EvaluatorValuePtr> {
1063 return success(std::make_shared<BasePathValue>(type.getContext()));
1065 .Case([&](FrozenPathType type) -> FailureOr<EvaluatorValuePtr> {
1068 std::make_shared<PathValue>(PathValue::getEmptyPath(loc)));
1070 .Default([&](Type type) -> FailureOr<EvaluatorValuePtr> {
1073 return success(AttributeValue::get(type, LocationAttr(loc)));
1077 if (succeeded(result))
1078 result->get()->markUnknown();
1084FailureOr<evaluator::EvaluatorValuePtr>
1086 return createUnknownValue(op.getType(), loc);
1094FailureOr<EvaluatorValuePtr>
1096 auto field = fields.find(name);
1097 if (field == fields.end())
1098 return cls.emitError(
"field ") << name <<
" does not exist";
1099 return success(fields[name]);
1105 SmallVector<Attribute> fieldNames;
1106 for (
auto &f : fields)
1107 fieldNames.push_back(f.first);
1109 llvm::sort(fieldNames, [](Attribute a, Attribute b) {
1110 return cast<StringAttr>(a).getValue() < cast<StringAttr>(b).getValue();
1113 return ArrayAttr::get(cls.getContext(), fieldNames);
1117 for (
auto &&[e, value] : fields)
1118 if (failed(finalizeEvaluatorValue(value)))
1129 auto result = getStrippedValue();
1132 value = std::move(result.value());
1134 if (failed(finalizeEvaluatorValue(value)))
1145 for (
auto &value : elements) {
1146 if (failed(finalizeEvaluatorValue(value)))
1158 path(PathAttr::get(
context, {})) {
1159 markFullyEvaluated();
1163 :
EvaluatorValue(path.getContext(), Kind::BasePath, loc), path(path) {}
1166 assert(isFullyEvaluated());
1171 assert(!isFullyEvaluated());
1172 auto newPath = llvm::to_vector(basepath.
path.getPath());
1173 auto oldPath = path.getPath();
1174 newPath.append(oldPath.begin(), oldPath.end());
1175 path = PathAttr::get(path.getContext(), newPath);
1176 markFullyEvaluated();
1184 StringAttr module, StringAttr ref,
1185 StringAttr field, Location loc)
1187 path(path), module(module), ref(ref), field(field) {}
1190 PathValue path(
nullptr,
nullptr,
nullptr,
nullptr,
nullptr, loc);
1198 return StringAttr::get(getContext(),
"OMDeleted:");
1199 SmallString<64> result;
1200 switch (targetKind.getValue()) {
1201 case TargetKind::DontTouch:
1202 result +=
"OMDontTouchedReferenceTarget";
1204 case TargetKind::Instance:
1205 result +=
"OMInstanceTarget";
1207 case TargetKind::MemberInstance:
1208 result +=
"OMMemberInstanceTarget";
1210 case TargetKind::MemberReference:
1211 result +=
"OMMemberReferenceTarget";
1213 case TargetKind::Reference:
1214 result +=
"OMReferenceTarget";
1218 if (!path.getPath().empty())
1219 result += path.getPath().front().module;
1221 result +=
module.getValue();
1223 for (
const auto &elt : path) {
1224 result += elt.module.getValue();
1226 result += elt.instance.getValue();
1229 if (!module.getValue().empty())
1230 result += module.getValue();
1231 if (!ref.getValue().empty()) {
1233 result += ref.getValue();
1235 if (!field.getValue().empty())
1236 result += field.getValue();
1237 return StringAttr::get(field.getContext(), result);
1241 assert(!isFullyEvaluated());
1242 auto newPath = llvm::to_vector(basepath.
getPath().getPath());
1243 auto oldPath = path.getPath();
1244 newPath.append(oldPath.begin(), oldPath.end());
1245 path = PathAttr::get(path.getContext(), newPath);
1246 markFullyEvaluated();
1254 if (cast<TypedAttr>(attr).getType() != this->type)
1255 return mlir::emitError(
getLoc(),
"cannot set AttributeValue of type ")
1256 << this->type <<
" to Attribute " << attr;
1257 if (isFullyEvaluated())
1258 return mlir::emitError(
1260 "cannot set AttributeValue that has already been fully evaluated");
1262 markFullyEvaluated();
1267 if (!isFullyEvaluated())
1268 return mlir::emitError(
1269 getLoc(),
"cannot finalize AttributeValue that is not fully evaluated");
1273std::shared_ptr<evaluator::EvaluatorValue>
1275 auto type = cast<TypedAttr>(attr).getType();
1276 auto *
context = type.getContext();
1278 loc = UnknownLoc::get(
context);
1282 if (
auto listType = dyn_cast<circt::om::ListType>(type)) {
1283 SmallVector<EvaluatorValuePtr> elements;
1284 auto listAttr = cast<om::ListAttr>(attr);
1286 listAttr.getContext(), listAttr.getElements().getValue());
1287 elements.append(values.begin(), values.end());
1288 auto list = std::make_shared<evaluator::ListValue>(listType, elements, loc);
1292 return std::shared_ptr<AttributeValue>(
1296std::shared_ptr<evaluator::EvaluatorValue>
1298 auto *
context = type.getContext();
1300 loc = UnknownLoc::get(
context);
1304 if (
auto listType = dyn_cast<circt::om::ListType>(type))
1305 return std::make_shared<evaluator::ListValue>(listType, loc);
1307 return std::shared_ptr<AttributeValue>(
assert(baseType &&"element must be base type")
static std::unique_ptr< Context > context
static Location getLoc(DefSlot slot)
FailureOr< evaluator::EvaluatorValuePtr > evaluateBasePathCreate(FrozenBasePathCreateOp op, ActualParameters actualParams, Location loc)
FailureOr< evaluator::EvaluatorValuePtr > evaluateEmptyPath(FrozenEmptyPathOp op, ActualParameters actualParams, Location loc)
FailureOr< evaluator::EvaluatorValuePtr > getPartiallyEvaluatedValue(Type type, Location loc)
FailureOr< EvaluatorValuePtr > evaluateValue(Value value, ActualParameters actualParams, Location loc)
Evaluate a Value in a Class body according to the small expression grammar described in the rationale...
FailureOr< EvaluatorValuePtr > evaluateConstant(ConstantOp op, ActualParameters actualParams, Location loc)
Evaluator dispatch function for constants.
FailureOr< EvaluatorValuePtr > evaluateStringConcat(StringConcatOp op, ActualParameters actualParams, Location loc)
Evaluator dispatch function for String concatenation.
LogicalResult evaluatePropertyAssert(PropertyAssertOp op, ActualParameters actualParams)
Evaluator dispatch function for property assertions.
mlir::ModuleOp getModule()
Get the Module this Evaluator is built from.
FailureOr< EvaluatorValuePtr > evaluateObjectField(ObjectFieldOp op, ActualParameters actualParams, Location loc)
Evaluator dispatch function for Object fields.
FailureOr< evaluator::EvaluatorValuePtr > createUnknownValue(Type type, Location loc)
Create an unknown value of the specified type.
FailureOr< EvaluatorValuePtr > evaluateIntegerBinary(IntegerBinaryOp op, ActualParameters actualParams, Location loc)
FailureOr< evaluator::EvaluatorValuePtr > evaluateUnknownValue(UnknownValueOp op, Location loc)
Evaluate an unknown value.
Evaluator(ModuleOp mod)
Construct an Evaluator with an IR module.
FailureOr< evaluator::EvaluatorValuePtr > instantiate(StringAttr className, ArrayRef< EvaluatorValuePtr > actualParams)
Instantiate an Object with its class name and actual parameters.
FailureOr< EvaluatorValuePtr > getOrCreateValue(Value value, ActualParameters actualParams, Location loc)
SmallVectorImpl< std::shared_ptr< evaluator::EvaluatorValue > > * ActualParameters
FailureOr< EvaluatorValuePtr > evaluateBinaryEquality(BinaryEqualityOp op, ActualParameters actualParams, Location loc)
FailureOr< EvaluatorValuePtr > evaluateListCreate(ListCreateOp op, ActualParameters actualParams, Location loc)
Evaluator dispatch function for List creation.
FailureOr< EvaluatorValuePtr > evaluateListConcat(ListConcatOp op, ActualParameters actualParams, Location loc)
Evaluator dispatch function for List concatenation.
std::pair< Value, ActualParameters > ObjectKey
FailureOr< EvaluatorValuePtr > evaluateParameter(BlockArgument formalParam, ActualParameters actualParams, Location loc)
Evaluator dispatch functions for the small expression grammar.
FailureOr< EvaluatorValuePtr > evaluateObjectInstance(StringAttr className, ActualParameters actualParams, Location loc, ObjectKey instanceKey={})
Instantiate an Object with its class name and actual parameters.
FailureOr< evaluator::EvaluatorValuePtr > evaluatePathCreate(FrozenPathCreateOp op, ActualParameters actualParams, Location loc)
FailureOr< ActualParameters > createParametersFromOperands(ValueRange range, ActualParameters actualParams, Location loc)
Evaluator dispatch function for Object instances.
Values which can be directly representable by MLIR attributes.
LogicalResult setAttr(Attribute attr)
LogicalResult finalizeImpl()
friend std::shared_ptr< EvaluatorValue > get(Attribute attr, LocationAttr loc)
Attribute getAttr() const
static std::shared_ptr< EvaluatorValue > get(Attribute attr, LocationAttr loc={})
BasePathValue(MLIRContext *context)
void setBasepath(const BasePathValue &basepath)
Set the basepath which this path is relative to.
om::PathAttr getPath() const
Base class for evaluator runtime values.
bool isFullyEvaluated() const
void markFullyEvaluated()
A List which contains variadic length of elements with the same type.
const auto & getElements() const
LogicalResult finalizeImpl()
A composite Object, which has a type and fields.
LogicalResult finalizeImpl()
FailureOr< EvaluatorValuePtr > getField(StringAttr field)
Get a field of the Object by name.
ArrayAttr getFieldNames()
Get all the field names of the Object.
StringAttr getAsString() const
void setBasepath(const BasePathValue &basepath)
PathValue(om::TargetKindAttr targetKind, om::PathAttr path, StringAttr module, StringAttr ref, StringAttr field, Location loc)
Create a path value representing a regular path.
static PathValue getEmptyPath(Location loc)
Values which can be used as pointers to different values.
LogicalResult finalizeImpl()
std::shared_ptr< EvaluatorValue > EvaluatorValuePtr
A value of an object in memory.
SmallVector< EvaluatorValuePtr > getEvaluatorValuesFromAttributes(MLIRContext *context, ArrayRef< Attribute > attributes)
RAII helper to increment/decrement debugNesting.