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 auto result =
74 TypeSwitch<mlir::Type, FailureOr<evaluator::EvaluatorValuePtr>>(type)
75 .Case([&](circt::om::ListType type) {
77 std::make_shared<evaluator::ListValue>(type, loc);
78 return success(result);
79 })
80 .Case([&](circt::om::ClassType type)
81 -> FailureOr<evaluator::EvaluatorValuePtr> {
82 auto classDef =
83 symbolTable.lookup<ClassLike>(type.getClassName().getValue());
84 if (!classDef)
85 return symbolTable.getOp()->emitError("unknown class name ")
86 << type.getClassName();
87
88 // Create an ObjectValue for both ClassOp and ClassExternOp
90 std::make_shared<evaluator::ObjectValue>(classDef, loc);
91
92 return success(result);
93 })
94 .Case([&](circt::om::StringType type) {
97 return success(result);
98 })
99 .Default([&](auto type) { return failure(); });
100
101 if (succeeded(result))
102 attachCounter(result.value());
103
104 return result;
105}
106
107FailureOr<evaluator::EvaluatorValuePtr> circt::om::Evaluator::getOrCreateValue(
108 Value value, ActualParameters actualParams, Location loc) {
109 LLVM_DEBUG(dbgs() << "- get: " << value << "\n");
110
111 auto it = objects.find({value, actualParams});
112 if (it != objects.end()) {
113 auto evalVal = it->second;
114 evalVal->setLocIfUnknown(loc);
115 return evalVal;
116 }
117
118 FailureOr<evaluator::EvaluatorValuePtr> result =
119 TypeSwitch<Value, FailureOr<evaluator::EvaluatorValuePtr>>(value)
120 .Case([&](BlockArgument arg) {
121 auto val = (*actualParams)[arg.getArgNumber()];
122 val->setLoc(loc);
123 return val;
124 })
125 .Case([&](OpResult result) {
126 return TypeSwitch<Operation *,
127 FailureOr<evaluator::EvaluatorValuePtr>>(
128 result.getDefiningOp())
129 .Case([&](ConstantOp op) {
130 return evaluateConstant(op, actualParams, loc);
131 })
132 .Case([&](IntegerBinaryOp op) {
133 // Create a partially evaluated AttributeValue in case we need
134 // to delay evaluation.
136 evaluator::AttributeValue::get(op.getResult().getType(),
137 loc);
138 return success(result);
139 })
140 .Case<ObjectFieldOp>([&](auto op) {
141 // Create a reference value since the value pointed by object
142 // field op is not created yet.
144 std::make_shared<evaluator::ReferenceValue>(
145 value.getType(), loc);
146 return success(result);
147 })
148 .Case<AnyCastOp>([&](AnyCastOp op) {
149 return getOrCreateValue(op.getInput(), actualParams, loc);
150 })
151 .Case<FrozenBasePathCreateOp>([&](FrozenBasePathCreateOp op) {
153 std::make_shared<evaluator::BasePathValue>(
154 op.getPathAttr(), loc);
155 return success(result);
156 })
157 .Case<FrozenPathCreateOp>([&](FrozenPathCreateOp op) {
159 std::make_shared<evaluator::PathValue>(
160 op.getTargetKindAttr(), op.getPathAttr(),
161 op.getModuleAttr(), op.getRefAttr(),
162 op.getFieldAttr(), loc);
163 return success(result);
164 })
165 .Case<FrozenEmptyPathOp>([&](FrozenEmptyPathOp op) {
167 std::make_shared<evaluator::PathValue>(
169 return success(result);
170 })
171 .Case([&](BinaryEqualityOp op) {
173 evaluator::AttributeValue::get(op.getResult().getType(),
174 loc);
175 return success(result);
176 })
177 .Case<ListCreateOp, ListConcatOp, StringConcatOp,
178 ObjectFieldOp>([&](auto op) {
179 return getPartiallyEvaluatedValue(op.getType(), loc);
180 })
181 .Case<ObjectOp>([&](auto op) {
182 return getPartiallyEvaluatedValue(op.getType(), op.getLoc());
183 })
184 .Case<UnknownValueOp>(
185 [&](auto op) { return evaluateUnknownValue(op, loc); })
186 .Default([&](Operation *op) {
187 auto error = op->emitError("unable to evaluate value");
188 error.attachNote() << "value: " << value;
189 return error;
190 });
191 });
192 if (failed(result))
193 return result;
194
195 // Attach listener to newly created values
196 attachCounter(result.value());
197 objects[{value, actualParams}] = result.value();
198 return result;
199}
200
201FailureOr<evaluator::EvaluatorValuePtr>
203 ActualParameters actualParams,
204 Location loc,
205 ObjectKey instanceKey) {
206#ifndef NDEBUG
207 DebugNesting nestOne(debugNesting);
208#endif
209 LLVM_DEBUG(dbgs() << "object:\n");
210#ifndef NDEBUG
211 DebugNesting nestTwo(debugNesting);
212#endif
213 LLVM_DEBUG(dbgs() << "name: " << className << "\n");
214
215 auto classDef = symbolTable.lookup<ClassLike>(className);
216 if (!classDef)
217 return symbolTable.getOp()->emitError("unknown class name ") << className;
218
219 // If this is an external class, create an ObjectValue and mark it unknown
220 if (isa<ClassExternOp>(classDef)) {
222 std::make_shared<evaluator::ObjectValue>(classDef, loc);
223 attachCounter(result);
224 result->markUnknown();
225 LLVM_DEBUG(dbgs(1) << "extern: <unknown-value>\n");
226 return result;
227 }
228
229 // Otherwise, it's a regular class, proceed normally
230 ClassOp cls = cast<ClassOp>(classDef);
231
232 auto formalParamNames = cls.getFormalParamNames().getAsRange<StringAttr>();
233 auto formalParamTypes = cls.getBodyBlock()->getArgumentTypes();
234
235 // Verify the actual parameters are the right size and types for this class.
236 if (actualParams->size() != formalParamTypes.size()) {
237 auto error = cls.emitError("actual parameter list length (")
238 << actualParams->size() << ") does not match formal "
239 << "parameter list length (" << formalParamTypes.size() << ")";
240 auto &diag = error.attachNote() << "actual parameters: ";
241 // FIXME: `diag << actualParams` doesn't work for some reason.
242 bool isFirst = true;
243 for (const auto &param : *actualParams) {
244 if (isFirst)
245 isFirst = false;
246 else
247 diag << ", ";
248 diag << param;
249 }
250 error.attachNote(cls.getLoc()) << "formal parameters: " << formalParamTypes;
251 return error;
252 }
253
254 // Verify the actual parameter types match.
255 for (auto [actualParam, formalParamName, formalParamType] :
256 llvm::zip(*actualParams, formalParamNames, formalParamTypes)) {
257 if (!actualParam || !actualParam.get())
258 return cls.emitError("actual parameter for ")
259 << formalParamName << " is null";
260
261 // Subtyping: if formal param is any type, any actual param may be passed.
262 if (isa<AnyType>(formalParamType))
263 continue;
264
265 Type actualParamType = actualParam->getType();
266
267 assert(actualParamType && "actualParamType must be non-null!");
268
269 if (actualParamType != formalParamType) {
270 auto error = cls.emitError("actual parameter for ")
271 << formalParamName << " has invalid type";
272 error.attachNote() << "actual parameter: " << *actualParam;
273 error.attachNote() << "format parameter type: " << formalParamType;
274 return error;
275 }
276 }
277
278 // Instantiate the fields.
280
281 auto *context = cls.getContext();
282 {
283 LLVM_DEBUG(dbgs() << "ops:\n");
284#ifndef NDEBUG
285 DebugNesting nestOne(debugNesting);
286#endif
287 for (auto &op : cls.getOps())
288 for (auto result : op.getResults()) {
289 // Allocate the value, with unknown loc. It will be later set when
290 // evaluating the fields.
291 if (failed(getOrCreateValue(result, actualParams,
292 UnknownLoc::get(context))))
293 return failure();
294 // Add to the worklist.
295 worklist.push_back({result, actualParams});
296 }
297 }
298
299 LLVM_DEBUG(dbgs() << "fields:\n");
300 auto fieldNames = cls.getFieldNames();
301 auto operands = cls.getFieldsOp()->getOperands();
302 for (size_t i = 0; i < fieldNames.size(); ++i) {
303 auto name = fieldNames[i];
304 auto value = operands[i];
305 auto fieldLoc = cls.getFieldLocByIndex(i);
306 LLVM_DEBUG(dbgs() << "- name: " << name << "\n"
307 << indent(1) << "evaluate:\n");
308#ifndef NDEBUG
309 DebugNesting nestOne(debugNesting);
310#endif
311 FailureOr<evaluator::EvaluatorValuePtr> result =
312 evaluateValue(value, actualParams, fieldLoc);
313 if (failed(result))
314 return result;
315
316 LLVM_DEBUG(dbgs() << "value: " << result.value() << "\n");
317 fields[cast<StringAttr>(name)] = result.value();
318 }
319
320 // Defer property assertions until after the worklist is drained, so that
321 // all ReferenceValues are fully resolved before we try to inspect them.
322 LLVM_DEBUG(dbgs() << "queuing asserts:\n");
323 for (auto assertOp : cls.getOps<PropertyAssertOp>()) {
324 LLVM_DEBUG(dbgs(1) << "- " << assertOp << "\n");
325 pendingAsserts.push({assertOp, actualParams});
326 }
327
328 // If the there is an instance, we must update the object value.
329 LLVM_DEBUG(dbgs() << "object value:\n");
330 if (instanceKey.first) {
331 auto result =
332 getOrCreateValue(instanceKey.first, instanceKey.second, loc).value();
333 auto *object = llvm::cast<evaluator::ObjectValue>(result.get());
334 object->setFields(std::move(fields));
335 return result;
336 }
337
338 // If it's external call, just allocate new ObjectValue.
340 std::make_shared<evaluator::ObjectValue>(cls, fields, loc);
341 // Object is already fully evaluated when created with fields.
342 assert(result->isFullyEvaluated() &&
343 "object with fields should be fully evaluated");
344 return result;
345}
346
347/// Instantiate an Object with its class name and actual parameters.
348FailureOr<std::shared_ptr<evaluator::EvaluatorValue>>
350 StringAttr className, ArrayRef<evaluator::EvaluatorValuePtr> actualParams) {
351 LLVM_DEBUG(dbgs() << "instantiate:\n");
352#ifndef NDEBUG
353 DebugNesting nest(debugNesting);
354#endif
355 LLVM_DEBUG({
356 dbgs() << "class: " << className << "\n" << indent() << "params:\n";
357 for (auto &param : actualParams)
358 dbgs() << "- " << param << "\n";
359 });
360
361 auto classDef = symbolTable.lookup<ClassLike>(className);
362 if (!classDef)
363 return symbolTable.getOp()->emitError("unknown class name ") << className;
364
365 // If this is an external class, create an ObjectValue and mark it unknown
366 if (isa<ClassExternOp>(classDef)) {
368 std::make_shared<evaluator::ObjectValue>(
369 classDef, UnknownLoc::get(classDef.getContext()));
370 attachCounter(result);
371 result->markUnknown();
372 LLVM_DEBUG(dbgs(1) << "result: <unknown extern>\n");
373 return result;
374 }
375
376 // Otherwise, it's a regular class, proceed normally
377 ClassOp cls = cast<ClassOp>(classDef);
378
379 auto parameters =
380 std::make_unique<SmallVector<std::shared_ptr<evaluator::EvaluatorValue>>>(
381 actualParams);
382
383 actualParametersBuffers.push_back(std::move(parameters));
384
385 auto loc = cls.getLoc();
386 LLVM_DEBUG(dbgs() << "evaluate object:\n");
387 auto result = evaluateObjectInstance(
388 className, actualParametersBuffers.back().get(), loc);
389
390 if (failed(result))
391 return failure();
392
393 // `evaluateObjectInstance` has populated the worklist. Continue evaluations
394 // unless there is a partially evaluated value.
395 LLVM_DEBUG(dbgs() << "worklist:\n");
396
397 // Use two-worklist approach: process all items from current worklist, and if
398 // at least one becomes fully evaluated, swap and continue. If a full pass
399 // completes with no progress, we have a cycle.
400 while (!worklist.empty()) {
401 uint64_t countBeforePass = fullyEvaluatedCount;
402 LLVM_DEBUG(dbgs() << "- processing " << worklist.size()
403 << " items (fully evaluated count: "
404 << fullyEvaluatedCount << ")\n");
405
406 // Process all items in the current worklist.
407 while (!worklist.empty()) {
408 auto [value, args] = worklist.back();
409 worklist.pop_back();
410 auto result = evaluateValue(value, args, loc);
411
412 if (failed(result))
413 return failure();
414
415 // If not fully evaluated, add to next worklist for retry.
416 if (!result.value()->isFullyEvaluated())
417 nextWorklist.push_back({value, args});
418 }
419
420 // Check if we made progress.
421 uint64_t evaluatedThisPass = fullyEvaluatedCount - countBeforePass;
422 LLVM_DEBUG(dbgs() << "- evaluated " << evaluatedThisPass
423 << " nodes this pass\n");
424
425 // If nothing became fully evaluated in this pass, we have a cycle.
426 if (evaluatedThisPass == 0 && !nextWorklist.empty())
427 return cls.emitError()
428 << "cycle detected: " << nextWorklist.size()
429 << " values remain partially evaluated after full pass with no "
430 "progress (total fully evaluated: "
431 << fullyEvaluatedCount << ")";
432
433 // Swap worklists for next iteration.
434 worklist = std::move(nextWorklist);
435 nextWorklist.clear();
436 }
437
438 // Now that all values are fully resolved, evaluate the deferred property
439 // assertions.
440 LLVM_DEBUG(dbgs() << "asserts:\n");
441 bool assertFailed = false;
442 while (!pendingAsserts.empty()) {
443 auto [assertOp, assertParams] = pendingAsserts.front();
444 pendingAsserts.pop();
445 assertFailed |= failed(evaluatePropertyAssert(assertOp, assertParams));
446 }
447 if (assertFailed)
448 return failure();
449
450 auto &object = result.value();
451 // Finalize the value. This will eliminate intermidiate ReferenceValue used as
452 // a placeholder in the initialization.
453 LLVM_DEBUG(dbgs() << "finalizing\n");
454 if (failed(object->finalize()))
455 return cls.emitError() << "failed to finalize evaluation. Probably the "
456 "class contains a dataflow cycle";
457 LLVM_DEBUG(dbgs() << "result: " << object << "\n");
458 return object;
459}
460
461FailureOr<evaluator::EvaluatorValuePtr>
463 Location loc) {
464 auto evaluatorValue = getOrCreateValue(value, actualParams, loc).value();
465
466 LLVM_DEBUG(dbgs() << "- eval: " << value << "\n");
467
468 // Return if the value is already evaluated.
469 if (evaluatorValue->isFullyEvaluated()) {
470 LLVM_DEBUG(dbgs(1) << "fully evaluated: " << evaluatorValue << "\n");
471 return evaluatorValue;
472 }
473
474 return llvm::TypeSwitch<Value, FailureOr<evaluator::EvaluatorValuePtr>>(value)
475 .Case([&](BlockArgument arg) {
476 return evaluateParameter(arg, actualParams, loc);
477 })
478 .Case([&](OpResult result) {
479 return TypeSwitch<Operation *, FailureOr<evaluator::EvaluatorValuePtr>>(
480 result.getDefiningOp())
481 .Case([&](ConstantOp op) {
482 return evaluateConstant(op, actualParams, loc);
483 })
484 .Case([&](IntegerBinaryOp op) {
485 return evaluateIntegerBinary(op, actualParams, loc);
486 })
487 .Case([&](ObjectOp op) {
488 return evaluateObjectInstance(op, actualParams);
489 })
490 .Case([&](ObjectFieldOp op) {
491 return evaluateObjectField(op, actualParams, loc);
492 })
493 .Case([&](ListCreateOp op) {
494 return evaluateListCreate(op, actualParams, loc);
495 })
496 .Case([&](ListConcatOp op) {
497 return evaluateListConcat(op, actualParams, loc);
498 })
499 .Case([&](StringConcatOp op) {
500 return evaluateStringConcat(op, actualParams, loc);
501 })
502 .Case([&](BinaryEqualityOp op) {
503 return evaluateBinaryEquality(op, actualParams, loc);
504 })
505 .Case([&](AnyCastOp op) {
506 return evaluateValue(op.getInput(), actualParams, loc);
507 })
508 .Case([&](FrozenBasePathCreateOp op) {
509 return evaluateBasePathCreate(op, actualParams, loc);
510 })
511 .Case([&](FrozenPathCreateOp op) {
512 return evaluatePathCreate(op, actualParams, loc);
513 })
514 .Case([&](FrozenEmptyPathOp op) {
515 return evaluateEmptyPath(op, actualParams, loc);
516 })
517 .Case<UnknownValueOp>([&](UnknownValueOp op) {
518 return evaluateUnknownValue(op, loc);
519 })
520 .Default([&](Operation *op) {
521 auto error = op->emitError("unable to evaluate value");
522 error.attachNote() << "value: " << value;
523 return error;
524 });
525 });
526}
527
528/// Evaluator dispatch function for parameters.
529FailureOr<evaluator::EvaluatorValuePtr> circt::om::Evaluator::evaluateParameter(
530 BlockArgument formalParam, ActualParameters actualParams, Location loc) {
531 auto val = (*actualParams)[formalParam.getArgNumber()];
532 val->setLoc(loc);
533 return success(val);
534}
535
536/// Evaluator dispatch function for constants.
537FailureOr<circt::om::evaluator::EvaluatorValuePtr>
539 ActualParameters actualParams,
540 Location loc) {
541 // For list constants, create ListValue.
542 return success(om::evaluator::AttributeValue::get(op.getValue(), loc));
543}
544
545// Evaluator dispatch function for integer binary operations.
547 IntegerBinaryOp op, ActualParameters actualParams, Location loc) {
548 // Get the op's EvaluatorValue handle, in case it hasn't been evaluated yet.
549 auto handle = getOrCreateValue(op.getResult(), actualParams, loc);
550
551 // If it's fully evaluated, we can return it.
552 if (handle.value()->isFullyEvaluated())
553 return handle;
554
555 // Evaluate operands if necessary, and return the partially evaluated value if
556 // they aren't ready.
557 auto lhsResult = evaluateValue(op.getLhs(), actualParams, loc);
558 if (failed(lhsResult))
559 return lhsResult;
560 if (!lhsResult.value()->isFullyEvaluated())
561 return handle;
562
563 auto rhsResult = evaluateValue(op.getRhs(), actualParams, loc);
564 if (failed(rhsResult))
565 return rhsResult;
566 if (!rhsResult.value()->isFullyEvaluated())
567 return handle;
568
569 // Check if any operand is unknown and propagate the unknown flag.
570 if (lhsResult.value()->isUnknown() || rhsResult.value()->isUnknown()) {
571 handle.value()->markUnknown();
572 return handle;
573 }
574
575 // Extract the attribute from an EvaluatorValue (handles both om::IntegerAttr
576 // and mlir::IntegerAttr).
577 auto extractAttr = [](evaluator::EvaluatorValue *value) -> Attribute {
578 return llvm::TypeSwitch<evaluator::EvaluatorValue *, Attribute>(value)
579 .Case([](evaluator::AttributeValue *val) { return val->getAttr(); })
580 .Case([](evaluator::ReferenceValue *val) {
581 return cast<evaluator::AttributeValue>(val->getStrippedValue()->get())
582 ->getAttr();
583 });
584 };
585
586 mlir::Attribute lhsAttr = extractAttr(lhsResult.value().get());
587 mlir::Attribute rhsAttr = extractAttr(rhsResult.value().get());
588 assert(lhsAttr && rhsAttr &&
589 "expected attribute for IntegerBinaryOp operands");
590
591 std::array<Attribute, 2> operandAttrs = {lhsAttr, rhsAttr};
592 SmallVector<mlir::OpFoldResult, 1> results;
593 mlir::Attribute resultAttr;
594 // Even with fully constant operands, folders may decline to fold or may
595 // produce a non-attribute result.
596 if (failed(op->fold(operandAttrs, results)) || results.size() != 1 ||
597 !(resultAttr = results[0].dyn_cast<Attribute>()))
598 return op->emitError("failed to evaluate integer operation");
599
600 // Finalize the op result value.
601 auto *handleValue = cast<evaluator::AttributeValue>(handle.value().get());
602 auto resultStatus = handleValue->setAttr(resultAttr);
603 if (failed(resultStatus))
604 return resultStatus;
605
606 auto finalizeStatus = handleValue->finalize();
607 if (failed(finalizeStatus))
608 return finalizeStatus;
609
610 return handle;
611}
612
613/// Evaluator dispatch function for property assertions.
614LogicalResult
616 ActualParameters actualParams) {
617#ifndef NDEBUG
618 DebugNesting nest(debugNesting);
619#endif
620
621 auto loc = op.getLoc();
622
623 // Evaluate the condition, returning early if it isn't ready yet.
624 LLVM_DEBUG(dbgs() << "op: " << op << "\n"
625 << indent() << "evaluate condition: \n");
626 auto condResult = evaluateValue(op.getCondition(), actualParams, loc);
627 if (failed(condResult))
628 return failure();
629 if (!condResult.value()->isFullyEvaluated()) {
630 LLVM_DEBUG(dbgs() << "evaluate condition: <not fully evaluated>\n");
631 return success();
632 }
633
634 // If the condition is unknown, skip silently (best-effort).
635 if (condResult.value()->isUnknown())
636 return success();
637
638 LLVM_DEBUG(dbgs() << "condition: " << condResult.value() << "\n");
639
640 // Extract the attribute from the condition value, handling the case where
641 // the condition resolves through a ReferenceValue (e.g. an ObjectFieldOp or
642 // a parameter that participates in cycle resolution).
643 auto extractAttr = [](evaluator::EvaluatorValue *value) -> mlir::Attribute {
644 return llvm::TypeSwitch<evaluator::EvaluatorValue *, mlir::Attribute>(value)
645 .Case([](evaluator::AttributeValue *val) { return val->getAttr(); })
646 .Case([](evaluator::ReferenceValue *val) -> mlir::Attribute {
647 auto stripped = val->getStrippedValue();
648 if (failed(stripped))
649 return {};
650 if (auto *attr =
651 dyn_cast<evaluator::AttributeValue>(stripped.value().get()))
652 return attr->getAttr();
653 return {};
654 })
655 .Default([](auto *) -> mlir::Attribute { return {}; });
656 };
657
658 auto condAttr = extractAttr(condResult.value().get());
659 if (!condAttr)
660 return success();
661
662 bool isFalse = false;
663 if (auto boolAttr = dyn_cast<BoolAttr>(condAttr))
664 isFalse = !boolAttr.getValue();
665 else if (auto intAttr = dyn_cast<mlir::IntegerAttr>(condAttr))
666 isFalse = intAttr.getValue().isZero();
667 else
668 return op.emitError("expected BoolAttr or mlir::IntegerAttr");
669
670 if (isFalse)
671 return op.emitError("OM property assertion failed: ") << op.getMessage();
672
673 return success();
674}
675
676/// Evaluator dispatch function for Object instances.
677FailureOr<circt::om::Evaluator::ActualParameters>
679 ValueRange range, ActualParameters actualParams, Location loc) {
680 // Create an unique storage to store parameters.
681 auto parameters = std::make_unique<
682 SmallVector<std::shared_ptr<evaluator::EvaluatorValue>>>();
683
684 // Collect operands' evaluator values in the current instantiation context.
685 for (auto input : range) {
686 auto inputResult = getOrCreateValue(input, actualParams, loc);
687 if (failed(inputResult))
688 return failure();
689 parameters->push_back(inputResult.value());
690 }
691
692 actualParametersBuffers.push_back(std::move(parameters));
693 return actualParametersBuffers.back().get();
694}
695
696/// Evaluator dispatch function for Object instances.
697FailureOr<evaluator::EvaluatorValuePtr>
699 ActualParameters actualParams) {
700 auto loc = op.getLoc();
701 if (isFullyEvaluated({op, actualParams}))
702 return getOrCreateValue(op, actualParams, loc);
703
704 auto params =
705 createParametersFromOperands(op.getOperands(), actualParams, loc);
706 if (failed(params))
707 return failure();
708 return evaluateObjectInstance(op.getClassNameAttr(), params.value(), loc,
709 {op, actualParams});
710}
711
712/// Evaluator dispatch function for Object fields.
713FailureOr<evaluator::EvaluatorValuePtr>
715 ActualParameters actualParams,
716 Location loc) {
717 // Evaluate the Object itself, in case it hasn't been evaluated yet.
718 FailureOr<evaluator::EvaluatorValuePtr> currentObjectResult =
719 evaluateValue(op.getObject(), actualParams, loc);
720 if (failed(currentObjectResult))
721 return currentObjectResult;
722
723 auto result = currentObjectResult.value();
724
725 auto objectFieldValue = getOrCreateValue(op, actualParams, loc).value();
726
727 if (result->isUnknown()) {
728 // If objectFieldValue is a ReferenceValue, set its value to a unknown value
729 // of the proper type
730 if (auto *ref =
731 llvm::dyn_cast<evaluator::ReferenceValue>(objectFieldValue.get())) {
732 auto unknownField = createUnknownValue(op.getResult().getType(), loc);
733 if (failed(unknownField))
734 return unknownField;
735 ref->setValue(unknownField.value());
736 }
737 // markUnknown() also marks the value as fully evaluated
738 objectFieldValue->markUnknown();
739 return objectFieldValue;
740 }
741
742 // If the result is a ReferenceValue, dereference it to get the actual object.
743 if (auto *ref = llvm::dyn_cast<evaluator::ReferenceValue>(result.get())) {
744 auto stripped = ref->getStrippedValue();
745 if (failed(stripped))
746 return failure();
747 result = stripped.value();
748 }
749
750 auto *currentObject = llvm::cast<evaluator::ObjectValue>(result.get());
751
752 auto field = op.getFieldAttr();
753
754 // `currentObject` might not be fully evaluated.
755 if (!currentObject->getFields().contains(field))
756 return objectFieldValue;
757
758 auto currentField = currentObject->getField(field);
759 auto finalField = currentField.value();
760
761 if (!finalField->isFullyEvaluated())
762 return objectFieldValue;
763
764 // Update the reference.
765 llvm::cast<evaluator::ReferenceValue>(objectFieldValue.get())
766 ->setValue(finalField);
767
768 // Return the field being accessed.
769 return objectFieldValue;
770}
771
772/// Evaluator dispatch function for List creation.
773FailureOr<evaluator::EvaluatorValuePtr>
775 ActualParameters actualParams,
776 Location loc) {
777 // Evaluate the Object itself, in case it hasn't been evaluated yet.
778 SmallVector<evaluator::EvaluatorValuePtr> values;
779 auto list = getOrCreateValue(op, actualParams, loc);
780 bool hasUnknown = false;
781 for (auto operand : op.getOperands()) {
782 auto result = evaluateValue(operand, actualParams, loc);
783 if (failed(result))
784 return result;
785 if (!result.value()->isFullyEvaluated())
786 return list;
787 // Check if any operand is unknown.
788 if (result.value()->isUnknown())
789 hasUnknown = true;
790 values.push_back(result.value());
791 }
792
793 // Set the list elements (this also marks the list as fully evaluated).
794 llvm::cast<evaluator::ListValue>(list.value().get())
795 ->setElements(std::move(values));
796
797 // If any operand is unknown, mark the list as unknown.
798 // markUnknown() checks if already fully evaluated before calling
799 // markFullyEvaluated().
800 if (hasUnknown)
801 list.value()->markUnknown();
802
803 return list;
804}
805
806/// Evaluator dispatch function for List concatenation.
807FailureOr<evaluator::EvaluatorValuePtr>
809 ActualParameters actualParams,
810 Location loc) {
811 // Evaluate the List concat op itself, in case it hasn't been evaluated yet.
812 SmallVector<evaluator::EvaluatorValuePtr> values;
813 auto list = getOrCreateValue(op, actualParams, loc);
814
815 // Extract the ListValue, either directly or through an object reference.
816 auto extractList = [](evaluator::EvaluatorValue *value) {
817 return std::move(
818 llvm::TypeSwitch<evaluator::EvaluatorValue *, evaluator::ListValue *>(
819 value)
820 .Case([](evaluator::ListValue *val) { return val; })
821 .Case([](evaluator::ReferenceValue *val) {
822 return cast<evaluator::ListValue>(val->getStrippedValue()->get());
823 }));
824 };
825
826 bool hasUnknown = false;
827 for (auto operand : op.getOperands()) {
828 auto result = evaluateValue(operand, actualParams, loc);
829 if (failed(result))
830 return result;
831 if (!result.value()->isFullyEvaluated())
832 return list;
833 // Check if any operand is unknown.
834 if (result.value()->isUnknown())
835 hasUnknown = true;
836
837 // Extract this sublist and ensure it's done evaluating.
838 evaluator::ListValue *subList = extractList(result.value().get());
839 if (!subList->isFullyEvaluated())
840 return list;
841
842 // Append each EvaluatorValue from the sublist.
843 for (const auto &subValue : subList->getElements())
844 values.push_back(subValue);
845 }
846
847 // Return the concatenated list.
848 llvm::cast<evaluator::ListValue>(list.value().get())
849 ->setElements(std::move(values));
850
851 // If any operand is unknown, mark the result as unknown.
852 // markUnknown() checks if already fully evaluated before calling
853 // markFullyEvaluated().
854 if (hasUnknown)
855 list.value()->markUnknown();
856
857 return list;
858}
859
860/// Evaluator dispatch function for String concatenation.
861FailureOr<evaluator::EvaluatorValuePtr>
863 ActualParameters actualParams,
864 Location loc) {
865 // Get the op's EvaluatorValue handle, in case it hasn't been evaluated yet.
866 auto handle = getOrCreateValue(op.getResult(), actualParams, loc);
867 if (failed(handle))
868 return handle;
869
870 // If it's fully evaluated, we can return it.
871 if (handle.value()->isFullyEvaluated())
872 return handle;
873
874 // Extract the string attributes, handling both AttributeValue and
875 // ReferenceValue cases.
876 auto extractAttr = [](evaluator::EvaluatorValue *value) -> StringAttr {
877 return llvm::TypeSwitch<evaluator::EvaluatorValue *, StringAttr>(value)
878 .Case([](evaluator::AttributeValue *val) {
879 return val->getAs<StringAttr>();
880 })
881 .Case([](evaluator::ReferenceValue *val) {
882 return cast<evaluator::AttributeValue>(val->getStrippedValue()->get())
883 ->getAs<StringAttr>();
884 });
885 };
886
887 // Evaluate all operands and concatenate them.
888 std::string result;
889 for (auto operand : op.getOperands()) {
890 auto operandResult = evaluateValue(operand, actualParams, loc);
891 if (failed(operandResult))
892 return operandResult;
893 if (!operandResult.value()->isFullyEvaluated())
894 return handle;
895
896 StringAttr str = extractAttr(operandResult.value().get());
897 assert(str && "expected StringAttr for StringConcatOp operand");
898 result += str.getValue().str();
899 }
900
901 // Create the concatenated string attribute.
902 auto resultStr = StringAttr::get(result, op.getResult().getType());
903
904 // Finalize the op result value.
905 auto *handleValue = cast<evaluator::AttributeValue>(handle.value().get());
906 auto resultStatus = handleValue->setAttr(resultStr);
907 if (failed(resultStatus))
908 return resultStatus;
909
910 auto finalizeStatus = handleValue->finalize();
911 if (failed(finalizeStatus))
912 return finalizeStatus;
913
914 return handle;
915}
916
917// Evaluator dispatch function for binary property equality operations.
918FailureOr<evaluator::EvaluatorValuePtr>
920 ActualParameters actualParams,
921 Location loc) {
922 // Get the op's EvaluatorValue handle, in case it hasn't been evaluated yet.
923 auto handle = getOrCreateValue(op.getResult(), actualParams, loc);
924 if (failed(handle))
925 return handle;
926
927 // If it's fully evaluated, we can return it.
928 if (handle.value()->isFullyEvaluated())
929 return handle;
930
931 // Evaluate both operands, returning the partially evaluated handle if either
932 // isn't ready yet.
933 auto lhsResult = evaluateValue(op.getLhs(), actualParams, loc);
934 if (failed(lhsResult))
935 return lhsResult;
936 if (!lhsResult.value()->isFullyEvaluated())
937 return handle;
938
939 auto rhsResult = evaluateValue(op.getRhs(), actualParams, loc);
940 if (failed(rhsResult))
941 return rhsResult;
942 if (!rhsResult.value()->isFullyEvaluated())
943 return handle;
944
945 // Check if any operand is unknown and propagate the unknown flag.
946 if (lhsResult.value()->isUnknown() || rhsResult.value()->isUnknown()) {
947 handle.value()->markUnknown();
948 return handle;
949 }
950
951 // Extract the underlying attribute, handling both AttributeValue and
952 // ReferenceValue cases.
953 auto extractAttr = [](evaluator::EvaluatorValue *value) -> mlir::Attribute {
954 return llvm::TypeSwitch<evaluator::EvaluatorValue *, mlir::Attribute>(value)
955 .Case([](evaluator::AttributeValue *val) { return val->getAttr(); })
956 .Case([](evaluator::ReferenceValue *val) -> mlir::Attribute {
957 return cast<evaluator::AttributeValue>(val->getStrippedValue()->get())
958 ->getAttr();
959 });
960 };
961
962 mlir::Attribute lhs = extractAttr(lhsResult.value().get());
963 mlir::Attribute rhs = extractAttr(rhsResult.value().get());
964 assert(lhs && rhs && "expected attribute for BinaryEqualityOp operands");
965
966 // Perform the binary equality operation.
967 FailureOr<mlir::Attribute> result = op.evaluateBinaryEquality(lhs, rhs);
968 if (failed(result))
969 return op->emitError("failed to evaluate binary equality operation");
970
971 // Finalize the op result value.
972 auto *handleValue = cast<evaluator::AttributeValue>(handle.value().get());
973 auto resultStatus = handleValue->setAttr(*result);
974 if (failed(resultStatus))
975 return resultStatus;
976
977 auto finalizeStatus = handleValue->finalize();
978 if (failed(finalizeStatus))
979 return finalizeStatus;
980
981 return handle;
982}
983
984FailureOr<evaluator::EvaluatorValuePtr>
986 ActualParameters actualParams,
987 Location loc) {
988 // Evaluate the Object itself, in case it hasn't been evaluated yet.
989 auto valueResult = getOrCreateValue(op, actualParams, loc).value();
990 auto *path = llvm::cast<evaluator::BasePathValue>(valueResult.get());
991 auto result = evaluateValue(op.getBasePath(), actualParams, loc);
992 if (failed(result))
993 return result;
994 auto &value = result.value();
995 if (!value->isFullyEvaluated())
996 return valueResult;
997
998 // If the base path is unknown, mark the result as unknown.
999 if (result.value()->isUnknown()) {
1000 valueResult->markUnknown();
1001 return valueResult;
1002 }
1003
1004 path->setBasepath(*llvm::cast<evaluator::BasePathValue>(value.get()));
1005 return valueResult;
1006}
1007
1008FailureOr<evaluator::EvaluatorValuePtr>
1010 ActualParameters actualParams,
1011 Location loc) {
1012 // Evaluate the Object itself, in case it hasn't been evaluated yet.
1013 auto valueResult = getOrCreateValue(op, actualParams, loc).value();
1014 auto *path = llvm::cast<evaluator::PathValue>(valueResult.get());
1015 auto result = evaluateValue(op.getBasePath(), actualParams, loc);
1016 if (failed(result))
1017 return result;
1018 auto &value = result.value();
1019 if (!value->isFullyEvaluated())
1020 return valueResult;
1021
1022 // If the base path is unknown, mark the result as unknown.
1023 if (result.value()->isUnknown()) {
1024 valueResult->markUnknown();
1025 return valueResult;
1026 }
1027
1028 path->setBasepath(*llvm::cast<evaluator::BasePathValue>(value.get()));
1029 return valueResult;
1030}
1031
1032FailureOr<evaluator::EvaluatorValuePtr> circt::om::Evaluator::evaluateEmptyPath(
1033 FrozenEmptyPathOp op, ActualParameters actualParams, Location loc) {
1034 auto valueResult = getOrCreateValue(op, actualParams, loc).value();
1035 return valueResult;
1036}
1037
1038/// Create an unknown value of the specified type
1039FailureOr<evaluator::EvaluatorValuePtr>
1041 using namespace circt::om::evaluator;
1042
1043 // Create an unknown value of the appropriate type by switching on the type
1044 auto result =
1045 TypeSwitch<Type, FailureOr<EvaluatorValuePtr>>(type)
1046 .Case([&](ListType type) -> FailureOr<EvaluatorValuePtr> {
1047 // Create an empty list
1048 return success(std::make_shared<ListValue>(type, loc));
1049 })
1050 .Case([&](ClassType type) -> FailureOr<EvaluatorValuePtr> {
1051 // Look up the class definition
1052 auto classDef =
1053 symbolTable.lookup<ClassLike>(type.getClassName().getValue());
1054 if (!classDef)
1055 return symbolTable.getOp()->emitError("unknown class name ")
1056 << type.getClassName();
1057
1058 // Create an ObjectValue for both ClassOp and ClassExternOp
1059 return success(std::make_shared<ObjectValue>(classDef, loc));
1060 })
1061 .Case([&](FrozenBasePathType type) -> FailureOr<EvaluatorValuePtr> {
1062 // Create an empty basepath
1063 return success(std::make_shared<BasePathValue>(type.getContext()));
1064 })
1065 .Case([&](FrozenPathType type) -> FailureOr<EvaluatorValuePtr> {
1066 // Create an empty path
1067 return success(
1068 std::make_shared<PathValue>(PathValue::getEmptyPath(loc)));
1069 })
1070 .Default([&](Type type) -> FailureOr<EvaluatorValuePtr> {
1071 // For all other types (primitives like integer, string,
1072 // etc.), create an AttributeValue
1073 return success(AttributeValue::get(type, LocationAttr(loc)));
1074 });
1075
1076 // Mark the result as unknown if successful.
1077 if (succeeded(result))
1078 result->get()->markUnknown();
1079
1080 return result;
1081}
1082
1083/// Evaluate an unknown value
1084FailureOr<evaluator::EvaluatorValuePtr>
1085circt::om::Evaluator::evaluateUnknownValue(UnknownValueOp op, Location loc) {
1086 return createUnknownValue(op.getType(), loc);
1087}
1088
1089//===----------------------------------------------------------------------===//
1090// ObjectValue
1091//===----------------------------------------------------------------------===//
1092
1093/// Get a field of the Object by name.
1094FailureOr<EvaluatorValuePtr>
1096 auto field = fields.find(name);
1097 if (field == fields.end())
1098 return cls.emitError("field ") << name << " does not exist";
1099 return success(fields[name]);
1100}
1101
1102/// Get an ArrayAttr with the names of the fields in the Object. Sort the fields
1103/// so there is always a stable order.
1105 SmallVector<Attribute> fieldNames;
1106 for (auto &f : fields)
1107 fieldNames.push_back(f.first);
1108
1109 llvm::sort(fieldNames, [](Attribute a, Attribute b) {
1110 return cast<StringAttr>(a).getValue() < cast<StringAttr>(b).getValue();
1111 });
1112
1113 return ArrayAttr::get(cls.getContext(), fieldNames);
1114}
1115
1117 for (auto &&[e, value] : fields)
1118 if (failed(finalizeEvaluatorValue(value)))
1119 return failure();
1120
1121 return success();
1122}
1123
1124//===----------------------------------------------------------------------===//
1125// ReferenceValue
1126//===----------------------------------------------------------------------===//
1127
1129 auto result = getStrippedValue();
1130 if (failed(result))
1131 return result;
1132 value = std::move(result.value());
1133 // the stripped value also needs to be finalized
1134 if (failed(finalizeEvaluatorValue(value)))
1135 return failure();
1136
1137 return success();
1138}
1139
1140//===----------------------------------------------------------------------===//
1141// ListValue
1142//===----------------------------------------------------------------------===//
1143
1145 for (auto &value : elements) {
1146 if (failed(finalizeEvaluatorValue(value)))
1147 return failure();
1148 }
1149 return success();
1150}
1151
1152//===----------------------------------------------------------------------===//
1153// BasePathValue
1154//===----------------------------------------------------------------------===//
1155
1157 : EvaluatorValue(context, Kind::BasePath, UnknownLoc::get(context)),
1158 path(PathAttr::get(context, {})) {
1159 markFullyEvaluated();
1160}
1161
1162evaluator::BasePathValue::BasePathValue(PathAttr path, Location loc)
1163 : EvaluatorValue(path.getContext(), Kind::BasePath, loc), path(path) {}
1164
1166 assert(isFullyEvaluated());
1167 return path;
1168}
1169
1171 assert(!isFullyEvaluated());
1172 auto newPath = llvm::to_vector(basepath.path.getPath());
1173 auto oldPath = path.getPath();
1174 newPath.append(oldPath.begin(), oldPath.end());
1175 path = PathAttr::get(path.getContext(), newPath);
1176 markFullyEvaluated();
1177}
1178
1179//===----------------------------------------------------------------------===//
1180// PathValue
1181//===----------------------------------------------------------------------===//
1182
1183evaluator::PathValue::PathValue(TargetKindAttr targetKind, PathAttr path,
1184 StringAttr module, StringAttr ref,
1185 StringAttr field, Location loc)
1186 : EvaluatorValue(loc.getContext(), Kind::Path, loc), targetKind(targetKind),
1187 path(path), module(module), ref(ref), field(field) {}
1188
1190 PathValue path(nullptr, nullptr, nullptr, nullptr, nullptr, loc);
1191 path.markFullyEvaluated();
1192 return path;
1193}
1194
1196 // If the module is null, then this is a path to a deleted object.
1197 if (!targetKind)
1198 return StringAttr::get(getContext(), "OMDeleted:");
1199 SmallString<64> result;
1200 switch (targetKind.getValue()) {
1201 case TargetKind::DontTouch:
1202 result += "OMDontTouchedReferenceTarget";
1203 break;
1204 case TargetKind::Instance:
1205 result += "OMInstanceTarget";
1206 break;
1207 case TargetKind::MemberInstance:
1208 result += "OMMemberInstanceTarget";
1209 break;
1210 case TargetKind::MemberReference:
1211 result += "OMMemberReferenceTarget";
1212 break;
1213 case TargetKind::Reference:
1214 result += "OMReferenceTarget";
1215 break;
1216 }
1217 result += ":~";
1218 if (!path.getPath().empty())
1219 result += path.getPath().front().module;
1220 else
1221 result += module.getValue();
1222 result += '|';
1223 for (const auto &elt : path) {
1224 result += elt.module.getValue();
1225 result += '/';
1226 result += elt.instance.getValue();
1227 result += ':';
1228 }
1229 if (!module.getValue().empty())
1230 result += module.getValue();
1231 if (!ref.getValue().empty()) {
1232 result += '>';
1233 result += ref.getValue();
1234 }
1235 if (!field.getValue().empty())
1236 result += field.getValue();
1237 return StringAttr::get(field.getContext(), result);
1238}
1239
1241 assert(!isFullyEvaluated());
1242 auto newPath = llvm::to_vector(basepath.getPath().getPath());
1243 auto oldPath = path.getPath();
1244 newPath.append(oldPath.begin(), oldPath.end());
1245 path = PathAttr::get(path.getContext(), newPath);
1246 markFullyEvaluated();
1247}
1248
1249//===----------------------------------------------------------------------===//
1250// AttributeValue
1251//===----------------------------------------------------------------------===//
1252
1254 if (cast<TypedAttr>(attr).getType() != this->type)
1255 return mlir::emitError(getLoc(), "cannot set AttributeValue of type ")
1256 << this->type << " to Attribute " << attr;
1257 if (isFullyEvaluated())
1258 return mlir::emitError(
1259 getLoc(),
1260 "cannot set AttributeValue that has already been fully evaluated");
1261 this->attr = attr;
1262 markFullyEvaluated();
1263 return success();
1264}
1265
1267 if (!isFullyEvaluated())
1268 return mlir::emitError(
1269 getLoc(), "cannot finalize AttributeValue that is not fully evaluated");
1270 return success();
1271}
1272
1273std::shared_ptr<evaluator::EvaluatorValue>
1274circt::om::evaluator::AttributeValue::get(Attribute attr, LocationAttr loc) {
1275 auto type = cast<TypedAttr>(attr).getType();
1276 auto *context = type.getContext();
1277 if (!loc)
1278 loc = UnknownLoc::get(context);
1279
1280 // Special handling for ListType to create proper ListValue objects instead of
1281 // AttributeValue objects.
1282 if (auto listType = dyn_cast<circt::om::ListType>(type)) {
1283 SmallVector<EvaluatorValuePtr> elements;
1284 auto listAttr = cast<om::ListAttr>(attr);
1286 listAttr.getContext(), listAttr.getElements().getValue());
1287 elements.append(values.begin(), values.end());
1288 auto list = std::make_shared<evaluator::ListValue>(listType, elements, loc);
1289 return list;
1290 }
1291
1292 return std::shared_ptr<AttributeValue>(
1293 new AttributeValue(PrivateTag{}, attr, loc));
1294}
1295
1296std::shared_ptr<evaluator::EvaluatorValue>
1297circt::om::evaluator::AttributeValue::get(Type type, LocationAttr loc) {
1298 auto *context = type.getContext();
1299 if (!loc)
1300 loc = UnknownLoc::get(context);
1301
1302 // Special handling for ListType to create proper ListValue objects instead of
1303 // AttributeValue objects.
1304 if (auto listType = dyn_cast<circt::om::ListType>(type))
1305 return std::make_shared<evaluator::ListValue>(listType, loc);
1306 // Create the AttributeValue with the private tag
1307 return std::shared_ptr<AttributeValue>(
1308 new AttributeValue(PrivateTag{}, type, loc));
1309}
assert(baseType &&"element must be base type")
static std::unique_ptr< Context > context
static Location getLoc(DefSlot slot)
Definition Mem2Reg.cpp:218
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 > 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< EvaluatorValuePtr > evaluateIntegerBinary(IntegerBinaryOp op, ActualParameters actualParams, Location loc)
FailureOr< evaluator::EvaluatorValuePtr > evaluateUnknownValue(UnknownValueOp op, Location loc)
Evaluate an unknown value.
Evaluator(ModuleOp mod)
Construct an Evaluator with an IR module.
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:401
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:403
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:161
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:222
const auto & getElements() const
Definition Evaluator.h:243
A composite Object, which has a type and fields.
Definition Evaluator.h:259
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:121
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:523