# Porting Relay Passes to Pass Manager
As the pass manager framework has been merged, we should start to move passes
to the pass manager. This RFC proposes the plans to move the Relay passes.
## Proposal (take constant folding as an example):
The proposal needs to solve problems from both the backend and the frontend. As
this could be a lot of refactoring work, we will mainly focus on the API
changes of the pass functions first, but leave others (like resolving
dependency) as follow-up work.
### C++ Backend
The C++ backend implements the functionality of a certain pass as the
`pass_func` for `module_pass` and `function_pass`, i.e. constant folding in
this example. Some passes are passed with a `Module` to identify global vars
and/or help report errors, but others are not.
1. Pass `Module` to every pass, or have a global `Module`? When `Module` is not
passed, we can call `GetModule`, like `FromExpr`. For backward compatibility,
we can default it to null. Therefore, users can still invoke the pass as
before. All frontend converters should return a module as well.
2. Previously, many passes are not aware of PassContext. We probably should
pass PassContext into a pass so that the internal context, e.g. ErrorReporter,
can be used by each pass.
3. How can a pass provide the frontend with the most convenient API so that it
could be invoked easily?
```c++
class ConstantFolder : public ExprMutator {
private:
PassContext pass_ctx;
// Other members are omitted..
};
Expr FoldConstant(const Expr& expr, const PassContext& ctx) {
return ConstantFolder(CreateInterpreter(...), ctx).Mutate(expr);
}
TVM_REGISTER_API("relay._ir_pass.FoldConstant")
.set_body([](TVMArgs args, TVMRetValue *ret) {
PassContext ctx = args[1];
if (!ctx.defined()) {
ctx = PassContext();
}
*ret = FoldConstant(args[0], ctx);
});
```
### Python frontend
Python frontend performs the following tasks
- Link to a pass function, i.e. `ir_pass.fold_constant`
- Register the pass using flattened pass info, e.g. `opt_level`, `name`, and
`required` passes.
- Setup `PassContext` when necessary. Otherwise, the backend will create it.
- Create a module for pass execution if it is not passed.
- Have an API to invoke pass functions in different manner?
- The old style invocation, `mypass(mod/expr)`, depending on the type
of pass, e.g. `ir_pass.fold_constant(expr)`
- Through pass manager
```python
# Create a module for all passes?
mod = relay.Module({})
# Method 1, Use decorator:
@ir_pass.function_pass(opt_level=opt_level, name=pass_name)
def mypass(expr, ctx):
class Transform(ExprVisitor):
def __init__():
def __call__(expr, ctx):
return Transform(expr, ctx)
mypass(mod)
# Method 2, pass registered passes directly:
pass_func = ir_pass.fold_constant
cf = ir_pass.function_pass(pass_func, opt_level=2, name=”FoldConstant”,
required=[])
cf(mod)
```
## Next Steps
- One pass may call another pass directly. We should setup the `required` field
and resolve dependencies. After that, this pass should be able to access the
returned analysis/optimization results.
- How to represent a `Pass` using pass info, particularly pass name. To resolve
pass dependency, we may only have the `required` passes. We then need to create
theses pass and execute them.
--
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/dmlc/tvm/issues/3146