LLZK 0.1.0
Veridise's ZK Language IR
Loading...
Searching...
No Matches
ArrayToScalarPass.cpp File Reference

This file implements the -llzk-array-to-scalar pass. More...

#include "llzk/Dialect/Array/IR/Ops.h"
#include "llzk/Dialect/Array/Transforms/TransformationPasses.h"
#include "llzk/Dialect/Array/Util/ArrayTypeHelper.h"
#include "llzk/Dialect/Constrain/IR/Dialect.h"
#include "llzk/Dialect/Felt/IR/Dialect.h"
#include "llzk/Dialect/Function/IR/Ops.h"
#include "llzk/Dialect/Include/IR/Dialect.h"
#include "llzk/Util/Concepts.h"
#include <mlir/IR/BuiltinOps.h>
#include <mlir/Pass/PassManager.h>
#include <mlir/Transforms/DialectConversion.h>
#include <mlir/Transforms/Passes.h>
#include <llvm/Support/Debug.h>
#include "llzk/Dialect/Array/Transforms/TransformationPasses.h.inc"
Include dependency graph for ArrayToScalarPass.cpp:

Go to the source code of this file.

Classes

class  llzk::array::impl::ArrayToScalarPassBase< DerivedT >
 

Namespaces

namespace  llzk
 
namespace  llzk::array
 
namespace  llzk::array::impl
 

Macros

#define GEN_PASS_DEF_ARRAYTOSCALARPASS
 
#define DEBUG_TYPE   "llzk-array-to-scalar"
 

Detailed Description

This file implements the -llzk-array-to-scalar pass.

The steps of this transformation are as follows:

  1. Run a dialect conversion that replaces ArrayType fields with N scalar fields.
  2. Run a dialect conversion that does the following:
    • Replace FieldReadOp and FieldWriteOp targeting the fields that were split in step 1 so they instead perform scalar reads and writes from the new fields. The transformation is local to the current op. Therefore, when replacing the FieldReadOp a new array is created locally and all uses of the FieldReadOp are replaced with the new array Value, then each scalar field read is followed by scalar write into the new array. Similarly, when replacing a FieldWriteOp, each element in the array operand needs a scalar read from the array followed by a scalar write to the new field. Making only local changes keeps this step simple and later steps will optimize.
    • Replace ArrayLengthOp with the constant size of the selected dimension.
    • Remove element initialization from CreateArrayOp and instead insert a list of WriteArrayOp immediately following.
    • Desugar InsertArrayOp and ExtractArrayOp into their element-wise scalar reads/writes.
    • Split arrays to scalars in FuncDefOp, CallOp, and ReturnOp and insert the necessary create/read/write ops so the changes are as local as possible (just as described for FieldReadOp and FieldWriteOp)
  3. Run MLIR "sroa" pass to split each array with linear size N into N arrays of size 1 (to prepare for "mem2reg" pass because it's API does not allow for indexing to split aggregates).
  4. Run MLIR "mem2reg" pass to convert all of the size 1 array allocation and access into SSA values. This pass also runs several standard optimizations so the final result is condensed.

Note: This transformation imposes a "last write wins" semantics on array elements. If different/configurable semantics are added in the future, some additional transformation would be necessary before/during this pass so that multiple writes to the same index can be handled properly while they still exist.

Note: This transformation will introduce an undef op when there exists a read from an array index that was not earlier written to.

Definition in file ArrayToScalarPass.cpp.

Macro Definition Documentation

◆ DEBUG_TYPE

#define DEBUG_TYPE   "llzk-array-to-scalar"

Definition at line 83 of file ArrayToScalarPass.cpp.

◆ GEN_PASS_DEF_ARRAYTOSCALARPASS

#define GEN_PASS_DEF_ARRAYTOSCALARPASS

Definition at line 73 of file ArrayToScalarPass.cpp.