Skip to content

Commit 32211a6

Browse files
authored
Support debuginfo context option in IRShow for IRCode/IncrementalCompact (#58642)
This allows us to get complete source information during printing for `IRCode` and `IncrementalCompact`, same as we do by default with `CodeInfo`. The user previously had to do: ```julia Compiler.IRShow.show_ir(stdout, ir, Compiler.IRShow.default_config(ir; verbose_linetable=true)) ``` and now, they only need to do: ```julia show(IOContext(stdout, :debuginfo => :source), ir) ```
1 parent 7a5c4b5 commit 32211a6

File tree

2 files changed

+60
-23
lines changed

2 files changed

+60
-23
lines changed

Compiler/src/ssair/show.jl

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ end
200200
end
201201

202202
"""
203-
Compute line number annotations for an IRCode
203+
Compute line number annotations for an IRCode or CodeInfo.
204204
205205
This functions compute three sets of annotations for each IR line. Take the following
206206
example (taken from `@code_typed sin(1.0)`):
@@ -259,7 +259,7 @@ to catch up and print the intermediate scopes. Which scope is printed is indicat
259259
by the indentation of the method name and by an increased thickness of the appropriate
260260
line for the scope.
261261
"""
262-
function compute_ir_line_annotations(code::IRCode)
262+
function compute_ir_line_annotations(code::Union{IRCode,CodeInfo})
263263
loc_annotations = String[]
264264
loc_methods = String[]
265265
loc_lineno = String[]
@@ -269,7 +269,8 @@ function compute_ir_line_annotations(code::IRCode)
269269
last_printed_depth = 0
270270
debuginfo = code.debuginfo
271271
def = :var"unknown scope"
272-
for idx in 1:length(code.stmts)
272+
n = isa(code, IRCode) ? length(code.stmts) : length(code.code)
273+
for idx in 1:n
273274
buf = IOBuffer()
274275
print(buf, "")
275276
stack = buildLineInfoNode(debuginfo, def, idx)
@@ -833,7 +834,7 @@ function new_nodes_iter(compact::IncrementalCompact)
833834
end
834835

835836
# print only line numbers on the left, some of the method names and nesting depth on the right
836-
function inline_linfo_printer(code::IRCode)
837+
function inline_linfo_printer(code::Union{IRCode,CodeInfo})
837838
loc_annotations, loc_methods, loc_lineno = compute_ir_line_annotations(code)
838839
max_loc_width = maximum(length, loc_annotations)
839840
max_lineno_width = maximum(length, loc_lineno)
@@ -902,12 +903,15 @@ function stmts_used(::IO, code::CodeInfo)
902903
return used
903904
end
904905

905-
function default_config(code::IRCode; verbose_linetable=false)
906-
return IRShowConfig(verbose_linetable ? statementidx_lineinfo_printer(code)
907-
: inline_linfo_printer(code);
908-
bb_color=:normal)
906+
function default_config(code::IRCode; debuginfo = :source_inline)
907+
return IRShowConfig(get_debuginfo_printer(code, debuginfo); bb_color=:normal)
908+
end
909+
default_config(code::CodeInfo; debuginfo = :source) = IRShowConfig(get_debuginfo_printer(code, debuginfo))
910+
function default_config(io::IO, src)
911+
debuginfo = get(io, :debuginfo, nothing)
912+
debuginfo !== nothing && return default_config(src; debuginfo)
913+
return default_config(src)
909914
end
910-
default_config(code::CodeInfo) = IRShowConfig(statementidx_lineinfo_printer(code))
911915

912916
function show_ir_stmts(io::IO, ir::Union{IRCode, CodeInfo, IncrementalCompact}, inds, config::IRShowConfig,
913917
sptypes::Vector{VarState}, used::BitSet, cfg::CFG, bb_idx::Int; pop_new_node! = Returns(nothing))
@@ -927,8 +931,7 @@ function finish_show_ir(io::IO, cfg::CFG, config::IRShowConfig)
927931
return nothing
928932
end
929933

930-
function show_ir(io::IO, ir::IRCode, config::IRShowConfig=default_config(ir);
931-
pop_new_node! = new_nodes_iter(ir))
934+
function show_ir(io::IO, ir::IRCode, config::IRShowConfig=default_config(io, ir); pop_new_node! = new_nodes_iter(ir))
932935
used = stmts_used(io, ir)
933936
cfg = ir.cfg
934937
maxssaid = length(ir.stmts) + length(ir.new_nodes)
@@ -938,7 +941,7 @@ function show_ir(io::IO, ir::IRCode, config::IRShowConfig=default_config(ir);
938941
finish_show_ir(io, cfg, config)
939942
end
940943

941-
function show_ir(io::IO, ci::CodeInfo, config::IRShowConfig=default_config(ci);
944+
function show_ir(io::IO, ci::CodeInfo, config::IRShowConfig=default_config(io, ci);
942945
pop_new_node! = Returns(nothing))
943946
used = stmts_used(io, ci)
944947
cfg = compute_basic_blocks(ci.code)
@@ -952,7 +955,7 @@ function show_ir(io::IO, ci::CodeInfo, config::IRShowConfig=default_config(ci);
952955
finish_show_ir(io, cfg, config)
953956
end
954957

955-
function show_ir(io::IO, compact::IncrementalCompact, config::IRShowConfig=default_config(compact.ir))
958+
function show_ir(io::IO, compact::IncrementalCompact, config::IRShowConfig=default_config(io, compact.ir))
956959
cfg = compact.ir.cfg
957960

958961

@@ -1154,3 +1157,35 @@ const __debuginfo = Dict{Symbol, Any}(
11541157
)
11551158
const default_debuginfo = Ref{Symbol}(:none)
11561159
debuginfo(sym) = sym === :default ? default_debuginfo[] : sym
1160+
1161+
const __debuginfo = Dict{Symbol, Any}(
1162+
# :full => src -> statementidx_lineinfo_printer(src), # and add variable slot information
1163+
:source => src -> statementidx_lineinfo_printer(src),
1164+
:source_inline => src -> inline_linfo_printer(src),
1165+
# :oneliner => src -> statementidx_lineinfo_printer(PartialLineInfoPrinter, src),
1166+
:none => src -> lineinfo_disabled,
1167+
)
1168+
1169+
const debuginfo_modes = [:none, :source, :source_inline]
1170+
@assert Set(debuginfo_modes) == Set(keys(__debuginfo))
1171+
1172+
function validate_debuginfo_mode(mode::Symbol)
1173+
in(mode, debuginfo_modes) && return true
1174+
throw(ArgumentError("`debuginfo` must be one of the following: $(join([repr(mode) for mode in debuginfo_modes], ", "))"))
1175+
end
1176+
1177+
const default_debuginfo_mode = Ref{Symbol}(:none)
1178+
function expand_debuginfo_mode(mode::Symbol, default = default_debuginfo_mode[])
1179+
if mode === :default
1180+
mode = default
1181+
end
1182+
validate_debuginfo_mode(mode)
1183+
return mode
1184+
end
1185+
1186+
function get_debuginfo_printer(mode::Symbol)
1187+
mode = expand_debuginfo_mode(mode)
1188+
return __debuginfo[mode]
1189+
end
1190+
1191+
get_debuginfo_printer(src, mode::Symbol) = get_debuginfo_printer(mode)(src)

test/show.jl

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ include("testenv.jl")
88
replstr(x, kv::Pair...) = sprint((io,x) -> show(IOContext(io, :limit => true, :displaysize => (24, 80), kv...), MIME("text/plain"), x), x)
99
showstr(x, kv::Pair...) = sprint((io,x) -> show(IOContext(io, :limit => true, :displaysize => (24, 80), kv...), x), x)
1010

11+
const IRShow = Base.Compiler.IRShow
12+
1113
@testset "IOContext" begin
1214
io = IOBuffer()
1315
ioc = IOContext(io)
@@ -2161,7 +2163,7 @@ end
21612163
function compute_annotations(f, types)
21622164
src = code_typed(f, types, debuginfo=:source)[1][1]
21632165
ir = Core.Compiler.inflate_ir(src)
2164-
la, lb, ll = Base.IRShow.compute_ir_line_annotations(ir)
2166+
la, lb, ll = IRShow.compute_ir_line_annotations(ir)
21652167
max_loc_method = maximum(length(s) for s in la)
21662168
return join((strip(string(a, " "^(max_loc_method-length(a)), b)) for (a, b) in zip(la, lb)), '\n')
21672169
end
@@ -2216,6 +2218,8 @@ eval(Meta._parse_string("""function my_fun28173(x)
22162218
return y
22172219
end""", "a"^80, 1, 1, :statement)[1]) # use parse to control the line numbers
22182220
let src = code_typed(my_fun28173, (Int,), debuginfo=:source)[1][1]
2221+
@test_throws "must be one of the following" sprint(IRShow.show_ir, src; context = :debuginfo => :_)
2222+
@test !contains(sprint(IRShow.show_ir, src; context = :debuginfo => :source_inline), "a"^80)
22192223
ir = Core.Compiler.inflate_ir(src)
22202224
src.debuginfo = Core.DebugInfo(src.debuginfo.def) # IRCode printing defaults to incomplete line info printing, so turn it off completely for CodeInfo too
22212225
let source_slotnames = String["my_fun28173", "x"],
@@ -2245,18 +2249,16 @@ let src = code_typed(my_fun28173, (Int,), debuginfo=:source)[1][1]
22452249
@test pop!(lines2) == "18 │ \$(QuoteNode(3))"
22462250
@test lines1 == lines2
22472251

2248-
# verbose linetable
2249-
io = IOBuffer()
2250-
Base.IRShow.show_ir(io, ir, Base.IRShow.default_config(ir; verbose_linetable=true))
2251-
seekstart(io)
2252-
@test count(contains(r"@ a{80}:\d+ within `my_fun28173"), eachline(io)) == 10
2252+
# debuginfo = :source
2253+
output = sprint(Base.IRShow.show_ir, ir, Base.IRShow.default_config(ir; debuginfo=:source))
2254+
@test count(contains(r"@ a{80}:\d+ within `my_fun28173"), split(output, '\n')) == 10
2255+
@test output == sprint(show, ir; context = :debuginfo => :source)
2256+
@test output != sprint(show, ir)
2257+
@test_throws "must be one of the following" sprint(show, ir; context = :debuginfo => :_)
22532258

22542259
# Test that a bad :invoke doesn't cause an error during printing
22552260
Core.Compiler.insert_node!(ir, 1, Core.Compiler.NewInstruction(Expr(:invoke, nothing, sin), Any), false)
2256-
io = IOBuffer()
2257-
Base.IRShow.show_ir(io, ir)
2258-
seekstart(io)
2259-
@test contains(String(take!(io)), "Expr(:invoke, nothing")
2261+
@test contains(string(ir), "Expr(:invoke, nothing")
22602262
end
22612263

22622264
# Verify that extra instructions at the end of the IR

0 commit comments

Comments
 (0)