27#include <llvm/ADT/STLExtras.h>
28#include <llvm/ADT/SmallVector.h>
29#include <llvm/ADT/TypeSwitch.h>
30#include <llvm/Support/Debug.h>
35#define DEBUG_TYPE "llzk-type-helpers"
42using namespace component;
44using namespace polymorphic;
45using namespace string;
50template <
typename Derived,
typename ResultType>
struct LLZKTypeSwitch {
51 inline ResultType
match(Type type) {
52 return llvm::TypeSwitch<Type, ResultType>(type)
53 .template Case<IndexType>([
this](
auto t) {
54 return static_cast<Derived *
>(
this)->caseIndex(t);
56 .
template Case<FeltType>([
this](
auto t) {
57 return static_cast<Derived *
>(
this)->caseFelt(t);
59 .
template Case<StringType>([
this](
auto t) {
60 return static_cast<Derived *
>(
this)->caseString(t);
62 .
template Case<TypeVarType>([
this](
auto t) {
63 return static_cast<Derived *
>(
this)->caseTypeVar(t);
65 .
template Case<ArrayType>([
this](
auto t) {
66 return static_cast<Derived *
>(
this)->caseArray(t);
68 .
template Case<StructType>([
this](
auto t) {
69 return static_cast<Derived *
>(
this)->caseStruct(t);
70 }).
template Case<PodType>([
this](
auto t) {
71 return static_cast<Derived *
>(
this)->casePod(t);
72 }).
template Case<NoneType>([
this](
auto t) {
73 return static_cast<Derived *
>(
this)->caseNone(t);
74 }).Default([
this](Type t) {
75 if (t.isSignlessInteger(1)) {
78 return static_cast<Derived *
>(
this)->caseInvalid(t);
88void BuildShortTypeString::appendSymName(StringRef str) {
96void BuildShortTypeString::appendSymRef(SymbolRefAttr sa) {
97 appendSymName(sa.getRootReference().getValue());
98 for (FlatSymbolRefAttr nestedRef : sa.getNestedReferences()) {
100 appendSymName(nestedRef.getValue());
105 struct Impl : LLZKTypeSwitch<Impl, void> {
106 BuildShortTypeString &outer;
107 Impl(BuildShortTypeString &outerRef) : outer(outerRef) {}
109 void caseInvalid(Type) { outer.ss <<
"!INVALID"; }
110 void caseNone(NoneType) { outer.ss <<
'n'; }
111 void caseBool(IntegerType) { outer.ss <<
'b'; }
112 void caseIndex(IndexType) { outer.ss <<
'i'; }
113 void caseFelt(FeltType) { outer.ss <<
'f'; }
114 void caseString(StringType) { outer.ss <<
's'; }
115 void caseTypeVar(TypeVarType t) {
117 outer.appendSymName(llvm::cast<TypeVarType>(t).getRefName());
120 void caseArray(ArrayType t) {
122 outer.append(t.getElementType());
124 outer.append(t.getDimensionSizes());
127 void casePod(PodType t) {
129 for (
auto record : t.getRecords()) {
130 outer.appendSymRef(record.getNameSym());
134 void caseStruct(StructType t) {
136 outer.appendSymRef(t.getNameRef());
137 if (ArrayAttr params = t.getParams()) {
139 outer.append(params.getValue());
144 Impl(*this).match(type);
149 assert(a &&
"BuildShortTypeString requires non-null attributes");
152 if (
auto ia = llvm::dyn_cast<IntegerAttr>(a)) {
153 Type ty = ia.getType();
154 bool isUnsigned = ty.isUnsignedInteger() || ty.isSignlessInteger(1);
155 ia.getValue().print(ss, !isUnsigned);
156 }
else if (
auto fa = llvm::dyn_cast<FeltConstAttr>(a)) {
158 fa.getValue().print(ss,
false);
159 if (StringAttr fieldName = fa.getFieldName()) {
163 ss <<
':' << fieldName.getValue().size() <<
':' << fieldName.getValue();
166 }
else if (
auto sra = llvm::dyn_cast<SymbolRefAttr>(a)) {
168 }
else if (
auto ta = llvm::dyn_cast<TypeAttr>(a)) {
169 append(ta.getValue());
170 }
else if (
auto ama = llvm::dyn_cast<AffineMapAttr>(a)) {
173 filtered_raw_ostream fs(ss, [](
char c) {
return c ==
' '; });
174 ama.getValue().print(fs);
177 }
else if (
auto aa = llvm::dyn_cast<ArrayAttr>(a)) {
178 append(aa.getValue());
187 llvm::interleave(attrs, ss, [
this](Attribute a) { append(a); },
"_");
193template <
typename... Types>
class TypeList {
196 template <
typename StreamType>
struct Appender {
199 template <
typename Ty>
static inline void append(StreamType &stream) {
200 stream <<
'\'' << Ty::name <<
'\'';
204 template <
typename First,
typename Second,
typename... Rest>
205 static void append(StreamType &stream) {
206 append<First>(stream);
208 append<Second, Rest...>(stream);
212 static inline void append(StreamType &stream) {
214 append<Types...>(stream);
221 template <
typename T>
static inline bool matches(
const T &value) {
222 return llvm::isa_and_present<Types...>(value);
225 static void reportInvalid(
EmitErrorFn emitError,
const Twine &foundName,
const char *aspect) {
226 InFlightDiagnosticWrapper diag = emitError().append(aspect,
" must be one of ");
227 Appender<InFlightDiagnosticWrapper>::append(diag);
228 diag.append(
" but found '", foundName,
'\'').report();
231 static inline void reportInvalid(
EmitErrorFn emitError, Attribute found,
const char *aspect) {
233 reportInvalid(emitError, found ? found.getAbstractAttribute().getName() :
"nullptr", aspect);
238 static inline std::string
getNames() {
245template <
class... Ts>
struct make_unique {
246 using type = TypeList<Ts...>;
249template <
class... Ts>
struct make_unique<TypeList<>, Ts...> : make_unique<Ts...> {};
251template <
class U,
class... Us,
class... Ts>
252struct make_unique<TypeList<U, Us...>, Ts...>
253 : std::conditional_t<
254 (std::is_same_v<U, Us> || ...) || (std::is_same_v<U, Ts> || ...),
255 make_unique<TypeList<Us...>, Ts...>, make_unique<TypeList<Us...>, Ts..., U>> {};
257template <
class... Ts>
using TypeListUnion =
typename make_unique<Ts...>::type;
263using ArrayDimensionTypes = TypeList<IntegerAttr, SymbolRefAttr, AffineMapAttr>;
271using StructParamTypes =
272 TypeList<IntegerAttr, FeltConstAttr, SymbolRefAttr, TypeAttr, AffineMapAttr>;
275 struct ColumnCheckData {
276 SymbolTableCollection *symbolTable =
nullptr;
277 Operation *op =
nullptr;
280 bool no_felt : 1 =
false;
281 bool no_string : 1 =
false;
282 bool no_struct : 1 =
false;
283 bool no_array : 1 =
false;
284 bool no_pod : 1 =
false;
285 bool no_var : 1 =
false;
286 bool no_int : 1 =
false;
287 bool no_struct_params : 1 =
false;
288 bool must_be_column : 1 =
false;
289 bool type_var_free : 1 =
false;
291 ColumnCheckData columnCheck;
296 bool validColumns(StructType s) {
297 if (!must_be_column) {
300 assert(columnCheck.symbolTable);
301 assert(columnCheck.op);
302 return succeeded(s.hasColumns(*columnCheck.symbolTable, columnCheck.op));
306 constexpr AllowedTypes &noFelt() {
311 constexpr AllowedTypes &noString() {
316 constexpr AllowedTypes &noStruct() {
321 constexpr AllowedTypes &noArray() {
326 constexpr AllowedTypes &noPod() {
331 constexpr AllowedTypes &noVar() {
336 constexpr AllowedTypes &noInt() {
341 constexpr AllowedTypes &noStructParams(
bool noStructParams =
true) {
342 no_struct_params = noStructParams;
346 constexpr AllowedTypes &typeVarFree() {
348 type_var_free =
true;
352 constexpr AllowedTypes &onlyInt() {
354 return noFelt().noString().noStruct().noArray().noPod().noVar();
357 constexpr AllowedTypes &mustBeColumn(SymbolTableCollection &symbolTable, Operation *op) {
358 must_be_column =
true;
359 columnCheck.symbolTable = &symbolTable;
365 bool isValidTypeImpl(Type type);
367 bool areValidArrayDimSizes(ArrayRef<Attribute> dimensionSizes,
EmitErrorFn emitError =
nullptr) {
369 if (dimensionSizes.empty()) {
371 emitError().append(
"array must have at least one dimension").report();
378 for (Attribute a : dimensionSizes) {
379 if (!ArrayDimensionTypes::matches(a)) {
380 ArrayDimensionTypes::reportInvalid(emitError, a,
"Array dimension");
382 }
else if (no_var && !type_var_free && !llvm::isa_and_present<IntegerAttr>(a)) {
383 TypeList<IntegerAttr>::reportInvalid(emitError, a,
"Concrete array dimension");
394 bool isValidArrayElemTypeImpl(Type type) {
397 return llvm::isa<NoneType>(type) || (!llvm::isa<ArrayType>(type) && isValidTypeImpl(type));
400 bool isValidArrayTypeImpl(
401 Type elementType, ArrayRef<Attribute> dimensionSizes,
EmitErrorFn emitError =
nullptr
403 if (!areValidArrayDimSizes(dimensionSizes, emitError)) {
408 if (!isValidArrayElemTypeImpl(elementType)) {
416 elementType.getAbstractType().getName(),
'\''
426 bool isValidArrayTypeImpl(Type type) {
427 if (ArrayType arrTy = llvm::dyn_cast<ArrayType>(type)) {
428 return isValidArrayTypeImpl(arrTy.getElementType(), arrTy.getDimensionSizes());
435 bool areValidStructTypeParams(ArrayAttr params,
EmitErrorFn emitError =
nullptr) {
439 if (no_struct_params) {
443 for (Attribute p : params) {
444 if (!StructParamTypes::matches(p)) {
445 StructParamTypes::reportInvalid(emitError, p,
"Struct parameter");
447 }
else if (IntegerAttr i = llvm::dyn_cast<IntegerAttr>(p); i &&
isDynamic(i)) {
449 emitError().append(
"wildcard '?' is not allowed as struct type parameter").report();
452 }
else if (TypeAttr tyAttr = llvm::dyn_cast<TypeAttr>(p)) {
453 if (!isValidTypeImpl(tyAttr.getValue())) {
455 emitError().append(
"expected a valid LLZK type but found ", tyAttr.getValue()).report();
459 }
else if (type_var_free && llvm::isa<SymbolRefAttr>(p)) {
460 TypeList<IntegerAttr, FeltConstAttr, TypeAttr, AffineMapAttr>::reportInvalid(
461 emitError, p,
"Type-variable-free struct parameter"
464 }
else if (no_var && !type_var_free && !llvm::isa<IntegerAttr, FeltConstAttr>(p)) {
465 TypeList<IntegerAttr>::reportInvalid(emitError, p,
"Concrete struct parameter");
477 bool areValidPodRecords(ArrayRef<RecordAttr> records) {
478 return llvm::all_of(records, [
this](
auto record) {
return isValidTypeImpl(record.getType()); });
482bool AllowedTypes::isValidTypeImpl(Type type) {
484 !(no_int && no_felt && no_string && no_var && no_struct && no_array && no_pod) &&
485 "All types have been deactivated"
487 struct Impl : LLZKTypeSwitch<Impl, bool> {
489 Impl(AllowedTypes &outerRef) : outer(outerRef) {}
491 bool caseBool(IntegerType t) {
return !outer.no_int && t.isSignlessInteger(1); }
492 bool caseIndex(IndexType) {
return !outer.no_int; }
493 bool caseFelt(FeltType) {
return !outer.no_felt; }
494 bool caseString(StringType) {
return !outer.no_string; }
495 bool caseTypeVar(TypeVarType) {
return !outer.no_var; }
496 bool caseArray(ArrayType t) {
497 return !outer.no_array &&
498 outer.isValidArrayTypeImpl(t.getElementType(), t.getDimensionSizes());
500 bool casePod(PodType t) {
return !outer.no_pod && outer.areValidPodRecords(t.getRecords()); }
501 bool caseStruct(StructType t) {
503 if (outer.no_struct || !outer.validColumns(t)) {
506 return !outer.no_struct && outer.areValidStructTypeParams(t.getParams());
508 bool caseNone(NoneType) {
return false; }
509 bool caseInvalid(Type) {
return false; }
511 return Impl(*this).match(type);
516bool isValidType(Type type) {
return AllowedTypes().isValidTypeImpl(type); }
519 return AllowedTypes().noString().noInt().mustBeColumn(symbolTable, op).isValidTypeImpl(type);
525 return AllowedTypes().noString().noStruct().isValidTypeImpl(type);
530 return AllowedTypes().noString().noStruct().noArray().noPod().isValidTypeImpl(type);
538 return AllowedTypes().noVar().noStructParams(!allowStructParams).isValidTypeImpl(type);
544 if (
auto tyAttr = llvm::dyn_cast<TypeAttr>(attr)) {
548 if (
auto intAttr = llvm::dyn_cast<IntegerAttr>(attr)) {
561 while (
ArrayType nestedArrTy = llvm::dyn_cast<ArrayType>(elementType)) {
562 llvm::append_range(mergedDims, nestedArrTy.getDimensionSizes());
563 elementType = nestedArrTy.getElementType();
570 uint64_t caseNone(NoneType) {
return 0; }
571 uint64_t caseBool(IntegerType) {
return 1; }
572 uint64_t caseIndex(IndexType) {
return 1; }
573 uint64_t caseFelt(
FeltType) {
return 1; }
576 if (elementCardinality == 0) {
579 int64_t n = t.getNumElements();
582 uint64_t caseStruct(
StructType) { llvm_unreachable(
"not a valid EmitEq type"); }
584 return std::accumulate(
586 [](
const uint64_t &acc,
const RecordAttr &record) {
587 return computeEmitEqCardinality(record.getType()) + acc;
591 uint64_t caseString(
StringType) { llvm_unreachable(
"not a valid EmitEq type"); }
592 uint64_t caseTypeVar(
TypeVarType) { llvm_unreachable(
"tvar has unknown cardinality"); }
593 uint64_t caseInvalid(Type) { llvm_unreachable(
"not a valid LLZK type"); }
595 return Impl().match(type);
608using AffineInstantiations = DenseMap<std::pair<AffineMapAttr, Side>, IntegerAttr>;
611 ArrayRef<StringRef> rhsRevPrefix;
612 UnificationMap *unifications;
613 AffineInstantiations *affineToIntTracker;
614 bool *staticLhsWithWildcardRhsTracker;
617 llvm::function_ref<bool(Type oldTy, Type newTy)> overrideSuccess;
619 UnifierImpl(UnificationMap *unificationMap, ArrayRef<StringRef> rhsReversePrefix = {})
620 : rhsRevPrefix(rhsReversePrefix), unifications(unificationMap), affineToIntTracker(nullptr),
621 staticLhsWithWildcardRhsTracker(nullptr), overrideSuccess(nullptr) {}
623 UnifierImpl &trackAffineToInt(AffineInstantiations *tracker) {
624 this->affineToIntTracker = tracker;
628 UnifierImpl &trackStaticLhsWithWildcardRhs(
bool *tracker) {
629 this->staticLhsWithWildcardRhsTracker = tracker;
633 UnifierImpl &withOverrides(llvm::function_ref<
bool(Type oldTy, Type newTy)> overrides) {
634 this->overrideSuccess = overrides;
640 template <
typename Iter1,
typename Iter2>
bool typeListsUnify(Iter1 lhs, Iter2 rhs) {
641 return (lhs.size() == rhs.size()) &&
642 std::equal(lhs.begin(), lhs.end(), rhs.begin(), [
this](Type a, Type b) {
643 return this->typesUnify(a, b);
650 const ArrayRef<Attribute> &lhsParams,
const ArrayRef<Attribute> &rhsParams,
651 bool unifyDynamicSize =
false
653 auto pred = [
this, unifyDynamicSize](
auto lhsAttr,
auto rhsAttr) {
654 return paramAttrUnify(lhsAttr, rhsAttr, unifyDynamicSize);
656 return (lhsParams.size() == rhsParams.size()) &&
657 std::equal(lhsParams.begin(), lhsParams.end(), rhsParams.begin(), pred);
665 const ArrayAttr &lhsParams,
const ArrayAttr &rhsParams,
bool unifyDynamicSize =
false
667 ArrayRef<Attribute> emptyParams;
669 lhsParams ? lhsParams.getValue() : emptyParams,
670 rhsParams ? rhsParams.getValue() : emptyParams, unifyDynamicSize
676 if (!
typesUnify(lhs.getElementType(), rhs.getElementType())) {
681 lhs.getDimensionSizes(), rhs.getDimensionSizes(),
true
687 llvm::dbgs() <<
"[structTypesUnify] lhs = " << lhs <<
", rhs = " << rhs <<
'\n';
690 SmallVector<StringRef> rhsNames =
getNames(rhs.getNameRef());
691 rhsNames.insert(rhsNames.begin(), rhsRevPrefix.rbegin(), rhsRevPrefix.rend());
692 auto lhsNames =
getNames(lhs.getNameRef());
693 if (rhsNames != lhsNames) {
695 llvm::interleaveComma(
696 lhsNames, llvm::dbgs() <<
"[structTypesUnify] names do not match\n"
699 llvm::interleaveComma(
700 rhsNames, llvm::dbgs() <<
"]\n"
703 llvm::dbgs() <<
"]\n";
707 LLVM_DEBUG({ llvm::dbgs() <<
"[structTypesUnify] checking unification of parameters\n"; });
714 auto lhsRecords = lhs.getRecords();
715 auto rhsRecords = rhs.getRecords();
717 return lhsRecords.size() == rhsRecords.size() &&
718 llvm::all_of(llvm::zip_equal(lhsRecords, rhsRecords), [
this](
auto &&records) {
719 auto &&[lhsRecord, rhsRecord] = records;
720 return lhsRecord.getName() == rhsRecord.getName() &&
721 typesUnify(lhsRecord.getType(), rhsRecord.getType());
734 if (overrideSuccess && overrideSuccess(lhs, rhs)) {
738 if (TypeVarType lhsTvar = llvm::dyn_cast<TypeVarType>(lhs)) {
739 track(Side::LHS, lhsTvar.getNameRef(), rhs);
742 if (TypeVarType rhsTvar = llvm::dyn_cast<TypeVarType>(rhs)) {
743 track(Side::RHS, rhsTvar.getNameRef(), lhs);
746 if (llvm::isa<StructType>(lhs) && llvm::isa<StructType>(rhs)) {
747 return structTypesUnify(llvm::cast<StructType>(lhs), llvm::cast<StructType>(rhs));
749 if (llvm::isa<ArrayType>(lhs) && llvm::isa<ArrayType>(rhs)) {
750 return arrayTypesUnify(llvm::cast<ArrayType>(lhs), llvm::cast<ArrayType>(rhs));
752 if (llvm::isa<PodType>(lhs) && llvm::isa<PodType>(rhs)) {
753 return podTypesUnify(llvm::cast<PodType>(lhs), llvm::cast<PodType>(rhs));
755 if (llvm::isa<FunctionType>(lhs) && llvm::isa<FunctionType>(rhs)) {
756 return functionTypesUnify(llvm::cast<FunctionType>(lhs), llvm::cast<FunctionType>(rhs));
762 template <
typename Tracker,
typename Key,
typename Val>
763 inline void track(Tracker &tracker, Side side, Key keyHead, Val val) {
764 auto key = std::make_pair(keyHead, side);
765 auto it = tracker.find(key);
766 if (it == tracker.end()) {
767 tracker.try_emplace(key, val);
768 }
else if (it->getSecond() != val) {
769 it->second =
nullptr;
773 void track(Side side, SymbolRefAttr symRef, Type ty) {
776 if (TypeVarType tvar = dyn_cast<TypeVarType>(ty)) {
778 attr = tvar.getNameRef();
781 attr = TypeAttr::get(ty);
785 track(*unifications, side, symRef, attr);
789 void track(Side side, SymbolRefAttr symRef, Attribute attr) {
792 if (TypeAttr tyAttr = dyn_cast<TypeAttr>(attr)) {
793 if (TypeVarType tvar = dyn_cast<TypeVarType>(tyAttr.getValue())) {
794 attr = tvar.getNameRef();
803 if (SymbolRefAttr otherSymAttr = dyn_cast<SymbolRefAttr>(attr)) {
804 track(*unifications,
reverse(side), otherSymAttr, symRef);
806 track(*unifications, side, symRef, attr);
810 void track(Side side, AffineMapAttr affineAttr, IntegerAttr intAttr) {
811 if (affineToIntTracker) {
815 track(*affineToIntTracker, side, affineAttr, intAttr);
819 bool paramAttrUnify(Attribute lhsAttr, Attribute rhsAttr,
bool unifyDynamicSize =
false) {
823 if (lhsAttr == rhsAttr) {
828 if (AffineMapAttr lhsAffine = llvm::dyn_cast<AffineMapAttr>(lhsAttr)) {
829 if (IntegerAttr rhsInt = llvm::dyn_cast<IntegerAttr>(rhsAttr)) {
831 track(Side::LHS, lhsAffine, rhsInt);
836 if (AffineMapAttr rhsAffine = llvm::dyn_cast<AffineMapAttr>(rhsAttr)) {
837 if (IntegerAttr lhsInt = llvm::dyn_cast<IntegerAttr>(lhsAttr)) {
839 track(Side::RHS, rhsAffine, lhsInt);
849 if (unifyDynamicSize) {
850 auto dyn_cast_if_dynamic = [](Attribute attr) -> IntegerAttr {
851 if (IntegerAttr intAttr = llvm::dyn_cast<IntegerAttr>(attr)) {
858 auto is_const_like = [](Attribute attr) {
859 return llvm::isa_and_present<IntegerAttr, SymbolRefAttr, AffineMapAttr>(attr);
861 if (IntegerAttr lhsIntAttr = dyn_cast_if_dynamic(lhsAttr)) {
862 if (is_const_like(rhsAttr)) {
866 if (IntegerAttr rhsIntAttr = dyn_cast_if_dynamic(rhsAttr)) {
867 if (is_const_like(lhsAttr)) {
868 if (staticLhsWithWildcardRhsTracker) {
869 *staticLhsWithWildcardRhsTracker =
true;
877 if (SymbolRefAttr lhsSymRef = llvm::dyn_cast<SymbolRefAttr>(lhsAttr)) {
878 track(Side::LHS, lhsSymRef, rhsAttr);
881 if (SymbolRefAttr rhsSymRef = llvm::dyn_cast<SymbolRefAttr>(rhsAttr)) {
882 track(Side::RHS, rhsSymRef, lhsAttr);
886 if (TypeAttr lhsTy = llvm::dyn_cast<TypeAttr>(lhsAttr)) {
887 if (TypeAttr rhsTy = llvm::dyn_cast<TypeAttr>(rhsAttr)) {
888 return typesUnify(lhsTy.getValue(), rhsTy.getValue());
899 const ArrayRef<Attribute> &lhsParams,
const ArrayRef<Attribute> &rhsParams,
902 return UnifierImpl(unifications).typeParamsUnify(lhsParams, rhsParams);
908 const ArrayAttr &lhsParams,
const ArrayAttr &rhsParams,
UnificationMap *unifications
910 return UnifierImpl(unifications).typeParamsUnify(lhsParams, rhsParams);
916 return UnifierImpl(unifications, rhsReversePrefix).arrayTypesUnify(lhs, rhs);
923 return UnifierImpl(unifications, rhsReversePrefix).structTypesUnify(lhs, rhs);
929 return UnifierImpl(unifications, rhsReversePrefix).podTypesUnify(lhs, rhs);
933 FunctionType lhs, FunctionType rhs, ArrayRef<StringRef> rhsReversePrefix,
936 return UnifierImpl(unifications, rhsReversePrefix).functionTypesUnify(lhs, rhs);
940 Type lhs, Type rhs, ArrayRef<StringRef> rhsReversePrefix,
UnificationMap *unifications
942 return UnifierImpl(unifications, rhsReversePrefix).typesUnify(lhs, rhs);
946 Type oldTy, Type newTy, llvm::function_ref<
bool(Type oldTy, Type newTy)> knownOldToNew
949 AffineInstantiations affineInstantiations;
950 bool staticLhsBecomesWildcardRhs =
false;
952 if (!UnifierImpl(&unifications)
953 .trackAffineToInt(&affineInstantiations)
954 .trackStaticLhsWithWildcardRhs(&staticLhsBecomesWildcardRhs)
955 .withOverrides(knownOldToNew)
961 if (staticLhsBecomesWildcardRhs) {
970 auto entryIsRHS = [](
const auto &entry) {
return entry.first.second ==
Side::RHS; };
971 return !llvm::any_of(unifications, entryIsRHS) && !llvm::any_of(affineInstantiations, entryIsRHS);
975 if (llvm::isa<IndexType>(attr.getType())) {
980 APInt value = attr.getValue();
981 auto compare = value.getBitWidth() <=> IndexType::kInternalStorageBitWidth;
983 value = attr.getType().isSignedInteger() ? value.sext(IndexType::kInternalStorageBitWidth)
984 : value.zext(IndexType::kInternalStorageBitWidth);
985 }
else if (compare > 0) {
990 bool isRepresentable = attr.getType().isSignedInteger()
991 ? value.isSignedIntN(IndexType::kInternalStorageBitWidth)
992 : value.isIntN(IndexType::kInternalStorageBitWidth);
993 if (!isRepresentable) {
994 return emitError().append(
"value is too large for `index` type: ",
debug::toStringOne(value));
996 value = value.trunc(IndexType::kInternalStorageBitWidth);
998 return IntegerAttr::get(IndexType::get(attr.getContext()), value);
1002 if (IntegerAttr intAttr = llvm::dyn_cast_if_present<IntegerAttr>(attr)) {
1008FailureOr<SmallVector<Attribute>>
1010 SmallVector<Attribute> result;
1011 for (Attribute attr : attrList) {
1013 if (failed(forced)) {
1016 result.push_back(*forced);
1022 if (IntegerAttr intAttr = llvm::dyn_cast_if_present<IntegerAttr>(in)) {
1023 Type attrTy = intAttr.getType();
1024 if (!AllowedTypes().onlyInt().isValidTypeImpl(attrTy)) {
1027 .append(
"IntegerAttr must have type 'index' or 'i1' but found '", attrTy,
'\'')
1037 if (AffineMapAttr affineAttr = llvm::dyn_cast_if_present<AffineMapAttr>(in)) {
1038 AffineMap map = affineAttr.getValue();
1039 if (map.getNumResults() != 1) {
1043 "AffineMapAttr must yield a single result, but found ", map.getNumResults(),
1055 return success(AllowedTypes().areValidStructTypeParams(params, emitError));
1059 return success(AllowedTypes().areValidArrayDimSizes(dimensionSizes, emitError));
1064 return success(AllowedTypes().isValidArrayTypeImpl(elementType, dimensionSizes, emitError));
1069 using TypeVarAttrs = TypeList<SymbolRefAttr>;
1070 if (!TypeListUnion<ArrayDimensionTypes, StructParamTypes, TypeVarAttrs>::matches(attr)) {
1071 llvm::report_fatal_error(
1072 "Legal type parameters are inconsistent. Encountered " +
1073 attr.getAbstractAttribute().getName()
1081 size_t numArrDims = dimsFromArr.size();
1083 size_t numSubArrDims = dimsFromSubArr.size();
1085 if (numArrDims < numSubArrDims) {
1086 return emitError().append(
1087 "subarray type ", subArrayType,
" has more dimensions than array type ", arrayType
1091 size_t toDrop = numArrDims - numSubArrDims;
1092 ArrayRef<Attribute> dimsFromArrReduced = dimsFromArr.drop_front(toDrop);
1096 std::string message;
1097 llvm::raw_string_ostream ss(message);
1099 ss <<
"cannot unify array dimensions [";
1100 llvm::interleaveComma(dimsFromArrReduced, ss, appendOne);
1102 llvm::interleaveComma(dimsFromSubArr, ss, appendOne);
1104 return emitError().append(message);
1109 return emitError().append(
1110 "incorrect array element type; expected: ", arrayType.
getElementType(),
1120 if (
auto subArrayType = llvm::dyn_cast<ArrayType>(subArrayOrElemType)) {
1124 return emitError().append(
1125 "incorrect array element type; expected: ", arrayType.
getElementType(),
1126 ", found: ", subArrayOrElemType
1134 return TypeSwitch<Type, bool>(ty)
1135 .Case<
FeltType>([](
auto) {
return true; })
1136 .Case<ArrayType>([](
auto arrTy) {
1139 .Case<PodType>([](
auto podTy) {
1140 for (
auto record : podTy.getRecords()) {
1146 }).Default([](
auto) {
return false; });
1150 if (
auto arrayParamTy = llvm::dyn_cast<ArrayType>(pType)) {
1151 return llvm::isa<FeltType>(arrayParamTy.getElementType());
1153 return llvm::isa<FeltType>(pType);
Note: If any symbol refs in an input Type/Attribute use any of the special characters that this class...
::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)
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)