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