24#include <mlir/IR/Builders.h>
25#include <mlir/IR/SymbolTable.h>
27#include <llvm/ADT/DenseMap.h>
28#include <llvm/ADT/DenseSet.h>
29#include <llvm/ADT/STLExtras.h>
30#include <llvm/Support/raw_ostream.h>
41bool isValidFamilyEntry(TypeAttr type, ArrayAttr indices, IntegerAttr
id) {
42 if (!type || !isa<llzk::component::StructType>(type.getValue()) || !indices || !
id ||
43 !
id.getValue().isSignedIntN(64) ||
id.getInt() < 0) {
46 return llvm::all_of(indices, [](Attribute attr) {
47 auto index = dyn_cast<IntegerAttr>(attr);
48 return index && index.getType().isIndex() && index.getInt() >= 0;
55 explicit LayoutBuilder(ModuleOp module) : builder(module.getContext()) {}
57 FailureOr<llzk::LLZKLayout> build(ModuleOp module) {
59 if (failed(mainType)) {
62 if (*mainType && mainType->getParams() && !mainType->getParams().empty()) {
63 return module.emitError("LLZK layout requires a monomorphized llzk.main");
70 return module.emitError("LLZK layout requires a concrete llzk.main");
72 if (
main->viaInclude()) {
73 return module.emitError("inline includes before exporting an LLZK layout");
80 specializations.emplace(*root);
82 auto constrain =
main->get().getConstrainFuncOp();
84 return main->get().emitError(
"LLZK layout requires a main constrain function");
87 SmallVector<Attribute> path;
89 layout.argumentNames.resize(constrain.getNumArguments());
90 for (
unsigned index = 1; index < constrain.getNumArguments(); ++index) {
91 if (
auto name = constrain.getArgNameAttr(index)) {
92 layout.argumentNames[index] = *name;
97 if (failed(visitType(constrain.getFunctionType().getInput(index), constrain, path,
true))) {
103 if (failed(visitStruct(
main->get(), path,
true))) {
107 return std::move(layout);
111 LogicalResult visitStruct(
112 llzk::component::StructDefOp
definition, SmallVectorImpl<Attribute> &path,
bool isMain =
false
115 return definition.emitError(
"LLZK layout requires monomorphized struct types");
117 if (!activeStructs.insert(
definition).second) {
118 return definition.emitError(
"recursive struct storage has no finite LLZK layout");
120 for (
auto member :
definition.getMemberDefs()) {
121 path.push_back(member.getSymNameAttr());
122 bool isSignal = member.getSignal() || (isMain && member.hasPublicAttr());
123 if (failed(visitType(member.getType(), member, path, isSignal))) {
134 LogicalResult loadFamily(Operation *site) {
135 if (families.contains(site)) {
138 auto &entries = families[site];
143 auto records = dyn_cast<ArrayAttr>(metadata);
145 return site->emitError(
"invalid poly.family metadata for LLZK layout");
147 for (Attribute record : records) {
148 auto dict = dyn_cast<DictionaryAttr>(record);
152 if (!isValidFamilyEntry(type, indices,
id)) {
153 return site->emitError(
"invalid poly.family entry for LLZK layout");
155 if (!entries.try_emplace(std::make_pair(type.getValue(), indices),
id.getInt()).second) {
156 return site->emitError(
"duplicate poly.family entry for LLZK layout");
162 LogicalResult visitType(
163 Type type, Operation *site, SmallVectorImpl<Attribute> &path,
bool isSignal,
164 ArrayRef<int64_t> indices = {}
168 if (!isSignal && !walkContains<llzk::component::StructType>(type)) {
171 if (isa<llzk::felt::FeltType>(type)) {
172 auto signalPath = builder.getArrayAttr(path);
173 layout.signalIds.try_emplace(signalPath, layout.signalPaths.size());
174 layout.signalPaths.push_back(signalPath);
177 if (
auto array = dyn_cast<llzk::array::ArrayType>(type)) {
178 for (int64_t size : array.getShape()) {
180 return site->emitError(
"LLZK layout requires concrete array dimensions");
183 SmallVector<int64_t> elementIndices;
184 return visitArray(array, site, path, isSignal, elementIndices, 0);
186 if (
auto pod = dyn_cast<llzk::pod::PodType>(type)) {
187 for (
auto record : pod.getRecords()) {
188 path.push_back(record.getName());
189 if (failed(visitType(record.getType(), site, path, isSignal, indices))) {
196 if (
auto structure = dyn_cast<llzk::component::StructType>(type)) {
197 if (
auto params = structure.getParams(); params && !params.empty()) {
198 SmallVector<Attribute> indexAttrs;
199 for (int64_t index : indices) {
200 indexAttrs.push_back(builder.getIndexAttr(index));
202 if (failed(loadFamily(site))) {
205 auto found = families[site].find({structure, builder.getArrayAttr(indexAttrs)});
206 if (found == families[site].end()) {
207 return site->emitError(
"missing concrete struct family element for LLZK layout");
210 specializations->resolve(tables, structure, found->second, site,
"LLZK layout");
216 auto definition = structure.getDefinition(tables, site);
221 return site->emitError() <<
"cannot resolve struct type " << structure
222 <<
" for LLZK layout";
225 return site->emitError(
"inline includes before exporting an LLZK layout");
228 return site->emitError(
"LLZK layout requires monomorphized struct types");
232 if (type.isIndex() || isa<IntegerType, llzk::string::StringType>(type)) {
235 return site->emitError() <<
"unsupported or unresolved type " << type <<
" in LLZK layout";
238 LogicalResult visitArray(
239 llzk::array::ArrayType array, Operation *site, SmallVectorImpl<Attribute> &path,
240 bool isSignal, SmallVectorImpl<int64_t> &indices,
unsigned dimension
242 if (dimension == array.getRank()) {
243 return visitType(array.
getElementType(), site, path, isSignal, indices);
245 for (int64_t index = 0; index < array.
getShape()[dimension]; ++index) {
246 path.push_back(builder.getIndexAttr(index));
247 indices.push_back(index);
248 if (failed(visitArray(array, site, path, isSignal, indices, dimension + 1))) {
258 SymbolTableCollection tables;
260 std::optional<StructSpecializationResolver> specializations;
261 llvm::DenseMap<Operation *, llvm::DenseMap<std::pair<Type, ArrayAttr>, int64_t>> families;
262 llvm::DenseSet<Operation *> activeStructs;
263 llzk::LLZKLayout layout;
267void printPath(ArrayAttr path, ArrayRef<StringAttr>
names, llvm::raw_ostream &output) {
269 assert(path && !path.empty() && isa<StringAttr>(path[0]) &&
"expected a layout path root");
276 assert(path.size() >= 2 && isa<IntegerAttr>(path[1]) &&
"expected an argument position");
278 assert(argument > 0 &&
"self is excluded from the layout");
281 names[argument].print(output);
287 for (Attribute segment : path.getValue().drop_front(isMain ? 1 : 2)) {
289 if (
auto name = dyn_cast<StringAttr>(segment)) {
292 output << cast<IntegerAttr>(segment).getInt();
301 return LayoutBuilder(module).build(module);
312 return found->second;
316 output <<
"# LLZK layout map v1\n# signals\n";
317 for (
auto [
id, path] : llvm::enumerate(layout.
signalPaths)) {
318 output <<
"signal " <<
id <<
'\t';
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for and distribution as defined by Sections through of this document Licensor shall mean the copyright owner or entity authorized by the copyright owner that is granting the License Legal Entity shall mean the union of the acting entity and all other entities that control are controlled by or are under common control with that entity For the purposes of this definition control direct or to cause the direction or management of such whether by contract or including but not limited to software source documentation and configuration files Object form shall mean any form resulting from mechanical transformation or translation of a Source including but not limited to compiled object generated and conversions to other media types Work shall mean the work of whether in Source or Object made available under the as indicated by a copyright notice that is included in or attached to the whether in Source or Object that is based or other modifications as a an original work of authorship For the purposes of this Derivative Works shall not include works that remain separable or merely the Work and Derivative Works thereof Contribution shall mean any work of including the original version of the Work and any modifications or additions to that Work or Derivative Works that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner For the purposes of this definition
within a display generated by the Derivative if and wherever such third party notices normally appear The contents of the NOTICE file are for informational purposes only and do not modify the License You may add Your own attribution notices within Derivative Works that You alongside or as an addendum to the NOTICE text from the provided that such additional attribution notices cannot be construed as modifying the License You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for or distribution of Your or for any such Derivative Works as a provided Your and distribution of the Work otherwise complies with the conditions stated in this License Submission of Contributions Unless You explicitly state any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this without any additional terms or conditions Notwithstanding the nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions Trademarks This License does not grant permission to use the trade names
::llvm::ArrayRef< int64_t > getShape() const
::mlir::Type getElementType() const
int main(int argc, char **argv)
constexpr llvm::StringLiteral FAMILY_ATTR
constexpr llvm::StringLiteral FAMILY_SPECIALIZATION_KEY
constexpr llvm::StringLiteral FAMILY_INDICES_KEY
bool isInTemplate(Operation *op)
constexpr llvm::StringLiteral FAMILY_TYPE_KEY
The original affine-parameterized struct family, paired with element indices and a concrete specializ...
void printLLZKLayout(const LLZKLayout &layout, llvm::raw_ostream &output)
Print the logical signal section of the .llzk-layout format.
FailureOr< StructType > getMainInstanceType(Operation *lookupFrom)
mlir::FailureOr< LLZKLayout > buildLLZKLayout(mlir::ModuleOp module)
Enumerate the signal leaves of llzk.main and its constrain arguments.
constexpr T checkedCast(U u) noexcept
FailureOr< ModuleOp > getTopRootModule(Operation *from)
FailureOr< SymbolLookupResult< StructDefOp > > getMainInstanceDef(SymbolTableCollection &symbolTable, Operation *lookupFrom)
constexpr char LAYOUT_ARGUMENT_ROOT[]
Structural path root for a constrain argument, followed by its position.
constexpr char LAYOUT_MAIN_ROOT[]
Structural path root for storage in the main instance.
Logical felt-signal paths in a monomorphized LLZK circuit.
llvm::SmallVector< mlir::ArrayAttr > signalPaths
Structural paths indexed by logical signal ID.
llvm::SmallVector< mlir::StringAttr > argumentNames
Optional display names indexed by constrain argument position.
std::optional< uint64_t > getSignalId(mlir::ArrayAttr path) const
Look up a structural path in this layout.
llvm::DenseMap< mlir::ArrayAttr, uint64_t > signalIds
Reverse mapping from structural storage paths to logical signal IDs.