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>
73 return TypeSwitch<mlir::Type, FailureOr<evaluator::EvaluatorValuePtr>>(type)
74 .Case([&](circt::om::ListType type) {
76 std::make_shared<evaluator::ListValue>(type, loc);
77 return success(result);
79 .Case([&](circt::om::ClassType type)
80 -> FailureOr<evaluator::EvaluatorValuePtr> {
82 symbolTable.lookup<ClassLike>(type.getClassName().getValue());
84 return symbolTable.getOp()->emitError(
"unknown class name ")
85 << type.getClassName();
89 std::make_shared<evaluator::ObjectValue>(classDef, loc);
91 return success(result);
93 .Case([&](circt::om::StringType type) {
96 return success(result);
98 .Default([&](
auto type) {
return failure(); });
103 LLVM_DEBUG(dbgs() <<
"- get: " << value <<
"\n");
105 auto it = objects.find({value, actualParams});
106 if (it != objects.end()) {
107 auto evalVal = it->second;
108 evalVal->setLocIfUnknown(loc);
112 FailureOr<evaluator::EvaluatorValuePtr> result =
113 TypeSwitch<Value, FailureOr<evaluator::EvaluatorValuePtr>>(value)
114 .Case([&](BlockArgument arg) {
115 auto val = (*actualParams)[arg.getArgNumber()];
119 .Case([&](OpResult result) {
120 return TypeSwitch<Operation *,
121 FailureOr<evaluator::EvaluatorValuePtr>>(
122 result.getDefiningOp())
123 .Case([&](ConstantOp op) {
124 return evaluateConstant(op, actualParams, loc);
126 .Case([&](IntegerBinaryArithmeticOp op) {
132 return success(result);
134 .Case<ObjectFieldOp>([&](
auto op) {
138 std::make_shared<evaluator::ReferenceValue>(
139 value.getType(), loc);
140 return success(result);
142 .Case<AnyCastOp>([&](AnyCastOp op) {
143 return getOrCreateValue(op.getInput(), actualParams, loc);
145 .Case<FrozenBasePathCreateOp>([&](FrozenBasePathCreateOp op) {
147 std::make_shared<evaluator::BasePathValue>(
148 op.getPathAttr(), loc);
149 return success(result);
151 .Case<FrozenPathCreateOp>([&](FrozenPathCreateOp op) {
153 std::make_shared<evaluator::PathValue>(
154 op.getTargetKindAttr(), op.getPathAttr(),
155 op.getModuleAttr(), op.getRefAttr(),
156 op.getFieldAttr(), loc);
157 return success(result);
159 .Case<FrozenEmptyPathOp>([&](FrozenEmptyPathOp op) {
161 std::make_shared<evaluator::PathValue>(
163 return success(result);
165 .Case([&](BinaryEqualityOp op) {
169 return success(result);
171 .Case<ListCreateOp, ListConcatOp, StringConcatOp,
172 ObjectFieldOp>([&](
auto op) {
173 return getPartiallyEvaluatedValue(op.getType(), loc);
175 .Case<ObjectOp>([&](
auto op) {
176 return getPartiallyEvaluatedValue(op.getType(), op.getLoc());
178 .Case<UnknownValueOp>(
179 [&](
auto op) {
return evaluateUnknownValue(op, loc); })
180 .Default([&](Operation *op) {
181 auto error = op->emitError(
"unable to evaluate value");
182 error.attachNote() <<
"value: " << value;
189 objects[{value, actualParams}] = result.value();
193FailureOr<evaluator::EvaluatorValuePtr>
201 LLVM_DEBUG(dbgs() <<
"object:\n");
205 LLVM_DEBUG(dbgs() <<
"name: " << className <<
"\n");
207 auto classDef = symbolTable.lookup<ClassLike>(className);
209 return symbolTable.getOp()->emitError(
"unknown class name ") << className;
212 if (isa<ClassExternOp>(classDef)) {
214 std::make_shared<evaluator::ObjectValue>(classDef, loc);
215 result->markUnknown();
216 LLVM_DEBUG(dbgs(1) <<
"extern: <unknown-value>\n");
221 ClassOp cls = cast<ClassOp>(classDef);
223 auto formalParamNames = cls.getFormalParamNames().getAsRange<StringAttr>();
224 auto formalParamTypes = cls.getBodyBlock()->getArgumentTypes();
227 if (actualParams->size() != formalParamTypes.size()) {
228 auto error = cls.emitError(
"actual parameter list length (")
229 << actualParams->size() <<
") does not match formal "
230 <<
"parameter list length (" << formalParamTypes.size() <<
")";
231 auto &diag = error.attachNote() <<
"actual parameters: ";
234 for (
const auto ¶m : *actualParams) {
241 error.attachNote(cls.getLoc()) <<
"formal parameters: " << formalParamTypes;
246 for (
auto [actualParam, formalParamName, formalParamType] :
247 llvm::zip(*actualParams, formalParamNames, formalParamTypes)) {
248 if (!actualParam || !actualParam.get())
249 return cls.emitError(
"actual parameter for ")
250 << formalParamName <<
" is null";
253 if (isa<AnyType>(formalParamType))
256 Type actualParamType = actualParam->getType();
258 assert(actualParamType &&
"actualParamType must be non-null!");
260 if (actualParamType != formalParamType) {
261 auto error = cls.emitError(
"actual parameter for ")
262 << formalParamName <<
" has invalid type";
263 error.attachNote() <<
"actual parameter: " << *actualParam;
264 error.attachNote() <<
"format parameter type: " << formalParamType;
272 auto *
context = cls.getContext();
274 LLVM_DEBUG(dbgs() <<
"ops:\n");
278 for (
auto &op : cls.getOps())
279 for (
auto result : op.getResults()) {
282 if (failed(getOrCreateValue(result, actualParams,
286 worklist.push({result, actualParams});
290 LLVM_DEBUG(dbgs() <<
"fields:\n");
291 auto fieldNames = cls.getFieldNames();
292 auto operands = cls.getFieldsOp()->getOperands();
293 for (
size_t i = 0; i < fieldNames.size(); ++i) {
294 auto name = fieldNames[i];
295 auto value = operands[i];
296 auto fieldLoc = cls.getFieldLocByIndex(i);
297 LLVM_DEBUG(dbgs() <<
"- name: " << name <<
"\n"
298 << indent(1) <<
"evaluate:\n");
302 FailureOr<evaluator::EvaluatorValuePtr> result =
303 evaluateValue(value, actualParams, fieldLoc);
307 LLVM_DEBUG(dbgs() <<
"value: " << result.value() <<
"\n");
308 fields[cast<StringAttr>(name)] = result.value();
313 LLVM_DEBUG(dbgs() <<
"queuing asserts:\n");
314 for (
auto assertOp : cls.getOps<PropertyAssertOp>()) {
315 LLVM_DEBUG(dbgs(1) <<
"- " << assertOp <<
"\n");
316 pendingAsserts.push({assertOp, actualParams});
320 LLVM_DEBUG(dbgs() <<
"object value:\n");
321 if (instanceKey.first) {
323 getOrCreateValue(instanceKey.first, instanceKey.second, loc).value();
324 auto *
object = llvm::cast<evaluator::ObjectValue>(result.get());
325 object->setFields(std::move(fields));
331 std::make_shared<evaluator::ObjectValue>(cls, fields, loc);
336FailureOr<std::shared_ptr<evaluator::EvaluatorValue>>
338 StringAttr className, ArrayRef<evaluator::EvaluatorValuePtr> actualParams) {
339 LLVM_DEBUG(dbgs() <<
"instantiate:\n");
344 dbgs() <<
"class: " << className <<
"\n" << indent() <<
"params:\n";
345 for (
auto ¶m : actualParams)
346 dbgs() <<
"- " << param <<
"\n";
349 auto classDef = symbolTable.lookup<ClassLike>(className);
351 return symbolTable.getOp()->emitError(
"unknown class name ") << className;
354 if (isa<ClassExternOp>(classDef)) {
356 std::make_shared<evaluator::ObjectValue>(
357 classDef, UnknownLoc::get(classDef.getContext()));
358 result->markUnknown();
359 LLVM_DEBUG(dbgs(1) <<
"result: <unknown extern>\n");
364 ClassOp cls = cast<ClassOp>(classDef);
367 std::make_unique<SmallVector<std::shared_ptr<evaluator::EvaluatorValue>>>(
370 actualParametersBuffers.push_back(std::move(parameters));
372 auto loc = cls.getLoc();
373 LLVM_DEBUG(dbgs() <<
"evaluate object:\n");
374 auto result = evaluateObjectInstance(
375 className, actualParametersBuffers.back().get(), loc);
382 LLVM_DEBUG(dbgs() <<
"worklist:\n");
383 while (!worklist.empty()) {
384 auto [value, args] = worklist.front();
387 auto result = evaluateValue(value, args, loc);
393 if (!result.value()->isFullyEvaluated())
394 worklist.push({value, args});
399 LLVM_DEBUG(dbgs() <<
"asserts:\n");
400 bool assertFailed =
false;
401 while (!pendingAsserts.empty()) {
402 auto [assertOp, assertParams] = pendingAsserts.front();
403 pendingAsserts.pop();
404 assertFailed |= failed(evaluatePropertyAssert(assertOp, assertParams));
409 auto &
object = result.value();
412 LLVM_DEBUG(dbgs() <<
"finalizing\n");
413 if (failed(object->finalize()))
414 return cls.emitError() <<
"failed to finalize evaluation. Probably the "
415 "class contains a dataflow cycle";
416 LLVM_DEBUG(dbgs() <<
"result: " <<
object <<
"\n");
420FailureOr<evaluator::EvaluatorValuePtr>
423 auto evaluatorValue = getOrCreateValue(value, actualParams, loc).value();
425 LLVM_DEBUG(dbgs() <<
"- eval: " << value <<
"\n");
428 if (evaluatorValue->isFullyEvaluated()) {
429 LLVM_DEBUG(dbgs(1) <<
"fully evaluated: " << evaluatorValue <<
"\n");
430 return evaluatorValue;
433 return llvm::TypeSwitch<Value, FailureOr<evaluator::EvaluatorValuePtr>>(value)
434 .Case([&](BlockArgument arg) {
435 return evaluateParameter(arg, actualParams, loc);
437 .Case([&](OpResult result) {
438 return TypeSwitch<Operation *, FailureOr<evaluator::EvaluatorValuePtr>>(
439 result.getDefiningOp())
440 .Case([&](ConstantOp op) {
441 return evaluateConstant(op, actualParams, loc);
443 .Case([&](IntegerBinaryArithmeticOp op) {
444 return evaluateIntegerBinaryArithmetic(op, actualParams, loc);
446 .Case([&](ObjectOp op) {
447 return evaluateObjectInstance(op, actualParams);
449 .Case([&](ObjectFieldOp op) {
450 return evaluateObjectField(op, actualParams, loc);
452 .Case([&](ListCreateOp op) {
453 return evaluateListCreate(op, actualParams, loc);
455 .Case([&](ListConcatOp op) {
456 return evaluateListConcat(op, actualParams, loc);
458 .Case([&](StringConcatOp op) {
459 return evaluateStringConcat(op, actualParams, loc);
461 .Case([&](BinaryEqualityOp op) {
462 return evaluateBinaryEquality(op, actualParams, loc);
464 .Case([&](AnyCastOp op) {
465 return evaluateValue(op.getInput(), actualParams, loc);
467 .Case([&](FrozenBasePathCreateOp op) {
468 return evaluateBasePathCreate(op, actualParams, loc);
470 .Case([&](FrozenPathCreateOp op) {
471 return evaluatePathCreate(op, actualParams, loc);
473 .Case([&](FrozenEmptyPathOp op) {
474 return evaluateEmptyPath(op, actualParams, loc);
476 .Case<UnknownValueOp>([&](UnknownValueOp op) {
477 return evaluateUnknownValue(op, loc);
479 .Default([&](Operation *op) {
480 auto error = op->emitError(
"unable to evaluate value");
481 error.attachNote() <<
"value: " << value;
490 auto val = (*actualParams)[formalParam.getArgNumber()];
496FailureOr<circt::om::evaluator::EvaluatorValuePtr>
505FailureOr<EvaluatorValuePtr>
507 IntegerBinaryArithmeticOp op,
ActualParameters actualParams, Location loc) {
509 auto handle = getOrCreateValue(op.getResult(), actualParams, loc);
512 if (handle.value()->isFullyEvaluated())
517 auto lhsResult = evaluateValue(op.getLhs(), actualParams, loc);
518 if (failed(lhsResult))
520 if (!lhsResult.value()->isFullyEvaluated())
523 auto rhsResult = evaluateValue(op.getRhs(), actualParams, loc);
524 if (failed(rhsResult))
526 if (!rhsResult.value()->isFullyEvaluated())
530 if (lhsResult.value()->isUnknown() || rhsResult.value()->isUnknown()) {
531 handle.value()->markUnknown();
538 llvm::TypeSwitch<evaluator::EvaluatorValue *, om::IntegerAttr>(value)
540 return val->
getAs<om::IntegerAttr>();
543 return cast<evaluator::AttributeValue>(
544 val->getStrippedValue()->
get())
545 ->getAs<om::IntegerAttr>();
549 om::IntegerAttr lhs = extractAttr(lhsResult.value().get());
550 om::IntegerAttr rhs = extractAttr(rhsResult.value().get());
552 "expected om::IntegerAttr for IntegerBinaryArithmeticOp operands");
558 APSInt lhsVal = lhs.getValue().getAPSInt();
559 APSInt rhsVal = rhs.getValue().getAPSInt();
560 if (lhsVal.getBitWidth() > rhsVal.getBitWidth())
561 rhsVal = rhsVal.extend(lhsVal.getBitWidth());
562 else if (rhsVal.getBitWidth() > lhsVal.getBitWidth())
563 lhsVal = lhsVal.extend(rhsVal.getBitWidth());
566 FailureOr<APSInt> result = op.evaluateIntegerOperation(lhsVal, rhsVal);
569 return op->emitError(
"failed to evaluate integer operation");
572 MLIRContext *ctx = op->getContext();
574 om::IntegerAttr::get(ctx, mlir::IntegerAttr::get(ctx, result.value()));
577 auto *handleValue = cast<evaluator::AttributeValue>(handle.value().get());
578 auto resultStatus = handleValue->setAttr(resultAttr);
579 if (failed(resultStatus))
582 auto finalizeStatus = handleValue->finalize();
583 if (failed(finalizeStatus))
584 return finalizeStatus;
597 auto loc = op.getLoc();
600 LLVM_DEBUG(dbgs() <<
"op: " << op <<
"\n"
601 << indent() <<
"evaluate condition: \n");
602 auto condResult = evaluateValue(op.getCondition(), actualParams, loc);
603 if (failed(condResult))
605 if (!condResult.value()->isFullyEvaluated()) {
606 LLVM_DEBUG(dbgs() <<
"evaluate condition: <not fully evaluated>\n");
611 if (condResult.value()->isUnknown())
614 LLVM_DEBUG(dbgs() <<
"condition: " << condResult.value() <<
"\n");
620 return llvm::TypeSwitch<evaluator::EvaluatorValue *, mlir::Attribute>(value)
623 auto stripped = val->getStrippedValue();
624 if (failed(stripped))
627 dyn_cast<evaluator::AttributeValue>(stripped.value().get()))
631 .Default([](
auto *) -> mlir::Attribute {
return {}; });
634 auto condAttr = extractAttr(condResult.value().get());
638 bool isFalse =
false;
639 if (
auto boolAttr = dyn_cast<BoolAttr>(condAttr))
640 isFalse = !boolAttr.getValue();
641 else if (
auto intAttr = dyn_cast<mlir::IntegerAttr>(condAttr))
642 isFalse = intAttr.getValue().isZero();
644 return op.emitError(
"expected BoolAttr or mlir::IntegerAttr");
647 return op.emitError(
"OM property assertion failed: ") << op.getMessage();
653FailureOr<circt::om::Evaluator::ActualParameters>
657 auto parameters = std::make_unique<
658 SmallVector<std::shared_ptr<evaluator::EvaluatorValue>>>();
661 for (
auto input : range) {
662 auto inputResult = getOrCreateValue(input, actualParams, loc);
663 if (failed(inputResult))
665 parameters->push_back(inputResult.value());
668 actualParametersBuffers.push_back(std::move(parameters));
669 return actualParametersBuffers.back().get();
673FailureOr<evaluator::EvaluatorValuePtr>
676 auto loc = op.getLoc();
677 if (isFullyEvaluated({op, actualParams}))
678 return getOrCreateValue(op, actualParams, loc);
681 createParametersFromOperands(op.getOperands(), actualParams, loc);
684 return evaluateObjectInstance(op.getClassNameAttr(), params.value(), loc,
689FailureOr<evaluator::EvaluatorValuePtr>
694 FailureOr<evaluator::EvaluatorValuePtr> currentObjectResult =
695 evaluateValue(op.getObject(), actualParams, loc);
696 if (failed(currentObjectResult))
697 return currentObjectResult;
699 auto result = currentObjectResult.value();
701 auto objectFieldValue = getOrCreateValue(op, actualParams, loc).value();
703 if (result->isUnknown()) {
707 llvm::dyn_cast<evaluator::ReferenceValue>(objectFieldValue.get())) {
708 auto unknownField = createUnknownValue(op.getResult().getType(), loc);
709 if (failed(unknownField))
711 ref->setValue(unknownField.value());
714 objectFieldValue->markUnknown();
715 return objectFieldValue;
718 auto *currentObject = llvm::cast<evaluator::ObjectValue>(result.get());
723 for (
auto field : op.getFieldPath().getAsRange<FlatSymbolRefAttr>()) {
725 if (!currentObject->getFields().contains(field.getAttr()))
726 return objectFieldValue;
728 auto currentField = currentObject->getField(field.getAttr());
729 finalField = currentField.value();
730 if (
auto *nextObject =
731 llvm::dyn_cast<evaluator::ObjectValue>(finalField.get()))
732 currentObject = nextObject;
736 llvm::cast<evaluator::ReferenceValue>(objectFieldValue.get())
737 ->setValue(finalField);
740 return objectFieldValue;
744FailureOr<evaluator::EvaluatorValuePtr>
749 SmallVector<evaluator::EvaluatorValuePtr> values;
750 auto list = getOrCreateValue(op, actualParams, loc);
751 bool hasUnknown =
false;
752 for (
auto operand : op.getOperands()) {
753 auto result = evaluateValue(operand, actualParams, loc);
756 if (!result.value()->isFullyEvaluated())
759 if (result.value()->isUnknown())
761 values.push_back(result.value());
765 llvm::cast<evaluator::ListValue>(list.value().get())
766 ->setElements(std::move(values));
772 list.value()->markUnknown();
778FailureOr<evaluator::EvaluatorValuePtr>
783 SmallVector<evaluator::EvaluatorValuePtr> values;
784 auto list = getOrCreateValue(op, actualParams, loc);
789 llvm::TypeSwitch<evaluator::EvaluatorValue *, evaluator::ListValue *>(
793 return cast<evaluator::ListValue>(val->getStrippedValue()->get());
797 bool hasUnknown =
false;
798 for (
auto operand : op.getOperands()) {
799 auto result = evaluateValue(operand, actualParams, loc);
802 if (!result.value()->isFullyEvaluated())
805 if (result.value()->isUnknown())
814 for (
const auto &subValue : subList->
getElements())
815 values.push_back(subValue);
819 llvm::cast<evaluator::ListValue>(list.value().get())
820 ->setElements(std::move(values));
826 list.value()->markUnknown();
832FailureOr<evaluator::EvaluatorValuePtr>
837 auto handle = getOrCreateValue(op.getResult(), actualParams, loc);
842 if (handle.value()->isFullyEvaluated())
848 return llvm::TypeSwitch<evaluator::EvaluatorValue *, StringAttr>(value)
850 return val->
getAs<StringAttr>();
853 return cast<evaluator::AttributeValue>(val->getStrippedValue()->
get())
854 ->getAs<StringAttr>();
860 for (
auto operand : op.getOperands()) {
861 auto operandResult = evaluateValue(operand, actualParams, loc);
862 if (failed(operandResult))
863 return operandResult;
864 if (!operandResult.value()->isFullyEvaluated())
867 StringAttr str = extractAttr(operandResult.value().get());
868 assert(str &&
"expected StringAttr for StringConcatOp operand");
869 result += str.getValue().str();
873 auto resultStr = StringAttr::get(result, op.getResult().getType());
876 auto *handleValue = cast<evaluator::AttributeValue>(handle.value().get());
877 auto resultStatus = handleValue->setAttr(resultStr);
878 if (failed(resultStatus))
881 auto finalizeStatus = handleValue->finalize();
882 if (failed(finalizeStatus))
883 return finalizeStatus;
889FailureOr<evaluator::EvaluatorValuePtr>
894 auto handle = getOrCreateValue(op.getResult(), actualParams, loc);
899 if (handle.value()->isFullyEvaluated())
904 auto lhsResult = evaluateValue(op.getLhs(), actualParams, loc);
905 if (failed(lhsResult))
907 if (!lhsResult.value()->isFullyEvaluated())
910 auto rhsResult = evaluateValue(op.getRhs(), actualParams, loc);
911 if (failed(rhsResult))
913 if (!rhsResult.value()->isFullyEvaluated())
917 if (lhsResult.value()->isUnknown() || rhsResult.value()->isUnknown()) {
918 handle.value()->markUnknown();
925 return llvm::TypeSwitch<evaluator::EvaluatorValue *, mlir::Attribute>(value)
928 return cast<evaluator::AttributeValue>(val->getStrippedValue()->
get())
933 mlir::Attribute lhs = extractAttr(lhsResult.value().get());
934 mlir::Attribute rhs = extractAttr(rhsResult.value().get());
935 assert(lhs && rhs &&
"expected attribute for BinaryEqualityOp operands");
938 FailureOr<mlir::Attribute> result = op.evaluateBinaryEquality(lhs, rhs);
940 return op->emitError(
"failed to evaluate binary equality operation");
943 auto *handleValue = cast<evaluator::AttributeValue>(handle.value().get());
944 auto resultStatus = handleValue->setAttr(*result);
945 if (failed(resultStatus))
948 auto finalizeStatus = handleValue->finalize();
949 if (failed(finalizeStatus))
950 return finalizeStatus;
955FailureOr<evaluator::EvaluatorValuePtr>
960 auto valueResult = getOrCreateValue(op, actualParams, loc).value();
961 auto *path = llvm::cast<evaluator::BasePathValue>(valueResult.get());
962 auto result = evaluateValue(op.getBasePath(), actualParams, loc);
965 auto &value = result.value();
966 if (!value->isFullyEvaluated())
970 if (result.value()->isUnknown()) {
971 valueResult->markUnknown();
975 path->setBasepath(*llvm::cast<evaluator::BasePathValue>(value.get()));
979FailureOr<evaluator::EvaluatorValuePtr>
984 auto valueResult = getOrCreateValue(op, actualParams, loc).value();
985 auto *path = llvm::cast<evaluator::PathValue>(valueResult.get());
986 auto result = evaluateValue(op.getBasePath(), actualParams, loc);
989 auto &value = result.value();
990 if (!value->isFullyEvaluated())
994 if (result.value()->isUnknown()) {
995 valueResult->markUnknown();
999 path->setBasepath(*llvm::cast<evaluator::BasePathValue>(value.get()));
1005 auto valueResult = getOrCreateValue(op, actualParams, loc).value();
1010FailureOr<evaluator::EvaluatorValuePtr>
1016 TypeSwitch<Type, FailureOr<EvaluatorValuePtr>>(type)
1017 .Case([&](ListType type) -> FailureOr<EvaluatorValuePtr> {
1019 return success(std::make_shared<ListValue>(type, loc));
1021 .Case([&](ClassType type) -> FailureOr<EvaluatorValuePtr> {
1024 symbolTable.lookup<ClassLike>(type.getClassName().getValue());
1026 return symbolTable.getOp()->emitError(
"unknown class name ")
1027 << type.getClassName();
1030 return success(std::make_shared<ObjectValue>(classDef, loc));
1032 .Case([&](FrozenBasePathType type) -> FailureOr<EvaluatorValuePtr> {
1034 return success(std::make_shared<BasePathValue>(type.getContext()));
1036 .Case([&](FrozenPathType type) -> FailureOr<EvaluatorValuePtr> {
1039 std::make_shared<PathValue>(PathValue::getEmptyPath(loc)));
1041 .Default([&](Type type) -> FailureOr<EvaluatorValuePtr> {
1044 return success(AttributeValue::get(type, LocationAttr(loc)));
1048 if (succeeded(result))
1049 result->get()->markUnknown();
1055FailureOr<evaluator::EvaluatorValuePtr>
1057 return createUnknownValue(op.getType(), loc);
1065FailureOr<EvaluatorValuePtr>
1067 auto field = fields.find(name);
1068 if (field == fields.end())
1069 return cls.emitError(
"field ") << name <<
" does not exist";
1070 return success(fields[name]);
1076 SmallVector<Attribute> fieldNames;
1077 for (
auto &f : fields)
1078 fieldNames.push_back(f.first);
1080 llvm::sort(fieldNames, [](Attribute a, Attribute b) {
1081 return cast<StringAttr>(a).getValue() < cast<StringAttr>(b).getValue();
1084 return ArrayAttr::get(cls.getContext(), fieldNames);
1088 for (
auto &&[e, value] : fields)
1089 if (failed(finalizeEvaluatorValue(value)))
1100 auto result = getStrippedValue();
1103 value = std::move(result.value());
1105 if (failed(finalizeEvaluatorValue(value)))
1116 for (
auto &value : elements) {
1117 if (failed(finalizeEvaluatorValue(value)))
1129 path(PathAttr::get(
context, {})) {
1130 markFullyEvaluated();
1134 :
EvaluatorValue(path.getContext(), Kind::BasePath, loc), path(path) {}
1137 assert(isFullyEvaluated());
1142 assert(!isFullyEvaluated());
1143 auto newPath = llvm::to_vector(basepath.
path.getPath());
1144 auto oldPath = path.getPath();
1145 newPath.append(oldPath.begin(), oldPath.end());
1146 path = PathAttr::get(path.getContext(), newPath);
1147 markFullyEvaluated();
1155 StringAttr module, StringAttr ref,
1156 StringAttr field, Location loc)
1158 path(path), module(module), ref(ref), field(field) {}
1161 PathValue path(
nullptr,
nullptr,
nullptr,
nullptr,
nullptr, loc);
1169 return StringAttr::get(getContext(),
"OMDeleted:");
1170 SmallString<64> result;
1171 switch (targetKind.getValue()) {
1172 case TargetKind::DontTouch:
1173 result +=
"OMDontTouchedReferenceTarget";
1175 case TargetKind::Instance:
1176 result +=
"OMInstanceTarget";
1178 case TargetKind::MemberInstance:
1179 result +=
"OMMemberInstanceTarget";
1181 case TargetKind::MemberReference:
1182 result +=
"OMMemberReferenceTarget";
1184 case TargetKind::Reference:
1185 result +=
"OMReferenceTarget";
1189 if (!path.getPath().empty())
1190 result += path.getPath().front().module;
1192 result +=
module.getValue();
1194 for (
const auto &elt : path) {
1195 result += elt.module.getValue();
1197 result += elt.instance.getValue();
1200 if (!module.getValue().empty())
1201 result += module.getValue();
1202 if (!ref.getValue().empty()) {
1204 result += ref.getValue();
1206 if (!field.getValue().empty())
1207 result += field.getValue();
1208 return StringAttr::get(field.getContext(), result);
1212 assert(!isFullyEvaluated());
1213 auto newPath = llvm::to_vector(basepath.
getPath().getPath());
1214 auto oldPath = path.getPath();
1215 newPath.append(oldPath.begin(), oldPath.end());
1216 path = PathAttr::get(path.getContext(), newPath);
1217 markFullyEvaluated();
1225 if (cast<TypedAttr>(attr).getType() != this->type)
1226 return mlir::emitError(
getLoc(),
"cannot set AttributeValue of type ")
1227 << this->type <<
" to Attribute " << attr;
1228 if (isFullyEvaluated())
1229 return mlir::emitError(
1231 "cannot set AttributeValue that has already been fully evaluated");
1233 markFullyEvaluated();
1238 if (!isFullyEvaluated())
1239 return mlir::emitError(
1240 getLoc(),
"cannot finalize AttributeValue that is not fully evaluated");
1244std::shared_ptr<evaluator::EvaluatorValue>
1246 auto type = cast<TypedAttr>(attr).getType();
1247 auto *
context = type.getContext();
1249 loc = UnknownLoc::get(
context);
1253 if (
auto listType = dyn_cast<circt::om::ListType>(type)) {
1254 SmallVector<EvaluatorValuePtr> elements;
1255 auto listAttr = cast<om::ListAttr>(attr);
1257 listAttr.getContext(), listAttr.getElements().getValue());
1258 elements.append(values.begin(), values.end());
1259 auto list = std::make_shared<evaluator::ListValue>(listType, elements, loc);
1263 return std::shared_ptr<AttributeValue>(
1267std::shared_ptr<evaluator::EvaluatorValue>
1269 auto *
context = type.getContext();
1271 loc = UnknownLoc::get(
context);
1275 if (
auto listType = dyn_cast<circt::om::ListType>(type))
1276 return std::make_shared<evaluator::ListValue>(listType, loc);
1278 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 > evaluateIntegerBinaryArithmetic(IntegerBinaryArithmeticOp op, ActualParameters actualParams, Location loc)
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< 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.