LLZK 3.0.0
An open-source IR for Zero Knowledge (ZK) circuits
Loading...
Searching...
No Matches
LLZKInliningExtensions.cpp
Go to the documentation of this file.
1//===-- LLZKInliningExtensions.cpp ------------------------------*- C++ -*-===//
2//
3// Part of the LLZK Project, under the Apache License v2.0.
4// See LICENSE.txt for license information.
5// Copyright 2025 Veridise Inc.
6// SPDX-License-Identifier: Apache-2.0
7//
8//===----------------------------------------------------------------------===//
9
25
26#include <mlir/Dialect/ControlFlow/IR/ControlFlowOps.h>
27#include <mlir/Transforms/InliningUtils.h>
28
29using namespace mlir;
30using namespace llzk;
31
32namespace {
33
34template <typename InlinerImpl, typename DialectImpl, typename... RequiredDialects>
35// Suppress false positive from `clang-tidy`
36// NOLINTNEXTLINE(bugprone-crtp-constructor-accessibility)
37struct BaseInlinerInterface : public DialectInlinerInterface {
38protected:
39 using DialectInlinerInterface::DialectInlinerInterface;
40
41public:
42 static void registrationHook(MLIRContext *ctx, DialectImpl *dialect) {
43 dialect->template addInterfaces<InlinerImpl>();
44 if constexpr (sizeof...(RequiredDialects) != 0) {
45 ctx->loadDialect<RequiredDialects...>();
46 }
47 }
48};
49
50// Adapted from `mlir/lib/Dialect/Func/Extensions/InlinerExtension.cpp`
51struct FuncInlinerInterface
52 : public BaseInlinerInterface<
53 FuncInlinerInterface, function::FunctionDialect, cf::ControlFlowDialect> {
54 using BaseInlinerInterface::BaseInlinerInterface;
55
57 bool isLegalToInline(Operation *, Operation *, bool) const final { return true; }
58 bool isLegalToInline(Operation *, Region *, bool, IRMapping &) const final { return true; }
59 bool isLegalToInline(Region *, Region *, bool, IRMapping &) const final { return true; }
60
61 void handleTerminator(Operation *op, Block *newDest) const final {
62 // Only return needs to be handled here. Replace the return with a branch to the dest.
63 // Note: This function is only called when there are multiple blocks in the region being
64 // inlined. In LLZK IR, that would only occur when the `cf` dialect is already used (since no
65 // LLZK dialect defines any kind of cross-block branching ops) so it's fine to add a
66 // `cf::BranchOp` here.
67 if (auto returnOp = llvm::dyn_cast<function::ReturnOp>(op)) {
68 OpBuilder builder(op);
69 builder.create<cf::BranchOp>(op->getLoc(), newDest, returnOp.getOperands());
70 op->erase();
71 }
72 }
73
74 void handleTerminator(Operation *op, ValueRange valuesToRepl) const final {
75 // ASSERT: when region contains a single block, terminator must be ReturnOp
76 assert(llvm::isa<function::ReturnOp>(op));
77
78 // Replace the values directly with the return operands.
79 auto returnOp = llvm::cast<function::ReturnOp>(op);
80 assert(returnOp.getNumOperands() == valuesToRepl.size());
81 for (const auto &it : llvm::enumerate(returnOp.getOperands())) {
82 valuesToRepl[it.index()].replaceAllUsesWith(it.value());
83 }
84 }
85};
86
87template <typename DialectImpl>
88struct FullyLegalForInlining
89 : public BaseInlinerInterface<FullyLegalForInlining<DialectImpl>, DialectImpl> {
90 using BaseInlinerInterface<FullyLegalForInlining<DialectImpl>, DialectImpl>::BaseInlinerInterface;
91
92 bool isLegalToInline(Operation *, Operation *, bool) const override { return true; }
93 bool isLegalToInline(Region *, Region *, bool, IRMapping &) const override { return true; }
94 bool isLegalToInline(Operation *, Region *, bool, IRMapping &) const override { return true; }
95};
96
97} // namespace
98
99namespace llzk {
100
101void registerInliningExtensions(DialectRegistry &registry) {
102 registry.addExtension(FuncInlinerInterface::registrationHook);
103 registry.addExtension(FullyLegalForInlining<component::StructDialect>::registrationHook);
104 registry.addExtension(FullyLegalForInlining<constrain::ConstrainDialect>::registrationHook);
105 registry.addExtension(FullyLegalForInlining<string::StringDialect>::registrationHook);
106 registry.addExtension(FullyLegalForInlining<polymorphic::PolymorphicDialect>::registrationHook);
107 registry.addExtension(FullyLegalForInlining<ram::RAMDialect>::registrationHook);
108 registry.addExtension(FullyLegalForInlining<felt::FeltDialect>::registrationHook);
109 registry.addExtension(FullyLegalForInlining<global::GlobalDialect>::registrationHook);
110 registry.addExtension(FullyLegalForInlining<boolean::BoolDialect>::registrationHook);
111 registry.addExtension(FullyLegalForInlining<array::ArrayDialect>::registrationHook);
112 registry.addExtension(FullyLegalForInlining<cast::CastDialect>::registrationHook);
113 registry.addExtension(FullyLegalForInlining<include::IncludeDialect>::registrationHook);
114 registry.addExtension(FullyLegalForInlining<llzk::LLZKDialect>::registrationHook);
115 registry.addExtension(FullyLegalForInlining<pod::PODDialect>::registrationHook);
116}
117
118} // namespace llzk
void registerInliningExtensions(DialectRegistry &registry)