@@ -6,56 +6,6 @@ const CC = Core.Compiler
6
6
using .. EscapeAnalysis
7
7
const EA = EscapeAnalysis
8
8
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
-
59
9
# AbstractInterpreter
60
10
# -------------------
61
11
@@ -99,10 +49,10 @@ mutable struct EscapeAnalyzer <: AbstractInterpreter
99
49
const opt_params:: OptimizationParams
100
50
const inf_cache:: Vector{InferenceResult}
101
51
const escape_cache:: EscapeCache
102
- const entry_mi:: MethodInstance
52
+ const entry_mi:: Union{Nothing, MethodInstance}
103
53
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 )
106
56
inf_params = InferenceParams ()
107
57
opt_params = OptimizationParams ()
108
58
inf_cache = InferenceResult[]
@@ -126,8 +76,9 @@ function CC.ipo_dataflow_analysis!(interp::EscapeAnalyzer, opt::OptimizationStat
126
76
estate = try
127
77
analyze_escapes (ir, nargs, 𝕃ₒ, get_escape_cache)
128
78
catch err
129
- @error " error happened within EA, inspect `Main.failed_escapeanalysis`"
130
- Main. failed_escapeanalysis = FailedAnalysis (ir, nargs, get_escape_cache)
79
+ @error " error happened within EA, inspect `Main.failedanalysis`"
80
+ failedanalysis = FailedAnalysis (caller, ir, nargs, get_escape_cache)
81
+ Core. eval (Main, :(failedanalysis = $ failedanalysis))
131
82
rethrow (err)
132
83
end
133
84
if caller. linfo === interp. entry_mi
@@ -157,6 +108,7 @@ function ((; escape_cache)::GetEscapeCache)(mi::MethodInstance)
157
108
end
158
109
159
110
struct FailedAnalysis
111
+ caller:: InferenceResult
160
112
ir:: IRCode
161
113
nargs:: Int
162
114
get_escape_cache:: GetEscapeCache
@@ -302,4 +254,83 @@ function print_with_info(preprint, postprint, io::IO, ir::IRCode, source::Bool)
302
254
return nothing
303
255
end
304
256
257
+ # entries
258
+ # -------
259
+
260
+ using InteractiveUtils: gen_call_with_extracted_types_and_kwargs
261
+
262
+ """
263
+ @code_escapes [options...] f(args...)
264
+
265
+ Evaluates the arguments to the function call, determines its types, and then calls
266
+ [`code_escapes`](@ref) on the resulting expression.
267
+ As with `@code_typed` and its family, any of `code_escapes` keyword arguments can be given
268
+ as the optional arguments like `@code_escapes optimize=false myfunc(myargs...)`.
269
+ """
270
+ macro code_escapes (ex0... )
271
+ return gen_call_with_extracted_types_and_kwargs (__module__, :code_escapes , ex0)
272
+ end
273
+
274
+ """
275
+ code_escapes(f, argtypes=Tuple{}; [world::UInt], [debuginfo::Symbol]) -> result::EscapeResult
276
+ code_escapes(mi::MethodInstance; [world::UInt], [interp::EscapeAnalyzer], [debuginfo::Symbol]) -> result::EscapeResult
277
+
278
+ Runs the escape analysis on optimized IR of a generic function call with the given type signature,
279
+ while caching the analysis results.
280
+
281
+ # Keyword Arguments
282
+
283
+ - `world::UInt = Base.get_world_counter()`:
284
+ controls the world age to use when looking up methods, use current world age if not specified.
285
+ - `interp::EscapeAnalyzer = EscapeAnalyzer(world)`:
286
+ specifies the escape analyzer to use, by default a new analyzer with the global cache is created.
287
+ - `debuginfo::Symbol = :none`:
288
+ controls the amount of code metadata present in the output, possible options are `:none` or `:source`.
289
+ """
290
+ function code_escapes (@nospecialize (f), @nospecialize (types= Base. default_tt (f));
291
+ world:: UInt = get_world_counter (),
292
+ debuginfo:: Symbol = :none )
293
+ tt = Base. signature_type (f, types)
294
+ match = Base. _which (tt; world, raise= true )
295
+ mi = Core. Compiler. specialize_method (match)
296
+ return code_escapes (mi; world, debuginfo)
297
+ end
298
+
299
+ function code_escapes (mi:: MethodInstance ;
300
+ world:: UInt = get_world_counter (),
301
+ interp:: EscapeAnalyzer = EscapeAnalyzer (world, GLOBAL_ESCAPE_CACHE; entry_mi= mi),
302
+ debuginfo:: Symbol = :none )
303
+ frame = Core. Compiler. typeinf_frame (interp, mi, #= run_optimizer=# true )
304
+ isdefined (interp, :result ) || error (" optimization didn't happen: maybe everything has been constant folded?" )
305
+ slotnames = let src = frame. src
306
+ src isa CodeInfo ? src. slotnames : nothing
307
+ end
308
+ return EscapeResult (interp. result. ir, interp. result. estate, interp. result. mi,
309
+ slotnames, debuginfo === :source , interp)
310
+ end
311
+
312
+ """
313
+ code_escapes(ir::IRCode, nargs::Int; [world::UInt], [interp::AbstractInterpreter]) -> result::EscapeResult
314
+
315
+ Runs the escape analysis on `ir::IRCode`.
316
+ `ir` is supposed to be optimized already, specifically after inlining has been applied.
317
+ Note that this version does not cache the analysis results.
318
+
319
+ # Keyword Arguments
320
+
321
+ - `world::UInt = Base.get_world_counter()`:
322
+ controls the world age to use when looking up methods, use current world age if not specified.
323
+ - `interp::AbstractInterpreter = EscapeAnalyzer(world, EscapeCache())`:
324
+ specifies the abstract interpreter to use, by default a new `EscapeAnalyzer` with an empty cache is created.
325
+ """
326
+ function code_escapes (ir:: IRCode , nargs:: Int ;
327
+ world:: UInt = get_world_counter (),
328
+ interp:: AbstractInterpreter = EscapeAnalyzer (world, EscapeCache ()))
329
+ estate = analyze_escapes (ir, nargs, CC. optimizer_lattice (interp), CC. get_escape_cache (interp))
330
+ return EscapeResult (ir, estate) # return back the result
331
+ end
332
+
333
+ # in order to run a whole analysis from ground zero (e.g. for benchmarking, etc.)
334
+ __clear_cache! () = empty! (GLOBAL_EA_CODE_CACHE)
335
+
305
336
end # module EAUtils
0 commit comments