-
Notifications
You must be signed in to change notification settings - Fork 123
Feat: Add API for Defining Symbolic Codegen Optimization Rules #812
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat: Add API for Defining Symbolic Codegen Optimization Rules #812
Conversation
Benchmark Results (Julia vlts)Time benchmarks
Memory benchmarks
|
AayushSabharwal
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it also help if I changed CSE so that the i'th element can be referred to with something like Code.cse_var[i]?
| OptimizationRule(name, detector, transformer, priority) | ||
| Defines an optimization rule with: | ||
| - `name`: A string identifier for the optimization. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're enforcing that the name is a string, should the field just be typed as ::String?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same applies for priority. Why not just make it Int? Less prone to errors.
| The detector function should implement the signature | ||
| ```julia | ||
| detector(expr::Code.Let, state::Code.CSEState) -> Union{Nothing, Vector{<:AbstractMatched}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does this need to return a Union? Can we just always return a Vector and check isempty? We should also document exactly what expr and state are, what modifications we can/cannot make to them, etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nothing is easier to ID imo, and can be used to dispatch as a shortcut if needed.
| priority::P | ||
| end | ||
|
|
||
| abstract type AbstractMatched end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there some sort of interface on AbstractMatched?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's more intended to be a part of the interface for OptimizationRule which returns matched objects that get passed to the transformation function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, but if AbstractMatched has no contract it doesn't really have a reason to exist? Or will a contract be added in the future?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The basic case is that the matched objects might contain wildly different fields/ data. It is specific to the optimization. What kind of contract did you have in mind? Its a container that passes information from the detection to the transformation.
src/code.jl
Outdated
|
|
||
| abstract type AbstractMatched end | ||
|
|
||
| function bank(dic, key, value) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All of these utility functions should be documented. It's not clear what the arguments are or what the function is intended to do.
| Base.isempty(l::Code.Let) = isempty(l.pairs) | ||
|
|
||
| # Apply optimization rules during CSE | ||
| function apply_optimization_rules(expr, state::Code.CSEState, rules) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The argument is named rules (along with the function name) but the function body treats it as a single rule?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes, I previously had it as a for loop over the rules sorted by priority. That way we could pass a number of rules transforming the code at every step.I had run into the case that that would require the detection functions to handle things like aliasing, which they should be aware of anyway but does add some complexity at the get go. If preferred we can add that aa a requirement and I'll work on checking what code we have that could potentially run afowl of these subtleties
Benchmark Results (Julia v1)Time benchmarks
Memory benchmarks
|
844e350
into
JuliaSymbolics:master
Adds an API that can define and apply optimizing rules on existing IR. Also allows for downstream packages to use as a hook to add additional rules as needed.