LLZK 3.0.0
An open-source IR for Zero Knowledge (ZK) circuits
Loading...
Searching...
No Matches
TransformationPasses.h
Go to the documentation of this file.
1//===-- TransformationPasses.h ----------------------------------*- C++ -*-===//
2//
3// Part of the LLZK Project, under the Apache License v2.0.
4// See LICENSE.txt for license information.
5// Copyright 2026 Project LLZK
6// SPDX-License-Identifier: Apache-2.0
7//
8//===----------------------------------------------------------------------===//
9
10#pragma once
11
13#include "llzk/Pass/PassBase.h"
14#include "llzk/Util/Walk.h"
15
16#include <mlir/Dialect/SCF/IR/SCF.h>
17#include <mlir/IR/Operation.h>
18#include <mlir/IR/ValueRange.h>
19
20#include <llvm/ADT/STLExtras.h>
21#include <llvm/ADT/SmallVector.h>
22
23namespace llzk::pod {
24
25namespace detail {
26
32inline mlir::Operation *findNearestLoopCarriedPodAccess(ReadPodOp readOp) {
33 auto isValueDefinedInside = [](mlir::Operation *ancestor, mlir::Value value) {
34 if (mlir::Operation *defOp = value.getDefiningOp()) {
35 return ancestor->isAncestor(defOp);
36 }
37
38 auto blockArg = llvm::dyn_cast<mlir::BlockArgument>(value);
39 mlir::Operation *parentOp = blockArg.getOwner()->getParentOp();
40 return parentOp && ancestor->isAncestor(parentOp);
41 };
42
43 for (mlir::Operation *parent = readOp->getParentOp(); parent; parent = parent->getParentOp()) {
44 if (!mlir::isa<mlir::scf::ForOp, mlir::scf::WhileOp>(parent) ||
45 isValueDefinedInside(parent, readOp.getPodRef())) {
46 continue;
47 }
48
49 if (walkContainsMatch<WritePodOp>(*parent, [&readOp](WritePodOp writeOp) {
50 return writeOp.getPodRef() == readOp.getPodRef() &&
51 writeOp.getRecordNameAttr() == readOp.getRecordNameAttr();
52 })) {
53 return parent;
54 }
55 }
56 return nullptr;
57}
58
64 mlir::ValueRange values, mlir::TypeRange expectedTypes,
65 llvm::SmallVectorImpl<mlir::Value> &output
66) {
67 if (values.size() != expectedTypes.size()) {
68 return false;
69 }
70
71 llvm::SmallVector<mlir::Value> stagedValues;
72 stagedValues.reserve(values.size());
73 for (auto [value, expectedType] : llvm::zip_equal(values, expectedTypes)) {
74 if (value.getType() != expectedType) {
75 return false;
76 }
77 stagedValues.push_back(value);
78 }
79
80 llvm::append_range(output, stagedValues);
81 return true;
82}
83
84} // namespace detail
85
86#define GEN_PASS_DECL
87#define GEN_PASS_REGISTRATION
89
90} // namespace llzk::pod
::mlir::TypedValue<::llzk::pod::PodType > getPodRef()
Definition Ops.h.inc:480
::mlir::StringAttr getRecordNameAttr()
Definition Ops.h.inc:512
::mlir::StringAttr getRecordNameAttr()
Definition Ops.h.inc:749
::mlir::TypedValue<::llzk::pod::PodType > getPodRef()
Definition Ops.h.inc:712
bool appendValuesWithExactTypes(mlir::ValueRange values, mlir::TypeRange expectedTypes, llvm::SmallVectorImpl< mlir::Value > &output)
Append values only when every entry exactly matches the corresponding expected type.
mlir::Operation * findNearestLoopCarriedPodAccess(ReadPodOp readOp)
Return the nearest enclosing SCF loop that carries writes to the same external POD record.