Loading [MathJax]/extensions/tex2jax.js
CIRCT 22.0.0git
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Evaluator.cpp
Go to the documentation of this file.
1//===- Evaluator.cpp - Object Model dialect evaluator ---------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements the Object Model dialect Evaluator.
10//
11//===----------------------------------------------------------------------===//
12
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"
19
20#define DEBUG_TYPE "om-evaluator"
21
22using namespace mlir;
23using namespace circt::om;
24
25/// Construct an Evaluator with an IR module.
26circt::om::Evaluator::Evaluator(ModuleOp mod) : symbolTable(mod) {}
27
28/// Get the Module this Evaluator is built from.
30 return cast<ModuleOp>(symbolTable.getOp());
31}
32
33SmallVector<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(evaluator::AttributeValue::get(cast<TypedAttr>(attr)));
40 return values;
41}
42
44 using namespace evaluator;
45 // Early return if already finalized.
46 if (finalized)
47 return success();
48 // Enable the flag to avoid infinite recursions.
49 finalized = true;
50 assert(isFullyEvaluated());
51 return llvm::TypeSwitch<EvaluatorValue *, LogicalResult>(this)
53 BasePathValue, PathValue>([](auto v) { return v->finalizeImpl(); });
54}
55
57 return llvm::TypeSwitch<const EvaluatorValue *, Type>(this)
58 .Case<AttributeValue>([](auto *attr) -> Type { return attr->getType(); })
59 .Case<ObjectValue>([](auto *object) { return object->getObjectType(); })
60 .Case<ListValue>([](auto *list) { return list->getListType(); })
61 .Case<ReferenceValue>([](auto *ref) { return ref->getValueType(); })
62 .Case<BasePathValue>(
63 [this](auto *tuple) { return FrozenBasePathType::get(ctx); })
64 .Case<PathValue>(
65 [this](auto *tuple) { return FrozenPathType::get(ctx); });
66}
67
68FailureOr<evaluator::EvaluatorValuePtr>
70 using namespace circt::om::evaluator;
71
72 return TypeSwitch<mlir::Type, FailureOr<evaluator::EvaluatorValuePtr>>(type)
73 .Case([&](circt::om::ListType type) {
75 std::make_shared<evaluator::ListValue>(type, loc);
76 return success(result);
77 })
78 .Case([&](circt::om::ClassType type)
79 -> FailureOr<evaluator::EvaluatorValuePtr> {
80 ClassOp cls =
81 symbolTable.lookup<ClassOp>(type.getClassName().getValue());
82 if (!cls)
83 return symbolTable.getOp()->emitError("unknown class name ")
84 << type.getClassName();
85
87 std::make_shared<evaluator::ObjectValue>(cls, loc);
88
89 return success(result);
90 })
91 .Default([&](auto type) { return failure(); });
92}
93
94FailureOr<evaluator::EvaluatorValuePtr> circt::om::Evaluator::getOrCreateValue(
95 Value value, ActualParameters actualParams, Location loc) {
96 auto it = objects.find({value, actualParams});
97 if (it != objects.end()) {
98 auto evalVal = it->second;
99 evalVal->setLocIfUnknown(loc);
100 return evalVal;
101 }
102
103 FailureOr<evaluator::EvaluatorValuePtr> result =
104 TypeSwitch<Value, FailureOr<evaluator::EvaluatorValuePtr>>(value)
105 .Case([&](BlockArgument arg) {
106 auto val = (*actualParams)[arg.getArgNumber()];
107 val->setLoc(loc);
108 return val;
109 })
110 .Case([&](OpResult result) {
111 return TypeSwitch<Operation *,
112 FailureOr<evaluator::EvaluatorValuePtr>>(
113 result.getDefiningOp())
114 .Case([&](ConstantOp op) {
115 return evaluateConstant(op, actualParams, loc);
116 })
117 .Case([&](IntegerBinaryArithmeticOp op) {
118 // Create a partially evaluated AttributeValue of
119 // om::IntegerType in case we need to delay evaluation.
121 evaluator::AttributeValue::get(op.getResult().getType(),
122 loc);
123 return success(result);
124 })
125 .Case<ObjectFieldOp>([&](auto op) {
126 // Create a reference value since the value pointed by object
127 // field op is not created yet.
129 std::make_shared<evaluator::ReferenceValue>(
130 value.getType(), loc);
131 return success(result);
132 })
133 .Case<AnyCastOp>([&](AnyCastOp op) {
134 return getOrCreateValue(op.getInput(), actualParams, loc);
135 })
136 .Case<FrozenBasePathCreateOp>([&](FrozenBasePathCreateOp op) {
138 std::make_shared<evaluator::BasePathValue>(
139 op.getPathAttr(), loc);
140 return success(result);
141 })
142 .Case<FrozenPathCreateOp>([&](FrozenPathCreateOp op) {
144 std::make_shared<evaluator::PathValue>(
145 op.getTargetKindAttr(), op.getPathAttr(),
146 op.getModuleAttr(), op.getRefAttr(),
147 op.getFieldAttr(), loc);
148 return success(result);
149 })
150 .Case<FrozenEmptyPathOp>([&](FrozenEmptyPathOp op) {
152 std::make_shared<evaluator::PathValue>(
154 return success(result);
155 })
156 .Case<ListCreateOp, ListConcatOp, ObjectFieldOp>([&](auto op) {
157 return getPartiallyEvaluatedValue(op.getType(), loc);
158 })
159 .Case<ObjectOp>([&](auto op) {
160 return getPartiallyEvaluatedValue(op.getType(), op.getLoc());
161 })
162 .Default([&](Operation *op) {
163 auto error = op->emitError("unable to evaluate value");
164 error.attachNote() << "value: " << value;
165 return error;
166 });
167 });
168 if (failed(result))
169 return result;
170
171 objects[{value, actualParams}] = result.value();
172 return result;
173}
174
175FailureOr<evaluator::EvaluatorValuePtr>
177 ActualParameters actualParams,
178 Location loc,
179 ObjectKey instanceKey) {
180 ClassOp cls = symbolTable.lookup<ClassOp>(className);
181 if (!cls)
182 return symbolTable.getOp()->emitError("unknown class name ") << className;
183
184 auto formalParamNames = cls.getFormalParamNames().getAsRange<StringAttr>();
185 auto formalParamTypes = cls.getBodyBlock()->getArgumentTypes();
186
187 // Verify the actual parameters are the right size and types for this class.
188 if (actualParams->size() != formalParamTypes.size()) {
189 auto error = cls.emitError("actual parameter list length (")
190 << actualParams->size() << ") does not match formal "
191 << "parameter list length (" << formalParamTypes.size() << ")";
192 auto &diag = error.attachNote() << "actual parameters: ";
193 // FIXME: `diag << actualParams` doesn't work for some reason.
194 bool isFirst = true;
195 for (const auto &param : *actualParams) {
196 if (isFirst)
197 isFirst = false;
198 else
199 diag << ", ";
200 diag << param;
201 }
202 error.attachNote(cls.getLoc()) << "formal parameters: " << formalParamTypes;
203 return error;
204 }
205
206 // Verify the actual parameter types match.
207 for (auto [actualParam, formalParamName, formalParamType] :
208 llvm::zip(*actualParams, formalParamNames, formalParamTypes)) {
209 if (!actualParam || !actualParam.get())
210 return cls.emitError("actual parameter for ")
211 << formalParamName << " is null";
212
213 // Subtyping: if formal param is any type, any actual param may be passed.
214 if (isa<AnyType>(formalParamType))
215 continue;
216
217 Type actualParamType = actualParam->getType();
218
219 assert(actualParamType && "actualParamType must be non-null!");
220
221 if (actualParamType != formalParamType) {
222 auto error = cls.emitError("actual parameter for ")
223 << formalParamName << " has invalid type";
224 error.attachNote() << "actual parameter: " << *actualParam;
225 error.attachNote() << "format parameter type: " << formalParamType;
226 return error;
227 }
228 }
229
230 // Instantiate the fields.
232
233 auto *context = cls.getContext();
234 for (auto &op : cls.getOps())
235 for (auto result : op.getResults()) {
236 // Allocate the value, with unknown loc. It will be later set when
237 // evaluating the fields.
238 if (failed(
239 getOrCreateValue(result, actualParams, UnknownLoc::get(context))))
240 return failure();
241 // Add to the worklist.
242 worklist.push({result, actualParams});
243 }
244
245 auto fieldNames = cls.getFieldNames();
246 auto operands = cls.getFieldsOp()->getOperands();
247 for (size_t i = 0; i < fieldNames.size(); ++i) {
248 auto name = fieldNames[i];
249 auto value = operands[i];
250 auto fieldLoc = cls.getFieldLocByIndex(i);
251 FailureOr<evaluator::EvaluatorValuePtr> result =
252 evaluateValue(value, actualParams, fieldLoc);
253 if (failed(result))
254 return result;
255
256 fields[cast<StringAttr>(name)] = result.value();
257 }
258
259 // If the there is an instance, we must update the object value.
260 if (instanceKey.first) {
261 auto result =
262 getOrCreateValue(instanceKey.first, instanceKey.second, loc).value();
263 auto *object = llvm::cast<evaluator::ObjectValue>(result.get());
264 object->setFields(std::move(fields));
265 return result;
266 }
267
268 // If it's external call, just allocate new ObjectValue.
270 std::make_shared<evaluator::ObjectValue>(cls, fields, loc);
271 return result;
272}
273
274/// Instantiate an Object with its class name and actual parameters.
275FailureOr<std::shared_ptr<evaluator::EvaluatorValue>>
277 StringAttr className, ArrayRef<evaluator::EvaluatorValuePtr> actualParams) {
278 ClassOp cls = symbolTable.lookup<ClassOp>(className);
279 if (!cls)
280 return symbolTable.getOp()->emitError("unknown class name ") << className;
281
282 auto parameters =
283 std::make_unique<SmallVector<std::shared_ptr<evaluator::EvaluatorValue>>>(
284 actualParams);
285
286 actualParametersBuffers.push_back(std::move(parameters));
287
288 auto loc = cls.getLoc();
289 auto result = evaluateObjectInstance(
290 className, actualParametersBuffers.back().get(), loc);
291
292 if (failed(result))
293 return failure();
294
295 // `evaluateObjectInstance` has populated the worklist. Continue evaluations
296 // unless there is a partially evaluated value.
297 while (!worklist.empty()) {
298 auto [value, args] = worklist.front();
299 worklist.pop();
300
301 auto result = evaluateValue(value, args, loc);
302
303 if (failed(result))
304 return failure();
305
306 // It's possible that the value is not fully evaluated.
307 if (!result.value()->isFullyEvaluated())
308 worklist.push({value, args});
309 }
310
311 auto &object = result.value();
312 // Finalize the value. This will eliminate intermidiate ReferenceValue used as
313 // a placeholder in the initialization.
314 if (failed(object->finalize()))
315 return cls.emitError() << "failed to finalize evaluation. Probably the "
316 "class contains a dataflow cycle";
317 return object;
318}
319
320FailureOr<evaluator::EvaluatorValuePtr>
322 Location loc) {
323 auto evaluatorValue = getOrCreateValue(value, actualParams, loc).value();
324
325 // Return if the value is already evaluated.
326 if (evaluatorValue->isFullyEvaluated())
327 return evaluatorValue;
328
329 return llvm::TypeSwitch<Value, FailureOr<evaluator::EvaluatorValuePtr>>(value)
330 .Case([&](BlockArgument arg) {
331 return evaluateParameter(arg, actualParams, loc);
332 })
333 .Case([&](OpResult result) {
334 return TypeSwitch<Operation *, FailureOr<evaluator::EvaluatorValuePtr>>(
335 result.getDefiningOp())
336 .Case([&](ConstantOp op) {
337 return evaluateConstant(op, actualParams, loc);
338 })
339 .Case([&](IntegerBinaryArithmeticOp op) {
340 return evaluateIntegerBinaryArithmetic(op, actualParams, loc);
341 })
342 .Case([&](ObjectOp op) {
343 return evaluateObjectInstance(op, actualParams);
344 })
345 .Case([&](ObjectFieldOp op) {
346 return evaluateObjectField(op, actualParams, loc);
347 })
348 .Case([&](ListCreateOp op) {
349 return evaluateListCreate(op, actualParams, loc);
350 })
351 .Case([&](ListConcatOp op) {
352 return evaluateListConcat(op, actualParams, loc);
353 })
354 .Case([&](AnyCastOp op) {
355 return evaluateValue(op.getInput(), actualParams, loc);
356 })
357 .Case([&](FrozenBasePathCreateOp op) {
358 return evaluateBasePathCreate(op, actualParams, loc);
359 })
360 .Case([&](FrozenPathCreateOp op) {
361 return evaluatePathCreate(op, actualParams, loc);
362 })
363 .Case([&](FrozenEmptyPathOp op) {
364 return evaluateEmptyPath(op, actualParams, loc);
365 })
366 .Default([&](Operation *op) {
367 auto error = op->emitError("unable to evaluate value");
368 error.attachNote() << "value: " << value;
369 return error;
370 });
371 });
372}
373
374/// Evaluator dispatch function for parameters.
375FailureOr<evaluator::EvaluatorValuePtr> circt::om::Evaluator::evaluateParameter(
376 BlockArgument formalParam, ActualParameters actualParams, Location loc) {
377 auto val = (*actualParams)[formalParam.getArgNumber()];
378 val->setLoc(loc);
379 return success(val);
380}
381
382/// Evaluator dispatch function for constants.
383FailureOr<circt::om::evaluator::EvaluatorValuePtr>
385 ActualParameters actualParams,
386 Location loc) {
387 // For list constants, create ListValue.
388 return success(om::evaluator::AttributeValue::get(op.getValue(), loc));
389}
390
391// Evaluator dispatch function for integer binary arithmetic.
392FailureOr<EvaluatorValuePtr>
394 IntegerBinaryArithmeticOp op, ActualParameters actualParams, Location loc) {
395 // Get the op's EvaluatorValue handle, in case it hasn't been evaluated yet.
396 auto handle = getOrCreateValue(op.getResult(), actualParams, loc);
397
398 // If it's fully evaluated, we can return it.
399 if (handle.value()->isFullyEvaluated())
400 return handle;
401
402 // Evaluate operands if necessary, and return the partially evaluated value if
403 // they aren't ready.
404 auto lhsResult = evaluateValue(op.getLhs(), actualParams, loc);
405 if (failed(lhsResult))
406 return lhsResult;
407 if (!lhsResult.value()->isFullyEvaluated())
408 return handle;
409
410 auto rhsResult = evaluateValue(op.getRhs(), actualParams, loc);
411 if (failed(rhsResult))
412 return rhsResult;
413 if (!rhsResult.value()->isFullyEvaluated())
414 return handle;
415
416 // Extract the integer attributes.
417 auto extractAttr = [](evaluator::EvaluatorValue *value) {
418 return std::move(
419 llvm::TypeSwitch<evaluator::EvaluatorValue *, om::IntegerAttr>(value)
420 .Case([](evaluator::AttributeValue *val) {
421 return val->getAs<om::IntegerAttr>();
422 })
423 .Case([](evaluator::ReferenceValue *val) {
424 return cast<evaluator::AttributeValue>(
425 val->getStrippedValue()->get())
426 ->getAs<om::IntegerAttr>();
427 }));
428 };
429
430 om::IntegerAttr lhs = extractAttr(lhsResult.value().get());
431 om::IntegerAttr rhs = extractAttr(rhsResult.value().get());
432 assert(lhs && rhs &&
433 "expected om::IntegerAttr for IntegerBinaryArithmeticOp operands");
434
435 // Extend values if necessary to match bitwidth. Most interesting arithmetic
436 // on APSInt asserts that both operands are the same bitwidth, but the
437 // IntegerAttrs we are working with may have used the smallest necessary
438 // bitwidth to represent the number they hold, and won't necessarily match.
439 APSInt lhsVal = lhs.getValue().getAPSInt();
440 APSInt rhsVal = rhs.getValue().getAPSInt();
441 if (lhsVal.getBitWidth() > rhsVal.getBitWidth())
442 rhsVal = rhsVal.extend(lhsVal.getBitWidth());
443 else if (rhsVal.getBitWidth() > lhsVal.getBitWidth())
444 lhsVal = lhsVal.extend(rhsVal.getBitWidth());
445
446 // Perform arbitrary precision signed integer binary arithmetic.
447 FailureOr<APSInt> result = op.evaluateIntegerOperation(lhsVal, rhsVal);
448
449 if (failed(result))
450 return op->emitError("failed to evaluate integer operation");
451
452 // Package the result as a new om::IntegerAttr.
453 MLIRContext *ctx = op->getContext();
454 auto resultAttr =
455 om::IntegerAttr::get(ctx, mlir::IntegerAttr::get(ctx, result.value()));
456
457 // Finalize the op result value.
458 auto *handleValue = cast<evaluator::AttributeValue>(handle.value().get());
459 auto resultStatus = handleValue->setAttr(resultAttr);
460 if (failed(resultStatus))
461 return resultStatus;
462
463 auto finalizeStatus = handleValue->finalize();
464 if (failed(finalizeStatus))
465 return finalizeStatus;
466
467 return handle;
468}
469
470/// Evaluator dispatch function for Object instances.
471FailureOr<circt::om::Evaluator::ActualParameters>
473 ValueRange range, ActualParameters actualParams, Location loc) {
474 // Create an unique storage to store parameters.
475 auto parameters = std::make_unique<
476 SmallVector<std::shared_ptr<evaluator::EvaluatorValue>>>();
477
478 // Collect operands' evaluator values in the current instantiation context.
479 for (auto input : range) {
480 auto inputResult = getOrCreateValue(input, actualParams, loc);
481 if (failed(inputResult))
482 return failure();
483 parameters->push_back(inputResult.value());
484 }
485
486 actualParametersBuffers.push_back(std::move(parameters));
487 return actualParametersBuffers.back().get();
488}
489
490/// Evaluator dispatch function for Object instances.
491FailureOr<evaluator::EvaluatorValuePtr>
493 ActualParameters actualParams) {
494 auto loc = op.getLoc();
495 if (isFullyEvaluated({op, actualParams}))
496 return getOrCreateValue(op, actualParams, loc);
497
498 auto params =
499 createParametersFromOperands(op.getOperands(), actualParams, loc);
500 if (failed(params))
501 return failure();
502 return evaluateObjectInstance(op.getClassNameAttr(), params.value(), loc,
503 {op, actualParams});
504}
505
506/// Evaluator dispatch function for Object fields.
507FailureOr<evaluator::EvaluatorValuePtr>
509 ActualParameters actualParams,
510 Location loc) {
511 // Evaluate the Object itself, in case it hasn't been evaluated yet.
512 FailureOr<evaluator::EvaluatorValuePtr> currentObjectResult =
513 evaluateValue(op.getObject(), actualParams, loc);
514 if (failed(currentObjectResult))
515 return currentObjectResult;
516
517 auto *currentObject =
518 llvm::cast<evaluator::ObjectValue>(currentObjectResult.value().get());
519
520 auto objectFieldValue = getOrCreateValue(op, actualParams, loc).value();
521
522 // Iteratively access nested fields through the path until we reach the final
523 // field in the path.
525 for (auto field : op.getFieldPath().getAsRange<FlatSymbolRefAttr>()) {
526 // `currentObject` might no be fully evaluated.
527 if (!currentObject->getFields().contains(field.getAttr()))
528 return objectFieldValue;
529
530 auto currentField = currentObject->getField(field.getAttr());
531 finalField = currentField.value();
532 if (auto *nextObject =
533 llvm::dyn_cast<evaluator::ObjectValue>(finalField.get()))
534 currentObject = nextObject;
535 }
536
537 // Update the reference.
538 llvm::cast<evaluator::ReferenceValue>(objectFieldValue.get())
539 ->setValue(finalField);
540
541 // Return the field being accessed.
542 return objectFieldValue;
543}
544
545/// Evaluator dispatch function for List creation.
546FailureOr<evaluator::EvaluatorValuePtr>
548 ActualParameters actualParams,
549 Location loc) {
550 // Evaluate the Object itself, in case it hasn't been evaluated yet.
551 SmallVector<evaluator::EvaluatorValuePtr> values;
552 auto list = getOrCreateValue(op, actualParams, loc);
553 for (auto operand : op.getOperands()) {
554 auto result = evaluateValue(operand, actualParams, loc);
555 if (failed(result))
556 return result;
557 if (!result.value()->isFullyEvaluated())
558 return list;
559 values.push_back(result.value());
560 }
561
562 // Return the list.
563 llvm::cast<evaluator::ListValue>(list.value().get())
564 ->setElements(std::move(values));
565 return list;
566}
567
568/// Evaluator dispatch function for List concatenation.
569FailureOr<evaluator::EvaluatorValuePtr>
571 ActualParameters actualParams,
572 Location loc) {
573 // Evaluate the List concat op itself, in case it hasn't been evaluated yet.
574 SmallVector<evaluator::EvaluatorValuePtr> values;
575 auto list = getOrCreateValue(op, actualParams, loc);
576
577 // Extract the ListValue, either directly or through an object reference.
578 auto extractList = [](evaluator::EvaluatorValue *value) {
579 return std::move(
580 llvm::TypeSwitch<evaluator::EvaluatorValue *, evaluator::ListValue *>(
581 value)
582 .Case([](evaluator::ListValue *val) { return val; })
583 .Case([](evaluator::ReferenceValue *val) {
584 return cast<evaluator::ListValue>(val->getStrippedValue()->get());
585 }));
586 };
587
588 for (auto operand : op.getOperands()) {
589 auto result = evaluateValue(operand, actualParams, loc);
590 if (failed(result))
591 return result;
592 if (!result.value()->isFullyEvaluated())
593 return list;
594
595 // Extract this sublist and ensure it's done evaluating.
596 evaluator::ListValue *subList = extractList(result.value().get());
597 if (!subList->isFullyEvaluated())
598 return list;
599
600 // Append each EvaluatorValue from the sublist.
601 for (const auto &subValue : subList->getElements())
602 values.push_back(subValue);
603 }
604
605 // Return the concatenated list.
606 llvm::cast<evaluator::ListValue>(list.value().get())
607 ->setElements(std::move(values));
608 return list;
609}
610
611FailureOr<evaluator::EvaluatorValuePtr>
613 ActualParameters actualParams,
614 Location loc) {
615 // Evaluate the Object itself, in case it hasn't been evaluated yet.
616 auto valueResult = getOrCreateValue(op, actualParams, loc).value();
617 auto *path = llvm::cast<evaluator::BasePathValue>(valueResult.get());
618 auto result = evaluateValue(op.getBasePath(), actualParams, loc);
619 if (failed(result))
620 return result;
621 auto &value = result.value();
622 if (!value->isFullyEvaluated())
623 return valueResult;
624 path->setBasepath(*llvm::cast<evaluator::BasePathValue>(value.get()));
625 return valueResult;
626}
627
628FailureOr<evaluator::EvaluatorValuePtr>
630 ActualParameters actualParams,
631 Location loc) {
632 // Evaluate the Object itself, in case it hasn't been evaluated yet.
633 auto valueResult = getOrCreateValue(op, actualParams, loc).value();
634 auto *path = llvm::cast<evaluator::PathValue>(valueResult.get());
635 auto result = evaluateValue(op.getBasePath(), actualParams, loc);
636 if (failed(result))
637 return result;
638 auto &value = result.value();
639 if (!value->isFullyEvaluated())
640 return valueResult;
641 path->setBasepath(*llvm::cast<evaluator::BasePathValue>(value.get()));
642 return valueResult;
643}
644
645FailureOr<evaluator::EvaluatorValuePtr> circt::om::Evaluator::evaluateEmptyPath(
646 FrozenEmptyPathOp op, ActualParameters actualParams, Location loc) {
647 auto valueResult = getOrCreateValue(op, actualParams, loc).value();
648 return valueResult;
649}
650
651//===----------------------------------------------------------------------===//
652// ObjectValue
653//===----------------------------------------------------------------------===//
654
655/// Get a field of the Object by name.
656FailureOr<EvaluatorValuePtr>
658 auto field = fields.find(name);
659 if (field == fields.end())
660 return cls.emitError("field ") << name << " does not exist";
661 return success(fields[name]);
662}
663
664/// Get an ArrayAttr with the names of the fields in the Object. Sort the fields
665/// so there is always a stable order.
667 SmallVector<Attribute> fieldNames;
668 for (auto &f : fields)
669 fieldNames.push_back(f.first);
670
671 llvm::sort(fieldNames, [](Attribute a, Attribute b) {
672 return cast<StringAttr>(a).getValue() < cast<StringAttr>(b).getValue();
673 });
674
675 return ArrayAttr::get(cls.getContext(), fieldNames);
676}
677
679 for (auto &&[e, value] : fields)
680 if (failed(finalizeEvaluatorValue(value)))
681 return failure();
682
683 return success();
684}
685
686//===----------------------------------------------------------------------===//
687// ReferenceValue
688//===----------------------------------------------------------------------===//
689
691 auto result = getStrippedValue();
692 if (failed(result))
693 return result;
694 value = std::move(result.value());
695 // the stripped value also needs to be finalized
696 if (failed(finalizeEvaluatorValue(value)))
697 return failure();
698
699 return success();
700}
701
702//===----------------------------------------------------------------------===//
703// ListValue
704//===----------------------------------------------------------------------===//
705
707 for (auto &value : elements) {
708 if (failed(finalizeEvaluatorValue(value)))
709 return failure();
710 }
711 return success();
712}
713
714//===----------------------------------------------------------------------===//
715// BasePathValue
716//===----------------------------------------------------------------------===//
717
719 : EvaluatorValue(context, Kind::BasePath, UnknownLoc::get(context)),
720 path(PathAttr::get(context, {})) {
721 markFullyEvaluated();
722}
723
724evaluator::BasePathValue::BasePathValue(PathAttr path, Location loc)
725 : EvaluatorValue(path.getContext(), Kind::BasePath, loc), path(path) {}
726
728 assert(isFullyEvaluated());
729 return path;
730}
731
733 assert(!isFullyEvaluated());
734 auto newPath = llvm::to_vector(basepath.path.getPath());
735 auto oldPath = path.getPath();
736 newPath.append(oldPath.begin(), oldPath.end());
737 path = PathAttr::get(path.getContext(), newPath);
738 markFullyEvaluated();
739}
740
741//===----------------------------------------------------------------------===//
742// PathValue
743//===----------------------------------------------------------------------===//
744
745evaluator::PathValue::PathValue(TargetKindAttr targetKind, PathAttr path,
746 StringAttr module, StringAttr ref,
747 StringAttr field, Location loc)
748 : EvaluatorValue(loc.getContext(), Kind::Path, loc), targetKind(targetKind),
749 path(path), module(module), ref(ref), field(field) {}
750
752 PathValue path(nullptr, nullptr, nullptr, nullptr, nullptr, loc);
753 path.markFullyEvaluated();
754 return path;
755}
756
758 // If the module is null, then this is a path to a deleted object.
759 if (!targetKind)
760 return StringAttr::get(getContext(), "OMDeleted:");
761 SmallString<64> result;
762 switch (targetKind.getValue()) {
763 case TargetKind::DontTouch:
764 result += "OMDontTouchedReferenceTarget";
765 break;
766 case TargetKind::Instance:
767 result += "OMInstanceTarget";
768 break;
769 case TargetKind::MemberInstance:
770 result += "OMMemberInstanceTarget";
771 break;
772 case TargetKind::MemberReference:
773 result += "OMMemberReferenceTarget";
774 break;
775 case TargetKind::Reference:
776 result += "OMReferenceTarget";
777 break;
778 }
779 result += ":~";
780 if (!path.getPath().empty())
781 result += path.getPath().front().module;
782 else
783 result += module.getValue();
784 result += '|';
785 for (const auto &elt : path) {
786 result += elt.module.getValue();
787 result += '/';
788 result += elt.instance.getValue();
789 result += ':';
790 }
791 if (!module.getValue().empty())
792 result += module.getValue();
793 if (!ref.getValue().empty()) {
794 result += '>';
795 result += ref.getValue();
796 }
797 if (!field.getValue().empty())
798 result += field.getValue();
799 return StringAttr::get(field.getContext(), result);
800}
801
803 assert(!isFullyEvaluated());
804 auto newPath = llvm::to_vector(basepath.getPath().getPath());
805 auto oldPath = path.getPath();
806 newPath.append(oldPath.begin(), oldPath.end());
807 path = PathAttr::get(path.getContext(), newPath);
808 markFullyEvaluated();
809}
810
811//===----------------------------------------------------------------------===//
812// AttributeValue
813//===----------------------------------------------------------------------===//
814
816 if (cast<TypedAttr>(attr).getType() != this->type)
817 return mlir::emitError(getLoc(), "cannot set AttributeValue of type ")
818 << this->type << " to Attribute " << attr;
819 if (isFullyEvaluated())
820 return mlir::emitError(
821 getLoc(),
822 "cannot set AttributeValue that has already been fully evaluated");
823 this->attr = attr;
824 markFullyEvaluated();
825 return success();
826}
827
829 if (!isFullyEvaluated())
830 return mlir::emitError(
831 getLoc(), "cannot finalize AttributeValue that is not fully evaluated");
832 return success();
833}
834
835std::shared_ptr<evaluator::EvaluatorValue>
836circt::om::evaluator::AttributeValue::get(Attribute attr, LocationAttr loc) {
837 auto type = cast<TypedAttr>(attr).getType();
838 auto *context = type.getContext();
839 if (!loc)
840 loc = UnknownLoc::get(context);
841
842 // Special handling for ListType to create proper ListValue objects instead of
843 // AttributeValue objects.
844 if (auto listType = dyn_cast<circt::om::ListType>(type)) {
845 SmallVector<EvaluatorValuePtr> elements;
846 auto listAttr = cast<om::ListAttr>(attr);
848 listAttr.getContext(), listAttr.getElements().getValue());
849 elements.append(values.begin(), values.end());
850 auto list = std::make_shared<evaluator::ListValue>(listType, elements, loc);
851 return list;
852 }
853
854 return std::shared_ptr<AttributeValue>(
855 new AttributeValue(PrivateTag{}, attr, loc));
856}
857
858std::shared_ptr<evaluator::EvaluatorValue>
859circt::om::evaluator::AttributeValue::get(Type type, LocationAttr loc) {
860 auto *context = type.getContext();
861 if (!loc)
862 loc = UnknownLoc::get(context);
863
864 // Special handling for ListType to create proper ListValue objects instead of
865 // AttributeValue objects.
866 if (auto listType = dyn_cast<circt::om::ListType>(type))
867 return std::make_shared<evaluator::ListValue>(listType, loc);
868 // Create the AttributeValue with the private tag
869 return std::shared_ptr<AttributeValue>(
870 new AttributeValue(PrivateTag{}, type, loc));
871}
assert(baseType &&"element must be base type")
static Location getLoc(DefSlot slot)
Definition Mem2Reg.cpp:215
std::shared_ptr< EvaluatorValue > EvaluatorValuePtr
A value of an object in memory.
Definition Evaluator.h:38
SmallVector< EvaluatorValuePtr > getEvaluatorValuesFromAttributes(MLIRContext *context, ArrayRef< Attribute > attributes)
Definition Evaluator.cpp:34
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)
Definition Evaluator.cpp:69
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)
mlir::ModuleOp getModule()
Get the Module this Evaluator is built from.
Definition Evaluator.cpp:29
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.
Definition Evaluator.cpp:26
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)
Definition Evaluator.cpp:94
SmallVectorImpl< std::shared_ptr< evaluator::EvaluatorValue > > * ActualParameters
Definition Evaluator.h:366
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
Definition Evaluator.h:368
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.
Definition Evaluator.h:132
LogicalResult setAttr(Attribute attr)
friend std::shared_ptr< EvaluatorValue > get(Attribute attr, LocationAttr loc)
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.
Base class for evaluator runtime values.
Definition Evaluator.h:48
A List which contains variadic length of elements with the same type.
Definition Evaluator.h:192
const auto & getElements() const
Definition Evaluator.h:212
A composite Object, which has a type and fields.
Definition Evaluator.h:228
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.
Definition Evaluator.h:93