- Sponsor
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
Add code_ircode
#45306
Add code_ircode
#45306
Conversation
This looks very useful. Your ShowCode.jl package has been very nice for working at the IRCode level |
Co-authored-by: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com>
A very exciting showcase of this PR!: https://nbviewer.org/gist/tkf/d4734be24d2694a3afd669f8f50e6b0f/00_notebook.ipynb |
Also, FYI, I'll probably tweak the API a little bit. So, the exact API may be a bit different by the time we merge #45305. But it'll have a similar flavor. |
To match `typeinf_ircode` with how typeinf lock is used ATM (i.e., optimizer is run inside the lock), we can manually lock it because the lock is re-entrant.
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.
Yep, let's go ahead!
Yup, looks good! |
base/compiler/optimize.jl
Outdated
""" | ||
function run_minimal_passes(ci::CodeInfo, sv::OptimizationState, caller::InferenceResult) | ||
@timeit "convert" ir = convert_to_ircode(ci, sv) | ||
@timeit "slot2reg" ir = slot2reg(ir, ci, sv) |
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.
I would not consider this to be a minimal pass, since it is quite a significant optimization and change to the IR
@timeit "slot2reg" ir = slot2reg(ir, ci, sv) |
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.
I think it would be very rare to deal with IRCode
without slog2reg (unless you are changing slog2reg itself). For one thing, verify_ir
considers IRCode
with slots invalid:
julia/base/compiler/ssair/verify.jl
Lines 47 to 48 in 2159bfb
elseif isa(op, Union{SlotNumber, TypedSlot}) | |
@verify_error "Left over slot detected in converted IR" |
So, I think running slot2reg with optimize = false
makes sense, if we treat it as "least optimized typical IRCode
that compiler passes deal with." But running slot2reg manually is not super hard. So I don't have super strong opinion about it.
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.
I guess we can also pass numeric optimize_level
function run_passes(ci::CodeInfo, sv::OptimizationState, caller::InferenceResult, optimize_level = typeinf(Int))
stage = 1
isdone() = optimize_level < (stage += 1)
@timeit "convert" ir = convert_to_ircode(ci, sv)
isdone() && return ir
@timeit "slot2reg" ir = slot2reg(ir, ci, sv)
isdone() && return ir
# TODO: Domsorting can produce an updated domtree - no need to recompute here
@timeit "compact 1" ir = compact!(ir)
isdone() && return ir
@timeit "Inlining" ir = ssa_inlining_pass!(ir, ir.linetable, sv.inlining, ci.propagate_inbounds)
isdone() && return ir
...
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.
I prefer running slot2reg
as we often work on post-slot2reg
IRCode
when developing Julia-level optimizer. I also think the other "pre-inlining optimizations (mostly DCE)" happening within convert_to_ircode
and type_annotate!
is also significant anyway.
And the optimize_level
idea sounds very useful!
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.
I added optimize_level
04797d5
julia> function demo(f)
y = f()
y isa Any ? nothing : f()
end;
julia> Base.code_ircode(demo; optimize_level = 1) |> only |> first
2 1 ─ (_3 = (_2)())::#UNDEF │
3 │ %2 = (_3 isa Main.Any)::#UNDEF │
└── goto #5 if not %2::#UNDEF │
2 ─ return Main.nothing::#UNDEF │
3 ─ Core.Const(:((_2)()))::#UNDEF │
│ Core.Const(:(return %5))::#UNDEF │
└── unreachable::#UNDEF │
julia> Base.code_ircode(demo; optimize_level = 2) |> only |> first
2 1 ─ %1 = (_2)()::Any │
3 │ %2 = (%1 isa Main.Any)::Core.Const(true) │
└── goto #3 if not %2 │
2 ─ return Main.nothing │
3 ─ Core.Const(:((_2)()))::Union{} │
│ Core.Const(:(return %5))::Union{} │
└── unreachable │
julia> Base.code_ircode(demo) |> only |> first
2 1 ─ (_2)()::Any │
3 └── goto #3 if not true │
2 ─ return Main.nothing │
3 ─ unreachable │
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Just in case: @nanosoldier |
Your benchmark job has completed - no performance regressions were detected. A full report can be found here. |
Good to go? @vtjnash Do you want to review this? |
When working on code like #45305, it would be helpful if we can easily get "real"
IRCode
examples. It's also useful for writing tests. So, I wonder if we can have acode_typed
-like API forIRCode
?