Skip to content

Commit

Permalink
slot2ssa: consider liveness when inserting PiNodes (#51406)
Browse files Browse the repository at this point in the history
  • Loading branch information
topolarity committed Sep 22, 2023
1 parent 9f0676c commit c476d84
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 1 deletion.
5 changes: 4 additions & 1 deletion base/compiler/ssair/slot2ssa.jl
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,7 @@ function construct_ssa!(ci::CodeInfo, ir::IRCode, sv::OptimizationState,
handler_at = compute_trycatch(code, BitSet())

phi_slots = Vector{Int}[Int[] for _ = 1:length(ir.cfg.blocks)]
live_slots = Vector{Int}[Int[] for _ = 1:length(ir.cfg.blocks)]
new_phi_nodes = Vector{NewPhiNode2}[NewPhiNode2[] for _ = 1:length(cfg.blocks)]
new_phic_nodes = IdDict{Int, Vector{NewPhiCNode2}}()
for (; leave_block) in catch_entry_blocks
Expand Down Expand Up @@ -617,8 +618,10 @@ function construct_ssa!(ci::CodeInfo, ir::IRCode, sv::OptimizationState,
end
continue
end

@timeit "liveness" (live = compute_live_ins(cfg, slot))
for li in live.live_in_bbs
push!(live_slots[li], idx)
cidx = findfirst(x::TryCatchRegion->x.leave_block==li, catch_entry_blocks)
if cidx !== nothing
# The slot is live-in into this block. We need to
Expand Down Expand Up @@ -735,7 +738,7 @@ function construct_ssa!(ci::CodeInfo, ir::IRCode, sv::OptimizationState,
end
# Record Pi nodes if necessary
has_pinode = fill(false, length(sv.slottypes))
for slot in 1:length(sv.slottypes)
for slot in live_slots[item]
(ival, idef) = incoming_vals[slot]
(ival === SSAValue(-1)) && continue
(ival === SSAValue(-2)) && continue
Expand Down
48 changes: 48 additions & 0 deletions test/compiler/irpasses.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1519,3 +1519,51 @@ let ir = first(only(Base.code_ircode(f_with_early_try_catch_exit, (); optimize_u
end

@test isnothing(f_with_early_try_catch_exit())

# Issue #51144 - UndefRefError during compaction
let m = Meta.@lower 1 + 1
@assert Meta.isexpr(m, :thunk)
src = m.args[1]::CodeInfo
src.code = Any[
# block 1 → 2, 3
#= %1: =# Expr(:(=), Core.SlotNumber(4), Core.Argument(2)),
#= %2: =# Expr(:call, :(===), Core.SlotNumber(4), nothing),
#= %3: =# GotoIfNot(Core.SSAValue(1), 5),
# block 2
#= %4: =# ReturnNode(nothing),
# block 3 → 4, 5
#= %5: =# Expr(:(=), Core.SlotNumber(4), false),
#= %6: =# GotoIfNot(Core.Argument(2), 8),
# block 4 → 5
#= %7: =# Expr(:(=), Core.SlotNumber(4), true),
# block 5
#= %8: =# ReturnNode(nothing), # Must not insert a π-node here
]
nstmts = length(src.code)
nslots = 4
src.ssavaluetypes = nstmts
src.codelocs = fill(Int32(1), nstmts)
src.ssaflags = fill(Int32(0), nstmts)
src.slotflags = fill(0, nslots)
src.slottypes = Any[Any, Union{Bool, Nothing}, Bool, Union{Bool, Nothing}]
ir = Core.Compiler.inflate_ir(src)

mi = ccall(:jl_new_method_instance_uninit, Ref{Core.MethodInstance}, ());
mi.specTypes = Tuple{}
mi.def = Module()

# Simulate the important results from inference
interp = Core.Compiler.NativeInterpreter()
sv = Core.Compiler.OptimizationState(mi, src, interp)
slot_id = 4
for block_id = 3:5
# (_4 !== nothing) conditional narrows the type, triggering PiNodes
sv.bb_vartables[block_id][slot_id] = VarState(Bool, #= maybe_undef =# false)
end

ir = Core.Compiler.convert_to_ircode(src, sv)
ir = Core.Compiler.slot2reg(ir, src, sv)
ir = Core.Compiler.compact!(ir)

Core.Compiler.verify_ir(ir)
end

0 comments on commit c476d84

Please sign in to comment.