26#include <llvm/ADT/STLExtras.h>
27#include <llvm/ADT/SmallVector.h>
28#include <llvm/ADT/TypeSwitch.h>
29#include <llvm/Support/Debug.h>
34#define DEBUG_TYPE "llzk-type-helpers"
41using namespace component;
43using namespace polymorphic;
44using namespace string;
49template <
typename Derived,
typename ResultType>
struct LLZKTypeSwitch {
50 inline ResultType
match(Type type) {
51 return llvm::TypeSwitch<Type, ResultType>(type)
52 .template Case<IndexType>([
this](
auto t) {
53 return static_cast<Derived *
>(
this)->caseIndex(t);
55 .
template Case<FeltType>([
this](
auto t) {
56 return static_cast<Derived *
>(
this)->caseFelt(t);
58 .
template Case<StringType>([
this](
auto t) {
59 return static_cast<Derived *
>(
this)->caseString(t);
61 .
template Case<TypeVarType>([
this](
auto t) {
62 return static_cast<Derived *
>(
this)->caseTypeVar(t);
64 .
template Case<ArrayType>([
this](
auto t) {
65 return static_cast<Derived *
>(
this)->caseArray(t);
67 .
template Case<StructType>([
this](
auto t) {
68 return static_cast<Derived *
>(
this)->caseStruct(t);
69 }).
template Case<PodType>([
this](
auto t) {
70 return static_cast<Derived *
>(
this)->casePod(t);
71 }).
template Case<NoneType>([
this](
auto t) {
72 return static_cast<Derived *
>(
this)->caseNone(t);
73 }).Default([
this](Type t) {
74 if (t.isSignlessInteger(1)) {
77 return static_cast<Derived *
>(
this)->caseInvalid(t);
87void BuildShortTypeString::appendSymName(StringRef str) {
95void BuildShortTypeString::appendSymRef(SymbolRefAttr sa) {
96 appendSymName(sa.getRootReference().getValue());
97 for (FlatSymbolRefAttr nestedRef : sa.getNestedReferences()) {
99 appendSymName(nestedRef.getValue());
104 struct Impl : LLZKTypeSwitch<Impl, void> {
105 BuildShortTypeString &outer;
106 Impl(BuildShortTypeString &outerRef) : outer(outerRef) {}
108 void caseInvalid(Type) { outer.ss <<
"!INVALID"; }
109 void caseNone(NoneType) { outer.ss <<
'n'; }
110 void caseBool(IntegerType) { outer.ss <<
'b'; }
111 void caseIndex(IndexType) { outer.ss <<
'i'; }
112 void caseFelt(FeltType) { outer.ss <<
'f'; }
113 void caseString(StringType) { outer.ss <<
's'; }
114 void caseTypeVar(TypeVarType t) {
116 outer.appendSymName(llvm::cast<TypeVarType>(t).getRefName());
119 void caseArray(ArrayType t) {
121 outer.append(t.getElementType());
123 outer.append(t.getDimensionSizes());
126 void casePod(PodType t) {
128 for (
auto record : t.getRecords()) {
129 outer.appendSymRef(record.getNameSym());
133 void caseStruct(StructType t) {
135 outer.appendSymRef(t.getNameRef());
136 if (ArrayAttr params = t.getParams()) {
138 outer.append(params.getValue());
143 Impl(*this).match(type);
155 if (
auto ia = llvm::dyn_cast<IntegerAttr>(a)) {
156 Type ty = ia.getType();
157 bool isUnsigned = ty.isUnsignedInteger() || ty.isSignlessInteger(1);
158 ia.getValue().print(ss, !isUnsigned);
159 }
else if (
auto sra = llvm::dyn_cast<SymbolRefAttr>(a)) {
161 }
else if (
auto ta = llvm::dyn_cast<TypeAttr>(a)) {
162 append(ta.getValue());
163 }
else if (
auto ama = llvm::dyn_cast<AffineMapAttr>(a)) {
166 filtered_raw_ostream fs(ss, [](
char c) {
return c ==
' '; });
167 ama.getValue().print(fs);
170 }
else if (
auto aa = llvm::dyn_cast<ArrayAttr>(a)) {
171 append(aa.getValue());
180 llvm::interleave(attrs, ss, [
this](Attribute a) { append(a); },
"_");
185 BuildShortTypeString bldr;
187 bldr.ret.reserve(base.size() + attrs.size());
190 const auto *END = attrs.end();
191 const auto *IT = attrs.begin();
194 for (
size_t pos; (pos = base.find(PLACEHOLDER, start)) != std::string::npos; start = pos + 1) {
196 bldr.ret.append(base, start, pos - start);
198 assert(IT != END &&
"must have an Attribute for every 'PLACEHOLDER' char");
202 bldr.ret.append(base, start, base.size() - start);
208 bldr.append(ArrayRef(IT, END));
216template <
typename... Types>
class TypeList {
219 template <
typename StreamType>
struct Appender {
222 template <
typename Ty>
static inline void append(StreamType &stream) {
223 stream <<
'\'' << Ty::name <<
'\'';
227 template <
typename First,
typename Second,
typename... Rest>
228 static void append(StreamType &stream) {
229 append<First>(stream);
231 append<Second, Rest...>(stream);
235 static inline void append(StreamType &stream) {
237 append<Types...>(stream);
244 template <
typename T>
static inline bool matches(
const T &value) {
245 return llvm::isa_and_present<Types...>(value);
248 static void reportInvalid(
EmitErrorFn emitError,
const Twine &foundName,
const char *aspect) {
249 InFlightDiagnosticWrapper diag = emitError().append(aspect,
" must be one of ");
250 Appender<InFlightDiagnosticWrapper>::append(diag);
251 diag.append(
" but found '", foundName,
'\'').report();
254 static inline void reportInvalid(
EmitErrorFn emitError, Attribute found,
const char *aspect) {
256 reportInvalid(emitError, found ? found.getAbstractAttribute().getName() :
"nullptr", aspect);
261 static inline std::string
getNames() {
268template <
class... Ts>
struct make_unique {
269 using type = TypeList<Ts...>;
272template <
class... Ts>
struct make_unique<TypeList<>, Ts...> : make_unique<Ts...> {};
274template <
class U,
class... Us,
class... Ts>
275struct make_unique<TypeList<U, Us...>, Ts...>
276 : std::conditional_t<
277 (std::is_same_v<U, Us> || ...) || (std::is_same_v<U, Ts> || ...),
278 make_unique<TypeList<Us...>, Ts...>, make_unique<TypeList<Us...>, Ts..., U>> {};
280template <
class... Ts>
using TypeListUnion =
typename make_unique<Ts...>::type;
286using ArrayDimensionTypes = TypeList<IntegerAttr, SymbolRefAttr, AffineMapAttr>;
294using StructParamTypes =
295 TypeList<IntegerAttr, FeltConstAttr, SymbolRefAttr, TypeAttr, AffineMapAttr>;
298 struct ColumnCheckData {
299 SymbolTableCollection *symbolTable =
nullptr;
300 Operation *op =
nullptr;
303 bool no_felt : 1 =
false;
304 bool no_string : 1 =
false;
305 bool no_struct : 1 =
false;
306 bool no_array : 1 =
false;
307 bool no_pod : 1 =
false;
308 bool no_var : 1 =
false;
309 bool no_int : 1 =
false;
310 bool no_struct_params : 1 =
false;
311 bool must_be_column : 1 =
false;
312 bool type_var_free : 1 =
false;
314 ColumnCheckData columnCheck;
319 bool validColumns(StructType s) {
320 if (!must_be_column) {
323 assert(columnCheck.symbolTable);
324 assert(columnCheck.op);
325 return succeeded(s.hasColumns(*columnCheck.symbolTable, columnCheck.op));
329 constexpr AllowedTypes &noFelt() {
334 constexpr AllowedTypes &noString() {
339 constexpr AllowedTypes &noStruct() {
344 constexpr AllowedTypes &noArray() {
349 constexpr AllowedTypes &noPod() {
354 constexpr AllowedTypes &noVar() {
359 constexpr AllowedTypes &noInt() {
364 constexpr AllowedTypes &noStructParams(
bool noStructParams =
true) {
365 no_struct_params = noStructParams;
369 constexpr AllowedTypes &typeVarFree() {
371 type_var_free =
true;
375 constexpr AllowedTypes &onlyInt() {
377 return noFelt().noString().noStruct().noArray().noPod().noVar();
380 constexpr AllowedTypes &mustBeColumn(SymbolTableCollection &symbolTable, Operation *op) {
381 must_be_column =
true;
382 columnCheck.symbolTable = &symbolTable;
388 bool isValidTypeImpl(Type type);
390 bool areValidArrayDimSizes(ArrayRef<Attribute> dimensionSizes,
EmitErrorFn emitError =
nullptr) {
392 if (dimensionSizes.empty()) {
394 emitError().append(
"array must have at least one dimension").report();
401 for (Attribute a : dimensionSizes) {
402 if (!ArrayDimensionTypes::matches(a)) {
403 ArrayDimensionTypes::reportInvalid(emitError, a,
"Array dimension");
405 }
else if (no_var && !type_var_free && !llvm::isa_and_present<IntegerAttr>(a)) {
406 TypeList<IntegerAttr>::reportInvalid(emitError, a,
"Concrete array dimension");
417 bool isValidArrayElemTypeImpl(Type type) {
420 return llvm::isa<NoneType>(type) || (!llvm::isa<ArrayType>(type) && isValidTypeImpl(type));
423 bool isValidArrayTypeImpl(
424 Type elementType, ArrayRef<Attribute> dimensionSizes,
EmitErrorFn emitError =
nullptr
426 if (!areValidArrayDimSizes(dimensionSizes, emitError)) {
431 if (!isValidArrayElemTypeImpl(elementType)) {
439 elementType.getAbstractType().getName(),
'\''
449 bool isValidArrayTypeImpl(Type type) {
450 if (ArrayType arrTy = llvm::dyn_cast<ArrayType>(type)) {
451 return isValidArrayTypeImpl(arrTy.getElementType(), arrTy.getDimensionSizes());
458 bool areValidStructTypeParams(ArrayAttr params,
EmitErrorFn emitError =
nullptr) {
462 if (no_struct_params) {
466 for (Attribute p : params) {
467 if (!StructParamTypes::matches(p)) {
468 StructParamTypes::reportInvalid(emitError, p,
"Struct parameter");
470 }
else if (TypeAttr tyAttr = llvm::dyn_cast<TypeAttr>(p)) {
471 if (!isValidTypeImpl(tyAttr.getValue())) {
473 emitError().append(
"expected a valid LLZK type but found ", tyAttr.getValue()).report();
477 }
else if (type_var_free && llvm::isa<SymbolRefAttr>(p)) {
478 TypeList<IntegerAttr, FeltConstAttr, TypeAttr, AffineMapAttr>::reportInvalid(
479 emitError, p,
"Type-variable-free struct parameter"
482 }
else if (no_var && !type_var_free && !llvm::isa<IntegerAttr, FeltConstAttr>(p)) {
483 TypeList<IntegerAttr>::reportInvalid(emitError, p,
"Concrete struct parameter");
495 bool areValidPodRecords(ArrayRef<RecordAttr> records) {
496 return llvm::all_of(records, [
this](
auto record) {
return isValidTypeImpl(record.getType()); });
500bool AllowedTypes::isValidTypeImpl(Type type) {
502 !(no_int && no_felt && no_string && no_var && no_struct && no_array && no_pod) &&
503 "All types have been deactivated"
505 struct Impl : LLZKTypeSwitch<Impl, bool> {
507 Impl(AllowedTypes &outerRef) : outer(outerRef) {}
509 bool caseBool(IntegerType t) {
return !outer.no_int && t.isSignlessInteger(1); }
510 bool caseIndex(IndexType) {
return !outer.no_int; }
511 bool caseFelt(FeltType) {
return !outer.no_felt; }
512 bool caseString(StringType) {
return !outer.no_string; }
513 bool caseTypeVar(TypeVarType) {
return !outer.no_var; }
514 bool caseArray(ArrayType t) {
515 return !outer.no_array &&
516 outer.isValidArrayTypeImpl(t.getElementType(), t.getDimensionSizes());
518 bool casePod(PodType t) {
return !outer.no_pod && outer.areValidPodRecords(t.getRecords()); }
519 bool caseStruct(StructType t) {
521 if (outer.no_struct || !outer.validColumns(t)) {
524 return !outer.no_struct && outer.areValidStructTypeParams(t.getParams());
526 bool caseNone(NoneType) {
return false; }
527 bool caseInvalid(Type) {
return false; }
529 return Impl(*this).match(type);
534bool isValidType(Type type) {
return AllowedTypes().isValidTypeImpl(type); }
537 return AllowedTypes().noString().noInt().mustBeColumn(symbolTable, op).isValidTypeImpl(type);
543 return AllowedTypes().noString().noStruct().isValidTypeImpl(type);
548 return AllowedTypes().noString().noStruct().noArray().noPod().isValidTypeImpl(type);
556 return AllowedTypes().noVar().noStructParams(!allowStructParams).isValidTypeImpl(type);
562 if (
auto tyAttr = llvm::dyn_cast<TypeAttr>(attr)) {
566 if (
auto intAttr = llvm::dyn_cast<IntegerAttr>(attr)) {
574 return type.walk([](AffineMapAttr) {
return WalkResult::interrupt(); }).wasInterrupted();
581 while (
ArrayType nestedArrTy = llvm::dyn_cast<ArrayType>(elementType)) {
582 llvm::append_range(mergedDims, nestedArrTy.getDimensionSizes());
583 elementType = nestedArrTy.getElementType();
590 uint64_t caseNone(NoneType) {
return 0; }
591 uint64_t caseBool(IntegerType) {
return 1; }
592 uint64_t caseIndex(IndexType) {
return 1; }
593 uint64_t caseFelt(
FeltType) {
return 1; }
596 if (elementCardinality == 0) {
599 int64_t n = t.getNumElements();
602 uint64_t caseStruct(
StructType) { llvm_unreachable(
"not a valid EmitEq type"); }
604 return std::accumulate(
606 [](
const uint64_t &acc,
const RecordAttr &record) {
607 return computeEmitEqCardinality(record.getType()) + acc;
611 uint64_t caseString(
StringType) { llvm_unreachable(
"not a valid EmitEq type"); }
612 uint64_t caseTypeVar(
TypeVarType) { llvm_unreachable(
"tvar has unknown cardinality"); }
613 uint64_t caseInvalid(Type) { llvm_unreachable(
"not a valid LLZK type"); }
615 return Impl().match(type);
628using AffineInstantiations = DenseMap<std::pair<AffineMapAttr, Side>, IntegerAttr>;
631 ArrayRef<StringRef> rhsRevPrefix;
632 UnificationMap *unifications;
633 AffineInstantiations *affineToIntTracker;
636 llvm::function_ref<bool(Type oldTy, Type newTy)> overrideSuccess;
638 UnifierImpl(UnificationMap *unificationMap, ArrayRef<StringRef> rhsReversePrefix = {})
639 : rhsRevPrefix(rhsReversePrefix), unifications(unificationMap), affineToIntTracker(nullptr),
640 overrideSuccess(nullptr) {}
642 UnifierImpl &trackAffineToInt(AffineInstantiations *tracker) {
643 this->affineToIntTracker = tracker;
647 UnifierImpl &withOverrides(llvm::function_ref<
bool(Type oldTy, Type newTy)> overrides) {
648 this->overrideSuccess = overrides;
654 template <
typename Iter1,
typename Iter2>
bool typeListsUnify(Iter1 lhs, Iter2 rhs) {
655 return (lhs.size() == rhs.size()) &&
656 std::equal(lhs.begin(), lhs.end(), rhs.begin(), [
this](Type a, Type b) {
657 return this->typesUnify(a, b);
664 const ArrayRef<Attribute> &lhsParams,
const ArrayRef<Attribute> &rhsParams,
665 bool unifyDynamicSize =
false
667 auto pred = [
this, unifyDynamicSize](
auto lhsAttr,
auto rhsAttr) {
668 return paramAttrUnify(lhsAttr, rhsAttr, unifyDynamicSize);
670 return (lhsParams.size() == rhsParams.size()) &&
671 std::equal(lhsParams.begin(), lhsParams.end(), rhsParams.begin(), pred);
679 const ArrayAttr &lhsParams,
const ArrayAttr &rhsParams,
bool unifyDynamicSize =
false
681 ArrayRef<Attribute> emptyParams;
683 lhsParams ? lhsParams.getValue() : emptyParams,
684 rhsParams ? rhsParams.getValue() : emptyParams, unifyDynamicSize
690 if (!
typesUnify(lhs.getElementType(), rhs.getElementType())) {
695 lhs.getDimensionSizes(), rhs.getDimensionSizes(),
true
701 llvm::dbgs() <<
"[structTypesUnify] lhs = " << lhs <<
", rhs = " << rhs <<
'\n';
704 SmallVector<StringRef> rhsNames =
getNames(rhs.getNameRef());
705 rhsNames.insert(rhsNames.begin(), rhsRevPrefix.rbegin(), rhsRevPrefix.rend());
706 auto lhsNames =
getNames(lhs.getNameRef());
707 if (rhsNames != lhsNames) {
709 llvm::interleaveComma(
710 lhsNames, llvm::dbgs() <<
"[structTypesUnify] names do not match\n"
713 llvm::interleaveComma(
714 rhsNames, llvm::dbgs() <<
"]\n"
717 llvm::dbgs() <<
"]\n";
721 LLVM_DEBUG({ llvm::dbgs() <<
"[structTypesUnify] checking unification of parameters\n"; });
728 auto lhsRecords = lhs.getRecords();
729 auto rhsRecords = rhs.getRecords();
731 return lhsRecords.size() == rhsRecords.size() &&
732 llvm::all_of(llvm::zip_equal(lhsRecords, rhsRecords), [
this](
auto &&records) {
733 auto &&[lhsRecord, rhsRecord] = records;
734 return lhsRecord.getName() == rhsRecord.getName() &&
735 typesUnify(lhsRecord.getType(), rhsRecord.getType());
748 if (overrideSuccess && overrideSuccess(lhs, rhs)) {
752 if (TypeVarType lhsTvar = llvm::dyn_cast<TypeVarType>(lhs)) {
753 track(Side::LHS, lhsTvar.getNameRef(), rhs);
756 if (TypeVarType rhsTvar = llvm::dyn_cast<TypeVarType>(rhs)) {
757 track(Side::RHS, rhsTvar.getNameRef(), lhs);
760 if (llvm::isa<StructType>(lhs) && llvm::isa<StructType>(rhs)) {
761 return structTypesUnify(llvm::cast<StructType>(lhs), llvm::cast<StructType>(rhs));
763 if (llvm::isa<ArrayType>(lhs) && llvm::isa<ArrayType>(rhs)) {
764 return arrayTypesUnify(llvm::cast<ArrayType>(lhs), llvm::cast<ArrayType>(rhs));
766 if (llvm::isa<PodType>(lhs) && llvm::isa<PodType>(rhs)) {
767 return podTypesUnify(llvm::cast<PodType>(lhs), llvm::cast<PodType>(rhs));
769 if (llvm::isa<FunctionType>(lhs) && llvm::isa<FunctionType>(rhs)) {
770 return functionTypesUnify(llvm::cast<FunctionType>(lhs), llvm::cast<FunctionType>(rhs));
776 template <
typename Tracker,
typename Key,
typename Val>
777 inline void track(Tracker &tracker, Side side, Key keyHead, Val val) {
778 auto key = std::make_pair(keyHead, side);
779 auto it = tracker.find(key);
780 if (it == tracker.end()) {
781 tracker.try_emplace(key, val);
782 }
else if (it->getSecond() != val) {
783 it->second =
nullptr;
787 void track(Side side, SymbolRefAttr symRef, Type ty) {
790 if (TypeVarType tvar = dyn_cast<TypeVarType>(ty)) {
792 attr = tvar.getNameRef();
795 attr = TypeAttr::get(ty);
799 track(*unifications, side, symRef, attr);
803 void track(Side side, SymbolRefAttr symRef, Attribute attr) {
806 if (TypeAttr tyAttr = dyn_cast<TypeAttr>(attr)) {
807 if (TypeVarType tvar = dyn_cast<TypeVarType>(tyAttr.getValue())) {
808 attr = tvar.getNameRef();
817 if (SymbolRefAttr otherSymAttr = dyn_cast<SymbolRefAttr>(attr)) {
818 track(*unifications,
reverse(side), otherSymAttr, symRef);
820 track(*unifications, side, symRef, attr);
824 void track(Side side, AffineMapAttr affineAttr, IntegerAttr intAttr) {
825 if (affineToIntTracker) {
829 track(*affineToIntTracker, side, affineAttr, intAttr);
833 bool paramAttrUnify(Attribute lhsAttr, Attribute rhsAttr,
bool unifyDynamicSize =
false) {
837 if (lhsAttr == rhsAttr) {
842 if (AffineMapAttr lhsAffine = llvm::dyn_cast<AffineMapAttr>(lhsAttr)) {
843 if (IntegerAttr rhsInt = llvm::dyn_cast<IntegerAttr>(rhsAttr)) {
845 track(Side::LHS, lhsAffine, rhsInt);
850 if (AffineMapAttr rhsAffine = llvm::dyn_cast<AffineMapAttr>(rhsAttr)) {
851 if (IntegerAttr lhsInt = llvm::dyn_cast<IntegerAttr>(lhsAttr)) {
853 track(Side::RHS, rhsAffine, lhsInt);
860 if (SymbolRefAttr lhsSymRef = llvm::dyn_cast<SymbolRefAttr>(lhsAttr)) {
861 track(Side::LHS, lhsSymRef, rhsAttr);
864 if (SymbolRefAttr rhsSymRef = llvm::dyn_cast<SymbolRefAttr>(rhsAttr)) {
865 track(Side::RHS, rhsSymRef, lhsAttr);
873 if (unifyDynamicSize) {
874 auto dyn_cast_if_dynamic = [](Attribute attr) -> IntegerAttr {
875 if (IntegerAttr intAttr = llvm::dyn_cast<IntegerAttr>(attr)) {
882 auto is_const_like = [](Attribute attr) {
883 return llvm::isa_and_present<IntegerAttr, SymbolRefAttr, AffineMapAttr>(attr);
885 if (IntegerAttr lhsIntAttr = dyn_cast_if_dynamic(lhsAttr)) {
886 if (is_const_like(rhsAttr)) {
890 if (IntegerAttr rhsIntAttr = dyn_cast_if_dynamic(rhsAttr)) {
891 if (is_const_like(lhsAttr)) {
897 if (TypeAttr lhsTy = llvm::dyn_cast<TypeAttr>(lhsAttr)) {
898 if (TypeAttr rhsTy = llvm::dyn_cast<TypeAttr>(rhsAttr)) {
899 return typesUnify(lhsTy.getValue(), rhsTy.getValue());
910 const ArrayRef<Attribute> &lhsParams,
const ArrayRef<Attribute> &rhsParams,
913 return UnifierImpl(unifications).typeParamsUnify(lhsParams, rhsParams);
919 const ArrayAttr &lhsParams,
const ArrayAttr &rhsParams,
UnificationMap *unifications
921 return UnifierImpl(unifications).typeParamsUnify(lhsParams, rhsParams);
927 return UnifierImpl(unifications, rhsReversePrefix).arrayTypesUnify(lhs, rhs);
934 return UnifierImpl(unifications, rhsReversePrefix).structTypesUnify(lhs, rhs);
940 return UnifierImpl(unifications, rhsReversePrefix).podTypesUnify(lhs, rhs);
944 FunctionType lhs, FunctionType rhs, ArrayRef<StringRef> rhsReversePrefix,
947 return UnifierImpl(unifications, rhsReversePrefix).functionTypesUnify(lhs, rhs);
951 Type lhs, Type rhs, ArrayRef<StringRef> rhsReversePrefix,
UnificationMap *unifications
953 return UnifierImpl(unifications, rhsReversePrefix).typesUnify(lhs, rhs);
957 Type oldTy, Type newTy, llvm::function_ref<
bool(Type oldTy, Type newTy)> knownOldToNew
960 AffineInstantiations affineInstantiations;
962 if (!UnifierImpl(&unifications)
963 .trackAffineToInt(&affineInstantiations)
964 .withOverrides(knownOldToNew)
974 auto entryIsRHS = [](
const auto &entry) {
return entry.first.second ==
Side::RHS; };
975 return !llvm::any_of(unifications, entryIsRHS) && !llvm::any_of(affineInstantiations, entryIsRHS);
979 if (llvm::isa<IndexType>(attr.getType())) {
984 APInt value = attr.getValue();
985 auto compare = value.getBitWidth() <=> IndexType::kInternalStorageBitWidth;
987 value = value.zext(IndexType::kInternalStorageBitWidth);
988 }
else if (compare > 0) {
989 return emitError().append(
"value is too large for `index` type: ",
debug::toStringOne(value));
991 return IntegerAttr::get(IndexType::get(attr.getContext()), value);
995 if (IntegerAttr intAttr = llvm::dyn_cast_if_present<IntegerAttr>(attr)) {
1001FailureOr<SmallVector<Attribute>>
1003 SmallVector<Attribute> result;
1004 for (Attribute attr : attrList) {
1006 if (failed(forced)) {
1009 result.push_back(*forced);
1015 if (IntegerAttr intAttr = llvm::dyn_cast_if_present<IntegerAttr>(in)) {
1016 Type attrTy = intAttr.getType();
1017 if (!AllowedTypes().onlyInt().isValidTypeImpl(attrTy)) {
1020 .append(
"IntegerAttr must have type 'index' or 'i1' but found '", attrTy,
'\'')
1030 if (AffineMapAttr affineAttr = llvm::dyn_cast_if_present<AffineMapAttr>(in)) {
1031 AffineMap map = affineAttr.getValue();
1032 if (map.getNumResults() != 1) {
1036 "AffineMapAttr must yield a single result, but found ", map.getNumResults(),
1048 return success(AllowedTypes().areValidStructTypeParams(params, emitError));
1052 return success(AllowedTypes().areValidArrayDimSizes(dimensionSizes, emitError));
1057 return success(AllowedTypes().isValidArrayTypeImpl(elementType, dimensionSizes, emitError));
1062 using TypeVarAttrs = TypeList<SymbolRefAttr>;
1063 if (!TypeListUnion<ArrayDimensionTypes, StructParamTypes, TypeVarAttrs>::matches(attr)) {
1064 llvm::report_fatal_error(
1065 "Legal type parameters are inconsistent. Encountered " +
1066 attr.getAbstractAttribute().getName()
1074 size_t numArrDims = dimsFromArr.size();
1076 size_t numSubArrDims = dimsFromSubArr.size();
1078 if (numArrDims < numSubArrDims) {
1079 return emitError().append(
1080 "subarray type ", subArrayType,
" has more dimensions than array type ", arrayType
1084 size_t toDrop = numArrDims - numSubArrDims;
1085 ArrayRef<Attribute> dimsFromArrReduced = dimsFromArr.drop_front(toDrop);
1089 std::string message;
1090 llvm::raw_string_ostream ss(message);
1092 ss <<
"cannot unify array dimensions [";
1093 llvm::interleaveComma(dimsFromArrReduced, ss, appendOne);
1095 llvm::interleaveComma(dimsFromSubArr, ss, appendOne);
1097 return emitError().append(message);
1102 return emitError().append(
1103 "incorrect array element type; expected: ", arrayType.
getElementType(),
1113 if (
auto subArrayType = llvm::dyn_cast<ArrayType>(subArrayOrElemType)) {
1117 return emitError().append(
1118 "incorrect array element type; expected: ", arrayType.
getElementType(),
1119 ", found: ", subArrayOrElemType
1127 return TypeSwitch<Type, bool>(ty)
1128 .Case<
FeltType>([](
auto) {
return true; })
1129 .Case<ArrayType>([](
auto arrTy) {
1132 .Case<PodType>([](
auto podTy) {
1133 for (
auto record : podTy.getRecords()) {
1139 }).Default([](
auto) {
return false; });
1143 if (
auto arrayParamTy = llvm::dyn_cast<ArrayType>(pType)) {
1144 return llvm::isa<FeltType>(arrayParamTy.getElementType());
1146 return llvm::isa<FeltType>(pType);
Note: If any symbol refs in an input Type/Attribute use any of the special characters that this class...
static std::string from(mlir::Type type)
Return a brief string representation of the given LLZK type.
::mlir::Type getElementType() const
static ArrayType get(::mlir::Type elementType, ::llvm::ArrayRef<::mlir::Attribute > dimensionSizes)
::llvm::ArrayRef<::mlir::Attribute > getDimensionSizes() const
static constexpr ::llvm::StringLiteral name
::llvm::ArrayRef<::llzk::pod::RecordAttr > getRecords() const
std::string toStringOne(const T &value)
LogicalResult verifyAffineMapAttrType(EmitErrorFn emitError, Attribute in)
void assertValidAttrForParamOfType(Attribute attr)
LogicalResult verifySubArrayType(EmitErrorFn emitError, ArrayType arrayType, ArrayType subArrayType)
Determine if the subArrayType is a valid subarray of arrayType.
FailureOr< Attribute > forceIntAttrType(Attribute attr, EmitErrorFn emitError)
uint64_t computeEmitEqCardinality(Type type)
bool isValidArrayType(Type type)
LogicalResult verifyIntAttrType(EmitErrorFn emitError, Attribute in)
bool typeListsUnify(Iter1 lhs, Iter2 rhs, mlir::ArrayRef< llvm::StringRef > rhsReversePrefix={}, UnificationMap *unifications=nullptr)
Return true iff the two lists of Type instances are equivalent or could be equivalent after full inst...
bool isConcreteType(Type type, bool allowStructParams)
bool isValidArrayElemType(Type type)
llvm::SmallVector< StringRef > getNames(SymbolRefAttr ref)
bool isValidGlobalType(Type type)
AttrConcreteness
Concreteness classification for an argument to a parameterized struct type.
FailureOr< IntegerAttr > forceIntType(IntegerAttr attr, EmitErrorFn emitError)
Convert an IntegerAttr with a type other than IndexType to use IndexType.
bool structTypesUnify(StructType lhs, StructType rhs, ArrayRef< StringRef > rhsReversePrefix, UnificationMap *unifications)
LogicalResult verifyArrayType(EmitErrorFn emitError, Type elementType, ArrayRef< Attribute > dimensionSizes)
bool isFeltOrSimpleFeltAggregate(Type ty)
LogicalResult verifySubArrayOrElementType(EmitErrorFn emitError, ArrayType arrayType, Type subArrayOrElemType)
bool isValidColumnType(Type type, SymbolTableCollection &symbolTable, Operation *op)
bool isValidMainSignalType(Type pType)
mlir::DenseMap< std::pair< mlir::SymbolRefAttr, Side >, mlir::Attribute > UnificationMap
Optional result from type unifications.
llvm::function_ref< InFlightDiagnosticWrapper()> EmitErrorFn
Callback to produce an error diagnostic.
FailureOr< SmallVector< Attribute > > forceIntAttrTypes(ArrayRef< Attribute > attrList, EmitErrorFn emitError)
bool isNullOrEmpty(mlir::ArrayAttr a)
AttrConcreteness classifyAttrConcreteness(Attribute attr, bool allowStructParams)
bool podTypesUnify(PodType lhs, PodType rhs, ArrayRef< StringRef > rhsReversePrefix, UnificationMap *unifications)
constexpr T checkedCast(U u) noexcept
ArrayType flattenArrayElementType(ArrayType outerArrTy, Type elementType)
bool isValidEmitEqType(Type type)
bool isValidType(Type type)
bool arrayTypesUnify(ArrayType lhs, ArrayType rhs, ArrayRef< StringRef > rhsReversePrefix, UnificationMap *unifications)
bool isDynamic(IntegerAttr intAttr)
int64_t fromAPInt(const llvm::APInt &i)
bool isTypeVarFreeType(Type type)
bool typesUnify(Type lhs, Type rhs, ArrayRef< StringRef > rhsReversePrefix, UnificationMap *unifications)
bool typeParamsUnify(const ArrayRef< Attribute > &lhsParams, const ArrayRef< Attribute > &rhsParams, UnificationMap *unifications)
bool isMoreConcreteUnification(Type oldTy, Type newTy, llvm::function_ref< bool(Type oldTy, Type newTy)> knownOldToNew)
bool functionTypesUnify(FunctionType lhs, FunctionType rhs, ArrayRef< StringRef > rhsReversePrefix, UnificationMap *unifications)
LogicalResult verifyStructTypeParams(EmitErrorFn emitError, ArrayAttr params)
void appendWithoutType(mlir::raw_ostream &os, mlir::Attribute a)
std::string buildStringViaCallback(Func &&appendFn, Args &&...args)
Generate a string by calling the given appendFn with an llvm::raw_ostream & as the first argument fol...
bool hasAffineMapAttr(Type type)
mlir::LogicalResult checkValidType(EmitErrorFn emitError, mlir::Type type)
bool isValidConstReadType(Type type)
LogicalResult verifyArrayDimSizes(EmitErrorFn emitError, ArrayRef< Attribute > dimensionSizes)
Template pattern for performing some operation by cases based on a given LLZK type.
ResultType match(Type type)