14#include <mlir/IR/Builders.h>
15#include <mlir/Support/LLVM.h>
17#include <llvm/Support/ErrorHandling.h>
27 auto mod = ModuleOp::create(loc);
33 MLIRContext *ctx =
mod.getContext();
34 if (
auto *dialect = ctx->getOrLoadDialect<
LLZKDialect>()) {
37 llvm::report_fatal_error(
"Could not load LLZK dialect!");
43template <
typename Derived>
46 llvm::report_fatal_error(
"global function " + Twine(funcName) +
" already exists!");
50template <
typename Derived>
53 llvm::report_fatal_error(
"global function " + Twine(funcName) +
" does not exist!");
57template <
typename Derived>
60 llvm::report_fatal_error(
"struct " + Twine(structName) +
" already exists!");
64template <
typename Derived>
67 llvm::report_fatal_error(
"struct " + Twine(structName) +
" does not exist!");
71template <
typename Derived>
74 llvm::report_fatal_error(
"struct " + Twine(structName) +
" already has a compute function!");
78template <
typename Derived>
81 llvm::report_fatal_error(
"struct " + Twine(structName) +
" has no compute function!");
85template <
typename Derived>
88 llvm::report_fatal_error(
"struct " + Twine(structName) +
" already has a constrain function!");
92template <
typename Derived>
95 llvm::report_fatal_error(
"struct " + Twine(structName) +
" has no constrain function!");
99template <
typename Derived>
102 llvm::report_fatal_error(
"struct " + Twine(structName) +
" already has a product function!");
106template <
typename Derived>
109 llvm::report_fatal_error(
"struct " + Twine(structName) +
" has no product function!");
113template <
typename Derived>
115 ensureNoSuchStruct(structName);
117 OpBuilder opBuilder(this->getBodyRegion());
118 auto structDef = opBuilder.create<
StructDefOp>(loc, StringAttr::get(context, structName));
120 (void)structDef.getRegion().emplaceBlock();
121 structMap[structName] = structDef;
123 return static_cast<Derived &
>(*this);
126template <
typename Derived>
128 MLIRContext *
context = op.getContext();
134 fnOp.setAllowWitnessAttr();
135 fnOp.addEntryBlock();
139template <
typename Derived>
141 ensureNoSuchComputeFn(op.getName());
142 computeFnMap[op.getName()] = buildComputeFn(op, loc);
143 return static_cast<Derived &
>(*this);
146template <
typename Derived>
148 ensureStructExists(structName);
149 return insertComputeFn(structMap.at(structName), loc);
152template <
typename Derived>
154 MLIRContext *
context = op.getContext();
160 fnOp.setAllowConstraintAttr();
161 fnOp.addEntryBlock();
165template <
typename Derived>
167 ensureNoSuchConstrainFn(op.getName());
168 constrainFnMap[op.getName()] = buildConstrainFn(op, loc);
169 return static_cast<Derived &
>(*this);
172template <
typename Derived>
174 ensureStructExists(structName);
175 return insertConstrainFn(structMap.at(structName), loc);
178template <
typename Derived>
180 MLIRContext *
context = op.getContext();
186 fnOp.setAllowWitnessAttr();
187 fnOp.setAllowConstraintAttr();
188 fnOp.addEntryBlock();
192template <
typename Derived>
194 ensureNoSuchProductFn(op.getName());
195 productFnMap[op.getName()] = buildProductFn(op, loc);
196 return static_cast<Derived &
>(*this);
199template <
typename Derived>
201 ensureStructExists(structName);
202 return insertProductFn(structMap.at(structName), loc);
205template <
typename Derived>
209 ensureComputeFnExists(caller.getName());
210 ensureComputeFnExists(callee.getName());
212 auto callerFn = computeFnMap.at(caller.getName());
213 auto calleeFn = computeFnMap.at(callee.getName());
215 OpBuilder builder(callerFn.getBody());
216 builder.create<
CallOp>(callLoc, calleeFn);
217 return static_cast<Derived &
>(*this);
220template <
typename Derived>
222 std::string_view caller, std::string_view callee, Location callLoc
224 ensureStructExists(caller);
225 ensureStructExists(callee);
226 return insertComputeCall(structMap.at(caller), structMap.at(callee), callLoc);
229template <
typename Derived>
240 size_t numOps = caller.getBody()->getOperations().size();
241 auto memberName = StringAttr::get(
context, callee.getName().str() + std::to_string(numOps));
246 builder.create<
MemberDefOp>(memberDefLoc, memberName, calleeTy);
251 OpBuilder builder(callerFn.
getBody());
260 return static_cast<Derived &
>(*this);
263template <
typename Derived>
265 std::string_view caller, std::string_view callee, Location callLoc, Location memberDefLoc
267 ensureStructExists(caller);
268 ensureStructExists(callee);
269 return insertConstrainCall(structMap.at(caller), structMap.at(callee), callLoc, memberDefLoc);
272template <
typename Derived>
274 std::string_view funcName, FunctionType type, Location loc,
275 llvm::function_ref<
void(OpBuilder &)> fnBody
277 ensureNoSuchFreeFunc(funcName);
279 OpBuilder opBuilder(this->getBodyRegion());
280 auto funcDef = opBuilder.create<
FuncDefOp>(loc, funcName, type);
281 auto *block = funcDef.addEntryBlock();
283 OpBuilder::InsertionGuard guard(opBuilder);
284 opBuilder.setInsertionPointToEnd(block);
287 freeFuncMap[funcName] = funcDef;
289 return static_cast<Derived &
>(*this);
292template <
typename Derived>
294 FuncDefOp caller, std::string_view callee, Location callLoc
296 ensureFreeFnExists(callee);
297 FuncDefOp calleeFn = freeFuncMap.at(callee);
299 OpBuilder builder(caller.getBody());
300 builder.create<
CallOp>(callLoc, calleeFn);
301 return static_cast<Derived &
>(*this);
306void ModuleBuilder::ensureNoSuchTemplate(std::string_view templateName) {
307 if (templateMap.find(templateName) != templateMap.end()) {
308 llvm::report_fatal_error(
"template " + Twine(templateName) +
" already exists!");
312void ModuleBuilder::ensureTemplateExists(std::string_view templateName) {
313 if (templateMap.find(templateName) == templateMap.end()) {
314 llvm::report_fatal_error(
"template " + Twine(templateName) +
" does not exist!");
320 ensureNoSuchTemplate(templateName);
322 OpBuilder opBuilder(myModule.getBodyRegion());
323 auto templateDef = opBuilder.create<TemplateOp>(loc, StringAttr::get(
context, templateName));
324 opBuilder.setInsertionPointToStart(&templateDef.getBodyRegion().emplaceBlock());
325 for (
unsigned i = 0; i < numParams; ++i) {
326 opBuilder.create<TemplateParamOp>(
327 loc, StringAttr::get(
context,
'T' + std::to_string(i)), TypeAttr()
331 auto key = templateDef.getName();
332 templateMap.emplace(key, std::make_unique<TemplateBuilder>(templateDef));
337void ModuleBuilder::ensureNoSuchNestedModule(std::string_view moduleName) {
338 if (nestedModuleMap.find(moduleName) != nestedModuleMap.end()) {
339 llvm::report_fatal_error(
"nested module " + Twine(moduleName) +
" already exists!");
343void ModuleBuilder::ensureNestedModuleExists(std::string_view moduleName) {
344 if (nestedModuleMap.find(moduleName) == nestedModuleMap.end()) {
345 llvm::report_fatal_error(
"nested module " + Twine(moduleName) +
" does not exist!");
350 ensureNoSuchNestedModule(moduleName);
352 OpBuilder opBuilder(myModule.getBodyRegion());
353 auto nestedMod = opBuilder.create<ModuleOp>(loc);
354 nestedMod.setSymName(moduleName);
356 auto key = *nestedMod.getSymName();
357 nestedModuleMap.emplace(key, std::make_unique<ModuleBuilder>(nestedMod));
mlir::MLIRContext * context
Builds out a LLZK-compliant module and provides utilities for populating that module.
ModuleBuilder & insertTemplate(std::string_view templateName, mlir::Location loc, unsigned numParams=0)
ModuleBuilder & insertNestedModule(std::string_view moduleName, mlir::Location loc)
Derived & insertComputeFn(component::StructDefOp op, mlir::Location loc)
Derived & insertConstrainCall(component::StructDefOp caller, component::StructDefOp callee, mlir::Location callLoc, mlir::Location memberDefLoc)
To call a constraint function, you must:
std::unordered_map< std::string_view, function::FuncDefOp > productFnMap
void ensureNoSuchFreeFunc(std::string_view funcName)
Ensure that a global function with the given funcName has not been added, reporting a fatal error oth...
std::unordered_map< std::string_view, function::FuncDefOp > constrainFnMap
Derived & insertEmptyStruct(std::string_view structName, mlir::Location loc)
static function::FuncDefOp buildComputeFn(component::StructDefOp op, mlir::Location loc)
compute returns the type of the struct that defines it.
Derived & insertComputeCall(component::StructDefOp caller, component::StructDefOp callee, mlir::Location callLoc)
Only requirement for compute is the call itself.
void ensureProductFnExists(std::string_view structName)
Ensure that the given struct has a product function, reporting a fatal error otherwise.
void ensureFreeFnExists(std::string_view funcName)
Ensure that a global function with the given funcName has been added, reporting a fatal error otherwi...
Derived & insertProductFn(component::StructDefOp op, mlir::Location loc)
Derived & insertConstrainFn(component::StructDefOp op, mlir::Location loc)
Derived & insertFreeFunc(std::string_view funcName, ::mlir::FunctionType type, mlir::Location loc, llvm::function_ref< void(mlir::OpBuilder &)> fnBody=nullptr)
void ensureNoSuchProductFn(std::string_view structName)
Ensure that the given struct does not have a product function, reporting a fatal error otherwise.
void ensureStructExists(std::string_view structName)
Ensure that a struct with the given structName exists, reporting a fatal error otherwise.
void ensureNoSuchConstrainFn(std::string_view structName)
Ensure that the given struct does not have a constrain function, reporting a fatal error otherwise.
Derived & insertFreeCall(function::FuncDefOp caller, std::string_view callee, mlir::Location callLoc)
std::unordered_map< std::string_view, function::FuncDefOp > freeFuncMap
void ensureNoSuchComputeFn(std::string_view structName)
Ensure that the given struct does not have a compute function, reporting a fatal error otherwise.
void ensureComputeFnExists(std::string_view structName)
Ensure that the given struct has a compute function, reporting a fatal error otherwise.
void ensureConstrainFnExists(std::string_view structName)
Ensure that the given struct has a constrain function, reporting a fatal error otherwise.
static function::FuncDefOp buildConstrainFn(component::StructDefOp op, mlir::Location loc)
constrain accepts the struct type as the first argument.
std::unordered_map< std::string_view, function::FuncDefOp > computeFnMap
std::unordered_map< std::string_view, component::StructDefOp > structMap
void ensureNoSuchStruct(std::string_view structName)
Ensure that a struct with the given structName has not been added, reporting a fatal error otherwise.
static function::FuncDefOp buildProductFn(component::StructDefOp op, mlir::Location loc)
product returns the type of the struct that defines it.
StructType getType(::std::optional<::mlir::ArrayAttr > constParams={})
Gets the StructType representing this struct.
::mlir::Region & getBodyRegion()
::mlir::Value getSelfValueFromConstrain()
Return the "self" value (i.e.
::mlir::SymbolRefAttr getFullyQualifiedName(bool requireParent=true)
Return the full name for this function from the root module, including all surrounding symbol table n...
::mlir::Region & getBody()
constexpr char FUNC_NAME_COMPUTE[]
Symbol name for the witness generation (and resp.
ExpressionValue mod(const llvm::SMTSolverRef &solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
constexpr char LANG_ATTR_NAME[]
Name of the attribute on the top-level ModuleOp that identifies the ModuleOp as the root module and s...
constexpr char FUNC_NAME_CONSTRAIN[]
constexpr char FUNC_NAME_PRODUCT[]
OwningOpRef< ModuleOp > createLLZKModule(MLIRContext *, Location loc)
void addLangAttrForLLZKDialect(ModuleOp mod)