Open
Description
This is basically a hand-written version of #53011 but the bug itself is different
include("test/compiler/irutils.jl")
mutable struct Foo
x
end
getfield_mi = only(Base.method_instances(Base.getfield, Tuple{Foo, Symbol}, Base.get_world_counter()))
setfield!_mi = only(Base.method_instances(Base.setfield!, Tuple{Foo, Symbol, Any}, Base.get_world_counter()))
let code = Any[
# Block 1
#= %1 =# Expr(:new, GlobalRef(Main, :Foo), Core.Compiler.Argument(2)),
#= %2 =# Core.Compiler.GotoIfNot(false, 5),
# Block 2
#= %3 =# Expr(:call, GlobalRef(Base, :getfield), Core.SSAValue(1), Core.QuoteNode(:x)),
#= %4 =# Core.Compiler.ReturnNode(Core.SSAValue(3)),
# Block 3
#= %5 =# Expr(:call, GlobalRef(Base, :getfield), Core.SSAValue(1), Core.QuoteNode(:x)),
#= %6 =# Expr(:call, GlobalRef(Base, :(+)), Core.SSAValue(5), 1),
#= %7 =# Expr(:call, GlobalRef(Base, :setfield!), Core.SSAValue(1), Core.QuoteNode(:x), Core.SSAValue(6)),
#= %8 =# Core.Compiler.GotoNode(3),
]
ir = make_ircode(code)
ir.stmts.type[1] = Main.Foo
push!(ir.argtypes, Tuple{})
push!(ir.argtypes, Int64)
interp = Core.Compiler.NativeInterpreter()
inlining = Core.Compiler.InliningState(interp)
ir = Core.Compiler.compact!(ir, true)
println(ir)
ir = Core.Compiler.sroa_pass!(ir, inlining)
println(ir)
Core.Compiler.verify_ir(ir)
end
In #53011, the bug is that compaction inserts the bad PhiNode. In this case, it's the SROA pass itself that is misbehaving.
First, compaction deletes the unreachable edge from BB1, leaving the blocks out of dominance order:
1 ─ %1 = %new(Main.Foo, _2)::Foo │
└── goto #3 │
2 ─ %3 = Base.getfield(%1, :x)::Any │
└── return %3 │
3 ─ %5 = Base.getfield(%1, :x)::Any │
│ %6 = (%5 + 1)::Any │
│ Base.setfield!(%1, :x, %6)::Any │
└── goto #2
Then, the SROA pass constructs a domtree that reports that BB3 dominates BB2, and inserts an invalid SSAValue:
1 ─ %1 = %new(Main.Foo, _2)::Foo │
└── goto #3 │
2 ─ %3 = %6::Any │
└── return %3 │
3 ─ %5 = _2::Any │
│ %6 = (%5 + 1)::Any │
│ Base.setfield!(%1, :x, %6)::Any │
└── goto #2
Finally, the IR verifier makes the same mistake and accepts this code even though codegen will mis-compile this