From 594079b68f2b1dabb8fae9e98867d09895592558 Mon Sep 17 00:00:00 2001 From: Cody Tapscott Date: Mon, 7 Oct 2024 18:40:32 -0400 Subject: [PATCH] IRShow: label builtin / intrinsic / dynamic calls in `code_typed` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes it much easier to spot dynamic dispatches: ```julia 3 ── %9 = (isa)(%4, @NamedTuple{x::Int64, y})::Bool └─── goto #5 if not %9 4 ── %11 = π (%4, @NamedTuple{x::Int64, y}) └─── goto #6 5 ── %13 = (Tuple{Int64, Any})(%4)::Tuple{Int64, Any} │ %14 = (getfield)(%13, 1)::Int64 │ %15 = (getfield)(%13, 2)::Any │ %16 = %new(@NamedTuple{x::Int64, y}, %14, %15)::@NamedTuple{x::Int64, y} ``` is now: ```julia 3 ── %9 = builtin (isa)(%4, @NamedTuple{x::Int64, y})::Bool └─── goto #5 if not %9 4 ── %11 = π (%4, @NamedTuple{x::Int64, y}) └─── goto #6 5 ── %13 = dynamic (Tuple{Int64, Any})(%4)::Tuple{Int64, Any} │ %14 = builtin (getfield)(%13, 1)::Int64 │ %15 = builtin (getfield)(%13, 2)::Any │ %16 = %new(@NamedTuple{x::Int64, y}, %14, %15)::@NamedTuple{x::Int64, y} ``` This is on by default when displaying a CodeInfo, and off by default for `code_warntype`, unless optimize=true. Can be enabled / disabled via IRShowConfig.label_dynamic_calls --- base/compiler/abstractinterpretation.jl | 1 + base/compiler/optimize.jl | 25 +++- base/compiler/ssair/ir.jl | 36 ++++-- base/compiler/ssair/show.jl | 126 +++++++++++++++---- base/compiler/types.jl | 2 + base/deprecated.jl | 1 + doc/src/base/reflection.md | 8 +- doc/src/devdocs/inference.md | 10 +- stdlib/InteractiveUtils/src/codeview.jl | 10 +- stdlib/InteractiveUtils/test/highlighting.jl | 5 +- test/compiler/EscapeAnalysis/EAUtils.jl | 2 +- 11 files changed, 178 insertions(+), 48 deletions(-) diff --git a/base/compiler/abstractinterpretation.jl b/base/compiler/abstractinterpretation.jl index 70623453e16665..04a62700e9de77 100644 --- a/base/compiler/abstractinterpretation.jl +++ b/base/compiler/abstractinterpretation.jl @@ -3114,6 +3114,7 @@ end abstract_eval_ssavalue(s::SSAValue, sv::InferenceState) = abstract_eval_ssavalue(s, sv.ssavaluetypes) function abstract_eval_ssavalue(s::SSAValue, ssavaluetypes::Vector{Any}) + (1 ≤ s.id ≤ length(ssavaluetypes)) || throw(InvalidIRError()) typ = ssavaluetypes[s.id] if typ === NOT_FOUND return Bottom diff --git a/base/compiler/optimize.jl b/base/compiler/optimize.jl index 02f6b46e2e73fa..5f0c5077688f81 100644 --- a/base/compiler/optimize.jl +++ b/base/compiler/optimize.jl @@ -411,26 +411,35 @@ function argextype(@nospecialize(x), compact::IncrementalCompact, sptypes::Vecto isa(x, AnySSAValue) && return types(compact)[x] return argextype(x, compact, sptypes, compact.ir.argtypes) end -argextype(@nospecialize(x), src::CodeInfo, sptypes::Vector{VarState}) = argextype(x, src, sptypes, src.slottypes::Vector{Any}) +function argextype(@nospecialize(x), src::CodeInfo, sptypes::Vector{VarState}) + return argextype(x, src, sptypes, src.slottypes::Union{Vector{Any},Nothing}) +end function argextype( @nospecialize(x), src::Union{IRCode,IncrementalCompact,CodeInfo}, - sptypes::Vector{VarState}, slottypes::Vector{Any}) + sptypes::Vector{VarState}, slottypes::Union{Vector{Any},Nothing}) if isa(x, Expr) if x.head === :static_parameter - return sptypes[x.args[1]::Int].typ + idx = x.args[1]::Int + (1 ≤ idx ≤ length(sptypes)) || throw(InvalidIRError()) + return sptypes[idx].typ elseif x.head === :boundscheck return Bool elseif x.head === :copyast + length(x.args) == 0 && throw(InvalidIRError()) return argextype(x.args[1], src, sptypes, slottypes) end Core.println("argextype called on Expr with head ", x.head, " which is not valid for IR in argument-position.") @assert false elseif isa(x, SlotNumber) + slottypes === nothing && return Any + (1 ≤ x.id ≤ length(slottypes)) || throw(InvalidIRError()) return slottypes[x.id] elseif isa(x, SSAValue) return abstract_eval_ssavalue(x, src) elseif isa(x, Argument) + slottypes === nothing && return Any + (1 ≤ x.n ≤ length(slottypes)) || throw(InvalidIRError()) return slottypes[x.n] elseif isa(x, QuoteNode) return Const(x.value) @@ -444,7 +453,15 @@ function argextype( return Const(x) end end -abstract_eval_ssavalue(s::SSAValue, src::CodeInfo) = abstract_eval_ssavalue(s, src.ssavaluetypes::Vector{Any}) +function abstract_eval_ssavalue(s::SSAValue, src::CodeInfo) + ssavaluetypes = src.ssavaluetypes + if ssavaluetypes isa Int + (1 ≤ s.id ≤ ssavaluetypes) || throw(InvalidIRError()) + return Any + else + return abstract_eval_ssavalue(s, ssavaluetypes::Vector{Any}) + end +end abstract_eval_ssavalue(s::SSAValue, src::Union{IRCode,IncrementalCompact}) = types(src)[s] """ diff --git a/base/compiler/ssair/ir.jl b/base/compiler/ssair/ir.jl index fdcb4621c5c0f1..90eab43a3f25b4 100644 --- a/base/compiler/ssair/ir.jl +++ b/base/compiler/ssair/ir.jl @@ -313,6 +313,7 @@ Instruction(is::InstructionStream) = Instruction(is, add_new_idx!(is)) fldarray = getfield(getfield(node, :data), fld) fldidx = getfield(node, :idx) (fld === :line) && return (fldarray[3fldidx-2], fldarray[3fldidx-1], fldarray[3fldidx-0]) + (1 ≤ fldidx ≤ length(fldarray)) || throw(InvalidIRError()) return fldarray[fldidx] end @inline function setindex!(node::Instruction, @nospecialize(val), fld::Symbol) @@ -481,11 +482,16 @@ function block_for_inst(ir::IRCode, inst::Int) end function getindex(ir::IRCode, s::SSAValue) + id = s.id + (id ≥ 1) || throw(InvalidIRError()) nstmts = length(ir.stmts) - if s.id <= nstmts - return ir.stmts[s.id] + if id <= nstmts + return ir.stmts[id] else - return ir.new_nodes.stmts[s.id - nstmts] + id -= nstmts + stmts = ir.new_nodes.stmts + (id ≤ length(stmts)) || throw(InvalidIRError()) + return stmts[id] end end @@ -801,12 +807,13 @@ end types(ir::Union{IRCode, IncrementalCompact}) = TypesView(ir) function getindex(compact::IncrementalCompact, ssa::SSAValue) - @assert ssa.id < compact.result_idx + (1 ≤ ssa.id ≤ compact.result_idx) || throw(InvalidIRError()) return compact.result[ssa.id] end function getindex(compact::IncrementalCompact, ssa::OldSSAValue) id = ssa.id + (id ≥ 1) || throw(InvalidIRError()) if id < compact.idx new_idx = compact.ssa_rename[id]::Int return compact.result[new_idx] @@ -818,12 +825,15 @@ function getindex(compact::IncrementalCompact, ssa::OldSSAValue) return compact.ir.new_nodes.stmts[id] end id -= length(compact.ir.new_nodes) + (id ≤ length(compact.pending_nodes.stmts)) || throw(InvalidIRError()) return compact.pending_nodes.stmts[id] end function getindex(compact::IncrementalCompact, ssa::NewSSAValue) if ssa.id < 0 - return compact.new_new_nodes.stmts[-ssa.id] + stmts = compact.new_new_nodes.stmts + (-ssa.id ≤ length(stmts)) || throw(InvalidIRError()) + return stmts[-ssa.id] else return compact[SSAValue(ssa.id)] end @@ -1069,6 +1079,7 @@ function getindex(view::TypesView, v::OldSSAValue) id = v.id ir = view.ir.ir stmts = ir.stmts + (id ≥ 1) || throw(InvalidIRError()) if id <= length(stmts) return stmts[id][:type] end @@ -1077,7 +1088,9 @@ function getindex(view::TypesView, v::OldSSAValue) return ir.new_nodes.stmts[id][:type] end id -= length(ir.new_nodes) - return view.ir.pending_nodes.stmts[id][:type] + stmts = view.ir.pending_nodes.stmts + (id ≤ length(stmts)) || throw(InvalidIRError()) + return stmts[id][:type] end function kill_current_use!(compact::IncrementalCompact, @nospecialize(val)) @@ -1204,20 +1217,27 @@ end getindex(view::TypesView, idx::SSAValue) = getindex(view, idx.id) function getindex(view::TypesView, idx::Int) + (idx ≥ 1) || throw(InvalidIRError()) if isa(view.ir, IncrementalCompact) && idx < view.ir.result_idx return view.ir.result[idx][:type] elseif isa(view.ir, IncrementalCompact) && view.ir.renamed_new_nodes if idx <= length(view.ir.result) return view.ir.result[idx][:type] else - return view.ir.new_new_nodes.stmts[idx - length(view.ir.result)][:type] + idx -= length(view.ir.result) + stmts = view.ir.new_new_nodes.stmts + (idx ≤ length(stmts)) || throw(InvalidIRError()) + return stmts[idx][:type] end else ir = isa(view.ir, IncrementalCompact) ? view.ir.ir : view.ir if idx <= length(ir.stmts) return ir.stmts[idx][:type] else - return ir.new_nodes.stmts[idx - length(ir.stmts)][:type] + idx -= length(ir.stmts) + stmts = ir.new_nodes.stmts + (idx ≤ length(stmts)) || throw(InvalidIRError()) + return stmts[idx][:type] end end end diff --git a/base/compiler/ssair/show.jl b/base/compiler/ssair/show.jl index 7d936a1688aba0..cc6c1ebde659fd 100644 --- a/base/compiler/ssair/show.jl +++ b/base/compiler/ssair/show.jl @@ -14,6 +14,8 @@ end import Base: show_unquoted using Base: printstyled, with_output_color, prec_decl, @invoke +using Core.Compiler: VarState, InvalidIRError, argextype, widenconst, singleton_type, + sptypes_from_meth_instance, EMPTY_SPTYPES function Base.show(io::IO, cfg::CFG) print(io, "CFG with $(length(cfg.blocks)) blocks:") @@ -31,7 +33,50 @@ function Base.show(io::IO, cfg::CFG) end end -function print_stmt(io::IO, idx::Int, @nospecialize(stmt), used::BitSet, maxlength_idx::Int, color::Bool, show_type::Bool) +function maybe_argextype( + @nospecialize(x), + src::Union{IRCode,IncrementalCompact,CodeInfo}, + sptypes::Vector{VarState}, +) + return try + argextype(x, src, sptypes) + catch err + !(err isa InvalidIRError) && rethrow() + nothing + end +end + +const inlined_apply_iterate_types = Union{Array,Memory,Tuple,NamedTuple,Core.SimpleVector} + +function builtin_call_has_dispatch( + @nospecialize(f), + args::Vector{Any}, + src::Union{IRCode,IncrementalCompact,CodeInfo}, + sptypes::Vector{VarState}, +) + if f === Core._apply_iterate && length(args) >= 3 + # The implementation of _apply_iterate has hand-inlined implementations + # for (v::Union{Tuple,NamedTuple,Memory,Array,SimpleVector}...) + # which perform no dynamic dispatch + constructort = maybe_argextype(args[3], src, sptypes) + if constructort === nothing || !(widenconst(constructort) <: Core.Builtin) + return true + end + for arg in args[4:end] + argt = maybe_argextype(arg, src, sptypes) + if argt === nothing || !(widenconst(argt) <: inlined_apply_iterate_types) + return true + end + end + elseif (f === Core._apply_pure || f === Core._call_in_world || f === Core._call_in_world_total || f === Core._call_latest) + # These apply-like builtins are effectively dynamic calls + return true + end + return false +end + +function print_stmt(io::IO, idx::Int, @nospecialize(stmt), code::Union{IRCode,CodeInfo,IncrementalCompact}, + sptypes::Vector{VarState}, used::BitSet, maxlength_idx::Int, color::Bool, show_type::Bool, label_dynamic_calls::Bool) if idx in used idx_s = string(idx) pad = " "^(maxlength_idx - length(idx_s) + 1) @@ -51,7 +96,7 @@ function print_stmt(io::IO, idx::Int, @nospecialize(stmt), used::BitSet, maxleng elseif isexpr(stmt, :invoke) && length(stmt.args) >= 2 && isa(stmt.args[1], MethodInstance) stmt = stmt::Expr # TODO: why is this here, and not in Base.show_unquoted - print(io, "invoke ") + printstyled(io, "invoke "; color = :light_black) mi = stmt.args[1]::Core.MethodInstance show_unquoted(io, stmt.args[2], indent) print(io, "(") @@ -66,6 +111,28 @@ function print_stmt(io::IO, idx::Int, @nospecialize(stmt), used::BitSet, maxleng end join(io, (print_arg(i) for i = 3:length(stmt.args)), ", ") print(io, ")") + elseif isexpr(stmt, :call) && length(stmt.args) >= 1 && label_dynamic_calls + ft = maybe_argextype(stmt.args[1], code, sptypes) + f = singleton_type(ft) + if isa(f, Core.IntrinsicFunction) + printstyled(io, "intrinsic "; color = :light_black) + elseif isa(f, Core.Builtin) + if builtin_call_has_dispatch(f, stmt.args, code, sptypes) + printstyled(io, "dynamic builtin "; color = :yellow) + else + printstyled(io, "builtin "; color = :light_black) + end + elseif ft === nothing + # This should only happen when, e.g., printing a call that targets + # an out-of-bounds SSAValue or similar + # (i.e. under normal circumstances, dead code) + printstyled(io, "unknown "; color = :light_black) + elseif widenconst(ft) <: Core.Builtin + printstyled(io, "dynamic builtin "; color = :yellow) + else + printstyled(io, "dynamic "; color = :yellow) + end + show_unquoted(io, stmt, indent, show_type ? prec_decl : 0) # given control flow information, we prefer to print these with the basic block #, instead of the ssa % elseif isa(stmt, EnterNode) print(io, "enter #", stmt.catch_dest, "") @@ -563,16 +630,28 @@ end - `should_print_stmt(idx::Int) -> Bool`: whether the statement at index `idx` should be printed as part of the IR or not - `bb_color`: color used for printing the basic block brackets on the left +- `label_dynamic_calls`: whether to label calls as dynamic / builtin / intrinsic """ struct IRShowConfig line_info_preprinter line_info_postprinter should_print_stmt bb_color::Symbol - function IRShowConfig(line_info_preprinter, line_info_postprinter=default_expr_type_printer; - should_print_stmt=Returns(true), bb_color::Symbol=:light_black) - return new(line_info_preprinter, line_info_postprinter, should_print_stmt, bb_color) - end + label_dynamic_calls::Bool + + IRShowConfig( + line_info_preprinter, + line_info_postprinter=default_expr_type_printer; + should_print_stmt=Returns(true), + bb_color::Symbol=:light_black, + label_dynamic_calls=true + ) = new( + line_info_preprinter, + line_info_postprinter, + should_print_stmt, + bb_color, + label_dynamic_calls + ) end struct _UNDEF @@ -628,13 +707,14 @@ end # at index `idx`. This function is repeatedly called until it returns `nothing`. # to iterate nodes that are to be inserted after the statement, set `attach_after=true`. function show_ir_stmt(io::IO, code::Union{IRCode, CodeInfo, IncrementalCompact}, idx::Int, config::IRShowConfig, - used::BitSet, cfg::CFG, bb_idx::Int; pop_new_node! = Returns(nothing), only_after::Bool=false) + sptypes::Vector{VarState}, used::BitSet, cfg::CFG, bb_idx::Int; pop_new_node! = Returns(nothing), only_after::Bool=false) return show_ir_stmt(io, code, idx, config.line_info_preprinter, config.line_info_postprinter, - used, cfg, bb_idx; pop_new_node!, only_after, config.bb_color) + sptypes, used, cfg, bb_idx; pop_new_node!, only_after, config.bb_color, config.label_dynamic_calls) end function show_ir_stmt(io::IO, code::Union{IRCode, CodeInfo, IncrementalCompact}, idx::Int, line_info_preprinter, line_info_postprinter, - used::BitSet, cfg::CFG, bb_idx::Int; pop_new_node! = Returns(nothing), only_after::Bool=false, bb_color=:light_black) + sptypes::Vector{VarState}, used::BitSet, cfg::CFG, bb_idx::Int; pop_new_node! = Returns(nothing), only_after::Bool=false, + bb_color=:light_black, label_dynamic_calls::Bool=true) stmt = _stmt(code, idx) type = _type(code, idx) max_bb_idx_size = length(string(length(cfg.blocks))) @@ -693,7 +773,7 @@ function show_ir_stmt(io::IO, code::Union{IRCode, CodeInfo, IncrementalCompact}, show_type = should_print_ssa_type(new_node_inst) let maxlength_idx=maxlength_idx, show_type=show_type with_output_color(:green, io) do io′ - print_stmt(io′, node_idx, new_node_inst, used, maxlength_idx, false, show_type) + print_stmt(io′, node_idx, new_node_inst, code, sptypes, used, maxlength_idx, false, show_type, label_dynamic_calls) end end @@ -722,7 +802,7 @@ function show_ir_stmt(io::IO, code::Union{IRCode, CodeInfo, IncrementalCompact}, stmt = statement_indices_to_labels(stmt, cfg) end show_type = type !== nothing && should_print_ssa_type(stmt) - print_stmt(io, idx, stmt, used, maxlength_idx, true, show_type) + print_stmt(io, idx, stmt, code, sptypes, used, maxlength_idx, true, show_type, label_dynamic_calls) if type !== nothing # ignore types for pre-inference code if type === UNDEF # This is an error, but can happen if passes don't update their type information @@ -881,10 +961,10 @@ end default_config(code::CodeInfo) = IRShowConfig(statementidx_lineinfo_printer(code)) function show_ir_stmts(io::IO, ir::Union{IRCode, CodeInfo, IncrementalCompact}, inds, config::IRShowConfig, - used::BitSet, cfg::CFG, bb_idx::Int; pop_new_node! = Returns(nothing)) + sptypes::Vector{VarState}, used::BitSet, cfg::CFG, bb_idx::Int; pop_new_node! = Returns(nothing)) for idx in inds if config.should_print_stmt(ir, idx, used) - bb_idx = show_ir_stmt(io, ir, idx, config, used, cfg, bb_idx; pop_new_node!) + bb_idx = show_ir_stmt(io, ir, idx, config, sptypes, used, cfg, bb_idx; pop_new_node!) elseif bb_idx <= length(cfg.blocks) && idx == cfg.blocks[bb_idx].stmts.stop bb_idx += 1 end @@ -904,7 +984,7 @@ function show_ir(io::IO, ir::IRCode, config::IRShowConfig=default_config(ir); cfg = ir.cfg maxssaid = length(ir.stmts) + Core.Compiler.length(ir.new_nodes) let io = IOContext(io, :maxssaid=>maxssaid) - show_ir_stmts(io, ir, 1:length(ir.stmts), config, used, cfg, 1; pop_new_node!) + show_ir_stmts(io, ir, 1:length(ir.stmts), config, ir.sptypes, used, cfg, 1; pop_new_node!) end finish_show_ir(io, cfg, config) end @@ -913,8 +993,12 @@ function show_ir(io::IO, ci::CodeInfo, config::IRShowConfig=default_config(ci); pop_new_node! = Returns(nothing)) used = stmts_used(io, ci) cfg = compute_basic_blocks(ci.code) + parent = ci.parent + sptypes = if parent isa MethodInstance + sptypes_from_meth_instance(parent) + else EMPTY_SPTYPES end let io = IOContext(io, :maxssaid=>length(ci.code)) - show_ir_stmts(io, ci, 1:length(ci.code), config, used, cfg, 1; pop_new_node!) + show_ir_stmts(io, ci, 1:length(ci.code), config, sptypes, used, cfg, 1; pop_new_node!) end finish_show_ir(io, cfg, config) end @@ -963,8 +1047,8 @@ function show_ir(io::IO, compact::IncrementalCompact, config::IRShowConfig=defau pop_new_node! = new_nodes_iter(compact) maxssaid = length(compact.result) + Core.Compiler.length(compact.new_new_nodes) bb_idx = let io = IOContext(io, :maxssaid=>maxssaid) - show_ir_stmts(io, compact, 1:compact.result_idx-1, config, used_compacted, - compact_cfg, 1; pop_new_node!) + show_ir_stmts(io, compact, 1:compact.result_idx-1, config, compact.ir.sptypes, + used_compacted, compact_cfg, 1; pop_new_node!) end @@ -995,13 +1079,13 @@ function show_ir(io::IO, compact::IncrementalCompact, config::IRShowConfig=defau let io = IOContext(io, :maxssaid=>maxssaid) # first show any new nodes to be attached after the last compacted statement if compact.idx > 1 - show_ir_stmt(io, compact.ir, compact.idx-1, config, used_uncompacted, - uncompacted_cfg, bb_idx; pop_new_node!, only_after=true) + show_ir_stmt(io, compact.ir, compact.idx-1, config, compact.ir.sptypes, + used_uncompacted, uncompacted_cfg, bb_idx; pop_new_node!, only_after=true) end # then show the actual uncompacted IR - show_ir_stmts(io, compact.ir, compact.idx:length(stmts), config, used_uncompacted, - uncompacted_cfg, bb_idx; pop_new_node!) + show_ir_stmts(io, compact.ir, compact.idx:length(stmts), config, compact.ir.sptypes, + used_uncompacted, uncompacted_cfg, bb_idx; pop_new_node!) end finish_show_ir(io, uncompacted_cfg, config) diff --git a/base/compiler/types.jl b/base/compiler/types.jl index ecf2417fd6199c..210adf7be96b2f 100644 --- a/base/compiler/types.jl +++ b/base/compiler/types.jl @@ -28,6 +28,8 @@ the following methods to satisfy the `AbstractInterpreter` API requirement: abstract type AbstractLattice end +struct InvalidIRError <: Exception end + struct ArgInfo fargs::Union{Nothing,Vector{Any}} argtypes::Vector{Any} diff --git a/base/deprecated.jl b/base/deprecated.jl index b43a4227d42c41..953de358a68eec 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -26,6 +26,7 @@ const __internal_changes_list = ( :miuninferredrm, :codeinfonargs, # #54341 :ocnopartial, + :printcodeinfocalls, # Add new change names above this line ) diff --git a/doc/src/base/reflection.md b/doc/src/base/reflection.md index 0f0af140b605f8..8299ec586baf9a 100644 --- a/doc/src/base/reflection.md +++ b/doc/src/base/reflection.md @@ -100,9 +100,9 @@ as assignments, branches, and calls: ```jldoctest; setup = (using Base: +, sin) julia> Meta.lower(@__MODULE__, :( [1+2, sin(0.5)] )) :($(Expr(:thunk, CodeInfo( -1 ─ %1 = 1 + 2 -│ %2 = sin(0.5) -│ %3 = Base.vect(%1, %2) +1 ─ %1 = dynamic 1 + 2 +│ %2 = dynamic sin(0.5) +│ %3 = dynamic Base.vect(%1, %2) └── return %3 )))) ``` @@ -146,7 +146,7 @@ debug information printed. julia> InteractiveUtils.@code_typed debuginfo=:source +(1,1) CodeInfo( @ int.jl:87 within `+` -1 ─ %1 = Base.add_int(x, y)::Int64 +1 ─ %1 = intrinsic Base.add_int(x, y)::Int64 └── return %1 ) => Int64 ``` diff --git a/doc/src/devdocs/inference.md b/doc/src/devdocs/inference.md index c885441e4dd848..0de93600133e3e 100644 --- a/doc/src/devdocs/inference.md +++ b/doc/src/devdocs/inference.md @@ -98,16 +98,16 @@ as follows: julia> Base.print_statement_costs(stdout, map, (typeof(sqrt), Tuple{Int},)) # map(sqrt, (2,)) map(f, t::Tuple{Any}) @ Base tuple.jl:281 0 1 ─ %1 = $(Expr(:boundscheck, true))::Bool - 0 │ %2 = Base.getfield(_3, 1, %1)::Int64 - 1 │ %3 = Base.sitofp(Float64, %2)::Float64 - 0 │ %4 = Base.lt_float(%3, 0.0)::Bool + 0 │ %2 = builtin Base.getfield(_3, 1, %1)::Int64 + 1 │ %3 = intrinsic Base.sitofp(Float64, %2)::Float64 + 0 │ %4 = intrinsic Base.lt_float(%3, 0.0)::Bool 0 └── goto #3 if not %4 0 2 ─ invoke Base.Math.throw_complex_domainerror(:sqrt::Symbol, %3::Float64)::Union{} 0 └── unreachable - 20 3 ─ %8 = Base.Math.sqrt_llvm(%3)::Float64 + 20 3 ─ %8 = intrinsic Base.Math.sqrt_llvm(%3)::Float64 0 └── goto #4 0 4 ─ goto #5 - 0 5 ─ %11 = Core.tuple(%8)::Tuple{Float64} + 0 5 ─ %11 = builtin Core.tuple(%8)::Tuple{Float64} 0 └── return %11 ``` diff --git a/stdlib/InteractiveUtils/src/codeview.jl b/stdlib/InteractiveUtils/src/codeview.jl index 9f1538cd4a7fe7..e3ef0a14a6608f 100644 --- a/stdlib/InteractiveUtils/src/codeview.jl +++ b/stdlib/InteractiveUtils/src/codeview.jl @@ -54,7 +54,7 @@ function is_expected_union(u::Union) return true end -function print_warntype_codeinfo(io::IO, src::Core.CodeInfo, @nospecialize(rettype), nargs::Int; lineprinter) +function print_warntype_codeinfo(io::IO, src::Core.CodeInfo, @nospecialize(rettype), nargs::Int; lineprinter, label_dynamic_calls) if src.slotnames !== nothing slotnames = Base.sourceinfo_slotnames(src) io = IOContext(io, :SOURCE_SLOTNAMES => slotnames) @@ -74,7 +74,7 @@ function print_warntype_codeinfo(io::IO, src::Core.CodeInfo, @nospecialize(retty print(io, "Body") warntype_type_printer(io; type=rettype, used=true) println(io) - irshow_config = Base.IRShow.IRShowConfig(lineprinter(src), warntype_type_printer) + irshow_config = Base.IRShow.IRShowConfig(lineprinter(src), warntype_type_printer; label_dynamic_calls) Base.IRShow.show_ir(io, src, irshow_config) println(io) end @@ -154,7 +154,8 @@ function code_warntype(io::IO, @nospecialize(f), @nospecialize(tt=Base.default_t nargs::Int = 0 if isa(f, Core.OpaqueClosure) isa(f.source, Method) && (nargs = f.source.nargs) - print_warntype_codeinfo(io, Base.code_typed_opaque_closure(f, tt)[1]..., nargs; lineprinter) + print_warntype_codeinfo(io, Base.code_typed_opaque_closure(f, tt)[1]..., nargs; + lineprinter, label_dynamic_calls = optimize) return nothing end tt = Base.signature_type(f, tt) @@ -167,7 +168,8 @@ function code_warntype(io::IO, @nospecialize(f), @nospecialize(tt=Base.default_t mi.def isa Method && (nargs = (mi.def::Method).nargs) print_warntype_mi(io, mi) if src isa Core.CodeInfo - print_warntype_codeinfo(io, src, src.rettype, nargs; lineprinter) + print_warntype_codeinfo(io, src, src.rettype, nargs; + lineprinter, label_dynamic_calls = optimize) else println(io, " inference not successful") end diff --git a/stdlib/InteractiveUtils/test/highlighting.jl b/stdlib/InteractiveUtils/test/highlighting.jl index 3531618e10dfc5..f49464557f9263 100644 --- a/stdlib/InteractiveUtils/test/highlighting.jl +++ b/stdlib/InteractiveUtils/test/highlighting.jl @@ -34,7 +34,10 @@ end c = Base.text_colors[Base.warn_color()] InteractiveUtils.highlighting[:warntype] = false code_warntype(IOContext(io, :color => true), f, Tuple{Int64}) - @test !occursin(c, String(take!(io))) + @test !any([ + occursin("Body", line) && occursin(c, line) + for line in split(String(take!(io)), "\n") + ]) InteractiveUtils.highlighting[:warntype] = true code_warntype(IOContext(io, :color => true), f, Tuple{Int64}) @test occursin(c, String(take!(io))) diff --git a/test/compiler/EscapeAnalysis/EAUtils.jl b/test/compiler/EscapeAnalysis/EAUtils.jl index b8ad4589db6261..c41e61e2318921 100644 --- a/test/compiler/EscapeAnalysis/EAUtils.jl +++ b/test/compiler/EscapeAnalysis/EAUtils.jl @@ -291,7 +291,7 @@ function print_with_info(preprint, postprint, io::IO, ir::IRCode, source::Bool) bb_idx_prev = bb_idx = 1 for idx = 1:length(ir.stmts) preprint(io, idx) - bb_idx = Base.IRShow.show_ir_stmt(io, ir, idx, line_info_preprinter, line_info_postprinter, used, ir.cfg, bb_idx) + bb_idx = Base.IRShow.show_ir_stmt(io, ir, idx, line_info_preprinter, line_info_postprinter, ir.sptypes, used, ir.cfg, bb_idx) postprint(io, idx, bb_idx != bb_idx_prev) bb_idx_prev = bb_idx end