diff --git a/base/compiler/ssair/slot2ssa.jl b/base/compiler/ssair/slot2ssa.jl index b4135fd9dc568..39e092332aae6 100644 --- a/base/compiler/ssair/slot2ssa.jl +++ b/base/compiler/ssair/slot2ssa.jl @@ -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 @@ -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 @@ -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 diff --git a/test/compiler/irpasses.jl b/test/compiler/irpasses.jl index 66d040fe8b893..225839d8e0cf3 100644 --- a/test/compiler/irpasses.jl +++ b/test/compiler/irpasses.jl @@ -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