21#include "mlir/Dialect/Arith/IR/Arith.h"
22#include "mlir/Dialect/Index/IR/IndexDialect.h"
23#include "mlir/Dialect/Index/IR/IndexOps.h"
24#include "mlir/Dialect/SCF/IR/SCF.h"
25#include "mlir/IR/IRMapping.h"
26#include "mlir/IR/PatternMatch.h"
27#include "llvm/ADT/DenseMapInfoVariant.h"
28#include "llvm/Support/Debug.h"
33#define GEN_PASS_DEF_ELABORATIONPASS
34#include "circt/Dialect/RTG/Transforms/RTGPasses.h.inc"
43#define DEBUG_TYPE "rtg-elaboration"
49 RngScope(
const RngScope &) =
delete;
50 RngScope &operator=(
const RngScope &) =
delete;
52 RngScope(RngScope &&) =
default;
53 RngScope &operator=(RngScope &&) =
default;
55 explicit RngScope(uint32_t seed) : rng(seed) {}
67 uint32_t getUniformlyInRange(uint32_t a, uint32_t b) {
68 const uint32_t diff = b - a + 1;
76 std::numeric_limits<uint32_t>::max() >> (32 - llvm::Log2_32_Ceil(diff));
85 RngScope getNested() {
return RngScope(rng()); }
99struct SequenceStorage;
100struct RandomizedSequenceStorage;
101struct InterleavedSequenceStorage;
103struct VirtualRegisterStorage;
104struct UniqueLabelStorage;
107struct MemoryBlockStorage;
108struct SymbolicComputationWithIdentityStorage;
109struct SymbolicComputationWithIdentityValue;
110struct SymbolicComputationStorage;
113using ElaboratorValue =
114 std::variant<TypedAttr, BagStorage *, bool, size_t, SequenceStorage *,
115 RandomizedSequenceStorage *, InterleavedSequenceStorage *,
116 SetStorage *, VirtualRegisterStorage *, UniqueLabelStorage *,
117 ArrayStorage *, TupleStorage *, MemoryStorage *,
118 MemoryBlockStorage *, SymbolicComputationWithIdentityStorage *,
119 SymbolicComputationWithIdentityValue *,
120 SymbolicComputationStorage *>;
123llvm::hash_code
hash_value(
const ElaboratorValue &val) {
125 [&val](
const auto &alternative) {
128 return llvm::hash_combine(val.index(), alternative);
143 static bool isEqual(
const bool &lhs,
const bool &rhs) {
return lhs == rhs; }
158template <
typename StorageTy>
159struct HashedStorage {
160 HashedStorage(
unsigned hashcode = 0, StorageTy *storage =
nullptr)
161 : hashcode(hashcode), storage(storage) {}
171template <
typename StorageTy>
172struct StorageKeyInfo {
173 static inline HashedStorage<StorageTy> getEmptyKey() {
174 return HashedStorage<StorageTy>(0,
175 DenseMapInfo<StorageTy *>::getEmptyKey());
177 static inline HashedStorage<StorageTy> getTombstoneKey() {
178 return HashedStorage<StorageTy>(
179 0, DenseMapInfo<StorageTy *>::getTombstoneKey());
182 static inline unsigned getHashValue(
const HashedStorage<StorageTy> &key) {
185 static inline unsigned getHashValue(
const StorageTy &key) {
189 static inline bool isEqual(
const HashedStorage<StorageTy> &lhs,
190 const HashedStorage<StorageTy> &rhs) {
191 return lhs.storage == rhs.storage;
193 static inline bool isEqual(
const StorageTy &lhs,
194 const HashedStorage<StorageTy> &rhs) {
195 if (isEqual(rhs, getEmptyKey()) || isEqual(rhs, getTombstoneKey()))
198 return lhs.isEqual(rhs.storage);
208struct CachableStorage {
213struct SetStorage : CachableStorage {
214 static unsigned computeHash(
const SetVector<ElaboratorValue> &set,
216 llvm::hash_code setHash = 0;
217 for (
auto el : set) {
222 setHash = setHash ^ llvm::hash_combine(el);
224 return llvm::hash_combine(type, setHash);
227 SetStorage(SetVector<ElaboratorValue> &&set, Type type)
228 : hashcode(computeHash(set, type)), set(std::move(set)), type(type) {}
230 bool isEqual(
const SetStorage *other)
const {
235 bool allContained =
true;
237 allContained &= other->set.contains(el);
239 return hashcode == other->hashcode && set.size() == other->set.size() &&
240 allContained && type == other->type;
244 const unsigned hashcode;
247 const SetVector<ElaboratorValue> set;
256 BagStorage(MapVector<ElaboratorValue, uint64_t> &&bag, Type type)
258 type,
llvm::hash_combine_range(bag.begin(), bag.
end()))),
259 bag(std::move(bag)), type(type) {}
261 bool isEqual(
const BagStorage *other)
const {
262 return hashcode == other->hashcode && llvm::equal(bag, other->bag) &&
267 const unsigned hashcode;
271 const MapVector<ElaboratorValue, uint64_t> bag;
279struct SequenceStorage {
280 SequenceStorage(StringAttr familyName, SmallVector<ElaboratorValue> &&args)
282 familyName,
llvm::hash_combine_range(args.begin(), args.
end()))),
283 familyName(familyName), args(std::move(args)) {}
285 bool isEqual(
const SequenceStorage *other)
const {
286 return hashcode == other->hashcode && familyName == other->familyName &&
291 const unsigned hashcode;
294 const StringAttr familyName;
297 const SmallVector<ElaboratorValue> args;
301struct InterleavedSequenceStorage {
302 InterleavedSequenceStorage(SmallVector<ElaboratorValue> &&sequences,
304 : sequences(std::move(sequences)), batchSize(batchSize),
306 llvm::hash_combine_range(sequences.begin(), sequences.
end()),
309 explicit InterleavedSequenceStorage(RandomizedSequenceStorage *sequence)
310 : sequences(SmallVector<ElaboratorValue>(1, sequence)), batchSize(1),
312 llvm::hash_combine_range(sequences.begin(), sequences.
end()),
315 bool isEqual(
const InterleavedSequenceStorage *other)
const {
316 return hashcode == other->hashcode && sequences == other->sequences &&
317 batchSize == other->batchSize;
320 const SmallVector<ElaboratorValue> sequences;
322 const uint32_t batchSize;
325 const unsigned hashcode;
330 ArrayStorage(Type type, SmallVector<ElaboratorValue> &&array)
332 type,
llvm::hash_combine_range(array.begin(), array.
end()))),
333 type(type), array(array) {}
335 bool isEqual(
const ArrayStorage *other)
const {
336 return hashcode == other->hashcode && type == other->type &&
337 array == other->array;
341 const unsigned hashcode;
348 const SmallVector<ElaboratorValue> array;
352struct TupleStorage : CachableStorage {
353 TupleStorage(SmallVector<ElaboratorValue> &&values)
354 : hashcode(
llvm::hash_combine_range(values.begin(), values.
end())),
355 values(std::move(values)) {}
357 bool isEqual(
const TupleStorage *other)
const {
358 return hashcode == other->hashcode && values == other->values;
362 const unsigned hashcode;
364 const SmallVector<ElaboratorValue> values;
367struct SymbolicComputationStorage {
368 SymbolicComputationStorage(
const DenseMap<Value, ElaboratorValue> &state,
370 : name(op->
getName()), resultTypes(op->getResultTypes()),
371 operands(
llvm::map_range(op->getOperands(),
372 [&](Value v) {
return state.lookup(v); })),
373 attributes(op->getAttrDictionary()),
374 properties(op->getPropertiesAsAttribute()),
375 hashcode(llvm::hash_combine(name, llvm::hash_combine_range(resultTypes),
376 llvm::hash_combine_range(operands),
377 attributes, op->hashProperties())) {}
379 bool isEqual(
const SymbolicComputationStorage *other)
const {
380 return hashcode == other->hashcode && name == other->name &&
381 resultTypes == other->resultTypes && operands == other->operands &&
382 attributes == other->attributes && properties == other->properties;
385 const OperationName name;
386 const SmallVector<Type> resultTypes;
387 const SmallVector<ElaboratorValue> operands;
388 const DictionaryAttr attributes;
389 const Attribute properties;
390 const unsigned hashcode;
401struct IdentityValue {
403 IdentityValue(Type type, Location loc) : type(type), loc(loc) {}
416 bool alreadyMaterialized =
false;
425struct VirtualRegisterStorage : IdentityValue {
426 VirtualRegisterStorage(VirtualRegisterConfigAttr allowedRegs, Type type,
428 : IdentityValue(type, loc), allowedRegs(allowedRegs) {}
435 const VirtualRegisterConfigAttr allowedRegs;
438struct UniqueLabelStorage : IdentityValue {
439 UniqueLabelStorage(
const ElaboratorValue &name, Location loc)
440 : IdentityValue(LabelType::
get(loc->getContext()), loc), name(name) {}
446 const ElaboratorValue name;
450struct MemoryBlockStorage : IdentityValue {
451 MemoryBlockStorage(
const APInt &baseAddress,
const APInt &endAddress,
452 Type type, Location loc)
453 : IdentityValue(type, loc), baseAddress(baseAddress),
454 endAddress(endAddress) {}
459 const APInt baseAddress;
462 const APInt endAddress;
466struct MemoryStorage : IdentityValue {
467 MemoryStorage(MemoryBlockStorage *memoryBlock,
size_t size,
size_t alignment,
469 : IdentityValue(MemoryType::
get(memoryBlock->type.getContext(),
472 memoryBlock(memoryBlock), size(size), alignment(alignment) {}
474 MemoryBlockStorage *memoryBlock;
476 const size_t alignment;
480struct RandomizedSequenceStorage : IdentityValue {
481 RandomizedSequenceStorage(ContextResourceAttrInterface context,
482 SequenceStorage *sequence, Location loc)
484 RandomizedSequenceType::
get(sequence->familyName.getContext()),
486 context(context), sequence(sequence) {}
489 const ContextResourceAttrInterface context;
491 const SequenceStorage *sequence;
495struct SymbolicComputationWithIdentityStorage : IdentityValue {
496 SymbolicComputationWithIdentityStorage(
497 const DenseMap<Value, ElaboratorValue> &state, Operation *op)
498 : IdentityValue(op->getResult(0).getType(), op->
getLoc()),
499 name(op->
getName()), resultTypes(op->getResultTypes()),
500 operands(
llvm::map_range(op->getOperands(),
501 [&](Value v) {
return state.lookup(v); })),
502 attributes(op->getAttrDictionary()),
503 properties(op->getPropertiesAsAttribute()) {}
505 const OperationName name;
506 const SmallVector<Type> resultTypes;
507 const SmallVector<ElaboratorValue> operands;
508 const DictionaryAttr attributes;
509 const Attribute properties;
512struct SymbolicComputationWithIdentityValue : IdentityValue {
513 SymbolicComputationWithIdentityValue(
514 Type type,
const SymbolicComputationWithIdentityStorage *storage,
516 : IdentityValue(type, storage->loc), storage(storage), idx(idx) {
519 "Use SymbolicComputationWithIdentityStorage for result with index 0.");
522 const SymbolicComputationWithIdentityStorage *storage;
536 template <
typename StorageTy,
typename... Args>
537 StorageTy *internalize(Args &&...args) {
538 static_assert(!std::is_base_of_v<IdentityValue, StorageTy> &&
539 "values with identity must not be internalized");
541 StorageTy storage(std::forward<Args>(args)...);
543 auto existing = getInternSet<StorageTy>().insert_as(
544 HashedStorage<StorageTy>(storage.hashcode), storage);
545 StorageTy *&storagePtr = existing.first->storage;
548 new (allocator.Allocate<StorageTy>()) StorageTy(std::move(storage));
553 template <
typename StorageTy,
typename... Args>
554 StorageTy *create(Args &&...args) {
555 static_assert(std::is_base_of_v<IdentityValue, StorageTy> &&
556 "values with structural equivalence must be internalized");
558 return new (allocator.Allocate<StorageTy>())
559 StorageTy(std::forward<Args>(args)...);
563 template <
typename StorageTy>
564 DenseSet<HashedStorage<StorageTy>, StorageKeyInfo<StorageTy>> &
566 if constexpr (std::is_same_v<StorageTy, ArrayStorage>)
567 return internedArrays;
568 else if constexpr (std::is_same_v<StorageTy, SetStorage>)
570 else if constexpr (std::is_same_v<StorageTy, BagStorage>)
572 else if constexpr (std::is_same_v<StorageTy, SequenceStorage>)
573 return internedSequences;
574 else if constexpr (std::is_same_v<StorageTy, RandomizedSequenceStorage>)
575 return internedRandomizedSequences;
576 else if constexpr (std::is_same_v<StorageTy, InterleavedSequenceStorage>)
577 return internedInterleavedSequences;
578 else if constexpr (std::is_same_v<StorageTy, TupleStorage>)
579 return internedTuples;
580 else if constexpr (std::is_same_v<StorageTy, SymbolicComputationStorage>)
581 return internedSymbolicComputationWithIdentityValues;
583 static_assert(!
sizeof(StorageTy),
584 "no intern set available for this storage type.");
589 llvm::BumpPtrAllocator allocator;
594 DenseSet<HashedStorage<ArrayStorage>, StorageKeyInfo<ArrayStorage>>
596 DenseSet<HashedStorage<SetStorage>, StorageKeyInfo<SetStorage>> internedSets;
597 DenseSet<HashedStorage<BagStorage>, StorageKeyInfo<BagStorage>> internedBags;
598 DenseSet<HashedStorage<SequenceStorage>, StorageKeyInfo<SequenceStorage>>
600 DenseSet<HashedStorage<RandomizedSequenceStorage>,
601 StorageKeyInfo<RandomizedSequenceStorage>>
602 internedRandomizedSequences;
603 DenseSet<HashedStorage<InterleavedSequenceStorage>,
604 StorageKeyInfo<InterleavedSequenceStorage>>
605 internedInterleavedSequences;
606 DenseSet<HashedStorage<TupleStorage>, StorageKeyInfo<TupleStorage>>
608 DenseSet<HashedStorage<SymbolicComputationStorage>,
609 StorageKeyInfo<SymbolicComputationStorage>>
610 internedSymbolicComputationWithIdentityValues;
617static llvm::raw_ostream &
operator<<(llvm::raw_ostream &os,
618 const ElaboratorValue &value);
620static void print(TypedAttr val, llvm::raw_ostream &os) {
621 os <<
"<attr " << val <<
">";
624static void print(BagStorage *val, llvm::raw_ostream &os) {
626 llvm::interleaveComma(val->bag, os,
627 [&](
const std::pair<ElaboratorValue, uint64_t> &el) {
628 os << el.first <<
" -> " << el.second;
630 os <<
"} at " << val <<
">";
633static void print(
bool val, llvm::raw_ostream &os) {
634 os <<
"<bool " << (val ?
"true" :
"false") <<
">";
637static void print(
size_t val, llvm::raw_ostream &os) {
638 os <<
"<index " << val <<
">";
641static void print(SequenceStorage *val, llvm::raw_ostream &os) {
642 os <<
"<sequence @" << val->familyName.getValue() <<
"(";
643 llvm::interleaveComma(val->args, os,
644 [&](
const ElaboratorValue &val) { os << val; });
645 os <<
") at " << val <<
">";
648static void print(RandomizedSequenceStorage *val, llvm::raw_ostream &os) {
649 os <<
"<randomized-sequence derived from @"
650 << val->sequence->familyName.getValue() <<
" under context "
651 << val->context <<
"(";
652 llvm::interleaveComma(val->sequence->args, os,
653 [&](
const ElaboratorValue &val) { os << val; });
654 os <<
") at " << val <<
">";
657static void print(InterleavedSequenceStorage *val, llvm::raw_ostream &os) {
658 os <<
"<interleaved-sequence [";
659 llvm::interleaveComma(val->sequences, os,
660 [&](
const ElaboratorValue &val) { os << val; });
661 os <<
"] batch-size " << val->batchSize <<
" at " << val <<
">";
664static void print(ArrayStorage *val, llvm::raw_ostream &os) {
666 llvm::interleaveComma(val->array, os,
667 [&](
const ElaboratorValue &val) { os << val; });
668 os <<
"] at " << val <<
">";
671static void print(SetStorage *val, llvm::raw_ostream &os) {
673 llvm::interleaveComma(val->set, os,
674 [&](
const ElaboratorValue &val) { os << val; });
675 os <<
"} at " << val <<
">";
678static void print(
const VirtualRegisterStorage *val, llvm::raw_ostream &os) {
679 os <<
"<virtual-register " << val <<
" " << val->allowedRegs <<
">";
682static void print(
const UniqueLabelStorage *val, llvm::raw_ostream &os) {
683 os <<
"<unique-label " << val <<
" " << val->name <<
">";
686static void print(
const TupleStorage *val, llvm::raw_ostream &os) {
688 llvm::interleaveComma(val->values, os,
689 [&](
const ElaboratorValue &val) { os << val; });
693static void print(
const MemoryStorage *val, llvm::raw_ostream &os) {
694 os <<
"<memory {" << ElaboratorValue(val->memoryBlock)
695 <<
", size=" << val->size <<
", alignment=" << val->alignment <<
"}>";
698static void print(
const MemoryBlockStorage *val, llvm::raw_ostream &os) {
699 os <<
"<memory-block {"
700 <<
", address-width=" << val->baseAddress.getBitWidth()
701 <<
", base-address=" << val->baseAddress
702 <<
", end-address=" << val->endAddress <<
"}>";
705static void print(
const SymbolicComputationWithIdentityValue *val,
706 llvm::raw_ostream &os) {
707 os <<
"<symbolic-computation-with-identity-value (" << val->storage <<
") at "
711static void print(
const SymbolicComputationWithIdentityStorage *val,
712 llvm::raw_ostream &os) {
713 os <<
"<symbolic-computation-with-identity " << val->name <<
"(";
714 llvm::interleaveComma(val->operands, os,
715 [&](
const ElaboratorValue &val) { os << val; });
716 os <<
") -> " << val->resultTypes <<
" with attributes " << val->attributes
717 <<
" and properties " << val->properties;
721static void print(
const SymbolicComputationStorage *val,
722 llvm::raw_ostream &os) {
723 os <<
"<symbolic-computation " << val->name <<
"(";
724 llvm::interleaveComma(val->operands, os,
725 [&](
const ElaboratorValue &val) { os << val; });
726 os <<
") -> " << val->resultTypes <<
" with attributes " << val->attributes
727 <<
" and properties " << val->properties;
732 const ElaboratorValue &value) {
733 std::visit([&](
auto val) {
print(val, os); }, value);
748class AttributeToElaboratorValueConverter {
750 AttributeToElaboratorValueConverter(Internalizer &internalizer)
751 : internalizer(internalizer) {}
754 FailureOr<ElaboratorValue>
convert(Attribute attr) {
755 return llvm::TypeSwitch<Attribute, FailureOr<ElaboratorValue>>(attr)
756 .Case<IntegerAttr, SetAttr, TupleAttr>(
757 [&](
auto attr) {
return convert(attr); })
758 .Case<TypedAttr>([&](
auto typedAttr) -> FailureOr<ElaboratorValue> {
759 return ElaboratorValue(typedAttr);
762 [&](Attribute) -> FailureOr<ElaboratorValue> {
return failure(); });
766 FailureOr<ElaboratorValue>
convert(IntegerAttr attr) {
767 if (attr.getType().isSignlessInteger(1))
768 return ElaboratorValue(
bool(attr.getInt()));
769 if (isa<IndexType>(attr.getType()))
770 return ElaboratorValue(
size_t(attr.getInt()));
771 return ElaboratorValue(attr);
774 FailureOr<ElaboratorValue>
convert(SetAttr setAttr) {
775 SetVector<ElaboratorValue> set;
776 for (
auto element : *setAttr.getElements()) {
777 auto converted =
convert(element);
778 if (failed(converted))
780 set.insert(*converted);
783 internalizer.internalize<SetStorage>(std::move(set), setAttr.getType());
785 storage->attrCache = setAttr;
786 return ElaboratorValue(storage);
789 FailureOr<ElaboratorValue>
convert(TupleAttr tupleAttr) {
790 SmallVector<ElaboratorValue> values;
791 for (
auto element : tupleAttr.getElements()) {
792 auto converted =
convert(element);
793 if (failed(converted))
795 values.push_back(*converted);
797 auto *storage = internalizer.internalize<TupleStorage>(std::move(values));
799 storage->attrCache = tupleAttr;
800 return ElaboratorValue(storage);
803 Internalizer &internalizer;
809class ElaboratorValueToAttributeConverter {
811 ElaboratorValueToAttributeConverter(MLIRContext *context)
812 : context(context) {}
816 TypedAttr
convert(
const ElaboratorValue &value) {
818 [&](
auto val) -> TypedAttr {
819 if constexpr (std::is_base_of_v<CachableStorage,
820 std::remove_pointer_t<
821 std::decay_t<
decltype(value)>>>) {
823 return val->attrCache;
831 TypedAttr visit(TypedAttr val) {
return val; }
833 TypedAttr visit(
bool val) {
834 return IntegerAttr::get(IntegerType::get(context, 1), val);
837 TypedAttr visit(
size_t val) {
838 return IntegerAttr::get(IndexType::get(context), val);
841 TypedAttr visit(SetStorage *val) {
842 DenseSet<TypedAttr> elements;
843 for (
auto element : val->set) {
844 auto converted =
convert(element);
847 auto typedAttr = dyn_cast<TypedAttr>(converted);
850 elements.insert(typedAttr);
852 return SetAttr::get(cast<SetType>(val->type), &elements);
855 TypedAttr visit(TupleStorage *val) {
856 SmallVector<TypedAttr> elements;
857 for (
auto element : val->values) {
858 auto converted =
convert(element);
861 auto typedAttr = dyn_cast<TypedAttr>(converted);
864 elements.push_back(typedAttr);
866 return TupleAttr::get(context, elements);
872#define VISIT_UNSUPPORTED(STORAGETYPE) \
874 TypedAttr visit(STORAGETYPE *val) { return {}; }
889#undef VISIT_UNSUPPORTED
891 MLIRContext *context;
904 SharedState(MLIRContext *ctxt, SymbolTable &table)
905 : ctxt(ctxt), table(table) {}
910 Internalizer internalizer;
915 explicit TestState(
unsigned seed) : rng(RngScope(seed)) {}
922 std::pair<ContextResourceAttrInterface, ContextResourceAttrInterface>,
933 Materializer(OpBuilder builder, TestState &testState,
934 SharedState &sharedState,
935 SmallVector<ElaboratorValue> &blockArgs)
936 : builder(builder), testState(testState), sharedState(sharedState),
937 blockArgs(blockArgs), attrConverter(builder.getContext()) {}
941 Value materialize(ElaboratorValue val, Location loc,
942 function_ref<InFlightDiagnostic()> emitError) {
943 auto iter = materializedValues.find(val);
944 if (iter != materializedValues.end())
947 LLVM_DEBUG(llvm::dbgs() <<
"Materializing " << val);
949 if (
auto res = tryMaterializeAsConstant(val, loc))
954 Value res = std::visit(
956 if constexpr (std::is_base_of_v<IdentityValue,
957 std::remove_pointer_t<
958 std::decay_t<
decltype(value)>>>) {
959 if (identityValueRoot.contains(value)) {
962 static_cast<IdentityValue *
>(value)->alreadyMaterialized;
963 assert(!materialized &&
"must not already be materialized");
967 return visit(value, loc, emitError);
970 Value arg = builder.getBlock()->addArgument(value->type, loc);
971 blockArgs.push_back(val);
972 blockArgTypes.push_back(arg.getType());
973 materializedValues[val] = arg;
977 return visit(value, loc, emitError);
981 LLVM_DEBUG(llvm::dbgs() <<
" to\n" << res <<
"\n\n");
986 bool isInPlace(Operation *op)
const {
987 return builder.getBlock()->getParent() == op->getParentRegion();
996 LogicalResult materialize(Operation *op,
997 DenseMap<Value, ElaboratorValue> &state) {
998 if (op->getNumRegions() > 0)
999 return op->emitOpError(
"ops with nested regions must be elaborated away");
1007 for (
auto res : op->getResults())
1008 if (!res.use_empty())
1009 return op->emitOpError(
1010 "ops with results that have uses are not supported");
1012 if (isInPlace(op)) {
1015 deleteOpsUntil([&](
auto iter) {
return &*iter == op; });
1017 if (builder.getInsertionPoint() == builder.getBlock()->end())
1018 return op->emitError(
"operation did not occur after the current "
1019 "materializer insertion point");
1021 LLVM_DEBUG(llvm::dbgs() <<
"Modifying in-place: " << *op <<
"\n\n");
1023 LLVM_DEBUG(llvm::dbgs() <<
"Materializing a clone of " << *op <<
"\n\n");
1024 op = builder.clone(*op);
1025 builder.setInsertionPoint(op);
1028 for (
auto &operand : op->getOpOperands()) {
1029 auto emitError = [&]() {
1030 auto diag = op->emitError();
1031 diag.attachNote(op->getLoc())
1032 <<
"while materializing value for operand#"
1033 << operand.getOperandNumber();
1037 auto elabVal = state.at(operand.get());
1038 Value val = materialize(elabVal, op->getLoc(), emitError);
1042 state[val] = elabVal;
1046 builder.setInsertionPointAfter(op);
1053 deleteOpsUntil([](
auto iter) {
return false; });
1055 for (
auto *op :
llvm::reverse(toDelete))
1062 void registerIdentityValue(IdentityValue *val) {
1063 identityValueRoot.insert(val);
1066 ArrayRef<Type> getBlockArgTypes()
const {
return blockArgTypes; }
1068 void map(ElaboratorValue eval, Value val) { materializedValues[eval] = val; }
1070 template <
typename OpTy,
typename... Args>
1071 OpTy create(Location location, Args &&...args) {
1072 return OpTy::create(builder, location, std::forward<Args>(args)...);
1076 Value tryMaterializeAsConstant(ElaboratorValue val, Location loc) {
1077 if (
auto attr = attrConverter.convert(val)) {
1078 Value res = ConstantOp::create(builder, loc, attr);
1079 materializedValues[val] = res;
1086 SequenceOp elaborateSequence(
const RandomizedSequenceStorage *
seq,
1087 SmallVector<ElaboratorValue> &elabArgs);
1089 void deleteOpsUntil(function_ref<
bool(Block::iterator)> stop) {
1090 auto ip = builder.getInsertionPoint();
1091 while (ip != builder.getBlock()->end() && !stop(ip)) {
1092 LLVM_DEBUG(llvm::dbgs() <<
"Marking to be deleted: " << *ip <<
"\n\n");
1093 toDelete.push_back(&*ip);
1095 builder.setInsertionPointAfter(&*ip);
1096 ip = builder.getInsertionPoint();
1100 Value visit(TypedAttr val, Location loc,
1101 function_ref<InFlightDiagnostic()> emitError) {
1105 Value visit(
size_t val, Location loc,
1106 function_ref<InFlightDiagnostic()> emitError) {
1110 Value visit(
bool val, Location loc,
1111 function_ref<InFlightDiagnostic()> emitError) {
1115 Value visit(ArrayStorage *val, Location loc,
1116 function_ref<InFlightDiagnostic()> emitError) {
1117 SmallVector<Value> elements;
1118 elements.reserve(val->array.size());
1119 for (
auto el : val->array) {
1120 auto materialized = materialize(el, loc, emitError);
1124 elements.push_back(materialized);
1127 Value res = ArrayCreateOp::create(builder, loc, val->type, elements);
1128 materializedValues[val] = res;
1132 Value visit(SetStorage *val, Location loc,
1133 function_ref<InFlightDiagnostic()> emitError) {
1134 SmallVector<Value> elements;
1135 elements.reserve(val->set.size());
1136 for (
auto el : val->set) {
1137 auto materialized = materialize(el, loc, emitError);
1141 elements.push_back(materialized);
1144 auto res = SetCreateOp::create(builder, loc, val->type, elements);
1145 materializedValues[val] = res;
1149 Value visit(BagStorage *val, Location loc,
1150 function_ref<InFlightDiagnostic()> emitError) {
1151 SmallVector<Value> values, weights;
1152 values.reserve(val->bag.size());
1153 weights.reserve(val->bag.size());
1154 for (
auto [val, weight] : val->bag) {
1155 auto materializedVal = materialize(val, loc, emitError);
1156 auto materializedWeight = materialize(weight, loc, emitError);
1157 if (!materializedVal || !materializedWeight)
1160 values.push_back(materializedVal);
1161 weights.push_back(materializedWeight);
1164 auto res = BagCreateOp::create(builder, loc, val->type, values, weights);
1165 materializedValues[val] = res;
1169 Value visit(MemoryBlockStorage *val, Location loc,
1170 function_ref<InFlightDiagnostic()> emitError) {
1171 auto intType = builder.getIntegerType(val->baseAddress.getBitWidth());
1172 Value res = MemoryBlockDeclareOp::create(
1173 builder, val->loc, val->type,
1174 IntegerAttr::get(intType, val->baseAddress),
1175 IntegerAttr::get(intType, val->endAddress));
1176 materializedValues[val] = res;
1180 Value visit(MemoryStorage *val, Location loc,
1181 function_ref<InFlightDiagnostic()> emitError) {
1182 auto memBlock = materialize(val->memoryBlock, val->loc, emitError);
1183 auto memSize = materialize(val->size, val->loc, emitError);
1184 auto memAlign = materialize(val->alignment, val->loc, emitError);
1185 if (!(memBlock && memSize && memAlign))
1189 MemoryAllocOp::create(builder, val->loc, memBlock, memSize, memAlign);
1190 materializedValues[val] = res;
1194 Value visit(SequenceStorage *val, Location loc,
1195 function_ref<InFlightDiagnostic()> emitError) {
1196 emitError() <<
"materializing a non-randomized sequence not supported yet";
1200 Value visit(RandomizedSequenceStorage *val, Location loc,
1201 function_ref<InFlightDiagnostic()> emitError) {
1207 SmallVector<ElaboratorValue> elabArgs;
1210 SequenceOp seqOp = elaborateSequence(val, elabArgs);
1216 SmallVector<Value> args;
1217 SmallVector<Type> argTypes;
1218 for (
auto arg : elabArgs) {
1219 Value materialized = materialize(arg, val->loc, emitError);
1223 args.push_back(materialized);
1224 argTypes.push_back(materialized.getType());
1227 Value res = GetSequenceOp::create(
1228 builder, val->loc, SequenceType::get(builder.getContext(), argTypes),
1229 seqOp.getSymName());
1234 res = SubstituteSequenceOp::create(builder, val->loc, res, args);
1236 res = RandomizeSequenceOp::create(builder, val->loc, res);
1238 materializedValues[val] = res;
1242 Value visit(InterleavedSequenceStorage *val, Location loc,
1243 function_ref<InFlightDiagnostic()> emitError) {
1244 SmallVector<Value> sequences;
1245 for (
auto seqVal : val->sequences) {
1246 Value materialized = materialize(seqVal, loc, emitError);
1250 sequences.push_back(materialized);
1253 if (sequences.size() == 1)
1254 return sequences[0];
1257 InterleaveSequencesOp::create(builder, loc, sequences, val->batchSize);
1258 materializedValues[val] = res;
1262 Value visit(VirtualRegisterStorage *val, Location loc,
1263 function_ref<InFlightDiagnostic()> emitError) {
1264 Value res = VirtualRegisterOp::create(builder, val->loc, val->allowedRegs);
1265 materializedValues[val] = res;
1269 Value visit(UniqueLabelStorage *val, Location loc,
1270 function_ref<InFlightDiagnostic()> emitError) {
1271 auto materialized = materialize(val->name, val->loc, emitError);
1274 Value res = LabelUniqueDeclOp::create(builder, val->loc, materialized);
1275 materializedValues[val] = res;
1279 Value visit(TupleStorage *val, Location loc,
1280 function_ref<InFlightDiagnostic()> emitError) {
1281 SmallVector<Value> materialized;
1282 materialized.reserve(val->values.size());
1283 for (
auto v : val->values)
1284 materialized.push_back(materialize(v, loc, emitError));
1285 Value res = TupleCreateOp::create(builder, loc, materialized);
1286 materializedValues[val] = res;
1290 Value visit(SymbolicComputationWithIdentityValue *val, Location loc,
1291 function_ref<InFlightDiagnostic()> emitError) {
1292 auto *noConstStorage =
1293 const_cast<SymbolicComputationWithIdentityStorage *
>(val->storage);
1294 auto res0 = materialize(noConstStorage, loc, emitError);
1298 auto *op = res0.getDefiningOp();
1299 auto res = op->getResults()[val->idx];
1300 materializedValues[val] = res;
1304 Value visit(SymbolicComputationWithIdentityStorage *val, Location loc,
1305 function_ref<InFlightDiagnostic()> emitError) {
1306 SmallVector<Value> operands;
1307 for (
auto operand : val->operands) {
1308 auto materialized = materialize(operand, val->loc, emitError);
1312 operands.push_back(materialized);
1315 OperationState state(val->loc, val->name);
1316 state.addTypes(val->resultTypes);
1317 state.attributes = val->attributes;
1318 state.propertiesAttr = val->properties;
1319 state.addOperands(operands);
1320 auto *op = builder.create(state);
1322 materializedValues[val] = op->getResult(0);
1323 return op->getResult(0);
1326 Value visit(SymbolicComputationStorage *val, Location loc,
1327 function_ref<InFlightDiagnostic()> emitError) {
1328 SmallVector<Value> operands;
1329 for (
auto operand : val->operands) {
1330 auto materialized = materialize(operand, loc, emitError);
1334 operands.push_back(materialized);
1337 OperationState state(loc, val->name);
1338 state.addTypes(val->resultTypes);
1339 state.attributes = val->attributes;
1340 state.propertiesAttr = val->properties;
1341 state.addOperands(operands);
1342 auto *op = builder.create(state);
1344 for (
auto res : op->getResults())
1345 materializedValues[val] = res;
1347 return op->getResult(0);
1356 DenseMap<ElaboratorValue, Value> materializedValues;
1362 SmallVector<Operation *> toDelete;
1364 TestState &testState;
1365 SharedState &sharedState;
1370 SmallVector<ElaboratorValue> &blockArgs;
1371 SmallVector<Type> blockArgTypes;
1376 DenseSet<IdentityValue *> identityValueRoot;
1379 ElaboratorValueToAttributeConverter attrConverter;
1388enum class DeletionKind { Keep, Delete };
1391class Elaborator :
public RTGOpVisitor<Elaborator, FailureOr<DeletionKind>> {
1394 using RTGBase::visitOp;
1396 Elaborator(SharedState &sharedState, TestState &testState,
1397 Materializer &materializer,
1398 ContextResourceAttrInterface currentContext = {})
1399 : sharedState(sharedState), testState(testState),
1400 materializer(materializer), currentContext(currentContext),
1401 attrConverter(sharedState.internalizer),
1402 elabValConverter(sharedState.ctxt) {}
1404 template <
typename ValueTy>
1405 inline ValueTy
get(Value val)
const {
1406 return std::get<ValueTy>(state.at(val));
1411 return visitOpGeneric(op);
1415 return visitOpGeneric(op);
1418 FailureOr<DeletionKind> visitOp(GetSequenceOp op) {
1419 SmallVector<ElaboratorValue> replacements;
1420 state[op.getResult()] =
1421 sharedState.internalizer.internalize<SequenceStorage>(
1422 op.getSequenceAttr().getAttr(), std::move(replacements));
1423 return DeletionKind::Delete;
1426 FailureOr<DeletionKind> visitOp(SubstituteSequenceOp op) {
1427 if (isSymbolic(state.at(op.getSequence())))
1428 return visitOpGeneric(op);
1430 auto *
seq = get<SequenceStorage *>(op.getSequence());
1432 SmallVector<ElaboratorValue> replacements(
seq->args);
1433 for (
auto replacement : op.getReplacements())
1434 replacements.push_back(state.at(replacement));
1436 state[op.getResult()] =
1437 sharedState.internalizer.internalize<SequenceStorage>(
1438 seq->familyName, std::move(replacements));
1440 return DeletionKind::Delete;
1443 FailureOr<DeletionKind> visitOp(RandomizeSequenceOp op) {
1444 auto *
seq = get<SequenceStorage *>(op.getSequence());
1445 auto *randomizedSeq =
1446 sharedState.internalizer.create<RandomizedSequenceStorage>(
1447 currentContext,
seq, op.getLoc());
1448 materializer.registerIdentityValue(randomizedSeq);
1449 state[op.getResult()] =
1450 sharedState.internalizer.internalize<InterleavedSequenceStorage>(
1452 return DeletionKind::Delete;
1455 FailureOr<DeletionKind> visitOp(InterleaveSequencesOp op) {
1456 SmallVector<ElaboratorValue> sequences;
1457 for (
auto seq : op.getSequences())
1458 sequences.push_back(state.at(
seq));
1460 state[op.getResult()] =
1461 sharedState.internalizer.internalize<InterleavedSequenceStorage>(
1462 std::move(sequences), op.getBatchSize());
1463 return DeletionKind::Delete;
1467 LogicalResult isValidContext(ElaboratorValue value, Operation *op)
const {
1468 if (std::holds_alternative<RandomizedSequenceStorage *>(value)) {
1469 auto *
seq = std::get<RandomizedSequenceStorage *>(value);
1470 if (
seq->context != currentContext) {
1471 auto err = op->emitError(
"attempting to place sequence derived from ")
1472 <<
seq->sequence->familyName.getValue() <<
" under context "
1474 <<
", but it was previously randomized for context ";
1476 err <<
seq->context;
1484 auto *interVal = std::get<InterleavedSequenceStorage *>(value);
1485 for (
auto val : interVal->sequences)
1486 if (failed(isValidContext(val, op)))
1491 FailureOr<DeletionKind> visitOp(EmbedSequenceOp op) {
1492 auto *seqVal = get<InterleavedSequenceStorage *>(op.getSequence());
1493 if (failed(isValidContext(seqVal, op)))
1496 return DeletionKind::Keep;
1499 FailureOr<DeletionKind> visitOp(SetCreateOp op) {
1500 SetVector<ElaboratorValue> set;
1501 for (
auto val : op.getElements())
1502 set.insert(state.at(val));
1504 state[op.getSet()] = sharedState.internalizer.internalize<SetStorage>(
1505 std::move(set), op.getSet().getType());
1506 return DeletionKind::Delete;
1509 FailureOr<DeletionKind> visitOp(SetSelectRandomOp op) {
1510 auto set = get<SetStorage *>(op.getSet())->set;
1513 return op->emitError(
"cannot select from an empty set");
1515 size_t selected = testState.rng.getUniformlyInRange(0, set.size() - 1);
1516 state[op.getResult()] = set[selected];
1517 return DeletionKind::Delete;
1520 FailureOr<DeletionKind> visitOp(SetDifferenceOp op) {
1521 auto original = get<SetStorage *>(op.getOriginal())->set;
1522 auto diff = get<SetStorage *>(op.getDiff())->set;
1524 SetVector<ElaboratorValue> result(original);
1525 result.set_subtract(diff);
1527 state[op.getResult()] = sharedState.internalizer.internalize<SetStorage>(
1528 std::move(result), op.getResult().getType());
1529 return DeletionKind::Delete;
1532 FailureOr<DeletionKind> visitOp(SetUnionOp op) {
1533 SetVector<ElaboratorValue> result;
1534 for (
auto set : op.getSets())
1535 result.set_union(
get<SetStorage *>(set)->set);
1537 state[op.getResult()] = sharedState.internalizer.internalize<SetStorage>(
1538 std::move(result), op.getType());
1539 return DeletionKind::Delete;
1542 FailureOr<DeletionKind> visitOp(SetSizeOp op) {
1543 auto size = get<SetStorage *>(op.getSet())->set.size();
1544 state[op.getResult()] = size;
1545 return DeletionKind::Delete;
1551 FailureOr<DeletionKind> visitOp(SetCartesianProductOp op) {
1552 SetVector<ElaboratorValue> result;
1553 SmallVector<SmallVector<ElaboratorValue>> tuples;
1554 tuples.push_back({});
1556 for (
auto input : op.getInputs()) {
1557 auto &set = get<SetStorage *>(input)->set;
1559 SetVector<ElaboratorValue>
empty;
1560 state[op.getResult()] =
1561 sharedState.internalizer.internalize<SetStorage>(std::move(
empty),
1563 return DeletionKind::Delete;
1566 for (
unsigned i = 0, e = tuples.size(); i < e; ++i) {
1567 for (
auto setEl : set.getArrayRef().drop_back()) {
1568 tuples.push_back(tuples[i]);
1569 tuples.back().push_back(setEl);
1571 tuples[i].push_back(set.back());
1575 for (
auto &tup : tuples)
1577 sharedState.internalizer.internalize<TupleStorage>(std::move(tup)));
1579 state[op.getResult()] = sharedState.internalizer.internalize<SetStorage>(
1580 std::move(result), op.getType());
1581 return DeletionKind::Delete;
1584 FailureOr<DeletionKind> visitOp(SetConvertToBagOp op) {
1585 auto set = get<SetStorage *>(op.getInput())->set;
1586 MapVector<ElaboratorValue, uint64_t> bag;
1587 for (
auto val : set)
1588 bag.insert({val, 1});
1589 state[op.getResult()] = sharedState.internalizer.internalize<BagStorage>(
1590 std::move(bag), op.getType());
1591 return DeletionKind::Delete;
1594 FailureOr<DeletionKind> visitOp(BagCreateOp op) {
1595 MapVector<ElaboratorValue, uint64_t> bag;
1596 for (
auto [val, multiple] :
1597 llvm::zip(op.getElements(), op.getMultiples())) {
1601 bag[state.at(val)] += get<size_t>(multiple);
1604 state[op.getBag()] = sharedState.internalizer.internalize<BagStorage>(
1605 std::move(bag), op.getType());
1606 return DeletionKind::Delete;
1609 FailureOr<DeletionKind> visitOp(BagSelectRandomOp op) {
1610 auto bag = get<BagStorage *>(op.getBag())->bag;
1613 return op->emitError(
"cannot select from an empty bag");
1615 SmallVector<std::pair<ElaboratorValue, uint32_t>> prefixSum;
1616 prefixSum.reserve(bag.size());
1617 uint32_t accumulator = 0;
1618 for (
auto [val, weight] : bag) {
1619 accumulator += weight;
1620 prefixSum.push_back({val, accumulator});
1623 auto idx = testState.rng.getUniformlyInRange(0, accumulator - 1);
1624 auto *iter = llvm::upper_bound(
1626 [](uint32_t a,
const std::pair<ElaboratorValue, uint32_t> &b) {
1627 return a <
b.second;
1630 state[op.getResult()] = iter->first;
1631 return DeletionKind::Delete;
1634 FailureOr<DeletionKind> visitOp(BagDifferenceOp op) {
1635 auto original = get<BagStorage *>(op.getOriginal())->bag;
1636 auto diff = get<BagStorage *>(op.getDiff())->bag;
1638 MapVector<ElaboratorValue, uint64_t> result;
1639 for (
const auto &el : original) {
1640 if (!diff.contains(el.first)) {
1648 auto toDiff = diff.lookup(el.first);
1649 if (el.second <= toDiff)
1652 result.insert({el.first, el.second - toDiff});
1655 state[op.getResult()] = sharedState.internalizer.internalize<BagStorage>(
1656 std::move(result), op.getType());
1657 return DeletionKind::Delete;
1660 FailureOr<DeletionKind> visitOp(BagUnionOp op) {
1661 MapVector<ElaboratorValue, uint64_t> result;
1662 for (
auto bag : op.getBags()) {
1663 auto val = get<BagStorage *>(bag)->bag;
1664 for (
auto [el, multiple] : val)
1665 result[el] += multiple;
1668 state[op.getResult()] = sharedState.internalizer.internalize<BagStorage>(
1669 std::move(result), op.getType());
1670 return DeletionKind::Delete;
1673 FailureOr<DeletionKind> visitOp(BagUniqueSizeOp op) {
1674 auto size = get<BagStorage *>(op.getBag())->bag.size();
1675 state[op.getResult()] = size;
1676 return DeletionKind::Delete;
1679 FailureOr<DeletionKind> visitOp(BagConvertToSetOp op) {
1680 auto bag = get<BagStorage *>(op.getInput())->bag;
1681 SetVector<ElaboratorValue> set;
1682 for (
auto [k, v] : bag)
1684 state[op.getResult()] = sharedState.internalizer.internalize<SetStorage>(
1685 std::move(set), op.getType());
1686 return DeletionKind::Delete;
1689 FailureOr<DeletionKind> visitOp(VirtualRegisterOp op) {
1690 auto *val = sharedState.internalizer.create<VirtualRegisterStorage>(
1691 op.getAllowedRegsAttr(), op.getType(), op.getLoc());
1692 state[op.getResult()] = val;
1693 materializer.registerIdentityValue(val);
1694 return DeletionKind::Delete;
1697 FailureOr<DeletionKind> visitOp(ArrayCreateOp op) {
1698 SmallVector<ElaboratorValue> array;
1699 array.reserve(op.getElements().size());
1700 for (
auto val : op.getElements())
1701 array.emplace_back(state.at(val));
1703 state[op.getResult()] = sharedState.internalizer.internalize<ArrayStorage>(
1704 op.getResult().getType(), std::move(array));
1705 return DeletionKind::Delete;
1708 FailureOr<DeletionKind> visitOp(ArrayExtractOp op) {
1709 auto array = get<ArrayStorage *>(op.getArray())->array;
1710 size_t idx = get<size_t>(op.getIndex());
1712 if (array.size() <= idx)
1713 return op->emitError(
"invalid to access index ")
1714 << idx <<
" of an array with " << array.size() <<
" elements";
1716 state[op.getResult()] = array[idx];
1717 return DeletionKind::Delete;
1720 FailureOr<DeletionKind> visitOp(ArrayInjectOp op) {
1721 auto arrayOpaque = state.at(op.getArray());
1722 auto idxOpaque = state.at(op.getIndex());
1723 if (isSymbolic(arrayOpaque) || isSymbolic(idxOpaque))
1724 return visitOpGeneric(op);
1726 auto array = std::get<ArrayStorage *>(arrayOpaque)->array;
1727 size_t idx = std::get<size_t>(idxOpaque);
1729 if (array.size() <= idx)
1730 return op->emitError(
"invalid to access index ")
1731 << idx <<
" of an array with " << array.size() <<
" elements";
1733 array[idx] = state.at(op.getValue());
1734 state[op.getResult()] = sharedState.internalizer.internalize<ArrayStorage>(
1735 op.getResult().getType(), std::move(array));
1736 return DeletionKind::Delete;
1739 FailureOr<DeletionKind> visitOp(ArrayAppendOp op) {
1740 auto array = std::get<ArrayStorage *>(state.at(op.getArray()))->array;
1741 array.push_back(state.at(op.getElement()));
1742 state[op.getResult()] = sharedState.internalizer.internalize<ArrayStorage>(
1743 op.getResult().getType(), std::move(array));
1744 return DeletionKind::Delete;
1747 FailureOr<DeletionKind> visitOp(ArraySizeOp op) {
1748 auto array = get<ArrayStorage *>(op.getArray())->array;
1749 state[op.getResult()] = array.size();
1750 return DeletionKind::Delete;
1753 FailureOr<DeletionKind> visitOp(LabelUniqueDeclOp op) {
1754 auto *val = sharedState.internalizer.create<UniqueLabelStorage>(
1755 state.at(op.getNamePrefix()), op.getLoc());
1756 state[op.getLabel()] = val;
1757 materializer.registerIdentityValue(val);
1758 return DeletionKind::Delete;
1761 FailureOr<DeletionKind> visitOp(RandomScopeOp op) {
1762 auto getNestedRng = [&]() -> RngScope {
1764 return RngScope(op.getSeed()->getZExtValue());
1765 return testState.rng.getNested();
1768 RngScope nestedRng = getNestedRng();
1769 std::swap(testState.rng, nestedRng);
1777 SmallVector<ElaboratorValue> yieldedVals;
1778 if (failed(elaborate(op.getBodyRegion(), {},
false,
1783 std::swap(testState.rng, nestedRng);
1786 for (
auto [res, out] :
llvm::zip(op.getResults(), yieldedVals))
1789 return DeletionKind::Delete;
1792 FailureOr<DeletionKind> visitOp(RandomNumberInRangeOp op) {
1793 size_t lower = get<size_t>(op.getLowerBound());
1794 size_t upper = get<size_t>(op.getUpperBound());
1796 return op->emitError(
"cannot select a number from an empty range");
1798 state[op.getResult()] =
1799 size_t(testState.rng.getUniformlyInRange(lower, upper));
1800 return DeletionKind::Delete;
1803 FailureOr<DeletionKind> visitOp(IntToImmediateOp op) {
1804 size_t input = get<size_t>(op.getInput());
1805 auto width = op.getType().getWidth();
1806 auto emitError = [&]() {
return op->emitError(); };
1807 if (input > APInt::getAllOnes(width).getZExtValue())
1808 return emitError() <<
"cannot represent " << input <<
" with " << width
1811 state[op.getResult()] =
1812 ImmediateAttr::get(op.getContext(), APInt(width, input));
1813 return DeletionKind::Delete;
1816 FailureOr<DeletionKind> visitOp(OnContextOp op) {
1817 ContextResourceAttrInterface from = currentContext,
1818 to = cast<ContextResourceAttrInterface>(
1819 get<TypedAttr>(op.getContext()));
1820 if (!currentContext)
1821 from = DefaultContextAttr::get(op->getContext(), to.getType());
1823 auto emitError = [&]() {
1824 auto diag = op.emitError();
1825 diag.attachNote(op.getLoc())
1826 <<
"while materializing value for context switching for " << op;
1831 Value seqVal = materializer.materialize(
1832 get<SequenceStorage *>(op.getSequence()), op.getLoc(), emitError);
1837 materializer.create<RandomizeSequenceOp>(op.getLoc(), seqVal);
1838 materializer.create<EmbedSequenceOp>(op.getLoc(), randSeqVal);
1839 return DeletionKind::Delete;
1845 auto *iter = testState.contextSwitches.find({from, to});
1848 if (iter == testState.contextSwitches.end())
1849 iter = testState.contextSwitches.find(
1850 {from, AnyContextAttr::get(op->getContext(), to.getType())});
1853 if (iter == testState.contextSwitches.end())
1854 iter = testState.contextSwitches.find(
1855 {AnyContextAttr::get(op->getContext(), from.getType()), to});
1858 if (iter == testState.contextSwitches.end())
1859 iter = testState.contextSwitches.find(
1860 {AnyContextAttr::get(op->getContext(), from.getType()),
1861 AnyContextAttr::get(op->getContext(), to.getType())});
1867 if (iter == testState.contextSwitches.end())
1868 return op->emitError(
"no context transition registered to switch from ")
1869 << from <<
" to " << to;
1871 auto familyName = iter->second->familyName;
1872 SmallVector<ElaboratorValue> args{from, to,
1873 get<SequenceStorage *>(op.getSequence())};
1874 auto *
seq = sharedState.internalizer.internalize<SequenceStorage>(
1875 familyName, std::move(args));
1876 auto *randSeq = sharedState.internalizer.create<RandomizedSequenceStorage>(
1877 to,
seq, op.getLoc());
1878 materializer.registerIdentityValue(randSeq);
1879 Value seqVal = materializer.materialize(randSeq, op.getLoc(), emitError);
1883 materializer.create<EmbedSequenceOp>(op.getLoc(), seqVal);
1884 return DeletionKind::Delete;
1887 FailureOr<DeletionKind> visitOp(ContextSwitchOp op) {
1888 testState.contextSwitches[{op.getFromAttr(), op.getToAttr()}] =
1889 get<SequenceStorage *>(op.getSequence());
1890 return DeletionKind::Delete;
1893 FailureOr<DeletionKind> visitOp(MemoryBlockDeclareOp op) {
1894 auto *val = sharedState.internalizer.create<MemoryBlockStorage>(
1895 op.getBaseAddress(), op.getEndAddress(), op.getType(), op.getLoc());
1896 state[op.getResult()] = val;
1897 materializer.registerIdentityValue(val);
1898 return DeletionKind::Delete;
1901 FailureOr<DeletionKind> visitOp(MemoryAllocOp op) {
1902 size_t size = get<size_t>(op.getSize());
1903 size_t alignment = get<size_t>(op.getAlignment());
1904 auto *memBlock = get<MemoryBlockStorage *>(op.getMemoryBlock());
1905 auto *val = sharedState.internalizer.create<MemoryStorage>(
1906 memBlock, size, alignment, op.getLoc());
1907 state[op.getResult()] = val;
1908 materializer.registerIdentityValue(val);
1909 return DeletionKind::Delete;
1912 FailureOr<DeletionKind> visitOp(MemorySizeOp op) {
1913 auto *memory = get<MemoryStorage *>(op.getMemory());
1914 state[op.getResult()] = memory->size;
1915 return DeletionKind::Delete;
1918 FailureOr<DeletionKind> visitOp(TupleCreateOp op) {
1919 SmallVector<ElaboratorValue> values;
1920 values.reserve(op.getElements().size());
1921 for (
auto el : op.getElements())
1922 values.push_back(state.at(el));
1924 state[op.getResult()] =
1925 sharedState.internalizer.internalize<TupleStorage>(std::move(values));
1926 return DeletionKind::Delete;
1929 FailureOr<DeletionKind> visitOp(TupleExtractOp op) {
1930 auto *tuple = get<TupleStorage *>(op.getTuple());
1931 state[op.getResult()] = tuple->values[op.getIndex().getZExtValue()];
1932 return DeletionKind::Delete;
1935 FailureOr<DeletionKind> visitOp(scf::IfOp op) {
1936 bool cond = get<bool>(op.getCondition());
1937 auto &toElaborate = cond ? op.getThenRegion() : op.getElseRegion();
1938 if (toElaborate.empty())
1939 return DeletionKind::Delete;
1945 SmallVector<ElaboratorValue> yieldedVals;
1947 elaborate(toElaborate, {},
false, yieldedVals)))
1951 for (
auto [res, out] :
llvm::zip(op.getResults(), yieldedVals))
1954 return DeletionKind::Delete;
1957 FailureOr<DeletionKind> visitOp(scf::ForOp op) {
1958 if (!(std::holds_alternative<size_t>(state.at(op.getLowerBound())) &&
1959 std::holds_alternative<size_t>(state.at(op.getStep())) &&
1960 std::holds_alternative<size_t>(state.at(op.getUpperBound()))))
1961 return op->emitOpError(
"can only elaborate index type iterator");
1963 auto lowerBound = get<size_t>(op.getLowerBound());
1964 auto step = get<size_t>(op.getStep());
1965 auto upperBound = get<size_t>(op.getUpperBound());
1971 state[op.getInductionVar()] = lowerBound;
1972 for (
auto [iterArg, initArg] :
1973 llvm::zip(op.getRegionIterArgs(), op.getInitArgs()))
1974 state[iterArg] = state.at(initArg);
1977 SmallVector<ElaboratorValue> yieldedVals;
1978 for (
size_t i = lowerBound; i < upperBound; i += step) {
1979 yieldedVals.clear();
1980 if (failed(elaborate(op.getBodyRegion(), {},
false,
1986 state[op.getInductionVar()] = i + step;
1987 for (
auto [iterArg, prevIterArg] :
1988 llvm::zip(op.getRegionIterArgs(), yieldedVals))
1989 state[iterArg] = prevIterArg;
1993 for (
auto [res, iterArg] :
1994 llvm::zip(op->getResults(), op.getRegionIterArgs()))
1995 state[res] = state.at(iterArg);
1997 return DeletionKind::Delete;
2000 FailureOr<DeletionKind> visitOp(arith::AddIOp op) {
2001 if (!isa<IndexType>(op.getType()))
2002 return visitOpGeneric(op);
2004 size_t lhs = get<size_t>(op.getLhs());
2005 size_t rhs = get<size_t>(op.getRhs());
2006 state[op.getResult()] = lhs + rhs;
2007 return DeletionKind::Delete;
2010 FailureOr<DeletionKind> visitOp(arith::AndIOp op) {
2011 if (!op.getType().isSignlessInteger(1))
2012 return visitOpGeneric(op);
2014 bool lhs = get<bool>(op.getLhs());
2015 bool rhs = get<bool>(op.getRhs());
2016 state[op.getResult()] = lhs && rhs;
2017 return DeletionKind::Delete;
2020 FailureOr<DeletionKind> visitOp(arith::XOrIOp op) {
2021 if (!op.getType().isSignlessInteger(1))
2022 return visitOpGeneric(op);
2024 bool lhs = get<bool>(op.getLhs());
2025 bool rhs = get<bool>(op.getRhs());
2026 state[op.getResult()] = lhs != rhs;
2027 return DeletionKind::Delete;
2030 FailureOr<DeletionKind> visitOp(arith::OrIOp op) {
2031 if (!op.getType().isSignlessInteger(1))
2032 return visitOpGeneric(op);
2034 bool lhs = get<bool>(op.getLhs());
2035 bool rhs = get<bool>(op.getRhs());
2036 state[op.getResult()] = lhs || rhs;
2037 return DeletionKind::Delete;
2040 FailureOr<DeletionKind> visitOp(arith::SelectOp op) {
2041 auto condOpaque = state.at(op.getCondition());
2042 if (isSymbolic(condOpaque))
2043 return visitOpGeneric(op);
2045 bool cond = std::get<bool>(condOpaque);
2046 auto trueVal = state.at(op.getTrueValue());
2047 auto falseVal = state.at(op.getFalseValue());
2048 state[op.getResult()] = cond ? trueVal : falseVal;
2049 return DeletionKind::Delete;
2052 FailureOr<DeletionKind> visitOp(index::AddOp op) {
2053 size_t lhs = get<size_t>(op.getLhs());
2054 size_t rhs = get<size_t>(op.getRhs());
2055 state[op.getResult()] = lhs + rhs;
2056 return DeletionKind::Delete;
2059 FailureOr<DeletionKind> visitOp(index::SubOp op) {
2060 size_t lhs = get<size_t>(op.getLhs());
2061 size_t rhs = get<size_t>(op.getRhs());
2062 state[op.getResult()] = lhs - rhs;
2063 return DeletionKind::Delete;
2066 FailureOr<DeletionKind> visitOp(index::MulOp op) {
2067 size_t lhs = get<size_t>(op.getLhs());
2068 size_t rhs = get<size_t>(op.getRhs());
2069 state[op.getResult()] = lhs * rhs;
2070 return DeletionKind::Delete;
2073 FailureOr<DeletionKind> visitOp(index::DivUOp op) {
2074 size_t lhs = get<size_t>(op.getLhs());
2075 size_t rhs = get<size_t>(op.getRhs());
2078 return op->emitOpError(
"attempted division by zero");
2080 state[op.getResult()] = lhs / rhs;
2081 return DeletionKind::Delete;
2084 FailureOr<DeletionKind> visitOp(index::CeilDivUOp op) {
2085 size_t lhs = get<size_t>(op.getLhs());
2086 size_t rhs = get<size_t>(op.getRhs());
2089 return op->emitOpError(
"attempted division by zero");
2092 state[op.getResult()] = (lhs + rhs - 1) / rhs;
2094 state[op.getResult()] = 1 + ((lhs - 1) / rhs);
2096 return DeletionKind::Delete;
2099 FailureOr<DeletionKind> visitOp(index::RemUOp op) {
2100 size_t lhs = get<size_t>(op.getLhs());
2101 size_t rhs = get<size_t>(op.getRhs());
2104 return op->emitOpError(
"attempted division by zero");
2106 state[op.getResult()] = lhs % rhs;
2107 return DeletionKind::Delete;
2110 FailureOr<DeletionKind> visitOp(index::AndOp op) {
2111 size_t lhs = get<size_t>(op.getLhs());
2112 size_t rhs = get<size_t>(op.getRhs());
2113 state[op.getResult()] = lhs & rhs;
2114 return DeletionKind::Delete;
2117 FailureOr<DeletionKind> visitOp(index::OrOp op) {
2118 size_t lhs = get<size_t>(op.getLhs());
2119 size_t rhs = get<size_t>(op.getRhs());
2120 state[op.getResult()] = lhs | rhs;
2121 return DeletionKind::Delete;
2124 FailureOr<DeletionKind> visitOp(index::XOrOp op) {
2125 size_t lhs = get<size_t>(op.getLhs());
2126 size_t rhs = get<size_t>(op.getRhs());
2127 state[op.getResult()] = lhs ^ rhs;
2128 return DeletionKind::Delete;
2131 FailureOr<DeletionKind> visitOp(index::ShlOp op) {
2132 size_t lhs = get<size_t>(op.getLhs());
2133 size_t rhs = get<size_t>(op.getRhs());
2134 state[op.getResult()] = lhs << rhs;
2135 return DeletionKind::Delete;
2138 FailureOr<DeletionKind> visitOp(index::ShrUOp op) {
2139 size_t lhs = get<size_t>(op.getLhs());
2140 size_t rhs = get<size_t>(op.getRhs());
2141 state[op.getResult()] = lhs >> rhs;
2142 return DeletionKind::Delete;
2145 FailureOr<DeletionKind> visitOp(index::MaxUOp op) {
2146 size_t lhs = get<size_t>(op.getLhs());
2147 size_t rhs = get<size_t>(op.getRhs());
2148 state[op.getResult()] = std::max(lhs, rhs);
2149 return DeletionKind::Delete;
2152 FailureOr<DeletionKind> visitOp(index::MinUOp op) {
2153 size_t lhs = get<size_t>(op.getLhs());
2154 size_t rhs = get<size_t>(op.getRhs());
2155 state[op.getResult()] = std::min(lhs, rhs);
2156 return DeletionKind::Delete;
2159 FailureOr<DeletionKind> visitOp(index::CmpOp op) {
2160 size_t lhs = get<size_t>(op.getLhs());
2161 size_t rhs = get<size_t>(op.getRhs());
2163 switch (op.getPred()) {
2164 case index::IndexCmpPredicate::EQ:
2165 result = lhs == rhs;
2167 case index::IndexCmpPredicate::NE:
2168 result = lhs != rhs;
2170 case index::IndexCmpPredicate::ULT:
2173 case index::IndexCmpPredicate::ULE:
2174 result = lhs <= rhs;
2176 case index::IndexCmpPredicate::UGT:
2179 case index::IndexCmpPredicate::UGE:
2180 result = lhs >= rhs;
2183 return op->emitOpError(
"elaboration not supported");
2185 state[op.getResult()] = result;
2186 return DeletionKind::Delete;
2189 bool isSymbolic(ElaboratorValue val) {
2190 return std::holds_alternative<SymbolicComputationWithIdentityValue *>(
2192 std::holds_alternative<SymbolicComputationWithIdentityStorage *>(
2194 std::holds_alternative<SymbolicComputationStorage *>(val);
2197 bool isSymbolic(Operation *op) {
2198 return llvm::any_of(op->getOperands(), [&](
auto operand) {
2199 auto val = state.at(operand);
2200 return isSymbolic(val);
2207 bool attemptConcreteCase(Operation *op) {
2208 if (op->getNumResults() == 0)
2211 SmallVector<Attribute> operands;
2212 for (
auto operand : op->getOperands()) {
2213 auto evalValue = state[operand];
2214 auto attr = elabValConverter.convert(evalValue);
2215 operands.push_back(attr);
2218 SmallVector<OpFoldResult> results;
2219 if (failed(op->fold(operands, results)))
2222 if (results.size() != op->getNumResults())
2225 for (
auto [res, val] :
llvm::zip(results, op->getResults())) {
2226 auto attr = llvm::dyn_cast_or_null<TypedAttr>(res.dyn_cast<Attribute>());
2230 if (attr.getType() != val.getType())
2234 auto converted = attrConverter.convert(attr);
2235 if (succeeded(converted)) {
2236 state[val] = *converted;
2245 FailureOr<DeletionKind> visitOpGeneric(Operation *op) {
2246 if (op->getNumResults() == 0)
2247 return DeletionKind::Keep;
2249 if (attemptConcreteCase(op))
2250 return DeletionKind::Delete;
2252 if (mlir::isMemoryEffectFree(op)) {
2253 if (op->getNumResults() != 1)
2254 return op->emitOpError(
2255 "symbolic elaboration of memory-effect-free operations with "
2256 "multiple results not supported");
2258 state[op->getResult(0)] =
2259 sharedState.internalizer.internalize<SymbolicComputationStorage>(
2261 return DeletionKind::Delete;
2272 bool onlyAlloc = mlir::hasSingleEffect<mlir::MemoryEffects::Allocate>(op);
2273 onlyAlloc |= isa<ValidateOp>(op);
2275 auto *validationVal =
2276 sharedState.internalizer.create<SymbolicComputationWithIdentityStorage>(
2278 materializer.registerIdentityValue(validationVal);
2279 state[op->getResult(0)] = validationVal;
2281 for (
auto [i, res] :
llvm::enumerate(op->getResults())) {
2285 sharedState.internalizer.create<SymbolicComputationWithIdentityValue>(
2286 res.getType(), validationVal, i);
2288 materializer.registerIdentityValue(val);
2290 return onlyAlloc ? DeletionKind::Delete : DeletionKind::Keep;
2293 bool supportsSymbolicValuesNonGenerically(Operation *op) {
2294 return isa<SubstituteSequenceOp, ArrayCreateOp, ArrayInjectOp,
2295 TupleCreateOp, arith::SelectOp>(op);
2298 FailureOr<DeletionKind> dispatchOpVisitor(Operation *op) {
2299 if (isSymbolic(op) && !supportsSymbolicValuesNonGenerically(op))
2300 return visitOpGeneric(op);
2302 return TypeSwitch<Operation *, FailureOr<DeletionKind>>(op)
2305 arith::AddIOp, arith::XOrIOp, arith::AndIOp, arith::OrIOp,
2308 index::AddOp, index::SubOp, index::MulOp, index::DivUOp,
2309 index::CeilDivUOp, index::RemUOp, index::AndOp, index::OrOp,
2310 index::XOrOp, index::ShlOp, index::ShrUOp, index::MaxUOp,
2311 index::MinUOp, index::CmpOp,
2313 scf::IfOp, scf::ForOp>([&](
auto op) {
return visitOp(op); })
2314 .Default([&](Operation *op) {
return RTGBase::dispatchOpVisitor(op); });
2318 LogicalResult elaborate(Region ®ion,
2319 ArrayRef<ElaboratorValue> regionArguments,
2320 bool keepTerminator,
2321 SmallVector<ElaboratorValue> &terminatorOperands) {
2322 if (region.getBlocks().size() > 1)
2323 return region.getParentOp()->emitOpError(
2324 "regions with more than one block are not supported");
2326 for (
auto [arg, elabArg] :
2327 llvm::zip(region.getArguments(), regionArguments))
2328 state[arg] = elabArg;
2330 Block *block = ®ion.front();
2331 auto iter = keepTerminator ? *block : block->without_terminator();
2332 for (
auto &op : iter) {
2333 auto result = dispatchOpVisitor(&op);
2337 if (*result == DeletionKind::Keep)
2338 if (failed(materializer.materialize(&op, state)))
2342 llvm::dbgs() <<
"Elaborated " << op <<
" to\n[";
2344 llvm::interleaveComma(op.getResults(), llvm::dbgs(), [&](
auto res) {
2345 if (state.contains(res))
2346 llvm::dbgs() << state.at(res);
2348 llvm::dbgs() <<
"unknown";
2351 llvm::dbgs() <<
"]\n\n";
2355 if (!block->empty() && block->back().hasTrait<OpTrait::IsTerminator>()) {
2356 auto *terminator = block->getTerminator();
2357 for (
auto val : terminator->getOperands())
2358 terminatorOperands.push_back(state.at(val));
2360 if (!keepTerminator && materializer.isInPlace(terminator))
2361 terminator->erase();
2369 SharedState &sharedState;
2372 TestState &testState;
2376 Materializer &materializer;
2379 DenseMap<Value, ElaboratorValue> state;
2382 ContextResourceAttrInterface currentContext;
2385 AttributeToElaboratorValueConverter attrConverter;
2388 ElaboratorValueToAttributeConverter elabValConverter;
2393Materializer::elaborateSequence(
const RandomizedSequenceStorage *
seq,
2394 SmallVector<ElaboratorValue> &elabArgs) {
2396 sharedState.table.lookup<SequenceOp>(
seq->sequence->familyName);
2399 OpBuilder builder(familyOp);
2400 auto seqOp = builder.cloneWithoutRegions(familyOp);
2401 auto name = sharedState.names.newName(
seq->sequence->familyName.getValue());
2402 seqOp.setSymName(name);
2403 seqOp.getBodyRegion().emplaceBlock();
2404 sharedState.table.insert(seqOp);
2405 assert(seqOp.getSymName() == name &&
"should not have been renamed");
2407 LLVM_DEBUG(llvm::dbgs() <<
"\n=== Elaborating sequence family @"
2408 << familyOp.getSymName() <<
" into @"
2409 << seqOp.getSymName() <<
" under context "
2410 <<
seq->context <<
"\n\n");
2412 Materializer materializer(OpBuilder::atBlockBegin(seqOp.getBody()), testState,
2413 sharedState, elabArgs);
2414 Elaborator elaborator(sharedState, testState, materializer,
seq->context);
2415 SmallVector<ElaboratorValue> yieldedVals;
2416 if (failed(elaborator.elaborate(familyOp.getBodyRegion(),
seq->sequence->args,
2417 false, yieldedVals)))
2420 seqOp.setSequenceType(
2421 SequenceType::get(builder.getContext(), materializer.getBlockArgTypes()));
2422 materializer.finalize();
2432struct ElaborationPass
2433 :
public rtg::impl::ElaborationPassBase<ElaborationPass> {
2436 void runOnOperation()
override;
2437 void matchTestsAgainstTargets(SymbolTable &table);
2438 LogicalResult elaborateModule(ModuleOp moduleOp, SymbolTable &table);
2442void ElaborationPass::runOnOperation() {
2443 auto moduleOp = getOperation();
2444 SymbolTable table(moduleOp);
2446 matchTestsAgainstTargets(table);
2448 if (failed(elaborateModule(moduleOp, table)))
2449 return signalPassFailure();
2452void ElaborationPass::matchTestsAgainstTargets(SymbolTable &table) {
2453 auto moduleOp = getOperation();
2455 for (
auto test :
llvm::make_early_inc_range(moduleOp.getOps<TestOp>())) {
2456 if (test.getTargetAttr())
2459 bool matched =
false;
2461 for (
auto target : moduleOp.getOps<TargetOp>()) {
2465 bool isSubtype =
true;
2466 auto testEntries = test.getTargetType().getEntries();
2467 auto targetEntries = target.getTarget().getEntries();
2471 size_t targetIdx = 0;
2472 for (
auto testEntry : testEntries) {
2474 while (targetIdx < targetEntries.size() &&
2475 targetEntries[targetIdx].name.getValue() <
2476 testEntry.name.getValue())
2480 if (targetIdx >= targetEntries.size() ||
2481 targetEntries[targetIdx].name != testEntry.name ||
2482 targetEntries[targetIdx].type != testEntry.type) {
2491 IRRewriter rewriter(test);
2493 auto newTest = cast<TestOp>(test->clone());
2494 newTest.setSymName(test.getSymName().str() +
"_" +
2495 target.getSymName().str());
2499 newTest.setTargetAttr(target.getSymNameAttr());
2501 table.insert(newTest, rewriter.getInsertionPoint());
2505 if (matched || deleteUnmatchedTests)
2511 return isa<MemoryBlockType, ContextResourceTypeInterface>(type);
2514LogicalResult ElaborationPass::elaborateModule(ModuleOp moduleOp,
2515 SymbolTable &table) {
2516 SharedState state(moduleOp.getContext(), table);
2519 state.names.add(moduleOp);
2521 struct TargetElabResult {
2522 TargetElabResult(DictType targetType, uint32_t seed)
2523 : targetType(targetType), testState(seed) {}
2525 DictType targetType;
2526 SmallVector<ElaboratorValue> yields;
2527 TestState testState;
2531 DenseMap<StringAttr, TargetElabResult> targetMap;
2532 for (
auto targetOp : moduleOp.getOps<TargetOp>()) {
2533 LLVM_DEBUG(llvm::dbgs() <<
"=== Elaborating target @"
2534 << targetOp.getSymName() <<
"\n\n");
2536 auto [it, inserted] = targetMap.try_emplace(targetOp.getSymNameAttr(),
2537 targetOp.getTarget(), seed);
2538 auto &result = it->second;
2540 SmallVector<ElaboratorValue> blockArgs;
2541 Materializer targetMaterializer(OpBuilder::atBlockBegin(targetOp.getBody()),
2542 result.testState, state, blockArgs);
2543 Elaborator targetElaborator(state, result.testState, targetMaterializer);
2546 if (failed(targetElaborator.elaborate(targetOp.getBodyRegion(), {},
2551 targetMaterializer.finalize();
2556 for (
auto testOp : moduleOp.getOps<TestOp>()) {
2560 if (!testOp.getTargetAttr())
2563 LLVM_DEBUG(llvm::dbgs()
2564 <<
"\n=== Elaborating test @" << testOp.getTemplateName()
2565 <<
" for target @" << *testOp.getTarget() <<
"\n\n");
2568 auto &targetResult = targetMap.at(testOp.getTargetAttr());
2569 TestState testState(seed);
2570 testState.contextSwitches = targetResult.testState.contextSwitches;
2571 testState.name = testOp.getSymNameAttr();
2573 SmallVector<ElaboratorValue> filteredYields;
2575 for (
auto [entry, yield] :
2576 llvm::zip(targetResult.targetType.getEntries(), targetResult.yields)) {
2577 if (i >= testOp.getTargetType().getEntries().size())
2580 if (entry.name == testOp.getTargetType().getEntries()[i].name) {
2581 filteredYields.push_back(yield);
2588 SmallVector<ElaboratorValue> blockArgs;
2589 Materializer materializer(OpBuilder::atBlockBegin(testOp.getBody()),
2590 testState, state, blockArgs);
2592 for (
auto [arg, val] :
2593 llvm::zip(testOp.getBody()->getArguments(), filteredYields))
2595 materializer.map(val, arg);
2597 Elaborator elaborator(state, testState, materializer);
2598 SmallVector<ElaboratorValue> ignore;
2599 if (failed(elaborator.elaborate(testOp.getBodyRegion(), filteredYields,
2603 materializer.finalize();
assert(baseType &&"element must be base type")
static bool onlyLegalToMaterializeInTarget(Type type)
#define VISIT_UNSUPPORTED(STORAGETYPE)
static void print(TypedAttr val, llvm::raw_ostream &os)
static LogicalResult convert(arc::ExecuteOp op, arc::ExecuteOp::Adaptor adaptor, ConversionPatternRewriter &rewriter, const TypeConverter &converter)
static Location getLoc(DefSlot slot)
static InstancePath empty
A namespace that is used to store existing names and generate new names in some scope within the IR.
This helps visit TypeOp nodes.
ResultType visitExternalOp(Operation *op, ExtraArgs... args)
ResultType visitUnhandledOp(Operation *op, ExtraArgs... args)
This callback is invoked on any operations that are not handled by the concrete visitor.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
StringAttr getName(ArrayAttr names, size_t idx)
Return the name at the specified index of the ArrayAttr or null if it cannot be determined.
OS & operator<<(OS &os, const InnerSymTarget &target)
Printing InnerSymTarget's.
static llvm::hash_code hash_value(const ModulePort &port)
int64_t getBitWidth(mlir::Type type)
Return the hardware bit width of a type.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
size_t hash_combine(size_t h1, size_t h2)
C++'s stdlib doesn't have a hash_combine function. This is a simple one.
static bool isEqual(const bool &lhs, const bool &rhs)
static unsigned getTombstoneKey()
static unsigned getHashValue(const bool &val)
static unsigned getEmptyKey()