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/Support/Debug.h"
20 #define DEBUG_TYPE "om-evaluator"
30 return cast<ModuleOp>(symbolTable.getOp());
33 SmallVector<evaluator::EvaluatorValuePtr>
35 ArrayRef<Attribute> attributes) {
36 SmallVector<evaluator::EvaluatorValuePtr> values;
37 values.reserve(attributes.size());
38 for (
auto attr : attributes)
39 values.push_back(std::make_shared<evaluator::AttributeValue>(attr));
44 using namespace evaluator;
50 assert(isFullyEvaluated());
51 return llvm::TypeSwitch<EvaluatorValue *, LogicalResult>(
this)
54 [](
auto v) {
return v->finalizeImpl(); });
58 return llvm::TypeSwitch<const EvaluatorValue *, Type>(
this)
60 return cast<TypedAttr>(attr->getAttr()).getType();
62 .Case<ObjectValue>([](
auto *
object) {
return object->getObjectType(); })
63 .Case<ListValue>([](
auto *list) {
return list->getListType(); })
64 .Case<MapValue>([](
auto *map) {
return map->getMapType(); })
65 .Case<ReferenceValue>([](
auto *ref) {
return ref->getValueType(); })
66 .Case<TupleValue>([](
auto *tuple) {
return tuple->getTupleType(); })
77 return TypeSwitch<mlir::Type, FailureOr<evaluator::EvaluatorValuePtr>>(type)
78 .Case([&](circt::om::MapType type) {
80 std::make_shared<evaluator::MapValue>(type, loc);
81 return success(result);
83 .Case([&](circt::om::ListType type) {
85 std::make_shared<evaluator::ListValue>(type, loc);
86 return success(result);
88 .Case([&](mlir::TupleType type) {
90 std::make_shared<evaluator::TupleValue>(type, loc);
91 return success(result);
94 .Case([&](circt::om::ClassType type)
97 symbolTable.lookup<ClassOp>(type.getClassName().getValue());
99 return symbolTable.getOp()->emitError(
"unknown class name ")
100 << type.getClassName();
103 std::make_shared<evaluator::ObjectValue>(cls, loc);
105 return success(result);
107 .Default([&](
auto type) {
return failure(); });
112 auto it = objects.find({
value, actualParams});
113 if (it != objects.end()) {
114 auto evalVal = it->second;
115 evalVal->setLocIfUnknown(loc);
120 TypeSwitch<Value, FailureOr<evaluator::EvaluatorValuePtr>>(
value)
121 .Case([&](BlockArgument arg) {
122 auto val = (*actualParams)[arg.getArgNumber()];
126 .Case([&](OpResult result) {
127 return TypeSwitch<Operation *,
129 result.getDefiningOp())
130 .Case([&](ConstantOp op) {
131 return evaluateConstant(op, actualParams, loc);
133 .Case<ObjectFieldOp>([&](
auto op) {
137 std::make_shared<evaluator::ReferenceValue>(
138 value.getType(), loc);
139 return success(result);
141 .Case<AnyCastOp>([&](AnyCastOp op) {
142 return getOrCreateValue(op.getInput(), actualParams, loc);
144 .Case<FrozenBasePathCreateOp>([&](FrozenBasePathCreateOp op) {
146 std::make_shared<evaluator::BasePathValue>(
147 op.getPathAttr(), loc);
148 return success(result);
150 .Case<FrozenPathCreateOp>([&](FrozenPathCreateOp op) {
152 std::make_shared<evaluator::PathValue>(
153 op.getTargetKindAttr(), op.getPathAttr(),
154 op.getModuleAttr(), op.getRefAttr(),
155 op.getFieldAttr(), loc);
156 return success(result);
158 .Case<FrozenEmptyPathOp>([&](FrozenEmptyPathOp op) {
160 std::make_shared<evaluator::PathValue>(
162 return success(result);
164 .Case<ListCreateOp, TupleCreateOp, MapCreateOp, ObjectFieldOp,
165 ObjectOp>([&](
auto op) {
166 return getPartiallyEvaluatedValue(op.getType(), loc);
168 .Default([&](Operation *op) {
169 auto error = op->emitError(
"unable to evaluate value");
170 error.attachNote() <<
"value: " <<
value;
177 objects[{
value, actualParams}] = result.value();
186 ClassOp cls = symbolTable.lookup<ClassOp>(className);
188 return symbolTable.getOp()->emitError(
"unknown class name ") << className;
190 auto formalParamNames = cls.getFormalParamNames().getAsRange<StringAttr>();
191 auto formalParamTypes = cls.getBodyBlock()->getArgumentTypes();
194 if (actualParams->size() != formalParamTypes.size()) {
195 auto error = cls.emitError(
"actual parameter list length (")
196 << actualParams->size() <<
") does not match formal "
197 <<
"parameter list length (" << formalParamTypes.size() <<
")";
198 auto &diag = error.attachNote() <<
"actual parameters: ";
201 for (
const auto ¶m : *actualParams) {
208 error.attachNote(cls.getLoc()) <<
"formal parameters: " << formalParamTypes;
213 for (
auto [actualParam, formalParamName, formalParamType] :
214 llvm::zip(*actualParams, formalParamNames, formalParamTypes)) {
215 if (!actualParam || !actualParam.get())
216 return cls.emitError(
"actual parameter for ")
217 << formalParamName <<
" is null";
220 if (isa<AnyType>(formalParamType))
223 Type actualParamType = actualParam->getType();
225 assert(actualParamType &&
"actualParamType must be non-null!");
227 if (actualParamType != formalParamType) {
228 auto error = cls.emitError(
"actual parameter for ")
229 << formalParamName <<
" has invalid type";
230 error.attachNote() <<
"actual parameter: " << *actualParam;
231 error.attachNote() <<
"format parameter type: " << formalParamType;
239 auto *context = cls.getContext();
240 for (
auto &op : cls.getOps())
241 for (
auto result : op.getResults()) {
248 worklist.push({result, actualParams});
251 for (
auto field : cls.getOps<ClassFieldOp>()) {
252 StringAttr name = field.getSymNameAttr();
253 Value
value = field.getValue();
255 evaluateValue(
value, actualParams, field.getLoc());
259 fields[name] = result.value();
263 if (instanceKey.first) {
265 getOrCreateValue(instanceKey.first, instanceKey.second, loc).value();
266 auto *
object = llvm::cast<evaluator::ObjectValue>(result.get());
267 object->setFields(std::move(fields));
273 std::make_shared<evaluator::ObjectValue>(cls, fields, loc);
280 StringAttr className, ArrayRef<evaluator::EvaluatorValuePtr> actualParams) {
281 ClassOp cls = symbolTable.lookup<ClassOp>(className);
283 return symbolTable.getOp()->emitError(
"unknown class name ") << className;
286 std::make_unique<SmallVector<std::shared_ptr<evaluator::EvaluatorValue>>>(
289 actualParametersBuffers.push_back(std::move(parameters));
291 auto loc = cls.getLoc();
292 auto result = evaluateObjectInstance(
293 className, actualParametersBuffers.back().get(), loc);
300 while (!worklist.empty()) {
301 auto [
value, args] = worklist.front();
304 auto result = evaluateValue(
value, args, loc);
310 if (!result.value()->isFullyEvaluated())
311 worklist.push({
value, args});
314 auto &
object = result.value();
317 if (failed(object->finalize()))
318 return cls.emitError() <<
"failed to finalize evaluation. Probably the "
319 "class contains a dataflow cycle";
326 auto evaluatorValue = getOrCreateValue(
value, actualParams, loc).value();
329 if (evaluatorValue->isFullyEvaluated())
330 return evaluatorValue;
332 return llvm::TypeSwitch<Value, FailureOr<evaluator::EvaluatorValuePtr>>(
value)
333 .Case([&](BlockArgument arg) {
334 return evaluateParameter(arg, actualParams, loc);
336 .Case([&](OpResult result) {
337 return TypeSwitch<Operation *, FailureOr<evaluator::EvaluatorValuePtr>>(
338 result.getDefiningOp())
339 .Case([&](ConstantOp op) {
340 return evaluateConstant(op, actualParams, loc);
342 .Case([&](ObjectOp op) {
343 return evaluateObjectInstance(op, actualParams);
345 .Case([&](ObjectFieldOp op) {
346 return evaluateObjectField(op, actualParams, loc);
348 .Case([&](ListCreateOp op) {
349 return evaluateListCreate(op, actualParams, loc);
351 .Case([&](TupleCreateOp op) {
352 return evaluateTupleCreate(op, actualParams, loc);
354 .Case([&](TupleGetOp op) {
355 return evaluateTupleGet(op, actualParams, loc);
357 .Case([&](AnyCastOp op) {
358 return evaluateValue(op.getInput(), actualParams, loc);
360 .Case([&](MapCreateOp op) {
361 return evaluateMapCreate(op, actualParams, loc);
363 .Case([&](FrozenBasePathCreateOp op) {
364 return evaluateBasePathCreate(op, actualParams, loc);
366 .Case([&](FrozenPathCreateOp op) {
367 return evaluatePathCreate(op, actualParams, loc);
369 .Case([&](FrozenEmptyPathOp op) {
370 return evaluateEmptyPath(op, actualParams, loc);
372 .Default([&](Operation *op) {
373 auto error = op->emitError(
"unable to evaluate value");
374 error.attachNote() <<
"value: " <<
value;
383 auto val = (*actualParams)[formalParam.getArgNumber()];
393 return success(std::make_shared<circt::om::evaluator::AttributeValue>(
394 op.getValue(), loc));
402 auto parameters = std::make_unique<
403 SmallVector<std::shared_ptr<evaluator::EvaluatorValue>>>();
406 for (
auto input : range) {
407 auto inputResult = getOrCreateValue(input, actualParams, loc);
408 if (failed(inputResult))
410 parameters->push_back(inputResult.value());
413 actualParametersBuffers.push_back(std::move(parameters));
414 return actualParametersBuffers.back().get();
421 auto loc = op.getLoc();
422 if (isFullyEvaluated({op, actualParams}))
423 return getOrCreateValue(op, actualParams, loc);
426 createParametersFromOperands(op.getOperands(), actualParams, loc);
429 return evaluateObjectInstance(op.getClassNameAttr(), params.value(), loc,
440 evaluateValue(op.getObject(), actualParams, loc);
441 if (failed(currentObjectResult))
442 return currentObjectResult;
444 auto *currentObject =
445 llvm::cast<evaluator::ObjectValue>(currentObjectResult.value().get());
447 auto objectFieldValue = getOrCreateValue(op, actualParams, loc).value();
452 for (
auto field : op.getFieldPath().getAsRange<FlatSymbolRefAttr>()) {
454 if (!currentObject->getFields().contains(field.getAttr()))
455 return objectFieldValue;
457 auto currentField = currentObject->getField(field.getAttr());
458 finalField = currentField.value();
459 if (
auto *nextObject =
460 llvm::dyn_cast<evaluator::ObjectValue>(finalField.get()))
461 currentObject = nextObject;
465 llvm::cast<evaluator::ReferenceValue>(objectFieldValue.get())
466 ->setValue(finalField);
469 return objectFieldValue;
478 SmallVector<evaluator::EvaluatorValuePtr> values;
479 auto list = getOrCreateValue(op, actualParams, loc);
480 for (
auto operand : op.getOperands()) {
481 auto result = evaluateValue(operand, actualParams, loc);
484 if (!result.value()->isFullyEvaluated())
486 values.push_back(result.value());
490 llvm::cast<evaluator::ListValue>(list.value().get())
491 ->setElements(std::move(values));
500 SmallVector<evaluator::EvaluatorValuePtr> values;
501 for (
auto operand : op.getOperands()) {
502 auto result = evaluateValue(operand, actualParams, loc);
505 values.push_back(result.value());
509 auto val = getOrCreateValue(op, actualParams, loc);
510 llvm::cast<evaluator::TupleValue>(val.value().get())
511 ->setElements(std::move(values));
518 auto tuple = evaluateValue(op.getInput(), actualParams, loc);
522 cast<evaluator::TupleValue>(tuple.value().get())
523 ->getElements()[op.getIndex()];
531 DenseMap<Attribute, evaluator::EvaluatorValuePtr> elements;
532 auto valueResult = getOrCreateValue(op, actualParams, loc).value();
533 for (
auto operand : op.getOperands()) {
534 auto result = evaluateValue(operand, actualParams, loc);
538 auto &
value = result.value();
539 if (!
value->isFullyEvaluated())
541 const auto &element =
542 llvm::cast<evaluator::TupleValue>(
value.get())->getElements();
543 assert(element.size() == 2);
545 llvm::cast<evaluator::AttributeValue>(element[0].
get())->getAttr();
546 if (!elements.insert({attr, element[1]}).second)
547 return op.emitError() <<
"map contains duplicated keys";
551 llvm::cast<evaluator::MapValue>(valueResult.get())
552 ->setElements(std::move(elements));
561 auto valueResult = getOrCreateValue(op, actualParams, loc).value();
562 auto *path = llvm::cast<evaluator::BasePathValue>(valueResult.get());
563 auto result = evaluateValue(op.getBasePath(), actualParams, loc);
566 auto &
value = result.value();
567 if (!
value->isFullyEvaluated())
569 path->setBasepath(*llvm::cast<evaluator::BasePathValue>(
value.get()));
578 auto valueResult = getOrCreateValue(op, actualParams, loc).value();
579 auto *path = llvm::cast<evaluator::PathValue>(valueResult.get());
580 auto result = evaluateValue(op.getBasePath(), actualParams, loc);
583 auto &
value = result.value();
584 if (!
value->isFullyEvaluated())
586 path->setBasepath(*llvm::cast<evaluator::BasePathValue>(
value.get()));
592 auto valueResult = getOrCreateValue(op, actualParams, loc).value();
603 auto field = fields.find(name);
604 if (field == fields.end())
605 return cls.emitError(
"field ") << name <<
" does not exist";
606 return success(fields[name]);
612 SmallVector<Attribute> fieldNames;
613 for (
auto &f : fields)
614 fieldNames.push_back(f.first);
616 llvm::sort(fieldNames, [](Attribute a, Attribute b) {
617 return cast<StringAttr>(a).getValue() < cast<StringAttr>(b).getValue();
624 for (
auto &&[e,
value] : fields)
637 SmallVector<Attribute> attrs;
638 for (
auto &[key, _] : elements)
639 attrs.push_back(key);
641 std::sort(attrs.begin(), attrs.end(), [](Attribute l, Attribute r) {
642 if (auto lInt = dyn_cast<mlir::IntegerAttr>(l))
643 if (auto rInt = dyn_cast<mlir::IntegerAttr>(r))
644 return lInt.getValue().ult(rInt.getValue());
646 assert(isa<StringAttr>(l) && isa<StringAttr>(r) &&
647 "key type should be integer or string");
648 return cast<StringAttr>(l).getValue() < cast<StringAttr>(r).getValue();
655 for (
auto &&[e,
value] : elements)
666 auto result = getStrippedValue();
669 value = std::move(result.value());
678 for (
auto &
value : elements) {
691 path(PathAttr::
get(context, {})) {
692 markFullyEvaluated();
696 :
EvaluatorValue(path.getContext(), Kind::BasePath, loc), path(path) {}
699 assert(isFullyEvaluated());
704 assert(!isFullyEvaluated());
705 auto newPath = llvm::to_vector(basepath.
path.getPath());
706 auto oldPath = path.getPath();
707 newPath.append(oldPath.begin(), oldPath.end());
709 markFullyEvaluated();
717 StringAttr module, StringAttr ref,
718 StringAttr field, Location loc)
720 path(path), module(module), ref(ref), field(field) {}
723 PathValue path(
nullptr,
nullptr,
nullptr,
nullptr,
nullptr, loc);
732 SmallString<64> result;
733 switch (targetKind.getValue()) {
734 case TargetKind::DontTouch:
735 result +=
"OMDontTouchedReferenceTarget";
737 case TargetKind::Instance:
738 result +=
"OMInstanceTarget";
740 case TargetKind::MemberInstance:
741 result +=
"OMMemberInstanceTarget";
743 case TargetKind::MemberReference:
744 result +=
"OMMemberReferenceTarget";
746 case TargetKind::Reference:
747 result +=
"OMReferenceTarget";
751 if (!path.getPath().empty())
752 result += path.getPath().front().module;
754 result += module.getValue();
756 for (
const auto &elt : path) {
757 result += elt.module.getValue();
759 result += elt.instance.getValue();
762 if (!module.getValue().empty())
763 result += module.getValue();
764 if (!ref.getValue().empty()) {
766 result += ref.getValue();
768 if (!field.getValue().empty())
769 result += field.getValue();
774 assert(!isFullyEvaluated());
775 auto newPath = llvm::to_vector(basepath.
getPath().getPath());
776 auto oldPath = path.getPath();
777 newPath.append(oldPath.begin(), oldPath.end());
779 markFullyEvaluated();
assert(baseType &&"element must be base type")
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
static LogicalResult finalizeEvaluatorValue(EvaluatorValuePtr &value)
std::shared_ptr< EvaluatorValue > EvaluatorValuePtr
A value of an object in memory.
SmallVector< EvaluatorValuePtr > getEvaluatorValuesFromAttributes(MLIRContext *context, ArrayRef< Attribute > attributes)
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.
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.
Evaluator(ModuleOp mod)
Construct an Evaluator with an IR module.
FailureOr< evaluator::EvaluatorValuePtr > evaluateMapCreate(MapCreateOp op, ActualParameters actualParams, Location loc)
Evaluator dispatch function for Map creation.
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 > evaluateListCreate(ListCreateOp op, ActualParameters actualParams, Location loc)
Evaluator dispatch function for List creation.
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< EvaluatorValuePtr > evaluateTupleGet(TupleGetOp op, ActualParameters actualParams, Location loc)
Evaluator dispatch function for List creation.
FailureOr< EvaluatorValuePtr > evaluateTupleCreate(TupleCreateOp op, ActualParameters actualParams, Location loc)
Evaluator dispatch function for Tuple creation.
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.
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.
void markFullyEvaluated()
A List which contains variadic length of elements with the same type.
LogicalResult finalizeImpl()
ArrayAttr getKeys()
Return an array of keys in the ascending order.
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()