@@ -25,16 +25,16 @@ import InteractiveUtils: gen_call_with_extracted_types_and_kwargs
25
25
Evaluates the arguments to the function call, determines its types, and then calls
26
26
[`code_escapes`](@ref) on the resulting expression.
27
27
As with `@code_typed` and its family, any of `code_escapes` keyword arguments can be given
28
- as the optional arguments like `@code_escapes interp=myinterp myfunc(myargs...)`.
28
+ as the optional arguments like `@code_escapes debuginfo=:source myfunc(myargs...)`.
29
29
"""
30
30
macro code_escapes (ex0... )
31
31
return gen_call_with_extracted_types_and_kwargs (__module__, :code_escapes , ex0)
32
32
end
33
33
end # @static if EA_AS_PKG
34
34
35
35
"""
36
- code_escapes(f, argtypes=Tuple{}; [world], [interp]) -> result::EscapeResult
37
- code_escapes(tt::Type{<:Tuple}; [world], [interp]) -> result::EscapeResult
36
+ code_escapes(f, argtypes=Tuple{}; [world], [interp], [debuginfo] ) -> result::EscapeResult
37
+ code_escapes(tt::Type{<:Tuple}; [world], [interp], [debuginfo] ) -> result::EscapeResult
38
38
39
39
Runs the escape analysis on optimized IR of a generic function call with the given type signature.
40
40
Note that the escape analysis runs after inlining, but before any other optimizations.
@@ -66,44 +66,44 @@ julia> result = code_escapes((String,String,String,String)) do s1, s2, s3, s4
66
66
return s2, s3, s4
67
67
end
68
68
#1(X _2::String, ↑ _3::String, ↑ _4::String, ✓ _5::String) in Main at REPL[6]:2
69
- 2 X 1 ── %1 = %new(Base.RefValue{String}, _2)::Base.RefValue{String} │╻╷╷ Ref
70
- 3 *′ │ %2 = %new(Base.RefValue{String}, _3)::Base.RefValue{String} │╻╷╷ Ref
71
- 4 ✓′ └─── %3 = %new(SafeRef{String}, _4)::SafeRef{String} │╻╷ SafeRef
72
- 5 ◌ 2 ── %4 = \$ (Expr(:enter, #8)) │
73
- ✓′ │ %5 = ϒ (%3)::SafeRef{String} │
74
- *′ │ %6 = ϒ (%2)::Base.RefValue{String} │
75
- ✓ └─── %7 = ϒ (_5)::String │
76
- 6 ◌ 3 ── %8 = Base.isdefined(%1, :x)::Bool │╻╷ get′
77
- ◌ └─── goto #5 if not %8 ││
78
- X 4 ── Base.getfield(%1, :x)::String ││╻ getindex
79
- ◌ └─── goto #6 ││
80
- ◌ 5 ── Main.throw(%1)::Union{} ││
81
- ◌ └─── unreachable ││
82
- 7 ◌ 6 ── nothing::typeof(Core.sizeof) │╻ sizeof
83
- ◌ │ nothing::Int64 ││
84
- ◌ └─── \$ (Expr(:leave, 1)) │
85
- ◌ 7 ── goto #10 │
86
- ✓′ 8 ── %18 = φᶜ (%5)::SafeRef{String} │
87
- *′ │ %19 = φᶜ (%6)::Base.RefValue{String} │
88
- ✓ │ %20 = φᶜ (%7)::String │
89
- ◌ └─── \$ (Expr(:leave, 1)) │
90
- X 9 ── %22 = \$ (Expr(:the_exception))::Any │
91
- 9 ◌ │ (Main.g = %22)::Any │
92
- ◌ └─── \$ (Expr(:pop_exception, :(%4)))::Any │
93
- 11 ✓′ 10 ┄ %25 = φ (#7 => %3, #9 => %18)::SafeRef{String} │
94
- *′ │ %26 = φ (#7 => %2, #9 => %19)::Base.RefValue{String} │
95
- ✓ │ %27 = φ (#7 => _5, #9 => %20)::String │
96
- ◌ │ %28 = Base.isdefined(%26, :x)::Bool ││╻ isassigned
97
- ◌ └─── goto #12 if not %28 ││
98
- ↑ 11 ─ %30 = Base.getfield(%26, :x)::String │││╻ getproperty
99
- ◌ └─── goto #13 ││
100
- ◌ 12 ─ Main.throw(%26)::Union{} ││
101
- ◌ └─── unreachable ││
102
- 12 ↑ 13 ─ %34 = Base.getfield(%25, :x)::String │╻╷╷ get′
103
- 13 ◌ │ %35 = Core.sizeof::typeof(Core.sizeof) │╻ sizeof
104
- ◌ │ %36 = (%35)(%27)::Int64 ││
105
- 14 ↑ │ %37 = Core.tuple(%30, %34, %36)::Tuple{String, String, Int64} │
106
- ◌ └─── return %37 │
69
+ X 1 ── %1 = %new(Base.RefValue{String}, _2)::Base.RefValue{String}
70
+ *′ │ %2 = %new(Base.RefValue{String}, _3)::Base.RefValue{String}
71
+ ✓′ └─── %3 = %new(SafeRef{String}, _4)::SafeRef{String}
72
+ ◌ 2 ── %4 = \$ (Expr(:enter, #8))
73
+ ✓′ │ %5 = ϒ (%3)::SafeRef{String}
74
+ *′ │ %6 = ϒ (%2)::Base.RefValue{String}
75
+ ✓ └─── %7 = ϒ (_5)::String
76
+ ◌ 3 ── %8 = Base.isdefined(%1, :x)::Bool
77
+ ◌ └─── goto #5 if not %8
78
+ X 4 ── Base.getfield(%1, :x)::String
79
+ ◌ └─── goto #6
80
+ ◌ 5 ── Main.throw(%1)::Union{}
81
+ ◌ └─── unreachable
82
+ ◌ 6 ── nothing::typeof(Core.sizeof)
83
+ ◌ │ nothing::Int64
84
+ ◌ └─── \$ (Expr(:leave, 1))
85
+ ◌ 7 ── goto #10
86
+ ✓′ 8 ── %18 = φᶜ (%5)::SafeRef{String}
87
+ *′ │ %19 = φᶜ (%6)::Base.RefValue{String}
88
+ ✓ │ %20 = φᶜ (%7)::String
89
+ ◌ └─── \$ (Expr(:leave, 1))
90
+ X 9 ── %22 = \$ (Expr(:the_exception))::Any
91
+ ◌ │ (Main.g = %22)::Any
92
+ ◌ └─── \$ (Expr(:pop_exception, :(%4)))::Any
93
+ ✓′ 10 ┄ %25 = φ (#7 => %3, #9 => %18)::SafeRef{String}
94
+ *′ │ %26 = φ (#7 => %2, #9 => %19)::Base.RefValue{String}
95
+ ✓ │ %27 = φ (#7 => _5, #9 => %20)::String
96
+ ◌ │ %28 = Base.isdefined(%26, :x)::Bool
97
+ ◌ └─── goto #12 if not %28
98
+ ↑ 11 ─ %30 = Base.getfield(%26, :x)::String
99
+ ◌ └─── goto #13
100
+ ◌ 12 ─ Main.throw(%26)::Union{}
101
+ ◌ └─── unreachable
102
+ ↑ 13 ─ %34 = Base.getfield(%25, :x)::String
103
+ ◌ │ %35 = Core.sizeof::typeof(Core.sizeof)
104
+ ◌ │ %36 = (%35)(%27)::Int64
105
+ ↑ │ %37 = Core.tuple(%30, %34, %36)::Tuple{String, String, Int64}
106
+ ◌ └─── return %37
107
107
```
108
108
109
109
The symbols in the side of each call argument and SSA statements represents the following meaning:
@@ -125,11 +125,12 @@ NoEscape′
125
125
"""
126
126
function code_escapes (@nospecialize (args... );
127
127
world = get_world_counter (),
128
- interp = Core. Compiler. NativeInterpreter (world))
128
+ interp = Core. Compiler. NativeInterpreter (world),
129
+ debuginfo = :none )
129
130
interp = EscapeAnalyzer (interp)
130
131
results = code_typed (args... ; optimize= true , world, interp)
131
132
isone (length (results)) || throw (ArgumentError (" `code_escapes` only supports single analysis result" ))
132
- return EscapeResult (interp. ir, interp. state, interp. linfo)
133
+ return EscapeResult (interp. ir, interp. state, interp. linfo, debuginfo === :source )
133
134
end
134
135
135
136
# AbstractInterpreter
@@ -342,10 +343,14 @@ struct EscapeResult
342
343
ir:: IRCode
343
344
state:: EscapeState
344
345
linfo:: Union{Nothing,MethodInstance}
345
- EscapeResult (ir:: IRCode , state:: EscapeState , linfo:: Union{Nothing,MethodInstance} = nothing ) =
346
- new (ir, state, linfo)
346
+ source:: Bool
347
+ function EscapeResult (ir:: IRCode , state:: EscapeState ,
348
+ linfo:: Union{Nothing,MethodInstance} = nothing ,
349
+ source:: Bool = false )
350
+ return new (ir, state, linfo, source)
351
+ end
347
352
end
348
- Base. show (io:: IO , result:: EscapeResult ) = print_with_info (io, result. ir, result . state, result . linfo )
353
+ Base. show (io:: IO , result:: EscapeResult ) = print_with_info (io, result)
349
354
@eval Base. iterate (res:: EscapeResult , state= 1 ) =
350
355
return state > $ (fieldcount (EscapeResult)) ? nothing : (getfield (res, state), state+ 1 )
351
356
@@ -356,8 +361,7 @@ Base.show(io::IO, result::EscapeResult) = print_with_info(io, result.ir, result.
356
361
end
357
362
358
363
# adapted from https://github.com/JuliaDebug/LoweredCodeUtils.jl/blob/4612349432447e868cf9285f647108f43bd0a11c/src/codeedges.jl#L881-L897
359
- function print_with_info (io:: IO ,
360
- ir:: IRCode , state:: EscapeState , linfo:: Union{Nothing,MethodInstance} )
364
+ function print_with_info (io:: IO , (; ir, state, linfo, source):: EscapeResult )
361
365
# print escape information on SSA values
362
366
function preprint (io:: IO )
363
367
ft = ir. argtypes[1 ]
@@ -389,17 +393,20 @@ function print_with_info(io::IO,
389
393
printstyled (io, rpad (c, 2 ), ' ' ; color)
390
394
end
391
395
392
- print_with_info (preprint, (args... )-> nothing , io, ir)
396
+ print_with_info (preprint, (args... )-> nothing , io, ir, source )
393
397
end
394
398
395
- function print_with_info (preprint, postprint, io:: IO , ir:: IRCode )
399
+ function print_with_info (preprint, postprint, io:: IO , ir:: IRCode , source :: Bool )
396
400
io = IOContext (io, :displaysize => displaysize (io))
397
401
used = Base. IRShow. stmts_used (io, ir)
398
- # line_info_preprinter = Base.IRShow.lineinfo_disabled
399
- line_info_preprinter = function (io:: IO , indent:: String , idx:: Int )
400
- r = Base. IRShow. inline_linfo_printer (ir)(io, indent, idx)
401
- idx ≠ 0 && preprint (io, idx)
402
- return r
402
+ if source
403
+ line_info_preprinter = function (io:: IO , indent:: String , idx:: Int )
404
+ r = Base. IRShow. inline_linfo_printer (ir)(io, indent, idx)
405
+ idx ≠ 0 && preprint (io, idx)
406
+ return r
407
+ end
408
+ else
409
+ line_info_preprinter = Base. IRShow. lineinfo_disabled
403
410
end
404
411
line_info_postprinter = Base. IRShow. default_expr_type_printer
405
412
preprint (io)
0 commit comments