Skip to content

Commit

Permalink
a bunch of minor fixes and improvements (JuliaLang#51421)
Browse files Browse the repository at this point in the history
- fixed the docstring of `ir_inline_unionsplit!`
- simplify `show` for `SlotNumber`
- tweak bootstrap.jl (it slightly improves bootstrapping time)
  • Loading branch information
aviatesk authored Sep 23, 2023
1 parent 2defa57 commit 6bca048
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 37 deletions.
9 changes: 5 additions & 4 deletions base/compiler/bootstrap.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@
# especially try to make sure any recursive and leaf functions have concrete signatures,
# since we won't be able to specialize & infer them at runtime

time() = ccall(:jl_clock_now, Float64, ())
let time() = ccall(:jl_clock_now, Float64, ())

let interp = NativeInterpreter()
interp = NativeInterpreter()

# analyze_escapes_tt = Tuple{typeof(analyze_escapes), IRCode, Int, Bool, TODO}
# analyze_escapes_tt = Tuple{typeof(analyze_escapes), IRCode, Int, TODO}
optimize_tt = Tuple{typeof(optimize), NativeInterpreter, OptimizationState{NativeInterpreter}, InferenceResult}
fs = Any[
# we first create caches for the optimizer, because they contain many loop constructions
# and they're better to not run in interpreter even during bootstrapping
#=analyze_escapes_tt,=# run_passes_ipo_safe,
#=analyze_escapes_tt,=# optimize_tt,
# then we create caches for inference entries
typeinf_ext, typeinf, typeinf_edge,
]
Expand Down
58 changes: 28 additions & 30 deletions base/compiler/ssair/inlining.jl
Original file line number Diff line number Diff line change
Expand Up @@ -504,62 +504,60 @@ end
"""
ir_inline_unionsplit!
The core idea of this function is to simulate the dispatch semantics by generating
(flat) `isa`-checks corresponding to the signatures of union-split dispatch candidates,
and then inline their bodies into each `isa`-conditional block.
This `isa`-based virtual dispatch requires few pre-conditions to hold in order to simulate
the actual semantics correctly.
The primary purpose of this function is to emulate the dispatch behavior by generating flat
`isa`-checks that correspond to the signatures of union-split dispatch candidates.
These checks allow us to inline the method bodies into respective `isa`-conditional blocks.
The first one is that these dispatch candidates need to be processed in order of their specificity,
and the corresponding `isa`-checks should reflect the method specificities, since now their
signatures are not necessarily concrete.
For example, given the following definitions:
Note that two pre-conditions are required for this emulation to work correctly:
1. Ordered Dispatch Candidates
The dispatch candidates must be processed in order of their specificity.
The generated `isa`-checks should reflect this order,
especially since the method signatures may not be concrete.
For instance, with the methods:
f(x::Int) = ...
f(x::Number) = ...
f(x::Any) = ...
and a callsite:
f(x::Any)
then a correct `isa`-based virtual dispatch would be:
A correct `isa`-based dispatch emulation for the call site `f(x::Any)` would look like:
if isa(x, Int)
[inlined/resolved f(x::Int)]
elseif isa(x, Number)
[inlined/resolved f(x::Number)]
else # implies `isa(x, Any)`, which fully covers this call signature,
# otherwise we need to insert a fallback dynamic dispatch case also
else
[inlined/resolved f(x::Any)]
end
Fortunately, `ml_matches` should already sorted them in that way, except cases when there is
any ambiguity, from which we already bail out at this point.
`ml_matches` should already sort the matched method candidates correctly,
except in ambiguous cases, which we've already excluded at this state.
Another consideration is type equality constraint from type variables: the `isa`-checks are
not enough to simulate the dispatch semantics in cases like:
Given a definition:
2. Type Equality Constraints
g(x::T, y::T) where T<:Integer = ...
transform a callsite:
Another factor is the type equality constraint imposed by type variables.
Simple `isa`-checks are insufficient to capture the semantics in some cases.
For example, given the following method definition:
g(x::Any, y::Any)
g(x::T, y::T) where T<:Integer = ...
into the optimized form:
it is _invalid_ to optimize a cal site like `g(x::Any, y::Any)` into:
if isa(x, Integer) && isa(y, Integer)
[inlined/resolved g(x::Integer, y::Integer)]
else
g(x, y) # fallback dynamic dispatch
end
But again, we should already bail out from such cases at this point, essentially by
excluding cases where `case.sig::UnionAll`.
since we also need to check that `x` and `y` are equal types.
But, we've already excluded such cases at this point,
mainly by filtering out `case.sig::UnionAll`,
so there is no need to worry about type equality at this point.
In short, here we can process the dispatch candidates in order, assuming we haven't changed
their order somehow somewhere up to this point.
In essence, we can process the dispatch candidates sequentially,
assuming their order stays the same post-discovery in `ml_matches`.
"""
function ir_inline_unionsplit!(compact::IncrementalCompact, idx::Int, argexprs::Vector{Any},
union_split::UnionSplit, boundscheck::Symbol,
Expand Down
5 changes: 2 additions & 3 deletions base/show.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1778,9 +1778,8 @@ end
function show_unquoted(io::IO, ex::SlotNumber, ::Int, ::Int)
slotid = ex.id
slotnames = get(io, :SOURCE_SLOTNAMES, false)
if (isa(slotnames, Vector{String}) &&
slotid <= length(slotnames::Vector{String}))
print(io, (slotnames::Vector{String})[slotid])
if isa(slotnames, Vector{String}) && slotid length(slotnames)
print(io, slotnames[slotid])
else
print(io, "_", slotid)
end
Expand Down

0 comments on commit 6bca048

Please sign in to comment.