From 6afde4b740960f39f49afbd8a8d138e7df3a4fdf Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki Date: Wed, 20 Mar 2024 00:58:22 +0900 Subject: [PATCH] set up a specific type to capture the 3-set data of `codelocs` --- base/compiler/ssair/inlining.jl | 13 ++++---- base/compiler/ssair/ir.jl | 54 +++++++++++++++++++++++---------- base/compiler/ssair/passes.jl | 11 ++++--- base/show.jl | 2 ++ doc/src/devdocs/ast.md | 5 +++ test/show.jl | 10 ++++++ 6 files changed, 68 insertions(+), 27 deletions(-) diff --git a/base/compiler/ssair/inlining.jl b/base/compiler/ssair/inlining.jl index 164102758a88f1..d93df28555efcb 100644 --- a/base/compiler/ssair/inlining.jl +++ b/base/compiler/ssair/inlining.jl @@ -321,7 +321,7 @@ function ir_prepare_inlining!(insert_node!::Inserter, inline_target::Union{IRCod debuginfo = inline_target isa IRCode ? inline_target.debuginfo : inline_target.ir.debuginfo linetable_offset = ir_inline_linetable!(debuginfo, di, mi) - topline = (inlined_at, linetable_offset, Int32(0)) + topline = DebugCodeLoc(inlined_at, linetable_offset, Int32(0)) if should_insert_coverage(def.module, di) insert_node!(NewInstruction(Expr(:code_coverage_effect), Nothing, topline)) end @@ -340,8 +340,9 @@ function ir_prepare_inlining!(insert_node!::Inserter, inline_target::Union{IRCod if def.is_for_opaque_closure # Replace the first argument by a load of the capture environment argexprs[1] = insert_node!( - NewInstruction(Expr(:call, GlobalRef(Core, :getfield), argexprs[1], QuoteNode(:captures)), - ir.argtypes[1], topline)) + NewInstruction( + Expr(:call, GlobalRef(Core, :getfield), argexprs[1], QuoteNode(:captures)), + ir.argtypes[1], topline)) end return SSASubstitute(mi, argexprs, spvals_ssa, (inlined_at, linetable_offset)) end @@ -379,7 +380,7 @@ function ir_inline_item!(compact::IncrementalCompact, idx::Int, argexprs::Vector # something better eventually. inline_compact[idx′] = nothing # alter the line number information for InsertBefore to point to the current instruction in the new linetable - inline_compact[SSAValue(idx′)][:line] = (ssa_substitute.inlined_at[1], ssa_substitute.inlined_at[2], Int32(lineidx)) + inline_compact[SSAValue(idx′)][:line] = DebugCodeLoc(ssa_substitute.inlined_at[1], ssa_substitute.inlined_at[2], lineidx) insert_node! = InsertBefore(inline_compact, SSAValue(idx′)) stmt′ = ssa_substitute_op!(insert_node!, inline_compact[SSAValue(idx′)], stmt′, ssa_substitute) if isa(stmt′, ReturnNode) @@ -411,7 +412,7 @@ function ir_inline_item!(compact::IncrementalCompact, idx::Int, argexprs::Vector @assert isempty(inline_compact.perm) && isempty(inline_compact.pending_perm) "linetable not in canonical form (missing compact call)" for ((lineidx, idx′), stmt′) in inline_compact inline_compact[idx′] = nothing - inline_compact[SSAValue(idx′)][:line] = (ssa_substitute.inlined_at[1], ssa_substitute.inlined_at[2], Int32(lineidx)) + inline_compact[SSAValue(idx′)][:line] = DebugCodeLoc(ssa_substitute.inlined_at[1], ssa_substitute.inlined_at[2], lineidx) insert_node! = InsertBefore(inline_compact, SSAValue(idx′)) stmt′ = ssa_substitute_op!(insert_node!, inline_compact[SSAValue(idx′)], stmt′, ssa_substitute) if isa(stmt′, ReturnNode) @@ -449,7 +450,7 @@ function ir_inline_item!(compact::IncrementalCompact, idx::Int, argexprs::Vector end function fix_va_argexprs!(insert_node!::Inserter, inline_target::Union{IRCode, IncrementalCompact}, - argexprs::Vector{Any}, nargs_def::Int, line_idx::NTuple{3,Int32}) + argexprs::Vector{Any}, nargs_def::Int, line_idx::DebugCodeLoc) newargexprs = argexprs[1:(nargs_def-1)] tuple_call = Expr(:call, TOP_TUPLE) tuple_typs = Any[] diff --git a/base/compiler/ssair/ir.jl b/base/compiler/ssair/ir.jl index c23f89e01f6646..661cd21bc40d0a 100644 --- a/base/compiler/ssair/ir.jl +++ b/base/compiler/ssair/ir.jl @@ -189,7 +189,7 @@ mutable struct DebugInfoStream end #DebugInfoStream(def::Union{MethodInstance,Nothing}, di::DebugInfo, nstmts::Int) = # if debuginfo_file1(di.def) === debuginfo_file1(di.def) - # new(def, di.linetable, Core.svec(di.edges...), getdebugidx(di, 0), + # new(def, di.linetable, Core.svec(di.edges...), getdebugidx(di, 0)[1], # ccall(:jl_uncompress_codelocs, Any, (Any, Int), di.codelocs, nstmts)::Vector{Int32}) # else function DebugInfoStream(def::Union{MethodInstance,Nothing}, di::DebugInfo, nstmts::Int) @@ -206,15 +206,37 @@ Core.DebugInfo(di::DebugInfoStream, nstmts::Int) = Core.DebugInfo(something(di.def), di.linetable, Core.svec(di.edges...), ccall(:jl_compress_codelocs, Any, (Int32, Any, Int), di.firstline, di.codelocs, nstmts)::String) -getdebugidx(debuginfo::Core.DebugInfo, pc::Int) = ccall(:jl_uncompress1_codeloc, NTuple{3,Int32}, (Any, Int), debuginfo.codelocs, pc) +struct DebugCodeLoc + line::Int32 + edge::Int32 + edge_line::Int32 +end +function getindex(dcl::DebugCodeLoc, idx::Int) + if idx == 1 + return dcl.line + elseif idx == 2 + return dcl.edge + elseif idx == 3 + return dcl.edge_line + else + throw(BoundsError(dcl, idx)) + end +end +function iterate(dcl::DebugCodeLoc, i::Int=1) + i > 3 && return nothing + return getfield(dcl, i), i+1 +end + +getdebugidx(debuginfo::Core.DebugInfo, pc::Int) = DebugCodeLoc( + ccall(:jl_uncompress1_codeloc, NTuple{3,Int32}, (Any, Int), debuginfo.codelocs, pc)...) function getdebugidx(debuginfo::DebugInfoStream, pc::Int) if 3 <= 3pc <= length(debuginfo.codelocs) - return (debuginfo.codelocs[3pc - 2], debuginfo.codelocs[3pc - 1], debuginfo.codelocs[3pc - 0]) + return DebugCodeLoc(debuginfo.codelocs[3pc - 2], debuginfo.codelocs[3pc - 1], debuginfo.codelocs[3pc - 0]) elseif pc == 0 - return (Int32(debuginfo.firstline), Int32(0), Int32(0)) + return DebugCodeLoc(debuginfo.firstline, 0, 0) else - return (Int32(-1), Int32(0), Int32(0)) + return DebugCodeLoc(-1, 0, 0) end end @@ -310,7 +332,7 @@ Instruction(is::InstructionStream) = Instruction(is, add_new_idx!(is)) isdefined(node, fld) && return getfield(node, fld) fldarray = getfield(getfield(node, :data), fld) fldidx = getfield(node, :idx) - (fld === :line) && return (fldarray[3fldidx-2], fldarray[3fldidx-1], fldarray[3fldidx-0]) + (fld === :line) && return DebugCodeLoc(fldarray[3fldidx-2], fldarray[3fldidx-1], fldarray[3fldidx-0]) return fldarray[fldidx] end @inline function setindex!(node::Instruction, @nospecialize(val), fld::Symbol) @@ -318,7 +340,7 @@ end fldarray = getfield(getfield(node, :data), fld) fldidx = getfield(node, :idx) if fld === :line - (fldarray[3fldidx-2], fldarray[3fldidx-1], fldarray[3fldidx-0]) = val::NTuple{3,Int32} + (fldarray[3fldidx-2], fldarray[3fldidx-1], fldarray[3fldidx-0]) = val::DebugCodeLoc else fldarray[fldidx] = val end @@ -370,15 +392,15 @@ struct NewInstruction stmt::Any type::Any info::CallInfo - line::Union{NTuple{3,Int32},Nothing} # if nothing, copy the line from previous statement in the insertion location + line::Union{DebugCodeLoc,Nothing} # if nothing, copy the line from previous statement in the insertion location flag::Union{UInt32,Nothing} # if nothing, IR flags will be recomputed on insertion function NewInstruction(@nospecialize(stmt), @nospecialize(type), @nospecialize(info::CallInfo), - line::Union{NTuple{3,Int32},Int32,Nothing}, flag::Union{UInt32,Nothing}) - line isa Int32 && (line = (line, zero(Int32), zero(Int32))) + line::Union{DebugCodeLoc,Int32,Nothing}, flag::Union{UInt32,Nothing}) + line isa Int32 && (line = DebugCodeLoc(line, 0, 0)) return new(stmt, type, info, line, flag) end end -function NewInstruction(@nospecialize(stmt), @nospecialize(type), line::Union{NTuple{3,Int32},Int32,Nothing}=nothing) +function NewInstruction(@nospecialize(stmt), @nospecialize(type), line::Union{DebugCodeLoc,Int32,Nothing}=nothing) return NewInstruction(stmt, type, NoCallInfo(), line, nothing) end @nospecialize @@ -386,7 +408,7 @@ function NewInstruction(newinst::NewInstruction; stmt::Any=newinst.stmt, type::Any=newinst.type, info::CallInfo=newinst.info, - line::Union{NTuple{3,Int32},Int32,Nothing}=newinst.line, + line::Union{DebugCodeLoc,Int32,Nothing}=newinst.line, flag::Union{UInt32,Nothing}=newinst.flag) return NewInstruction(stmt, type, info, line, flag) end @@ -394,7 +416,7 @@ function NewInstruction(inst::Instruction; stmt::Any=inst[:stmt], type::Any=inst[:type], info::CallInfo=inst[:info], - line::Union{NTuple{3,Int32},Int32,Nothing}=inst[:line], + line::Union{DebugCodeLoc,Int32,Nothing}=inst[:line], flag::Union{UInt32,Nothing}=inst[:flag]) return NewInstruction(stmt, type, info, line, flag) end @@ -939,7 +961,7 @@ function add_pending!(compact::IncrementalCompact, pos::Int, attach_after::Bool) end function inst_from_newinst!(node::Instruction, newinst::NewInstruction, - newline::NTuple{3,Int32}=newinst.line::NTuple{3,Int32}, newflag::UInt32=newinst.flag::UInt32) + newline::DebugCodeLoc=newinst.line::DebugCodeLoc, newflag::UInt32=newinst.flag::UInt32) node[:stmt] = newinst.stmt node[:type] = newinst.type node[:info] = newinst.info @@ -1029,7 +1051,7 @@ function maybe_reopen_bb!(compact) end function insert_node_here!(compact::IncrementalCompact, newinst::NewInstruction, reverse_affinity::Bool=false) - newline = newinst.line::NTuple{3,Int32} + newline = newinst.line::DebugCodeLoc refinish = false result_idx = compact.result_idx result_bbs = compact.cfg_transform.result_bbs @@ -1671,7 +1693,7 @@ function resize!(compact::IncrementalCompact, nnewnodes::Int) return compact end -const NoLineUpdate = (Int32(0), Int32(0), Int32(0)) +const NoLineUpdate = DebugCodeLoc(0, 0, 0) function finish_current_bb!(compact::IncrementalCompact, active_bb::Int, old_result_idx::Int=compact.result_idx, unreachable::Bool=false) diff --git a/base/compiler/ssair/passes.jl b/base/compiler/ssair/passes.jl index 946ba9633d3663..3269534ec755aa 100644 --- a/base/compiler/ssair/passes.jl +++ b/base/compiler/ssair/passes.jl @@ -1523,14 +1523,15 @@ function try_inline_finalizer!(ir::IRCode, argexprs::Vector{Any}, idx::Int, ssa_rename = Vector{Any}(undef, length(src.stmts)) for idx′ = 1:length(src.stmts) inst = src[SSAValue(idx′)] - stmt′ = inst[:stmt] - isa(stmt′, ReturnNode) && continue - stmt′ = ssamap(stmt′) do ssa::SSAValue + stmt = inst[:stmt] + isa(stmt, ReturnNode) && continue + stmt = ssamap(stmt) do ssa::SSAValue ssa_rename[ssa.id] end - stmt′ = ssa_substitute_op!(InsertBefore(ir, SSAValue(idx)), inst, stmt′, ssa_substitute) + stmt = ssa_substitute_op!(InsertBefore(ir, SSAValue(idx)), inst, stmt, ssa_substitute) + line = DebugCodeLoc(ssa_substitute.inlined_at[1], ssa_substitute.inlined_at[2], idx′) ssa_rename[idx′] = insert_node!(ir, idx, - NewInstruction(inst; stmt=stmt′, line=(ssa_substitute.inlined_at[1], ssa_substitute.inlined_at[2], Int32(idx′))), + NewInstruction(inst; stmt, line), attach_after) end diff --git a/base/show.jl b/base/show.jl index f7846e316c3301..e4d447f2d66606 100644 --- a/base/show.jl +++ b/base/show.jl @@ -2838,6 +2838,8 @@ module IRShow Base.iterate(is::Compiler.InstructionStream, st::Int=1) = (st <= Compiler.length(is)) ? (is[st], st + 1) : nothing Base.getindex(is::Compiler.InstructionStream, idx::Int) = Compiler.getindex(is, idx) Base.getindex(node::Compiler.Instruction, fld::Symbol) = Compiler.getindex(node, fld) + Base.getindex(dcl::Compiler.DebugCodeLoc, idx::Int) = Compiler.getindex(dcl, idx) + Base.iterate(dcl::Compiler.DebugCodeLoc, s::Int=1) = Compiler.iterate(dcl, s) Base.getindex(ir::IRCode, ssa::SSAValue) = Compiler.getindex(ir, ssa) include("compiler/ssair/show.jl") diff --git a/doc/src/devdocs/ast.md b/doc/src/devdocs/ast.md index b34bdfd2eb6065..50f2863d95a3b7 100644 --- a/doc/src/devdocs/ast.md +++ b/doc/src/devdocs/ast.md @@ -844,3 +844,8 @@ end depth also might have changed, though most callers should ignore that. - (zero, non-zero, *) : no line number, just edges (usually because of macro-expansion into top-level code) + + `Core.Compiler` has a bunch of utility types and functions for handling this data. + The `Core.Compiler.DebugCodeLoc` object represents the 3 values. And there's a handy + utility function, `Core.Compiler.getdebugidx(debuginfo::Union{Core.DebugInfo,Core.Compiler.DebugInfoStream}, idx::Int)`, + that gives you the `DebugCodeLoc` matching a specific statement index (`idx`). diff --git a/test/show.jl b/test/show.jl index 4bc7540326923b..e4e7e9e1b4a621 100644 --- a/test/show.jl +++ b/test/show.jl @@ -2694,3 +2694,13 @@ let lowered = Meta.lower(Main, Expr(:let, Expr(:block), Expr(:block, Expr(:tople # Check that this gets printed as `_1 = 1` not `y = 1` @test contains(sprint(show, ci), "_1 = 1") end + +# exercise DILineInfoPrinter +test_DILineInfoPrinter(x) = @inline sin(x) +test_DILineInfoPrinter(42) # ensure we have code instance cache for `test_DILineInfoPrinter(::Int)` +let io = IOContext(IOBuffer(), :color=>true) + mi = only(methods(test_DILineInfoPrinter, (Int,))).specializations + src = Core.Compiler._uncompressed_ir(mi.cache, mi.cache.inferred::String) + Base.IRShow.show_ir(io, src, Base.IRShow.IRShowConfig(Base.IRShow.DILineInfoPrinter(src.debuginfo, :var"unknown scope"))); + Base.IRShow.show_ir(io, src, Base.IRShow.IRShowConfig(Base.IRShow.DILineInfoPrinter(src.debuginfo, :var"unknown scope", true))); +end