42static inline FailureOr<NormalizedGlobalInitializer>
44 if (
auto intValue = llvm::dyn_cast<IntegerAttr>(value)) {
45 if (!llvm::isa<BoolAttr>(value)) {
46 const APInt &intValueBits = intValue.getValue();
47 if (intValue.getType().isSignlessInteger() && intValueBits.isNegative() &&
48 intValueBits.getBitWidth() < IndexType::kInternalStorageBitWidth) {
49 return emitError().append(
50 "signless integer with sign bit set cannot be widened to `index`"
53 FailureOr<IntegerAttr> normalized =
forceIntType(intValue, emitError);
54 if (failed(normalized)) {
63static inline FailureOr<NormalizedGlobalInitializer>
65 if (
auto intValue = llvm::dyn_cast<IntegerAttr>(value)) {
68 }
else if (
auto feltValue = llvm::dyn_cast<FeltConstAttr>(value)) {
69 FeltType valueType = feltValue.getType();
71 expectedType = valueType;
73 value = FeltConstAttr::get(value.getContext(), feltValue.getRawValue(), expectedType);
79static inline FailureOr<NormalizedGlobalInitializer>
81 if (
auto arrayValue = llvm::dyn_cast<ArrayAttr>(value)) {
83 if (
auto feltElementType = llvm::dyn_cast<FeltType>(elementType)) {
87 for (Attribute element : arrayValue) {
88 if (
auto feltValue = llvm::dyn_cast<FeltConstAttr>(element)) {
89 FeltType valueType = feltValue.getType();
93 if (feltElementType.hasField() && feltElementType != valueType) {
96 feltElementType = valueType;
99 elementType = feltElementType;
100 expectedType = expectedType.
cloneWith(elementType);
105 SmallVector<Attribute> elements;
106 elements.reserve(arrayValue.size());
107 for (Attribute element : arrayValue) {
108 FailureOr<NormalizedGlobalInitializer> normalized =
110 if (failed(normalized)) {
113 elementType = normalized->type;
114 elements.push_back(normalized->value);
117 expectedType = expectedType.
cloneWith(elementType);
118 value = ArrayAttr::get(value.getContext(), elements);
123static inline FailureOr<NormalizedGlobalInitializer>
125 if (
auto stringValue = llvm::dyn_cast<StringAttr>(value)) {
126 value = StringAttr::get(stringValue.getValue(), expectedType);
133FailureOr<NormalizedGlobalInitializer>
135 if (
auto idxType = llvm::dyn_cast<IndexType>(expectedType)) {
137 }
else if (
auto feltType = llvm::dyn_cast<FeltType>(expectedType)) {
139 }
else if (
auto arrayType = llvm::dyn_cast<ArrayType>(expectedType)) {
141 }
else if (
auto stringType = llvm::dyn_cast<StringType>(expectedType)) {
143 }
else if (expectedType.isSignlessInteger(1)) {
144 if (
auto intValue = llvm::dyn_cast<IntegerAttr>(value)) {
145 const APInt &intValueBits = intValue.getValue();
146 if (!intValueBits.isZero() && !intValueBits.isOne()) {
147 return emitError().append(
"integer constant out of range for attribute");
149 value = IntegerAttr::get(expectedType, APInt(1, intValueBits.getZExtValue()));
161static ParseResult normalizeParsedInitialValue(
162 OpAsmParser &parser, SMLoc initializerLoc, Type &declaredType, Attribute &initialValue
164 FailureOr<NormalizedGlobalInitializer> normalized =
168 if (failed(normalized)) {
171 declaredType = normalized->
type;
172 initialValue = normalized->value;
179static ParseResult parseInitialValueForType(OpAsmParser &parser, Type type, Attribute &value) {
180 if (llvm::isa<FeltType>(type)) {
181 FeltConstAttr feltValue;
182 if (parser.parseCustomAttributeWithFallback<FeltConstAttr>(feltValue)) {
188 if (
auto arrayType = llvm::dyn_cast<ArrayType>(type);
189 arrayType && llvm::isa<FeltType>(arrayType.getElementType())) {
190 SmallVector<Attribute> elements;
191 auto parseElement = [&]() -> ParseResult {
193 if (failed(parseInitialValueForType(parser, arrayType.getElementType(), element))) {
196 elements.push_back(element);
199 if (failed(parser.parseCommaSeparatedList(AsmParser::Delimiter::Square, parseElement))) {
202 value = ArrayAttr::get(parser.getContext(), elements);
205 return parser.parseAttribute(value, type);
210 if (succeeded(parser.parseOptionalKeyword(
"const"))) {
211 props.constant = parser.getBuilder().getUnitAttr();
215 if (parser.parseSymbolName(symName) || parser.parseColon()) {
218 props.sym_name = symName;
221 if (parser.parseCustomAttributeWithFallback(typeAttr, parser.getBuilder().getNoneType())) {
224 Type declaredType = typeAttr.getValue();
225 if (succeeded(parser.parseOptionalEqual())) {
226 Attribute initialValue;
227 SMLoc initializerLoc = parser.getCurrentLocation();
228 if (failed(parseInitialValueForType(parser, declaredType, initialValue)) ||
229 failed(normalizeParsedInitialValue(parser, initializerLoc, declaredType, initialValue))) {
232 props.initial_value = initialValue;
234 props.type = TypeAttr::get(declaredType);
236 SMLoc loc = parser.getCurrentLocation();
237 if (parser.parseOptionalAttrDict(result.attributes)) {
241 return parser.emitError(loc) <<
'\'' << result.name.getStringRef() <<
"' op ";
249static void printInitialValue(AsmPrinter &printer, Attribute value) {
250 if (
auto arrayValue = llvm::dyn_cast<ArrayAttr>(value)) {
252 llvm::interleaveComma(arrayValue, printer.getStream(), [&printer](Attribute element) {
253 printInitialValue(printer, element);
256 }
else if (
auto feltValue = llvm::dyn_cast<FeltConstAttr>(value)) {
257 printer.printStrippedAttrOrType<FeltConstAttr>(feltValue);
259 printer.printAttributeWithoutType(value);
275 printInitialValue(p, initialValue);
277 p.printOptionalAttrDict((*this)->getAttrs(), {
"constant",
"sym_name",
"type",
"initial_value"});
288 EmitErrorFn errFn, Type rootType,
const Twine &aspect,
const Twine &expected,
const Twine &found
291 "with type ", rootType,
" expected ", expected,
' ', aspect,
" but found ", found
296 EmitErrorFn errFn, Type rootType,
const Twine &aspect,
const Twine &expected, Attribute found
298 return reportMismatch(errFn, rootType, aspect, expected, found.getAbstractAttribute().getName());
301static LogicalResult ensureAttrTypeMatch(
302 Type type, Attribute valAttr,
const OwningEmitErrorFn &errFn, Type rootType,
const Twine &aspect
306 return errFn().append(
307 "attribute 'type' failed to satisfy constraint: type attribute of "
308 "any LLZK type except non-constant types"
311 if (
auto typedAttr = llvm::dyn_cast<TypedAttr>(valAttr);
312 typedAttr && typedAttr.getType() != type) {
313 return errFn().append(
314 "with type ", rootType,
" expected ", aspect,
" with type ", type,
" but found ",
318 if (type.isSignlessInteger(1)) {
319 if (IntegerAttr ia = llvm::dyn_cast<IntegerAttr>(valAttr)) {
320 const APInt &val = ia.getValue();
321 if (!val.isZero() && !val.isOne()) {
322 return errFn().append(
"integer constant out of range for attribute");
324 }
else if (!llvm::isa<BoolAttr>(valAttr)) {
325 return reportMismatch(errFn, rootType, aspect,
"builtin.bool or builtin.integer", valAttr);
327 }
else if (llvm::isa<IndexType>(type)) {
330 bool isBool = llvm::isa<BoolAttr>(valAttr);
331 if (isBool || !llvm::isa<IntegerAttr>(valAttr)) {
332 return reportMismatch(
333 errFn, rootType, aspect,
"builtin.index",
334 isBool ?
"builtin.bool" : valAttr.getAbstractAttribute().getName()
337 }
else if (llvm::isa<FeltType>(type)) {
338 if (!llvm::isa<FeltConstAttr>(valAttr)) {
339 return reportMismatch(errFn, rootType, aspect,
"felt.type", valAttr);
341 }
else if (llvm::isa<StringType>(type)) {
342 if (!llvm::isa<StringAttr>(valAttr)) {
343 return errFn().append(
344 "with type ", rootType,
" expected ", aspect,
" with type ", type,
" but found ",
345 valAttr.getAbstractAttribute().getName()
348 }
else if (ArrayType arrTy = llvm::dyn_cast<ArrayType>(type)) {
349 if (ArrayAttr arrVal = llvm::dyn_cast<ArrayAttr>(valAttr)) {
351 assert(arrTy.hasStaticShape() &&
"implied by earlier isValidGlobalType() check");
352 int64_t expectedCount = arrTy.getNumElements();
353 size_t actualCount = arrVal.size();
354 if (std::cmp_not_equal(actualCount, expectedCount)) {
355 return reportMismatch(
356 errFn, rootType, Twine(aspect) +
" to contain " + Twine(expectedCount) +
" elements",
357 "builtin.array", Twine(actualCount)
360 if (
auto feltElemTy = llvm::dyn_cast<FeltType>(arrTy.getElementType())) {
361 for (Attribute element : arrVal) {
362 if (
auto feltValue = llvm::dyn_cast<FeltConstAttr>(element)) {
363 FeltType valueType = feltValue.getType();
367 if (feltElemTy.hasField() && feltElemTy != valueType) {
368 return errFn().append(
369 "initializer array contains conflicting types ", valueType,
" vs ", feltElemTy
372 feltElemTy = valueType;
379 bool hasFailure =
false;
380 Type expectedElemTy = arrTy.getElementType();
381 for (Attribute e : arrVal.getValue()) {
383 failed(ensureAttrTypeMatch(expectedElemTy, e, errFn, rootType,
"array element"));
389 return reportMismatch(errFn, rootType, aspect,
"builtin.array", valAttr);
392 return errFn().append(
"expected a valid LLZK type but found ", type);
403 return ensureAttrTypeMatch(ty, initValAttr, errFn, ty,
"attribute value");
407 return emitOpError(
"marked as 'const' must be assigned a value");
416FailureOr<SymbolLookupResult<GlobalDefOp>>
423static FailureOr<SymbolLookupResult<GlobalDefOp>>
431 Type globalType = tgt->get().getType();
432 if (!
typesUnify(refOp.
getVal().getType(), globalType, tgt->getIncludeSymNames())) {
433 return refOp->emitOpError() <<
"has wrong type; expected " << globalType <<
", got "
434 << refOp.
getVal().getType();
442 auto tgt = verifySymbolUsesImpl(*
this, tables);
446 if (
isConstant() && !tgt->get().isConstant()) {
447 return emitOpError().append(
449 "' marked as 'const'"
452 if (!
isConstant() && tgt->get().isConstant()) {
456 "' marked as 'const'"
467 auto &prop = state.getOrAddProperties<
Properties>();
471 return reader.readAttribute(prop.name_ref);
474 if (failed(reader.readOptionalAttribute(prop.constant))) {
477 return reader.readAttribute(prop.name_ref);
482 auto &prop = getProperties();
483 writer.writeOptionalAttribute(prop.constant);
484 writer.writeAttribute(prop.name_ref);
488 SmallVectorImpl<SideEffects::EffectInstance<MemoryEffects::Effect>> &effects
491 effects.emplace_back(MemoryEffects::Read::get(), GlobalMemoryResource::get());
496 auto tgt = verifySymbolUsesImpl(*
this, tables);
500 if (tgt->get().isConstant()) {
501 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.
ArrayType cloneWith(std::optional<::llvm::ArrayRef< int64_t > > shape, ::mlir::Type elementType) const
Clone this type with the given shape and element type.
::mlir::Type getElementType() const
::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)
bool isConstant()
Returns true when this def is marked as const.
::mlir::Attribute getInitialValueAttr()
::llvm::LogicalResult verifySymbolUses(::mlir::SymbolTableCollection &symbolTable)
void print(::mlir::OpAsmPrinter &p)
static constexpr ::llvm::StringLiteral getOperationName()
::llvm::LogicalResult verify()
LLZK support for global values, defined outside of structs.
void writeProperties(::mlir::DialectBytecodeWriter &writer)
FoldAdaptor::Properties Properties
::llvm::LogicalResult verifySymbolUses(::mlir::SymbolTableCollection &symbolTable)
void getEffects(::llvm::SmallVectorImpl<::mlir::SideEffects::EffectInstance<::mlir::MemoryEffects::Effect > > &effects)
bool isConstant()
Returns true when this read is marked as const.
::llvm::LogicalResult readProperties(::mlir::DialectBytecodeReader &reader, ::mlir::OperationState &state)
::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)
llvm::DynamicAPInt integerAttrToDynamicAPInt(mlir::IntegerAttr attr)
Decode an MLIR integer using its signedness; signless i1 denotes a boolean.
mlir::StringRef getName() const final
A global initializer and its normalized type.