CIRCT 23.0.0git
Loading...
Searching...
No Matches
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/ADT/iterator_range.h"
19#include "llvm/Support/Debug.h"
20
21#define DEBUG_TYPE "om-evaluator"
22
23using namespace mlir;
24using namespace circt::om;
25
26/// Construct an Evaluator with an IR module.
27circt::om::Evaluator::Evaluator(ModuleOp mod) : symbolTable(mod) {}
28
29/// Get the Module this Evaluator is built from.
31 return cast<ModuleOp>(symbolTable.getOp());
32}
33
34SmallVector<evaluator::EvaluatorValuePtr>
36 ArrayRef<Attribute> attributes) {
37 SmallVector<evaluator::EvaluatorValuePtr> values;
38 values.reserve(attributes.size());
39 for (auto attr : attributes)
40 values.push_back(evaluator::AttributeValue::get(cast<TypedAttr>(attr)));
41 return values;
42}
43
45 using namespace evaluator;
46 // Early return if already finalized.
47 if (finalized)
48 return success();
49 // Enable the flag to avoid infinite recursions.
50 finalized = true;
51 assert(isFullyEvaluated());
52 return llvm::TypeSwitch<EvaluatorValue *, LogicalResult>(this)
54 BasePathValue, PathValue>([](auto v) { return v->finalizeImpl(); });
55}
56
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(); })
63 .Case<BasePathValue>(
64 [this](auto *tuple) { return FrozenBasePathType::get(ctx); })
65 .Case<PathValue>(
66 [this](auto *tuple) { return FrozenPathType::get(ctx); });
67}
68
69FailureOr<evaluator::EvaluatorValuePtr>
71 using namespace circt::om::evaluator;
72
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);
78 })
79 .Case([&](circt::om::ClassType type)
80 -> FailureOr<evaluator::EvaluatorValuePtr> {
81 auto classDef =
82 symbolTable.lookup<ClassLike>(type.getClassName().getValue());
83 if (!classDef)
84 return symbolTable.getOp()->emitError("unknown class name ")
85 << type.getClassName();
86
87 // Create an ObjectValue for both ClassOp and ClassExternOp
89 std::make_shared<evaluator::ObjectValue>(classDef, loc);
90
91 return success(result);
92 })
93 .Case([&](circt::om::StringType type) {
96 return success(result);
97 })
98 .Default([&](auto type) { return failure(); });
99}
100
101FailureOr<evaluator::EvaluatorValuePtr> circt::om::Evaluator::getOrCreateValue(
102 Value value, ActualParameters actualParams, Location loc) {
103 LLVM_DEBUG(dbgs() << "- get: " << value << "\n");
104
105 auto it = objects.find({value, actualParams});
106 if (it != objects.end()) {
107 auto evalVal = it->second;
108 evalVal->setLocIfUnknown(loc);
109 return evalVal;
110 }
111
112 FailureOr<evaluator::EvaluatorValuePtr> result =
113 TypeSwitch<Value, FailureOr<evaluator::EvaluatorValuePtr>>(value)
114 .Case([&](BlockArgument arg) {
115 auto val = (*actualParams)[arg.getArgNumber()];
116 val->setLoc(loc);
117 return val;
118 })
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);
125 })
126 .Case([&](IntegerBinaryArithmeticOp op) {
127 // Create a partially evaluated AttributeValue of
128 // om::IntegerType in case we need to delay evaluation.
130 evaluator::AttributeValue::get(op.getResult().getType(),
131 loc);
132 return success(result);
133 })
134 .Case<ObjectFieldOp>([&](auto op) {
135 // Create a reference value since the value pointed by object
136 // field op is not created yet.
138 std::make_shared<evaluator::ReferenceValue>(
139 value.getType(), loc);
140 return success(result);
141 })
142 .Case<AnyCastOp>([&](AnyCastOp op) {
143 return getOrCreateValue(op.getInput(), actualParams, loc);
144 })
145 .Case<FrozenBasePathCreateOp>([&](FrozenBasePathCreateOp op) {
147 std::make_shared<evaluator::BasePathValue>(
148 op.getPathAttr(), loc);
149 return success(result);
150 })
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);
158 })
159 .Case<FrozenEmptyPathOp>([&](FrozenEmptyPathOp op) {
161 std::make_shared<evaluator::PathValue>(
163 return success(result);
164 })
165 .Case([&](BinaryEqualityOp op) {
167 evaluator::AttributeValue::get(op.getResult().getType(),
168 loc);
169 return success(result);
170 })
171 .Case<ListCreateOp, ListConcatOp, StringConcatOp,
172 ObjectFieldOp>([&](auto op) {
173 return getPartiallyEvaluatedValue(op.getType(), loc);
174 })
175 .Case<ObjectOp>([&](auto op) {
176 return getPartiallyEvaluatedValue(op.getType(), op.getLoc());
177 })
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;
183 return error;
184 });
185 });
186 if (failed(result))
187 return result;
188
189 objects[{value, actualParams}] = result.value();
190 return result;
191}
192
193FailureOr<evaluator::EvaluatorValuePtr>
195 ActualParameters actualParams,
196 Location loc,
197 ObjectKey instanceKey) {
198#ifndef NDEBUG
199 DebugNesting nestOne(debugNesting);
200#endif
201 LLVM_DEBUG(dbgs() << "object:\n");
202#ifndef NDEBUG
203 DebugNesting nestTwo(debugNesting);
204#endif
205 LLVM_DEBUG(dbgs() << "name: " << className << "\n");
206
207 auto classDef = symbolTable.lookup<ClassLike>(className);
208 if (!classDef)
209 return symbolTable.getOp()->emitError("unknown class name ") << className;
210
211 // If this is an external class, create an ObjectValue and mark it unknown
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");
217 return result;
218 }
219
220 // Otherwise, it's a regular class, proceed normally
221 ClassOp cls = cast<ClassOp>(classDef);
222
223 auto formalParamNames = cls.getFormalParamNames().getAsRange<StringAttr>();
224 auto formalParamTypes = cls.getBodyBlock()->getArgumentTypes();
225
226 // Verify the actual parameters are the right size and types for this class.
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: ";
232 // FIXME: `diag << actualParams` doesn't work for some reason.
233 bool isFirst = true;
234 for (const auto &param : *actualParams) {
235 if (isFirst)
236 isFirst = false;
237 else
238 diag << ", ";
239 diag << param;
240 }
241 error.attachNote(cls.getLoc()) << "formal parameters: " << formalParamTypes;
242 return error;
243 }
244
245 // Verify the actual parameter types match.
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";
251
252 // Subtyping: if formal param is any type, any actual param may be passed.
253 if (isa<AnyType>(formalParamType))
254 continue;
255
256 Type actualParamType = actualParam->getType();
257
258 assert(actualParamType && "actualParamType must be non-null!");
259
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;
265 return error;
266 }
267 }
268
269 // Instantiate the fields.
271
272 auto *context = cls.getContext();
273 {
274 LLVM_DEBUG(dbgs() << "ops:\n");
275#ifndef NDEBUG
276 DebugNesting nestOne(debugNesting);
277#endif
278 for (auto &op : cls.getOps())
279 for (auto result : op.getResults()) {
280 // Allocate the value, with unknown loc. It will be later set when
281 // evaluating the fields.
282 if (failed(getOrCreateValue(result, actualParams,
283 UnknownLoc::get(context))))
284 return failure();
285 // Add to the worklist.
286 worklist.push({result, actualParams});
287 }
288 }
289
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");
299#ifndef NDEBUG
300 DebugNesting nestOne(debugNesting);
301#endif
302 FailureOr<evaluator::EvaluatorValuePtr> result =
303 evaluateValue(value, actualParams, fieldLoc);
304 if (failed(result))
305 return result;
306
307 LLVM_DEBUG(dbgs() << "value: " << result.value() << "\n");
308 fields[cast<StringAttr>(name)] = result.value();
309 }
310
311 // Defer property assertions until after the worklist is drained, so that
312 // all ReferenceValues are fully resolved before we try to inspect them.
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});
317 }
318
319 // If the there is an instance, we must update the object value.
320 LLVM_DEBUG(dbgs() << "object value:\n");
321 if (instanceKey.first) {
322 auto result =
323 getOrCreateValue(instanceKey.first, instanceKey.second, loc).value();
324 auto *object = llvm::cast<evaluator::ObjectValue>(result.get());
325 object->setFields(std::move(fields));
326 return result;
327 }
328
329 // If it's external call, just allocate new ObjectValue.
331 std::make_shared<evaluator::ObjectValue>(cls, fields, loc);
332 return result;
333}
334
335/// Instantiate an Object with its class name and actual parameters.
336FailureOr<std::shared_ptr<evaluator::EvaluatorValue>>
338 StringAttr className, ArrayRef<evaluator::EvaluatorValuePtr> actualParams) {
339 LLVM_DEBUG(dbgs() << "instantiate:\n");
340#ifndef NDEBUG
341 DebugNesting nest(debugNesting);
342#endif
343 LLVM_DEBUG({
344 dbgs() << "class: " << className << "\n" << indent() << "params:\n";
345 for (auto &param : actualParams)
346 dbgs() << "- " << param << "\n";
347 });
348
349 auto classDef = symbolTable.lookup<ClassLike>(className);
350 if (!classDef)
351 return symbolTable.getOp()->emitError("unknown class name ") << className;
352
353 // If this is an external class, create an ObjectValue and mark it unknown
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");
360 return result;
361 }
362
363 // Otherwise, it's a regular class, proceed normally
364 ClassOp cls = cast<ClassOp>(classDef);
365
366 auto parameters =
367 std::make_unique<SmallVector<std::shared_ptr<evaluator::EvaluatorValue>>>(
368 actualParams);
369
370 actualParametersBuffers.push_back(std::move(parameters));
371
372 auto loc = cls.getLoc();
373 LLVM_DEBUG(dbgs() << "evaluate object:\n");
374 auto result = evaluateObjectInstance(
375 className, actualParametersBuffers.back().get(), loc);
376
377 if (failed(result))
378 return failure();
379
380 // `evaluateObjectInstance` has populated the worklist. Continue evaluations
381 // unless there is a partially evaluated value.
382 LLVM_DEBUG(dbgs() << "worklist:\n");
383 while (!worklist.empty()) {
384 auto [value, args] = worklist.front();
385 worklist.pop();
386
387 auto result = evaluateValue(value, args, loc);
388
389 if (failed(result))
390 return failure();
391
392 // It's possible that the value is not fully evaluated.
393 if (!result.value()->isFullyEvaluated())
394 worklist.push({value, args});
395 }
396
397 // Now that all values are fully resolved, evaluate the deferred property
398 // assertions.
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));
405 }
406 if (assertFailed)
407 return failure();
408
409 auto &object = result.value();
410 // Finalize the value. This will eliminate intermidiate ReferenceValue used as
411 // a placeholder in the initialization.
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");
417 return object;
418}
419
420FailureOr<evaluator::EvaluatorValuePtr>
422 Location loc) {
423 auto evaluatorValue = getOrCreateValue(value, actualParams, loc).value();
424
425 LLVM_DEBUG(dbgs() << "- eval: " << value << "\n");
426
427 // Return if the value is already evaluated.
428 if (evaluatorValue->isFullyEvaluated()) {
429 LLVM_DEBUG(dbgs(1) << "fully evaluated: " << evaluatorValue << "\n");
430 return evaluatorValue;
431 }
432
433 return llvm::TypeSwitch<Value, FailureOr<evaluator::EvaluatorValuePtr>>(value)
434 .Case([&](BlockArgument arg) {
435 return evaluateParameter(arg, actualParams, loc);
436 })
437 .Case([&](OpResult result) {
438 return TypeSwitch<Operation *, FailureOr<evaluator::EvaluatorValuePtr>>(
439 result.getDefiningOp())
440 .Case([&](ConstantOp op) {
441 return evaluateConstant(op, actualParams, loc);
442 })
443 .Case([&](IntegerBinaryArithmeticOp op) {
444 return evaluateIntegerBinaryArithmetic(op, actualParams, loc);
445 })
446 .Case([&](ObjectOp op) {
447 return evaluateObjectInstance(op, actualParams);
448 })
449 .Case([&](ObjectFieldOp op) {
450 return evaluateObjectField(op, actualParams, loc);
451 })
452 .Case([&](ListCreateOp op) {
453 return evaluateListCreate(op, actualParams, loc);
454 })
455 .Case([&](ListConcatOp op) {
456 return evaluateListConcat(op, actualParams, loc);
457 })
458 .Case([&](StringConcatOp op) {
459 return evaluateStringConcat(op, actualParams, loc);
460 })
461 .Case([&](BinaryEqualityOp op) {
462 return evaluateBinaryEquality(op, actualParams, loc);
463 })
464 .Case([&](AnyCastOp op) {
465 return evaluateValue(op.getInput(), actualParams, loc);
466 })
467 .Case([&](FrozenBasePathCreateOp op) {
468 return evaluateBasePathCreate(op, actualParams, loc);
469 })
470 .Case([&](FrozenPathCreateOp op) {
471 return evaluatePathCreate(op, actualParams, loc);
472 })
473 .Case([&](FrozenEmptyPathOp op) {
474 return evaluateEmptyPath(op, actualParams, loc);
475 })
476 .Case<UnknownValueOp>([&](UnknownValueOp op) {
477 return evaluateUnknownValue(op, loc);
478 })
479 .Default([&](Operation *op) {
480 auto error = op->emitError("unable to evaluate value");
481 error.attachNote() << "value: " << value;
482 return error;
483 });
484 });
485}
486
487/// Evaluator dispatch function for parameters.
488FailureOr<evaluator::EvaluatorValuePtr> circt::om::Evaluator::evaluateParameter(
489 BlockArgument formalParam, ActualParameters actualParams, Location loc) {
490 auto val = (*actualParams)[formalParam.getArgNumber()];
491 val->setLoc(loc);
492 return success(val);
493}
494
495/// Evaluator dispatch function for constants.
496FailureOr<circt::om::evaluator::EvaluatorValuePtr>
498 ActualParameters actualParams,
499 Location loc) {
500 // For list constants, create ListValue.
501 return success(om::evaluator::AttributeValue::get(op.getValue(), loc));
502}
503
504// Evaluator dispatch function for integer binary arithmetic.
505FailureOr<EvaluatorValuePtr>
507 IntegerBinaryArithmeticOp op, ActualParameters actualParams, Location loc) {
508 // Get the op's EvaluatorValue handle, in case it hasn't been evaluated yet.
509 auto handle = getOrCreateValue(op.getResult(), actualParams, loc);
510
511 // If it's fully evaluated, we can return it.
512 if (handle.value()->isFullyEvaluated())
513 return handle;
514
515 // Evaluate operands if necessary, and return the partially evaluated value if
516 // they aren't ready.
517 auto lhsResult = evaluateValue(op.getLhs(), actualParams, loc);
518 if (failed(lhsResult))
519 return lhsResult;
520 if (!lhsResult.value()->isFullyEvaluated())
521 return handle;
522
523 auto rhsResult = evaluateValue(op.getRhs(), actualParams, loc);
524 if (failed(rhsResult))
525 return rhsResult;
526 if (!rhsResult.value()->isFullyEvaluated())
527 return handle;
528
529 // Check if any operand is unknown and propagate the unknown flag.
530 if (lhsResult.value()->isUnknown() || rhsResult.value()->isUnknown()) {
531 handle.value()->markUnknown();
532 return handle;
533 }
534
535 // Extract the integer attributes.
536 auto extractAttr = [](evaluator::EvaluatorValue *value) {
537 return std::move(
538 llvm::TypeSwitch<evaluator::EvaluatorValue *, om::IntegerAttr>(value)
539 .Case([](evaluator::AttributeValue *val) {
540 return val->getAs<om::IntegerAttr>();
541 })
542 .Case([](evaluator::ReferenceValue *val) {
543 return cast<evaluator::AttributeValue>(
544 val->getStrippedValue()->get())
545 ->getAs<om::IntegerAttr>();
546 }));
547 };
548
549 om::IntegerAttr lhs = extractAttr(lhsResult.value().get());
550 om::IntegerAttr rhs = extractAttr(rhsResult.value().get());
551 assert(lhs && rhs &&
552 "expected om::IntegerAttr for IntegerBinaryArithmeticOp operands");
553
554 // Extend values if necessary to match bitwidth. Most interesting arithmetic
555 // on APSInt asserts that both operands are the same bitwidth, but the
556 // IntegerAttrs we are working with may have used the smallest necessary
557 // bitwidth to represent the number they hold, and won't necessarily match.
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());
564
565 // Perform arbitrary precision signed integer binary arithmetic.
566 FailureOr<APSInt> result = op.evaluateIntegerOperation(lhsVal, rhsVal);
567
568 if (failed(result))
569 return op->emitError("failed to evaluate integer operation");
570
571 // Package the result as a new om::IntegerAttr.
572 MLIRContext *ctx = op->getContext();
573 auto resultAttr =
574 om::IntegerAttr::get(ctx, mlir::IntegerAttr::get(ctx, result.value()));
575
576 // Finalize the op result value.
577 auto *handleValue = cast<evaluator::AttributeValue>(handle.value().get());
578 auto resultStatus = handleValue->setAttr(resultAttr);
579 if (failed(resultStatus))
580 return resultStatus;
581
582 auto finalizeStatus = handleValue->finalize();
583 if (failed(finalizeStatus))
584 return finalizeStatus;
585
586 return handle;
587}
588
589/// Evaluator dispatch function for property assertions.
590LogicalResult
592 ActualParameters actualParams) {
593#ifndef NDEBUG
594 DebugNesting nest(debugNesting);
595#endif
596
597 auto loc = op.getLoc();
598
599 // Evaluate the condition, returning early if it isn't ready yet.
600 LLVM_DEBUG(dbgs() << "op: " << op << "\n"
601 << indent() << "evaluate condition: \n");
602 auto condResult = evaluateValue(op.getCondition(), actualParams, loc);
603 if (failed(condResult))
604 return failure();
605 if (!condResult.value()->isFullyEvaluated()) {
606 LLVM_DEBUG(dbgs() << "evaluate condition: <not fully evaluated>\n");
607 return success();
608 }
609
610 // If the condition is unknown, skip silently (best-effort).
611 if (condResult.value()->isUnknown())
612 return success();
613
614 LLVM_DEBUG(dbgs() << "condition: " << condResult.value() << "\n");
615
616 // Extract the attribute from the condition value, handling the case where
617 // the condition resolves through a ReferenceValue (e.g. an ObjectFieldOp or
618 // a parameter that participates in cycle resolution).
619 auto extractAttr = [](evaluator::EvaluatorValue *value) -> mlir::Attribute {
620 return llvm::TypeSwitch<evaluator::EvaluatorValue *, mlir::Attribute>(value)
621 .Case([](evaluator::AttributeValue *val) { return val->getAttr(); })
622 .Case([](evaluator::ReferenceValue *val) -> mlir::Attribute {
623 auto stripped = val->getStrippedValue();
624 if (failed(stripped))
625 return {};
626 if (auto *attr =
627 dyn_cast<evaluator::AttributeValue>(stripped.value().get()))
628 return attr->getAttr();
629 return {};
630 })
631 .Default([](auto *) -> mlir::Attribute { return {}; });
632 };
633
634 auto condAttr = extractAttr(condResult.value().get());
635 if (!condAttr)
636 return success();
637
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();
643 else
644 return op.emitError("expected BoolAttr or mlir::IntegerAttr");
645
646 if (isFalse)
647 return op.emitError("OM property assertion failed: ") << op.getMessage();
648
649 return success();
650}
651
652/// Evaluator dispatch function for Object instances.
653FailureOr<circt::om::Evaluator::ActualParameters>
655 ValueRange range, ActualParameters actualParams, Location loc) {
656 // Create an unique storage to store parameters.
657 auto parameters = std::make_unique<
658 SmallVector<std::shared_ptr<evaluator::EvaluatorValue>>>();
659
660 // Collect operands' evaluator values in the current instantiation context.
661 for (auto input : range) {
662 auto inputResult = getOrCreateValue(input, actualParams, loc);
663 if (failed(inputResult))
664 return failure();
665 parameters->push_back(inputResult.value());
666 }
667
668 actualParametersBuffers.push_back(std::move(parameters));
669 return actualParametersBuffers.back().get();
670}
671
672/// Evaluator dispatch function for Object instances.
673FailureOr<evaluator::EvaluatorValuePtr>
675 ActualParameters actualParams) {
676 auto loc = op.getLoc();
677 if (isFullyEvaluated({op, actualParams}))
678 return getOrCreateValue(op, actualParams, loc);
679
680 auto params =
681 createParametersFromOperands(op.getOperands(), actualParams, loc);
682 if (failed(params))
683 return failure();
684 return evaluateObjectInstance(op.getClassNameAttr(), params.value(), loc,
685 {op, actualParams});
686}
687
688/// Evaluator dispatch function for Object fields.
689FailureOr<evaluator::EvaluatorValuePtr>
691 ActualParameters actualParams,
692 Location loc) {
693 // Evaluate the Object itself, in case it hasn't been evaluated yet.
694 FailureOr<evaluator::EvaluatorValuePtr> currentObjectResult =
695 evaluateValue(op.getObject(), actualParams, loc);
696 if (failed(currentObjectResult))
697 return currentObjectResult;
698
699 auto result = currentObjectResult.value();
700
701 auto objectFieldValue = getOrCreateValue(op, actualParams, loc).value();
702
703 if (result->isUnknown()) {
704 // If objectFieldValue is a ReferenceValue, set its value to a unknown value
705 // of the proper type
706 if (auto *ref =
707 llvm::dyn_cast<evaluator::ReferenceValue>(objectFieldValue.get())) {
708 auto unknownField = createUnknownValue(op.getResult().getType(), loc);
709 if (failed(unknownField))
710 return unknownField;
711 ref->setValue(unknownField.value());
712 }
713 // markUnknown() also marks the value as fully evaluated
714 objectFieldValue->markUnknown();
715 return objectFieldValue;
716 }
717
718 auto *currentObject = llvm::cast<evaluator::ObjectValue>(result.get());
719
720 // Iteratively access nested fields through the path until we reach the final
721 // field in the path.
723 for (auto field : op.getFieldPath().getAsRange<FlatSymbolRefAttr>()) {
724 // `currentObject` might no be fully evaluated.
725 if (!currentObject->getFields().contains(field.getAttr()))
726 return objectFieldValue;
727
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;
733 }
734
735 // Update the reference.
736 llvm::cast<evaluator::ReferenceValue>(objectFieldValue.get())
737 ->setValue(finalField);
738
739 // Return the field being accessed.
740 return objectFieldValue;
741}
742
743/// Evaluator dispatch function for List creation.
744FailureOr<evaluator::EvaluatorValuePtr>
746 ActualParameters actualParams,
747 Location loc) {
748 // Evaluate the Object itself, in case it hasn't been evaluated yet.
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);
754 if (failed(result))
755 return result;
756 if (!result.value()->isFullyEvaluated())
757 return list;
758 // Check if any operand is unknown.
759 if (result.value()->isUnknown())
760 hasUnknown = true;
761 values.push_back(result.value());
762 }
763
764 // Set the list elements (this also marks the list as fully evaluated).
765 llvm::cast<evaluator::ListValue>(list.value().get())
766 ->setElements(std::move(values));
767
768 // If any operand is unknown, mark the list as unknown.
769 // markUnknown() checks if already fully evaluated before calling
770 // markFullyEvaluated().
771 if (hasUnknown)
772 list.value()->markUnknown();
773
774 return list;
775}
776
777/// Evaluator dispatch function for List concatenation.
778FailureOr<evaluator::EvaluatorValuePtr>
780 ActualParameters actualParams,
781 Location loc) {
782 // Evaluate the List concat op itself, in case it hasn't been evaluated yet.
783 SmallVector<evaluator::EvaluatorValuePtr> values;
784 auto list = getOrCreateValue(op, actualParams, loc);
785
786 // Extract the ListValue, either directly or through an object reference.
787 auto extractList = [](evaluator::EvaluatorValue *value) {
788 return std::move(
789 llvm::TypeSwitch<evaluator::EvaluatorValue *, evaluator::ListValue *>(
790 value)
791 .Case([](evaluator::ListValue *val) { return val; })
792 .Case([](evaluator::ReferenceValue *val) {
793 return cast<evaluator::ListValue>(val->getStrippedValue()->get());
794 }));
795 };
796
797 bool hasUnknown = false;
798 for (auto operand : op.getOperands()) {
799 auto result = evaluateValue(operand, actualParams, loc);
800 if (failed(result))
801 return result;
802 if (!result.value()->isFullyEvaluated())
803 return list;
804 // Check if any operand is unknown.
805 if (result.value()->isUnknown())
806 hasUnknown = true;
807
808 // Extract this sublist and ensure it's done evaluating.
809 evaluator::ListValue *subList = extractList(result.value().get());
810 if (!subList->isFullyEvaluated())
811 return list;
812
813 // Append each EvaluatorValue from the sublist.
814 for (const auto &subValue : subList->getElements())
815 values.push_back(subValue);
816 }
817
818 // Return the concatenated list.
819 llvm::cast<evaluator::ListValue>(list.value().get())
820 ->setElements(std::move(values));
821
822 // If any operand is unknown, mark the result as unknown.
823 // markUnknown() checks if already fully evaluated before calling
824 // markFullyEvaluated().
825 if (hasUnknown)
826 list.value()->markUnknown();
827
828 return list;
829}
830
831/// Evaluator dispatch function for String concatenation.
832FailureOr<evaluator::EvaluatorValuePtr>
834 ActualParameters actualParams,
835 Location loc) {
836 // Get the op's EvaluatorValue handle, in case it hasn't been evaluated yet.
837 auto handle = getOrCreateValue(op.getResult(), actualParams, loc);
838 if (failed(handle))
839 return handle;
840
841 // If it's fully evaluated, we can return it.
842 if (handle.value()->isFullyEvaluated())
843 return handle;
844
845 // Extract the string attributes, handling both AttributeValue and
846 // ReferenceValue cases.
847 auto extractAttr = [](evaluator::EvaluatorValue *value) -> StringAttr {
848 return llvm::TypeSwitch<evaluator::EvaluatorValue *, StringAttr>(value)
849 .Case([](evaluator::AttributeValue *val) {
850 return val->getAs<StringAttr>();
851 })
852 .Case([](evaluator::ReferenceValue *val) {
853 return cast<evaluator::AttributeValue>(val->getStrippedValue()->get())
854 ->getAs<StringAttr>();
855 });
856 };
857
858 // Evaluate all operands and concatenate them.
859 std::string result;
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())
865 return handle;
866
867 StringAttr str = extractAttr(operandResult.value().get());
868 assert(str && "expected StringAttr for StringConcatOp operand");
869 result += str.getValue().str();
870 }
871
872 // Create the concatenated string attribute.
873 auto resultStr = StringAttr::get(result, op.getResult().getType());
874
875 // Finalize the op result value.
876 auto *handleValue = cast<evaluator::AttributeValue>(handle.value().get());
877 auto resultStatus = handleValue->setAttr(resultStr);
878 if (failed(resultStatus))
879 return resultStatus;
880
881 auto finalizeStatus = handleValue->finalize();
882 if (failed(finalizeStatus))
883 return finalizeStatus;
884
885 return handle;
886}
887
888// Evaluator dispatch function for binary property equality operations.
889FailureOr<evaluator::EvaluatorValuePtr>
891 ActualParameters actualParams,
892 Location loc) {
893 // Get the op's EvaluatorValue handle, in case it hasn't been evaluated yet.
894 auto handle = getOrCreateValue(op.getResult(), actualParams, loc);
895 if (failed(handle))
896 return handle;
897
898 // If it's fully evaluated, we can return it.
899 if (handle.value()->isFullyEvaluated())
900 return handle;
901
902 // Evaluate both operands, returning the partially evaluated handle if either
903 // isn't ready yet.
904 auto lhsResult = evaluateValue(op.getLhs(), actualParams, loc);
905 if (failed(lhsResult))
906 return lhsResult;
907 if (!lhsResult.value()->isFullyEvaluated())
908 return handle;
909
910 auto rhsResult = evaluateValue(op.getRhs(), actualParams, loc);
911 if (failed(rhsResult))
912 return rhsResult;
913 if (!rhsResult.value()->isFullyEvaluated())
914 return handle;
915
916 // Check if any operand is unknown and propagate the unknown flag.
917 if (lhsResult.value()->isUnknown() || rhsResult.value()->isUnknown()) {
918 handle.value()->markUnknown();
919 return handle;
920 }
921
922 // Extract the underlying attribute, handling both AttributeValue and
923 // ReferenceValue cases.
924 auto extractAttr = [](evaluator::EvaluatorValue *value) -> mlir::Attribute {
925 return llvm::TypeSwitch<evaluator::EvaluatorValue *, mlir::Attribute>(value)
926 .Case([](evaluator::AttributeValue *val) { return val->getAttr(); })
927 .Case([](evaluator::ReferenceValue *val) -> mlir::Attribute {
928 return cast<evaluator::AttributeValue>(val->getStrippedValue()->get())
929 ->getAttr();
930 });
931 };
932
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");
936
937 // Perform the binary equality operation.
938 FailureOr<mlir::Attribute> result = op.evaluateBinaryEquality(lhs, rhs);
939 if (failed(result))
940 return op->emitError("failed to evaluate binary equality operation");
941
942 // Finalize the op result value.
943 auto *handleValue = cast<evaluator::AttributeValue>(handle.value().get());
944 auto resultStatus = handleValue->setAttr(*result);
945 if (failed(resultStatus))
946 return resultStatus;
947
948 auto finalizeStatus = handleValue->finalize();
949 if (failed(finalizeStatus))
950 return finalizeStatus;
951
952 return handle;
953}
954
955FailureOr<evaluator::EvaluatorValuePtr>
957 ActualParameters actualParams,
958 Location loc) {
959 // Evaluate the Object itself, in case it hasn't been evaluated yet.
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);
963 if (failed(result))
964 return result;
965 auto &value = result.value();
966 if (!value->isFullyEvaluated())
967 return valueResult;
968
969 // If the base path is unknown, mark the result as unknown.
970 if (result.value()->isUnknown()) {
971 valueResult->markUnknown();
972 return valueResult;
973 }
974
975 path->setBasepath(*llvm::cast<evaluator::BasePathValue>(value.get()));
976 return valueResult;
977}
978
979FailureOr<evaluator::EvaluatorValuePtr>
981 ActualParameters actualParams,
982 Location loc) {
983 // Evaluate the Object itself, in case it hasn't been evaluated yet.
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);
987 if (failed(result))
988 return result;
989 auto &value = result.value();
990 if (!value->isFullyEvaluated())
991 return valueResult;
992
993 // If the base path is unknown, mark the result as unknown.
994 if (result.value()->isUnknown()) {
995 valueResult->markUnknown();
996 return valueResult;
997 }
998
999 path->setBasepath(*llvm::cast<evaluator::BasePathValue>(value.get()));
1000 return valueResult;
1001}
1002
1003FailureOr<evaluator::EvaluatorValuePtr> circt::om::Evaluator::evaluateEmptyPath(
1004 FrozenEmptyPathOp op, ActualParameters actualParams, Location loc) {
1005 auto valueResult = getOrCreateValue(op, actualParams, loc).value();
1006 return valueResult;
1007}
1008
1009/// Create an unknown value of the specified type
1010FailureOr<evaluator::EvaluatorValuePtr>
1012 using namespace circt::om::evaluator;
1013
1014 // Create an unknown value of the appropriate type by switching on the type
1015 auto result =
1016 TypeSwitch<Type, FailureOr<EvaluatorValuePtr>>(type)
1017 .Case([&](ListType type) -> FailureOr<EvaluatorValuePtr> {
1018 // Create an empty list
1019 return success(std::make_shared<ListValue>(type, loc));
1020 })
1021 .Case([&](ClassType type) -> FailureOr<EvaluatorValuePtr> {
1022 // Look up the class definition
1023 auto classDef =
1024 symbolTable.lookup<ClassLike>(type.getClassName().getValue());
1025 if (!classDef)
1026 return symbolTable.getOp()->emitError("unknown class name ")
1027 << type.getClassName();
1028
1029 // Create an ObjectValue for both ClassOp and ClassExternOp
1030 return success(std::make_shared<ObjectValue>(classDef, loc));
1031 })
1032 .Case([&](FrozenBasePathType type) -> FailureOr<EvaluatorValuePtr> {
1033 // Create an empty basepath
1034 return success(std::make_shared<BasePathValue>(type.getContext()));
1035 })
1036 .Case([&](FrozenPathType type) -> FailureOr<EvaluatorValuePtr> {
1037 // Create an empty path
1038 return success(
1039 std::make_shared<PathValue>(PathValue::getEmptyPath(loc)));
1040 })
1041 .Default([&](Type type) -> FailureOr<EvaluatorValuePtr> {
1042 // For all other types (primitives like integer, string,
1043 // etc.), create an AttributeValue
1044 return success(AttributeValue::get(type, LocationAttr(loc)));
1045 });
1046
1047 // Mark the result as unknown if successful
1048 if (succeeded(result))
1049 result->get()->markUnknown();
1050
1051 return result;
1052}
1053
1054/// Evaluate an unknown value
1055FailureOr<evaluator::EvaluatorValuePtr>
1056circt::om::Evaluator::evaluateUnknownValue(UnknownValueOp op, Location loc) {
1057 return createUnknownValue(op.getType(), loc);
1058}
1059
1060//===----------------------------------------------------------------------===//
1061// ObjectValue
1062//===----------------------------------------------------------------------===//
1063
1064/// Get a field of the Object by name.
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]);
1071}
1072
1073/// Get an ArrayAttr with the names of the fields in the Object. Sort the fields
1074/// so there is always a stable order.
1076 SmallVector<Attribute> fieldNames;
1077 for (auto &f : fields)
1078 fieldNames.push_back(f.first);
1079
1080 llvm::sort(fieldNames, [](Attribute a, Attribute b) {
1081 return cast<StringAttr>(a).getValue() < cast<StringAttr>(b).getValue();
1082 });
1083
1084 return ArrayAttr::get(cls.getContext(), fieldNames);
1085}
1086
1088 for (auto &&[e, value] : fields)
1089 if (failed(finalizeEvaluatorValue(value)))
1090 return failure();
1091
1092 return success();
1093}
1094
1095//===----------------------------------------------------------------------===//
1096// ReferenceValue
1097//===----------------------------------------------------------------------===//
1098
1100 auto result = getStrippedValue();
1101 if (failed(result))
1102 return result;
1103 value = std::move(result.value());
1104 // the stripped value also needs to be finalized
1105 if (failed(finalizeEvaluatorValue(value)))
1106 return failure();
1107
1108 return success();
1109}
1110
1111//===----------------------------------------------------------------------===//
1112// ListValue
1113//===----------------------------------------------------------------------===//
1114
1116 for (auto &value : elements) {
1117 if (failed(finalizeEvaluatorValue(value)))
1118 return failure();
1119 }
1120 return success();
1121}
1122
1123//===----------------------------------------------------------------------===//
1124// BasePathValue
1125//===----------------------------------------------------------------------===//
1126
1128 : EvaluatorValue(context, Kind::BasePath, UnknownLoc::get(context)),
1129 path(PathAttr::get(context, {})) {
1130 markFullyEvaluated();
1131}
1132
1133evaluator::BasePathValue::BasePathValue(PathAttr path, Location loc)
1134 : EvaluatorValue(path.getContext(), Kind::BasePath, loc), path(path) {}
1135
1137 assert(isFullyEvaluated());
1138 return path;
1139}
1140
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();
1148}
1149
1150//===----------------------------------------------------------------------===//
1151// PathValue
1152//===----------------------------------------------------------------------===//
1153
1154evaluator::PathValue::PathValue(TargetKindAttr targetKind, PathAttr path,
1155 StringAttr module, StringAttr ref,
1156 StringAttr field, Location loc)
1157 : EvaluatorValue(loc.getContext(), Kind::Path, loc), targetKind(targetKind),
1158 path(path), module(module), ref(ref), field(field) {}
1159
1161 PathValue path(nullptr, nullptr, nullptr, nullptr, nullptr, loc);
1162 path.markFullyEvaluated();
1163 return path;
1164}
1165
1167 // If the module is null, then this is a path to a deleted object.
1168 if (!targetKind)
1169 return StringAttr::get(getContext(), "OMDeleted:");
1170 SmallString<64> result;
1171 switch (targetKind.getValue()) {
1172 case TargetKind::DontTouch:
1173 result += "OMDontTouchedReferenceTarget";
1174 break;
1175 case TargetKind::Instance:
1176 result += "OMInstanceTarget";
1177 break;
1178 case TargetKind::MemberInstance:
1179 result += "OMMemberInstanceTarget";
1180 break;
1181 case TargetKind::MemberReference:
1182 result += "OMMemberReferenceTarget";
1183 break;
1184 case TargetKind::Reference:
1185 result += "OMReferenceTarget";
1186 break;
1187 }
1188 result += ":~";
1189 if (!path.getPath().empty())
1190 result += path.getPath().front().module;
1191 else
1192 result += module.getValue();
1193 result += '|';
1194 for (const auto &elt : path) {
1195 result += elt.module.getValue();
1196 result += '/';
1197 result += elt.instance.getValue();
1198 result += ':';
1199 }
1200 if (!module.getValue().empty())
1201 result += module.getValue();
1202 if (!ref.getValue().empty()) {
1203 result += '>';
1204 result += ref.getValue();
1205 }
1206 if (!field.getValue().empty())
1207 result += field.getValue();
1208 return StringAttr::get(field.getContext(), result);
1209}
1210
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();
1218}
1219
1220//===----------------------------------------------------------------------===//
1221// AttributeValue
1222//===----------------------------------------------------------------------===//
1223
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(
1230 getLoc(),
1231 "cannot set AttributeValue that has already been fully evaluated");
1232 this->attr = attr;
1233 markFullyEvaluated();
1234 return success();
1235}
1236
1238 if (!isFullyEvaluated())
1239 return mlir::emitError(
1240 getLoc(), "cannot finalize AttributeValue that is not fully evaluated");
1241 return success();
1242}
1243
1244std::shared_ptr<evaluator::EvaluatorValue>
1245circt::om::evaluator::AttributeValue::get(Attribute attr, LocationAttr loc) {
1246 auto type = cast<TypedAttr>(attr).getType();
1247 auto *context = type.getContext();
1248 if (!loc)
1249 loc = UnknownLoc::get(context);
1250
1251 // Special handling for ListType to create proper ListValue objects instead of
1252 // AttributeValue objects.
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);
1260 return list;
1261 }
1262
1263 return std::shared_ptr<AttributeValue>(
1264 new AttributeValue(PrivateTag{}, attr, loc));
1265}
1266
1267std::shared_ptr<evaluator::EvaluatorValue>
1268circt::om::evaluator::AttributeValue::get(Type type, LocationAttr loc) {
1269 auto *context = type.getContext();
1270 if (!loc)
1271 loc = UnknownLoc::get(context);
1272
1273 // Special handling for ListType to create proper ListValue objects instead of
1274 // AttributeValue objects.
1275 if (auto listType = dyn_cast<circt::om::ListType>(type))
1276 return std::make_shared<evaluator::ListValue>(listType, loc);
1277 // Create the AttributeValue with the private tag
1278 return std::shared_ptr<AttributeValue>(
1279 new AttributeValue(PrivateTag{}, type, loc));
1280}
assert(baseType &&"element must be base type")
static std::unique_ptr< Context > context
static Location getLoc(DefSlot slot)
Definition Mem2Reg.cpp:216
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:70
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.
Definition Evaluator.cpp:30
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.
Definition Evaluator.cpp:27
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
Definition Evaluator.h:392
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
Definition Evaluator.h:394
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:152
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:49
A List which contains variadic length of elements with the same type.
Definition Evaluator.h:213
const auto & getElements() const
Definition Evaluator.h:234
A composite Object, which has a type and fields.
Definition Evaluator.h:250
FailureOr< EvaluatorValuePtr > getField(StringAttr field)
Get a field of the Object by name.
ArrayAttr getFieldNames()
Get all the field names of the Object.
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:112
std::shared_ptr< EvaluatorValue > EvaluatorValuePtr
A value of an object in memory.
Definition Evaluator.h:39
SmallVector< EvaluatorValuePtr > getEvaluatorValuesFromAttributes(MLIRContext *context, ArrayRef< Attribute > attributes)
Definition Evaluator.cpp:35
RAII helper to increment/decrement debugNesting.
Definition Evaluator.h:500