Skip to content

Commit 592ef2a

Browse files
committed
better EAUtils.jl
1 parent 02ed45d commit 592ef2a

File tree

1 file changed

+82
-53
lines changed

1 file changed

+82
-53
lines changed

test/compiler/EscapeAnalysis/EAUtils.jl

Lines changed: 82 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -6,56 +6,6 @@ const CC = Core.Compiler
66
using ..EscapeAnalysis
77
const EA = EscapeAnalysis
88

9-
# entries
10-
# -------
11-
12-
using Base: IdSet, unwrap_unionall, rewrap_unionall
13-
using InteractiveUtils: gen_call_with_extracted_types_and_kwargs
14-
15-
"""
16-
@code_escapes [options...] f(args...)
17-
18-
Evaluates the arguments to the function call, determines its types, and then calls
19-
[`code_escapes`](@ref) on the resulting expression.
20-
As with `@code_typed` and its family, any of `code_escapes` keyword arguments can be given
21-
as the optional arguments like `@code_escapes optimize=false myfunc(myargs...)`.
22-
"""
23-
macro code_escapes(ex0...)
24-
return gen_call_with_extracted_types_and_kwargs(__module__, :code_escapes, ex0)
25-
end
26-
27-
"""
28-
code_escapes(f, argtypes=Tuple{}; [debuginfo::Symbol = :none], [optimize::Bool = true]) -> result::EscapeResult
29-
30-
Runs the escape analysis on optimized IR of a generic function call with the given type signature.
31-
32-
# Keyword Arguments
33-
34-
- `optimize::Bool = true`:
35-
if `true` returns escape information of post-inlining IR (used for local optimization),
36-
otherwise returns escape information of pre-inlining IR (used for interprocedural escape information generation)
37-
- `debuginfo::Symbol = :none`:
38-
controls the amount of code metadata present in the output, possible options are `:none` or `:source`.
39-
"""
40-
function code_escapes(@nospecialize(f), @nospecialize(types=Base.default_tt(f));
41-
world::UInt = get_world_counter(),
42-
debuginfo::Symbol = :none)
43-
tt = Base.signature_type(f, types)
44-
match = Base._which(tt; world, raise=true)
45-
mi = Core.Compiler.specialize_method(match)::MethodInstance
46-
interp = EscapeAnalyzer(world, mi)
47-
frame = Core.Compiler.typeinf_frame(interp, mi, #=run_optimizer=#true)
48-
isdefined(interp, :result) || error("optimization didn't happen: maybe everything has been constant folded?")
49-
slotnames = let src = frame.src
50-
src isa CodeInfo ? src.slotnames : nothing
51-
end
52-
return EscapeResult(interp.result.ir, interp.result.estate, interp.result.mi,
53-
slotnames, debuginfo === :source, interp)
54-
end
55-
56-
# in order to run a whole analysis from ground zero (e.g. for benchmarking, etc.)
57-
__clear_cache!() = empty!(GLOBAL_EA_CODE_CACHE)
58-
599
# AbstractInterpreter
6010
# -------------------
6111

@@ -99,10 +49,10 @@ mutable struct EscapeAnalyzer <: AbstractInterpreter
9949
const opt_params::OptimizationParams
10050
const inf_cache::Vector{InferenceResult}
10151
const escape_cache::EscapeCache
102-
const entry_mi::MethodInstance
52+
const entry_mi::Union{Nothing,MethodInstance}
10353
result::EscapeResultForEntry
104-
function EscapeAnalyzer(world::UInt, entry_mi::MethodInstance,
105-
escape_cache::EscapeCache=GLOBAL_ESCAPE_CACHE)
54+
function EscapeAnalyzer(world::UInt, escape_cache::EscapeCache;
55+
entry_mi::Union{Nothing,MethodInstance}=nothing)
10656
inf_params = InferenceParams()
10757
opt_params = OptimizationParams()
10858
inf_cache = InferenceResult[]
@@ -299,4 +249,83 @@ function print_with_info(preprint, postprint, io::IO, ir::IRCode, source::Bool)
299249
return nothing
300250
end
301251

252+
# entries
253+
# -------
254+
255+
using InteractiveUtils: gen_call_with_extracted_types_and_kwargs
256+
257+
"""
258+
@code_escapes [options...] f(args...)
259+
260+
Evaluates the arguments to the function call, determines its types, and then calls
261+
[`code_escapes`](@ref) on the resulting expression.
262+
As with `@code_typed` and its family, any of `code_escapes` keyword arguments can be given
263+
as the optional arguments like `@code_escapes optimize=false myfunc(myargs...)`.
264+
"""
265+
macro code_escapes(ex0...)
266+
return gen_call_with_extracted_types_and_kwargs(__module__, :code_escapes, ex0)
267+
end
268+
269+
"""
270+
code_escapes(f, argtypes=Tuple{}; [world::UInt], [debuginfo::Symbol]) -> result::EscapeResult
271+
code_escapes(mi::MethodInstance; [world::UInt], [interp::EscapeAnalyzer], [debuginfo::Symbol]) -> result::EscapeResult
272+
273+
Runs the escape analysis on optimized IR of a generic function call with the given type signature,
274+
while caching the analysis results.
275+
276+
# Keyword Arguments
277+
278+
- `world::UInt = Base.get_world_counter()`:
279+
controls the world age to use when looking up methods, use current world age if not specified.
280+
- `interp::EscapeAnalyzer = EscapeAnalyzer(world)`:
281+
specifies the escape analyzer to use, by default a new analyzer with the global cache is created.
282+
- `debuginfo::Symbol = :none`:
283+
controls the amount of code metadata present in the output, possible options are `:none` or `:source`.
284+
"""
285+
function code_escapes(@nospecialize(f), @nospecialize(types=Base.default_tt(f));
286+
world::UInt = get_world_counter(),
287+
debuginfo::Symbol = :none)
288+
tt = Base.signature_type(f, types)
289+
match = Base._which(tt; world, raise=true)
290+
mi = Core.Compiler.specialize_method(match)
291+
return code_escapes(mi; world, debuginfo)
292+
end
293+
294+
function code_escapes(mi::MethodInstance;
295+
world::UInt = get_world_counter(),
296+
interp::EscapeAnalyzer=EscapeAnalyzer(world, GLOBAL_ESCAPE_CACHE; entry_mi=mi),
297+
debuginfo::Symbol = :none)
298+
frame = Core.Compiler.typeinf_frame(interp, mi, #=run_optimizer=#true)
299+
isdefined(interp, :result) || error("optimization didn't happen: maybe everything has been constant folded?")
300+
slotnames = let src = frame.src
301+
src isa CodeInfo ? src.slotnames : nothing
302+
end
303+
return EscapeResult(interp.result.ir, interp.result.estate, interp.result.mi,
304+
slotnames, debuginfo === :source, interp)
305+
end
306+
307+
"""
308+
code_escapes(ir::IRCode, nargs::Int; [world::UInt], [interp::AbstractInterpreter]) -> result::EscapeResult
309+
310+
Runs the escape analysis on `ir::IRCode`.
311+
`ir` is supposed to be optimized already, specifically after inlining has been applied.
312+
Note that this version does not cache the analysis results.
313+
314+
# Keyword Arguments
315+
316+
- `world::UInt = Base.get_world_counter()`:
317+
controls the world age to use when looking up methods, use current world age if not specified.
318+
- `interp::AbstractInterpreter = EscapeAnalyzer(world, EscapeCache())`:
319+
specifies the abstract interpreter to use, by default a new `EscapeAnalyzer` with an empty cache is created.
320+
"""
321+
function code_escapes(ir::IRCode, nargs::Int;
322+
world::UInt = get_world_counter(),
323+
interp::AbstractInterpreter=EscapeAnalyzer(world, EscapeCache()))
324+
estate = analyze_escapes(ir, nargs, CC.optimizer_lattice(interp), CC.get_escape_cache(interp))
325+
return EscapeResult(ir, estate) # return back the result
326+
end
327+
328+
# in order to run a whole analysis from ground zero (e.g. for benchmarking, etc.)
329+
__clear_cache!() = empty!(GLOBAL_EA_CODE_CACHE)
330+
302331
end # module EAUtils

0 commit comments

Comments
 (0)