From 1d1c935edbd0c49792bb88ac4dcff75e743f69ce Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com> Date: Wed, 22 Sep 2021 13:32:19 +0900 Subject: [PATCH] optimizer: fix #42258, make sure to set `ssaflags` correctly (#42262) Essentially, this PR adds missing `ssaflags` deletion of `type_annotate!`. Built on top of #42260. --- base/compiler/optimize.jl | 2 +- base/compiler/ssair/legacy.jl | 5 +++-- base/compiler/ssair/slot2ssa.jl | 9 +++++---- base/compiler/typeinfer.jl | 2 ++ base/compiler/validation.jl | 12 ++++++++---- test/compiler/ssair.jl | 20 ++++++++++++++++++++ test/compiler/validation.jl | 8 ++++++++ 7 files changed, 47 insertions(+), 11 deletions(-) diff --git a/base/compiler/optimize.jl b/base/compiler/optimize.jl index 5acfd22eb995a2..02ee5cdc9ecc11 100644 --- a/base/compiler/optimize.jl +++ b/base/compiler/optimize.jl @@ -85,7 +85,7 @@ mutable struct OptimizationState if nssavalues isa Int src.ssavaluetypes = Any[ Any for i = 1:nssavalues ] else - nssavalues = length(src.ssavaluetypes) + nssavalues = length(src.ssavaluetypes::Vector{Any}) end nslots = length(src.slotflags) slottypes = src.slottypes diff --git a/base/compiler/ssair/legacy.jl b/base/compiler/ssair/legacy.jl index 4d2bafc2f38d9b..88f529d2814de8 100644 --- a/base/compiler/ssair/legacy.jl +++ b/base/compiler/ssair/legacy.jl @@ -29,9 +29,10 @@ function inflate_ir(ci::CodeInfo, sptypes::Vector{Any}, argtypes::Vector{Any}) code[i] = stmt end end - ssavaluetypes = ci.ssavaluetypes nstmts = length(code) - ssavaluetypes = ci.ssavaluetypes isa Vector{Any} ? copy(ci.ssavaluetypes) : Any[ Any for i = 1:(ci.ssavaluetypes::Int) ] + ssavaluetypes = let ssavaluetypes = ci.ssavaluetypes + ssavaluetypes isa Vector{Any} ? copy(ssavaluetypes) : Any[ Any for i = 1:(ssavaluetypes::Int) ] + end stmts = InstructionStream(code, ssavaluetypes, Any[nothing for i = 1:nstmts], copy(ci.codelocs), copy(ci.ssaflags)) ir = IRCode(stmts, cfg, collect(LineInfoNode, ci.linetable), argtypes, Any[], sptypes) return ir diff --git a/base/compiler/ssair/slot2ssa.jl b/base/compiler/ssair/slot2ssa.jl index 656df9b17e4c4a..846ebde4c0bb11 100644 --- a/base/compiler/ssair/slot2ssa.jl +++ b/base/compiler/ssair/slot2ssa.jl @@ -177,13 +177,14 @@ function strip_trailing_junk!(ci::CodeInfo, code::Vector{Any}, info::Vector{Any} # Remove `nothing`s at the end, we don't handle them well # (we expect the last instruction to be a terminator) ssavaluetypes = ci.ssavaluetypes::Vector{Any} + (; codelocs, ssaflags) = ci for i = length(code):-1:1 if code[i] !== nothing resize!(code, i) resize!(ssavaluetypes, i) - resize!(ci.codelocs, i) + resize!(codelocs, i) resize!(info, i) - resize!(ci.ssaflags, i) + resize!(ssaflags, i) break end end @@ -193,9 +194,9 @@ function strip_trailing_junk!(ci::CodeInfo, code::Vector{Any}, info::Vector{Any} if !isa(term, GotoIfNot) && !isa(term, GotoNode) && !isa(term, ReturnNode) push!(code, ReturnNode()) push!(ssavaluetypes, Union{}) - push!(ci.codelocs, 0) + push!(codelocs, 0) push!(info, nothing) - push!(ci.ssaflags, IR_FLAG_NULL) + push!(ssaflags, IR_FLAG_NULL) end nothing end diff --git a/base/compiler/typeinfer.jl b/base/compiler/typeinfer.jl index c3b7c4dc3a3d0d..a197731b62f32a 100644 --- a/base/compiler/typeinfer.jl +++ b/base/compiler/typeinfer.jl @@ -475,6 +475,7 @@ function finish(me::InferenceState, interp::AbstractInterpreter) end me.result.valid_worlds = me.valid_worlds me.result.result = me.bestguess + validate_code_in_debug_mode(me.linfo, me.src, "inferred") nothing end @@ -666,6 +667,7 @@ function type_annotate!(sv::InferenceState, run_optimizer::Bool) deleteat!(ssavaluetypes, i) deleteat!(src.codelocs, i) deleteat!(sv.stmt_info, i) + deleteat!(src.ssaflags, i) nexpr -= 1 changemap[oldidx] = -1 continue diff --git a/base/compiler/validation.jl b/base/compiler/validation.jl index b7e63900a3fdf3..bcde5d894159c6 100644 --- a/base/compiler/validation.jl +++ b/base/compiler/validation.jl @@ -48,6 +48,7 @@ const EMPTY_SLOTNAMES = "slotnames field is empty" const SLOTFLAGS_MISMATCH = "length(slotnames) < length(slotflags)" const SSAVALUETYPES_MISMATCH = "not all SSAValues in AST have a type in ssavaluetypes" const SSAVALUETYPES_MISMATCH_UNINFERRED = "uninferred CodeInfo ssavaluetypes field does not equal the number of present SSAValues" +const SSAFLAGS_MISMATCH = "not all SSAValues have a corresponding `ssaflags`" const NON_TOP_LEVEL_METHOD = "encountered `Expr` head `:method` in non-top-level code (i.e. `nargs` > 0)" const NON_TOP_LEVEL_GLOBAL = "encountered `Expr` head `:global` in non-top-level code (i.e. `nargs` > 0)" const SIGNATURE_NARGS_MISMATCH = "method signature does not match number of method arguments" @@ -183,13 +184,16 @@ function validate_code!(errors::Vector{>:InvalidCodeError}, c::CodeInfo, is_top_ nssavals = length(c.code) !is_top_level && nslotnames == 0 && push!(errors, InvalidCodeError(EMPTY_SLOTNAMES)) nslotnames < nslotflags && push!(errors, InvalidCodeError(SLOTFLAGS_MISMATCH, (nslotnames, nslotflags))) - if c.inferred - nssavaluetypes = length(c.ssavaluetypes::Vector{Any}) + ssavaluetypes = c.ssavaluetypes + if isa(ssavaluetypes, Vector{Any}) + nssavaluetypes = length(ssavaluetypes) nssavaluetypes < nssavals && push!(errors, InvalidCodeError(SSAVALUETYPES_MISMATCH, (nssavals, nssavaluetypes))) else - ssavaluetypes = c.ssavaluetypes::Int - ssavaluetypes != nssavals && push!(errors, InvalidCodeError(SSAVALUETYPES_MISMATCH_UNINFERRED, (nssavals, ssavaluetypes))) + nssavaluetypes = ssavaluetypes::Int + nssavaluetypes ≠ nssavals && push!(errors, InvalidCodeError(SSAVALUETYPES_MISMATCH_UNINFERRED, (nssavals, nssavaluetypes))) end + nssaflags = length(c.ssaflags) + nssavals ≠ nssaflags && push!(errors, InvalidCodeError(SSAFLAGS_MISMATCH, (nssavals, nssaflags))) return errors end diff --git a/test/compiler/ssair.jl b/test/compiler/ssair.jl index 17a0753eddc640..ffb48a9de38e9c 100644 --- a/test/compiler/ssair.jl +++ b/test/compiler/ssair.jl @@ -314,3 +314,23 @@ end # Issue #41975 - SSA conversion drops type check f_if_typecheck() = (if nothing; end; unsafe_load(Ptr{Int}(0))) @test_throws TypeError f_if_typecheck() + +@test let # https://github.com/JuliaLang/julia/issues/42258 + code = quote + function foo() + a = @noinline rand(rand(0:10)) + if isempty(a) + err = BoundsError(a) + throw(err) + return nothing + end + return a + end + code_typed(foo; optimize=true) + + code_typed(Core.Compiler.setindex!, (Core.Compiler.UseRef,Core.Compiler.NewSSAValue); optimize=true) + end |> string + cmd = `$(Base.julia_cmd()) -g 2 -e $code` + stderr = IOBuffer() + success(pipeline(Cmd(cmd); stdout=stdout, stderr=stderr)) && isempty(String(take!(stderr))) +end diff --git a/test/compiler/validation.jl b/test/compiler/validation.jl index 3863d3b11351fb..6326cb709e30d3 100644 --- a/test/compiler/validation.jl +++ b/test/compiler/validation.jl @@ -105,6 +105,14 @@ end @test errors[1].kind === Core.Compiler.SSAVALUETYPES_MISMATCH_UNINFERRED end +@testset "SSAFLAGS_MISMATCH" begin + c = copy(c0) + empty!(c.ssaflags) + errors = Core.Compiler.validate_code(c) + @test length(errors) == 1 + @test errors[1].kind === Core.Compiler.SSAFLAGS_MISMATCH +end + @testset "SIGNATURE_NARGS_MISMATCH" begin old_sig = mi.def.sig mi.def.sig = Tuple{1,2}