37static inline FailureOr<NormalizedGlobalInitializer>
39 if (
auto intValue = llvm::dyn_cast<IntegerAttr>(value)) {
40 if (!llvm::isa<BoolAttr>(value)) {
41 APInt intValueBits = intValue.getValue();
42 if (intValue.getType().isSignlessInteger() && intValueBits.isNegative() &&
43 intValueBits.getBitWidth() < IndexType::kInternalStorageBitWidth) {
44 return emitError().append(
45 "signless integer with sign bit set cannot be widened to `index`"
48 FailureOr<IntegerAttr> normalized =
forceIntType(intValue, emitError);
49 if (failed(normalized)) {
58static inline FailureOr<NormalizedGlobalInitializer>
60 if (
auto intValue = llvm::dyn_cast<IntegerAttr>(value)) {
61 value = FeltConstAttr::get(value.getContext(), intValue.getValue(), expectedType);
62 }
else if (
auto feltValue = llvm::dyn_cast<FeltConstAttr>(value)) {
63 FeltType valueType = feltValue.getType();
64 if (!expectedType.hasField() && valueType.
hasField()) {
65 expectedType = valueType;
66 }
else if (expectedType.hasField() && !valueType.
hasField()) {
67 value = FeltConstAttr::get(value.getContext(), feltValue.getValue(), expectedType);
73static inline FailureOr<NormalizedGlobalInitializer>
75 if (
auto arrayValue = llvm::dyn_cast<ArrayAttr>(value)) {
76 Type elementType = expectedType.getElementType();
77 if (
auto feltElementType = llvm::dyn_cast<FeltType>(elementType)) {
81 for (Attribute element : arrayValue) {
82 if (
auto feltValue = llvm::dyn_cast<FeltConstAttr>(element)) {
83 FeltType valueType = feltValue.getType();
87 if (feltElementType.hasField() && feltElementType != valueType) {
90 feltElementType = valueType;
93 elementType = feltElementType;
94 expectedType = expectedType.cloneWith(elementType);
99 SmallVector<Attribute> elements;
100 elements.reserve(arrayValue.size());
101 for (Attribute element : arrayValue) {
102 FailureOr<NormalizedGlobalInitializer> normalized =
104 if (failed(normalized)) {
107 elementType = normalized->type;
108 elements.push_back(normalized->value);
111 expectedType = expectedType.cloneWith(elementType);
112 value = ArrayAttr::get(value.getContext(), elements);
117static inline FailureOr<NormalizedGlobalInitializer>
119 if (
auto stringValue = llvm::dyn_cast<StringAttr>(value)) {
120 value = StringAttr::get(stringValue.getValue(), expectedType);
127FailureOr<NormalizedGlobalInitializer>
129 if (
auto idxType = llvm::dyn_cast<IndexType>(expectedType)) {
131 }
else if (
auto feltType = llvm::dyn_cast<FeltType>(expectedType)) {
133 }
else if (
auto arrayType = llvm::dyn_cast<ArrayType>(expectedType)) {
135 }
else if (
auto stringType = llvm::dyn_cast<StringType>(expectedType)) {
137 }
else if (expectedType.isSignlessInteger(1)) {
138 if (
auto intValue = llvm::dyn_cast<IntegerAttr>(value)) {
139 APInt intValueBits = intValue.getValue();
140 if (!intValueBits.isZero() && !intValueBits.isOne()) {
141 return emitError().append(
"integer constant out of range for attribute");
143 value = IntegerAttr::get(expectedType, APInt(1, intValueBits.getZExtValue()));
155static ParseResult normalizeParsedInitialValue(
156 OpAsmParser &parser, SMLoc initializerLoc, Type &declaredType, Attribute &initialValue
158 FailureOr<NormalizedGlobalInitializer> normalized =
162 if (failed(normalized)) {
165 declaredType = normalized->
type;
166 initialValue = normalized->value;
173static ParseResult parseInitialValueForType(OpAsmParser &parser, Type type, Attribute &value) {
174 if (llvm::isa<FeltType>(type)) {
175 FeltConstAttr feltValue;
176 if (parser.parseCustomAttributeWithFallback<FeltConstAttr>(feltValue)) {
182 if (
auto arrayType = llvm::dyn_cast<ArrayType>(type);
183 arrayType && llvm::isa<FeltType>(arrayType.getElementType())) {
184 SmallVector<Attribute> elements;
185 auto parseElement = [&]() -> ParseResult {
187 if (failed(parseInitialValueForType(parser, arrayType.getElementType(), element))) {
190 elements.push_back(element);
193 if (failed(parser.parseCommaSeparatedList(AsmParser::Delimiter::Square, parseElement))) {
196 value = ArrayAttr::get(parser.getContext(), elements);
199 return parser.parseAttribute(value, type);
204 if (succeeded(parser.parseOptionalKeyword(
"const"))) {
205 props.constant = parser.getBuilder().getUnitAttr();
209 if (parser.parseSymbolName(symName) || parser.parseColon()) {
212 props.sym_name = symName;
215 if (parser.parseCustomAttributeWithFallback(typeAttr, parser.getBuilder().getNoneType())) {
218 Type declaredType = typeAttr.getValue();
219 if (succeeded(parser.parseOptionalEqual())) {
220 Attribute initialValue;
221 SMLoc initializerLoc = parser.getCurrentLocation();
222 if (failed(parseInitialValueForType(parser, declaredType, initialValue)) ||
223 failed(normalizeParsedInitialValue(parser, initializerLoc, declaredType, initialValue))) {
226 props.initial_value = initialValue;
228 props.type = TypeAttr::get(declaredType);
230 SMLoc loc = parser.getCurrentLocation();
231 if (parser.parseOptionalAttrDict(result.attributes)) {
235 return parser.emitError(loc) <<
'\'' << result.name.getStringRef() <<
"' op ";
243static void printInitialValue(AsmPrinter &printer, Attribute value) {
244 if (
auto arrayValue = llvm::dyn_cast<ArrayAttr>(value)) {
246 llvm::interleaveComma(arrayValue, printer.getStream(), [&printer](Attribute element) {
247 printInitialValue(printer, element);
250 }
else if (
auto feltValue = llvm::dyn_cast<FeltConstAttr>(value)) {
251 printer.printStrippedAttrOrType<FeltConstAttr>(feltValue);
253 printer.printAttributeWithoutType(value);
269 printInitialValue(p, initialValue);
271 p.printOptionalAttrDict((*this)->getAttrs(), {
"constant",
"sym_name",
"type",
"initial_value"});
282 EmitErrorFn errFn, Type rootType,
const Twine &aspect,
const Twine &expected,
const Twine &found
285 "with type ", rootType,
" expected ", expected,
' ', aspect,
" but found ", found
290 EmitErrorFn errFn, Type rootType,
const Twine &aspect,
const Twine &expected, Attribute found
292 return reportMismatch(errFn, rootType, aspect, expected, found.getAbstractAttribute().getName());
295static LogicalResult ensureAttrTypeMatch(
296 Type type, Attribute valAttr,
const OwningEmitErrorFn &errFn, Type rootType,
const Twine &aspect
300 return errFn().append(
301 "attribute 'type' failed to satisfy constraint: type attribute of "
302 "any LLZK type except non-constant types"
305 if (
auto typedAttr = llvm::dyn_cast<TypedAttr>(valAttr);
306 typedAttr && typedAttr.getType() != type) {
307 return errFn().append(
308 "with type ", rootType,
" expected ", aspect,
" with type ", type,
" but found ",
312 if (type.isSignlessInteger(1)) {
313 if (IntegerAttr ia = llvm::dyn_cast<IntegerAttr>(valAttr)) {
314 APInt val = ia.getValue();
315 if (!val.isZero() && !val.isOne()) {
316 return errFn().append(
"integer constant out of range for attribute");
318 }
else if (!llvm::isa<BoolAttr>(valAttr)) {
319 return reportMismatch(errFn, rootType, aspect,
"builtin.bool or builtin.integer", valAttr);
321 }
else if (llvm::isa<IndexType>(type)) {
324 bool isBool = llvm::isa<BoolAttr>(valAttr);
325 if (isBool || !llvm::isa<IntegerAttr>(valAttr)) {
326 return reportMismatch(
327 errFn, rootType, aspect,
"builtin.index",
328 isBool ?
"builtin.bool" : valAttr.getAbstractAttribute().getName()
331 }
else if (llvm::isa<FeltType>(type)) {
332 if (!llvm::isa<FeltConstAttr>(valAttr)) {
333 return reportMismatch(errFn, rootType, aspect,
"felt.type", valAttr);
335 }
else if (llvm::isa<StringType>(type)) {
336 if (!llvm::isa<StringAttr>(valAttr)) {
337 return errFn().append(
338 "with type ", rootType,
" expected ", aspect,
" with type ", type,
" but found ",
339 valAttr.getAbstractAttribute().getName()
342 }
else if (ArrayType arrTy = llvm::dyn_cast<ArrayType>(type)) {
343 if (ArrayAttr arrVal = llvm::dyn_cast<ArrayAttr>(valAttr)) {
345 assert(arrTy.hasStaticShape() &&
"implied by earlier isValidGlobalType() check");
346 int64_t expectedCount = arrTy.getNumElements();
347 size_t actualCount = arrVal.size();
348 if (std::cmp_not_equal(actualCount, expectedCount)) {
349 return reportMismatch(
350 errFn, rootType, Twine(aspect) +
" to contain " + Twine(expectedCount) +
" elements",
351 "builtin.array", Twine(actualCount)
354 if (
auto feltElemTy = llvm::dyn_cast<FeltType>(arrTy.getElementType())) {
355 for (Attribute element : arrVal) {
356 if (
auto feltValue = llvm::dyn_cast<FeltConstAttr>(element)) {
357 FeltType valueType = feltValue.getType();
361 if (feltElemTy.hasField() && feltElemTy != valueType) {
362 return errFn().append(
363 "initializer array contains conflicting types ", valueType,
" vs ", feltElemTy
366 feltElemTy = valueType;
373 bool hasFailure =
false;
374 Type expectedElemTy = arrTy.getElementType();
375 for (Attribute e : arrVal.getValue()) {
377 failed(ensureAttrTypeMatch(expectedElemTy, e, errFn, rootType,
"array element"));
383 return reportMismatch(errFn, rootType, aspect,
"builtin.array", valAttr);
386 return errFn().append(
"expected a valid LLZK type but found ", type);
397 return ensureAttrTypeMatch(ty, initValAttr, errFn, ty,
"attribute value");
401 return emitOpError(
"marked as 'const' must be assigned a value");
410FailureOr<SymbolLookupResult<GlobalDefOp>>
417static FailureOr<SymbolLookupResult<GlobalDefOp>>
425 Type globalType = tgt->get().getType();
426 if (!
typesUnify(refOp.
getVal().getType(), globalType, tgt->getIncludeSymNames())) {
427 return refOp->emitOpError() <<
"has wrong type; expected " << globalType <<
", got "
428 << refOp.
getVal().getType();
436 if (failed(verifySymbolUsesImpl(*
this, tables))) {
444 auto tgt = verifySymbolUsesImpl(*
this, tables);
448 if (tgt->get().isConstant()) {
449 return emitOpError().append(
Wrapper around InFlightDiagnostic that can either be a regular InFlightDiagnostic or a special versio...
InFlightDiagnosticWrapper & append(Args &&...args) &
Append arguments to the diagnostic.
::llvm::LogicalResult verifyInherentAttrs(::mlir::OperationName opName, ::mlir::NamedAttrList &attrs, llvm::function_ref<::mlir::InFlightDiagnostic()> emitError)
FoldAdaptor::Properties Properties
::mlir::TypeAttr getTypeAttr()
::llvm::StringRef getSymName()
::mlir::ParseResult parse(::mlir::OpAsmParser &parser, ::mlir::OperationState &result)
::mlir::Attribute getInitialValueAttr()
::llvm::LogicalResult verifySymbolUses(::mlir::SymbolTableCollection &symbolTable)
void print(::mlir::OpAsmPrinter &p)
static constexpr ::llvm::StringLiteral getOperationName()
::llvm::LogicalResult verify()
::llvm::LogicalResult verifySymbolUses(::mlir::SymbolTableCollection &symbolTable)
::mlir::Value getVal()
Gets the SSA Value that holds the read/write data for the GlobalRefOp.
::mlir::FailureOr< SymbolLookupResult< GlobalDefOp > > getGlobalDefOp(::mlir::SymbolTableCollection &tables)
Gets the definition for the global referenced in this op.
::mlir::SymbolRefAttr getNameRef()
Gets the global name attribute from the GlobalRefOp.
::llvm::LogicalResult verifySymbolUses(::mlir::SymbolTableCollection &symbolTable)
mlir::FailureOr< NormalizedGlobalInitializer > normalizeGlobalInitializer(mlir::Type type, mlir::Attribute value, EmitErrorFn emitError)
Normalize unambiguous initializer representations and their declared type.
mlir::FailureOr< SymbolLookupResultUntyped > lookupTopLevelSymbol(mlir::SymbolTableCollection &tables, mlir::SymbolRefAttr symbol, mlir::Operation *origin, bool reportMissing=true)
bool isValidGlobalType(Type type)
FailureOr< IntegerAttr > forceIntType(IntegerAttr attr, EmitErrorFn emitError)
llvm::function_ref< InFlightDiagnosticWrapper()> EmitErrorFn
Callback to produce an error diagnostic.
LogicalResult verifyTypeResolution(SymbolTableCollection &tables, Operation *origin, Type ty)
OwningEmitErrorFn getEmitOpErrFn(mlir::Operation *op)
std::function< InFlightDiagnosticWrapper()> OwningEmitErrorFn
This type is required in cases like the functions below to take ownership of the lambda so it is not ...
bool typesUnify(Type lhs, Type rhs, ArrayRef< StringRef > rhsReversePrefix, UnificationMap *unifications)
A global initializer and its normalized type.