28#include <mlir/IR/IRMapping.h>
29#include <mlir/IR/OpImplementation.h>
31#include <llvm/ADT/MapVector.h>
32#include <llvm/ADT/STLExtras.h>
33#include <llvm/ADT/StringRef.h>
34#include <llvm/ADT/StringSet.h>
35#include <llvm/ADT/TypeSwitch.h>
70 if (parentFunc.getSymName().compare(funcName) == 0) {
80 assert(llvm::isa<StructDefOp>(structOp));
81 Region &bodyRegion = llvm::cast<StructDefOp>(structOp).getBodyRegion();
82 if (!bodyRegion.empty()) {
83 bodyRegion.front().walk([](
FuncDefOp funcDef) {
100 std::string prefix = std::string();
101 if (SymbolOpInterface symbol = llvm::dyn_cast<SymbolOpInterface>(origin)) {
103 prefix += symbol.getName();
106 return origin->emitOpError().append(
112static inline InFlightDiagnostic structFuncDefError(Operation *origin) {
122 SymbolTableCollection &tables,
StructDefOp expectedStruct, Type actualType, Operation *origin,
125 if (
StructType actualStructType = llvm::dyn_cast<StructType>(actualType)) {
126 auto actualStructOpt =
128 if (failed(actualStructOpt)) {
129 return origin->emitError().append(
131 actualStructType.getNameRef(),
'"'
134 StructDefOp actualStruct = actualStructOpt.value().get();
135 if (actualStruct != expectedStruct) {
137 .attachNote(actualStruct.getLoc())
138 .append(
"uses this type instead");
141 ArrayAttr actualTypeParamsAttr = actualStructType.getParams();
142 ArrayRef<Attribute> actualTypeParams =
143 actualTypeParamsAttr ? actualTypeParamsAttr.getValue() : ArrayRef<Attribute> {};
153 .attachNote(actualStruct.getLoc())
168 assert(succeeded(pathRes));
170 if (constParams.has_value()) {
184 if (succeeded(pathToExpected)) {
185 ss << pathToExpected.value();
206 return SmallVector<Attribute>();
214 return SmallVector<Attribute>();
223checkMainFuncParamType(Type pType,
FuncDefOp inFunc, std::optional<StructType> appendSelfType) {
229 ss <<
"main entry component \"@" << inFunc.
getSymName()
230 <<
"\" function parameters must be one of: {";
231 if (appendSelfType.has_value()) {
232 ss << appendSelfType.value() <<
", ";
237 return inFunc.emitError(message);
240inline LogicalResult checkMainFuncOutputSignalType(Type pType,
StructDefOp structOp) {
246 ss <<
"main entry component output signals must be one of: {";
250 return structOp.emitError(message);
253inline LogicalResult verifyStructComputeConstrain(
254 StructDefOp structDef, FuncDefOp computeFunc, FuncDefOp constrainFunc
264 ArrayRef<Type> computeParams = computeFunc.
getFunctionType().getInputs();
265 ArrayRef<Type> constrainParams = constrainFunc.
getFunctionType().getInputs().drop_front();
270 for (Type t : computeParams) {
271 if (failed(checkMainFuncParamType(t, computeFunc, std::nullopt))) {
275 auto appendSelf = std::make_optional(structDef.
getType());
276 for (Type t : constrainParams) {
277 if (failed(checkMainFuncParamType(t, constrainFunc, appendSelf))) {
284 return constrainFunc.emitError()
287 "\" function argument types (sans the first one) to match \"@",
FUNC_NAME_COMPUTE,
288 "\" function argument types"
290 .attachNote(computeFunc.getLoc())
297inline LogicalResult verifyStructProduct(
StructDefOp structDef, FuncDefOp productFunc) {
304 ArrayRef<Type> productParams = productFunc.
getFunctionType().getInputs();
308 for (Type t : productParams) {
309 if (failed(checkMainFuncParamType(t, productFunc, std::nullopt))) {
321 std::optional<FuncDefOp> foundCompute = std::nullopt;
322 std::optional<FuncDefOp> foundConstrain = std::nullopt;
323 std::optional<FuncDefOp> foundProduct = std::nullopt;
331 if (!bodyRegion.empty()) {
332 for (Operation &op : bodyRegion.front()) {
333 auto member = llvm::dyn_cast<MemberDefOp>(op);
335 if (
FuncDefOp funcDef = llvm::dyn_cast<FuncDefOp>(op)) {
336 if (funcDef.nameIsCompute()) {
338 return structFuncDefError(funcDef.getOperation())
341 foundCompute = std::make_optional(funcDef);
342 }
else if (funcDef.nameIsConstrain()) {
343 if (foundConstrain) {
344 return structFuncDefError(funcDef.getOperation())
347 foundConstrain = std::make_optional(funcDef);
348 }
else if (funcDef.nameIsProduct()) {
350 return structFuncDefError(funcDef.getOperation())
353 foundProduct = std::make_optional(funcDef);
357 return structFuncDefError(funcDef.getOperation())
358 <<
"found \"@" << funcDef.getSymName() <<
'"';
361 return op.emitOpError()
369 failed(checkMainFuncOutputSignalType(member.getType(), *
this))) {
376 if (!foundCompute.has_value() && foundConstrain.has_value()) {
380 if (!foundConstrain.has_value() && foundCompute.has_value()) {
386 if (!foundCompute.has_value() && !foundConstrain.has_value() && !foundProduct.has_value()) {
387 return structFuncDefError(getOperation())
393 auto nonderived = [](std::optional<FuncDefOp> op) ->
bool {
397 auto attachDerivedNotes = [&foundCompute, &foundConstrain,
398 &foundProduct](InFlightDiagnostic &&error) {
400 error.attachNote(foundProduct->getLoc()) <<
"derived \"@" <<
FUNC_NAME_PRODUCT <<
"\" here";
403 error.attachNote(foundCompute->getLoc()) <<
"derived \"@" <<
FUNC_NAME_COMPUTE <<
"\" here";
406 error.attachNote(foundConstrain->getLoc())
416 if (!nonderived(foundCompute) && !nonderived(foundConstrain) && !nonderived(foundProduct)) {
417 return attachDerivedNotes(
418 structFuncDefError(getOperation())
425 if (nonderived(foundCompute) ^ nonderived(foundConstrain)) {
426 return attachDerivedNotes(
427 structFuncDefError(getOperation())
429 <<
"\" must both be either derived or non-derived"
435 if (nonderived(foundCompute) && nonderived(foundConstrain) && !nonderived(foundProduct)) {
436 return verifyStructComputeConstrain(*
this, *foundCompute, *foundConstrain);
439 assert(!nonderived(foundCompute) && !nonderived(foundConstrain) && nonderived(foundProduct));
440 return verifyStructProduct(*
this, *foundProduct);
444 for (Operation &op : *getBody()) {
445 if (
MemberDefOp memberDef = llvm::dyn_cast_if_present<MemberDefOp>(op)) {
446 if (memberName.compare(memberDef.getSymNameAttr()) == 0) {
455 std::vector<MemberDefOp> res;
456 for (Operation &op : *getBody()) {
457 if (
MemberDefOp memberDef = llvm::dyn_cast_if_present<MemberDefOp>(op)) {
458 res.push_back(memberDef);
478 if (succeeded(mainTypeOpt)) {
479 if (
StructType mainType = mainTypeOpt.value()) {
489 auto &prop = state.getOrAddProperties<
Properties>();
492 if (succeeded(versionOpt)) {
494 if (ver.majorVersion < 2) {
497 ArrayAttr constParams;
498 if (failed(reader.readOptionalAttribute(constParams))) {
502 state.addAttribute(llzk::kV1ConstParamsAttr, constParams);
504 return reader.readAttribute(prop.sym_name);
509 return reader.readAttribute(prop.sym_name);
514 auto &prop = getProperties();
515 writer.writeAttribute(prop.sym_name);
523 OpBuilder &odsBuilder, OperationState &odsState, StringAttr sym_name, TypeAttr type,
524 bool isSignal,
bool isColumn
530 props.column = odsBuilder.getUnitAttr();
533 props.signal = odsBuilder.getUnitAttr();
538 OpBuilder &odsBuilder, OperationState &odsState, StringRef sym_name, Type type,
bool isSignal,
542 odsBuilder, odsState, odsBuilder.getStringAttr(sym_name), TypeAttr::get(type), isSignal,
548 OpBuilder &odsBuilder, OperationState &odsState, TypeRange resultTypes, ValueRange operands,
549 ArrayRef<NamedAttribute> attributes,
bool isSignal,
bool isColumn
551 assert(operands.size() == 0u &&
"mismatched number of parameters");
552 odsState.addOperands(operands);
553 odsState.addAttributes(attributes);
554 assert(resultTypes.size() == 0u &&
"mismatched number of return types");
555 odsState.addTypes(resultTypes);
557 odsState.getOrAddProperties<
Properties>().column = odsBuilder.getUnitAttr();
560 odsState.getOrAddProperties<
Properties>().signal = odsBuilder.getUnitAttr();
566 getOperation()->setAttr(PublicAttr::name, UnitAttr::get(getContext()));
568 getOperation()->removeAttr(PublicAttr::name);
573verifyMemberDefTypeImpl(Type memberType, SymbolTableCollection &tables, Operation *origin) {
574 if (
StructType memberStructType = llvm::dyn_cast<StructType>(memberType)) {
578 if (failed(memberTypeRes)) {
582 assert(parentRes &&
"MemberDefOp parent is always StructDefOp");
583 if (memberTypeRes.value() == parentRes) {
584 return origin->emitOpError()
585 .append(
"type is circular")
586 .attachNote(parentRes.getLoc())
587 .append(
"references parent component defined here");
596 Type memberType = this->
getType();
597 if (failed(verifyMemberDefTypeImpl(memberType, tables, *
this))) {
606 return emitOpError() <<
"marked as column can only contain felts, arrays of column types, or "
607 "structs with columns, but has type "
615 return emitOpError() <<
"with type " <<
getType() <<
" cannot have the signal attribute";
625FailureOr<SymbolLookupResult<MemberDefOp>>
627 Operation *op = refOp.getOperation();
629 if (failed(structDefRes)) {
633 llvm::SmallVector<llvm::StringRef> structDefOpNs(structDefRes->getNamespace());
635 tables, SymbolRefAttr::get(refOp->getContext(), refOp.
getMemberName()),
636 std::move(*structDefRes), op
645 res->prependNamespace(structDefOpNs);
646 return std::move(res.value());
649static FailureOr<SymbolLookupResult<MemberDefOp>>
657 return getMemberDefOpImpl(refOp, tables, tyStruct);
660static LogicalResult verifySymbolUsesImpl(
662 SymbolLookupResult<MemberDefOp> &member
665 Type actualType = refOp.
getVal().getType();
666 Type memberType = member.
get().getType();
668 return refOp->emitOpError() <<
"has wrong type; expected " << memberType <<
", got "
677 auto member = findMember(refOp, tables);
678 if (failed(member)) {
681 return verifySymbolUsesImpl(refOp, tables, *member);
686FailureOr<SymbolLookupResult<MemberDefOp>>
692 auto member = findMember(*
this, tables);
693 if (failed(member)) {
696 if (failed(verifySymbolUsesImpl(*
this, tables, *member))) {
701 return emitOpError(
"cannot read with table offset from a member that is not a column")
702 .attachNote(member->
get().getLoc())
703 .append(
"member defined here");
709 if (failed(memberParentRes)) {
716 FailureOr<SymbolLookupResult<StructDefOp>> contractTarget;
718 contractTarget = contractParent.getStructTarget(tables);
720 StructDefOp memberParentStruct = memberParentRes.value();
721 bool correctContractTarget =
722 succeeded(contractTarget) && memberParentStruct == contractTarget->get();
723 bool inMemberParent = thisParent && (thisParent == memberParentStruct);
724 bool validParent = inMemberParent || correctContractTarget;
725 if (!member->
get().hasPublicAttr() && !validParent) {
728 "cannot read from private member of struct \"", memberParentStruct.
getHeaderString(),
731 .attachNote(member->
get().getLoc())
732 .append(
"member defined here");
740 if (failed(getParentRes)) {
747 return verifySymbolUsesImpl(*
this, tables);
755 OpBuilder &builder, OperationState &state, Type resultType, Value
component, StringAttr member
759 state.addTypes(resultType);
765 OpBuilder &builder, OperationState &state, Type resultType, Value
component, StringAttr member,
766 Attribute dist, ValueRange mapOperands, std::optional<int32_t> numDims
769 assert(mapOperands.empty() || numDims.has_value());
771 state.addTypes(resultType);
772 if (numDims.has_value()) {
774 builder, state, ArrayRef({mapOperands}), builder.getDenseI32ArrayAttr({*numDims})
780 props.setMemberName(FlatSymbolRefAttr::get(member));
781 props.setTableOffset(dist);
785 OpBuilder & , OperationState &odsState, TypeRange resultTypes,
786 ValueRange operands, ArrayRef<NamedAttribute> attrs
788 odsState.addTypes(resultTypes);
789 odsState.addOperands(operands);
790 odsState.addAttributes(attrs);
794 SmallVector<AffineMapAttr, 1> mapAttrs;
795 if (AffineMapAttr map =
796 llvm::dyn_cast_if_present<AffineMapAttr>(
getTableOffset().value_or(
nullptr))) {
797 mapAttrs.push_back(map);
814 if (failed(getParentRes)) {
817 if (failed(
checkSelfType(tables, *getParentRes, this->getType(), *
this,
"result"))) {
llvm::ArrayRef< llvm::StringRef > getNamespace() const
Return the stack of symbol names from either IncludeOp or ModuleOp that were traversed to load this r...
static constexpr ::llvm::StringLiteral name
::llvm::LogicalResult verifySymbolUses(::mlir::SymbolTableCollection &symbolTable)
void getAsmResultNames(::mlir::OpAsmSetValueNameFn setNameFn)
::mlir::TypedValue<::llzk::component::StructType > getResult()
void setPublicAttr(bool newValue=true)
Adds or removes the unit llzk.pub attribute according to newValue.
static constexpr ::llvm::StringLiteral getOperationName()
static void build(::mlir::OpBuilder &odsBuilder, ::mlir::OperationState &odsState, ::mlir::StringAttr sym_name, ::mlir::TypeAttr type, bool isSignal=false, bool isColumn=false)
::llvm::LogicalResult verifySymbolUses(::mlir::SymbolTableCollection &symbolTable)
::llvm::LogicalResult verify()
FoldAdaptor::Properties Properties
::std::optional<::mlir::Attribute > getTableOffset()
::mlir::OperandRangeRange getMapOperands()
static void build(::mlir::OpBuilder &odsBuilder, ::mlir::OperationState &odsState, ::mlir::Type resultType, ::mlir::Value component, ::mlir::StringAttr member)
::llvm::LogicalResult verifySymbolUses(::mlir::SymbolTableCollection &symbolTable)
::llvm::ArrayRef< int32_t > getNumDimsPerMap()
::llvm::LogicalResult verify()
FoldAdaptor::Properties Properties
::mlir::Value getVal()
Gets the SSA Value that holds the read/write data for the MemberRefOp.
::mlir::FailureOr< SymbolLookupResult< MemberDefOp > > getMemberDefOp(::mlir::SymbolTableCollection &tables)
Gets the definition for the member referenced in this op.
::llvm::StringRef getMemberName()
Gets the member name attribute value from the MemberRefOp.
::llzk::component::StructType getStructType()
Gets the struct type of the target component.
::mlir::TypedValue<::llzk::component::StructType > getComponent()
::llvm::LogicalResult verifySymbolUses(::mlir::SymbolTableCollection &symbolTable)
static mlir::LogicalResult verifyTrait(mlir::Operation *op)
::llvm::SmallVector<::mlir::Attribute > getTemplateParamOpNames()
If this struct.def is within a poly.template, return names of all poly.param within the poly....
StructType getType(::std::optional<::mlir::ArrayAttr > constParams={})
Gets the StructType representing this struct.
::mlir::Region & getBodyRegion()
static constexpr ::llvm::StringLiteral getOperationName()
::llvm::LogicalResult readProperties(::mlir::DialectBytecodeReader &reader, ::mlir::OperationState &state)
::llvm::SmallVector<::mlir::Attribute > getTemplateExprOpNames()
If this struct.def is within a poly.template, return names of all poly.expr within the poly....
::llvm::StringRef getSymName()
::mlir::SymbolRefAttr getFullyQualifiedName()
Return the full name for this struct from the root module, including any surrounding module scopes.
::std::vector< MemberDefOp > getMemberDefs()
Get all MemberDefOp in this structure.
FoldAdaptor::Properties Properties
::llzk::function::FuncDefOp getProductFuncOp()
Gets the FuncDefOp that defines the product function in this structure, if present,...
MemberDefOp getMemberDef(::mlir::StringAttr memberName)
Gets the MemberDefOp that defines the member in this structure with the given name,...
void writeProperties(::mlir::DialectBytecodeWriter &writer)
::llzk::function::FuncDefOp getConstrainFuncOp()
Gets the FuncDefOp that defines the constrain function in this structure, if present,...
bool hasTemplateSymbolBindings()
Return true iff the struct.def appears within a poly.template that defines constant parameters and/or...
::llvm::LogicalResult verifyRegions()
::llzk::function::FuncDefOp getComputeFuncOp()
Gets the FuncDefOp that defines the compute function in this structure, if present,...
bool isMainComponent()
Return true iff this struct.def is the main struct. See llzk::MAIN_ATTR_NAME.
::std::string getHeaderString()
Generate header string, in the same format as the assemblyFormat.
::mlir::SymbolRefAttr getNameRef() const
static StructType get(::mlir::SymbolRefAttr structName)
::mlir::FailureOr< SymbolLookupResult< StructDefOp > > getDefinition(::mlir::SymbolTableCollection &symbolTable, ::mlir::Operation *op, bool reportMissing=true) const
Gets the struct op that defines this struct.
::mlir::LogicalResult verifySymbolRef(::mlir::SymbolTableCollection &symbolTable, ::mlir::Operation *op)
static constexpr ::llvm::StringLiteral name
void setAllowWitnessAttr(bool newValue=true)
Add (resp. remove) the allow_witness attribute to (resp. from) the function def.
::mlir::FunctionType getFunctionType()
bool nameIsCompute()
Return true iff the function name is FUNC_NAME_COMPUTE (if needed, a check that this FuncDefOp is loc...
bool hasAllowWitnessAttr()
Return true iff the function def has the allow_witness attribute.
bool nameIsProduct()
Return true iff the function name is FUNC_NAME_PRODUCT (if needed, a check that this FuncDefOp is loc...
::llvm::StringRef getSymName()
bool nameIsConstrain()
Return true iff the function name is FUNC_NAME_CONSTRAIN (if needed, a check that this FuncDefOp is l...
static constexpr ::llvm::StringLiteral getOperationName()
void setAllowConstraintAttr(bool newValue=true)
Add (resp. remove) the allow_constraint attribute to (resp. from) the function def.
bool hasAllowConstraintAttr()
Return true iff the function def has the allow_constraint attribute.
OpClass::Properties & buildInstantiationAttrsEmptyNoSegments(mlir::OpBuilder &odsBuilder, mlir::OperationState &odsState)
Utility for build() functions that initializes the mapOpGroupSizes, and numDimsPerMap attributes for ...
void buildInstantiationAttrsNoSegments(mlir::OpBuilder &odsBuilder, mlir::OperationState &odsState, mlir::ArrayRef< mlir::ValueRange > mapOperands, mlir::DenseI32ArrayAttr numDimsPerMap)
Utility for build() functions that initializes the mapOpGroupSizes, and numDimsPerMap attributes for ...
LogicalResult verifyAffineMapInstantiations(OperandRangeRange mapOps, ArrayRef< int32_t > numDimsPerMap, ArrayRef< AffineMapAttr > mapAttrs, Operation *origin)
bool isInStruct(Operation *op)
InFlightDiagnostic genCompareErr(StructDefOp expected, Operation *origin, const char *aspect)
LogicalResult checkSelfType(SymbolTableCollection &tables, StructDefOp expectedStruct, Type actualType, Operation *origin, const char *aspect)
Verifies that the given actualType matches the StructDefOp given (i.e., for the "self" type parameter...
FailureOr< StructDefOp > verifyInStruct(Operation *op)
bool isInStructFunctionNamed(Operation *op, char const *funcName)
std::string toStringList(InputIt begin, InputIt end)
Generate a comma-separated string representation by traversing elements from begin to end where the e...
constexpr char FUNC_NAME_COMPUTE[]
Symbol name for the witness generation (and resp.
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...
mlir::FailureOr< SymbolLookupResultUntyped > lookupTopLevelSymbol(mlir::SymbolTableCollection &tables, mlir::SymbolRefAttr symbol, mlir::Operation *origin, bool reportMissing=true)
FailureOr< StructType > getMainInstanceType(Operation *lookupFrom)
constexpr char FUNC_NAME_CONSTRAIN[]
bool structTypesUnify(StructType lhs, StructType rhs, ArrayRef< StringRef > rhsReversePrefix, UnificationMap *unifications)
bool isFeltOrSimpleFeltAggregate(Type ty)
bool isValidColumnType(Type type, SymbolTableCollection &symbolTable, Operation *op)
bool isValidMainSignalType(Type pType)
OpClass getParentOfType(mlir::Operation *op)
Return the closest surrounding parent/ancestor operation that is of type 'OpClass'.
constexpr char FUNC_NAME_PRODUCT[]
constexpr char DERIVED_ATTR_NAME[]
Name of the attribute on a @product func that has been automatically aligned from @compute + @constra...
FailureOr< StructDefOp > verifyStructTypeResolution(SymbolTableCollection &tables, StructType ty, Operation *origin)
LogicalResult verifyParamsOfType(SymbolTableCollection &tables, ArrayRef< Attribute > tyParams, Type parameterizedType, Operation *origin, std::optional< Type > requiredParamType)
LogicalResult verifyTypeResolution(SymbolTableCollection &tables, Operation *origin, Type ty)
OwningEmitErrorFn getEmitOpErrFn(mlir::Operation *op)
mlir::FailureOr< SymbolLookupResultUntyped > lookupSymbolIn(mlir::SymbolTableCollection &tables, mlir::SymbolRefAttr symbol, Within &&lookupWithin, mlir::Operation *origin, bool reportMissing=true)
std::function< InFlightDiagnosticWrapper()> OwningEmitErrorFn
This type is required in cases like the functions below to take ownership of the lambda so it is not ...
mlir::SymbolRefAttr getFullyQualifiedName(mlir::SymbolOpInterface symbol, bool requireParent=true)
Return the full name for this symbol from the root module, including any surrounding symbol table nam...
bool typesUnify(Type lhs, Type rhs, ArrayRef< StringRef > rhsReversePrefix, UnificationMap *unifications)
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...
FailureOr< SymbolRefAttr > getPathFromRoot(SymbolOpInterface to, ModuleOp *foundRoot)
void setSymName(const ::mlir::StringAttr &propValue)
void setMemberName(const ::mlir::FlatSymbolRefAttr &propValue)