diff --git a/base/compiler/abstractinterpretation.jl b/base/compiler/abstractinterpretation.jl index 50ccf9ac25e6b..6e328e4af49ea 100644 --- a/base/compiler/abstractinterpretation.jl +++ b/base/compiler/abstractinterpretation.jl @@ -2250,6 +2250,13 @@ function abstract_eval_statement_expr(interp::AbstractInterpreter, e::Expr, vtyp merge_effects!(interp, sv, effects) if isa(sv, InferenceState) sv.stmt_info[sv.currpc] = info + # mark this call statement as DCE-elgible + # TODO better to do this in a single pass based on the `info` object at the end of abstractinterpret? + if is_removable_if_unused(effects) + add_curr_ssaflag!(sv, IR_FLAG_EFFECT_FREE) + else + sub_curr_ssaflag!(sv, IR_FLAG_EFFECT_FREE) + end end end t = rt @@ -2359,6 +2366,14 @@ function abstract_eval_statement_expr(interp::AbstractInterpreter, e::Expr, vtyp (;rt, effects) = abstract_eval_foreigncall(interp, e, vtypes, sv, mi) t = rt merge_effects!(interp, sv, effects) + if isa(sv, InferenceState) + # mark this call statement as DCE-elgible + if is_removable_if_unused(effects) + add_curr_ssaflag!(sv, IR_FLAG_EFFECT_FREE) + else + sub_curr_ssaflag!(sv, IR_FLAG_EFFECT_FREE) + end + end elseif ehead === :cfunction effects = EFFECTS_UNKNOWN merge_effects!(interp, sv, effects) diff --git a/base/compiler/inferencestate.jl b/base/compiler/inferencestate.jl index 61b2fe1f27c72..df65d6668df3d 100644 --- a/base/compiler/inferencestate.jl +++ b/base/compiler/inferencestate.jl @@ -532,6 +532,8 @@ function print_callstack(sv::InferenceState) end get_curr_ssaflag(sv::InferenceState) = sv.src.ssaflags[sv.currpc] +add_curr_ssaflag!(sv::InferenceState, flag::UInt8) = sv.src.ssaflags[sv.currpc] |= flag +sub_curr_ssaflag!(sv::InferenceState, flag::UInt8) = sv.src.ssaflags[sv.currpc] &= ~flag function narguments(sv::InferenceState) def = sv.linfo.def diff --git a/test/compiler/inline.jl b/test/compiler/inline.jl index c8cfacd09cd9f..5991b67b1618b 100644 --- a/test/compiler/inline.jl +++ b/test/compiler/inline.jl @@ -1077,8 +1077,7 @@ Base.setindex!(s::SafeRef, x) = setfield!(s, 1, x) noninlined_dce_new(s) nothing end -# should be resolved once we merge https://github.com/JuliaLang/julia/pull/43923 -@test_broken fully_eliminated((Union{Symbol,String},)) do s +@test fully_eliminated((Union{Symbol,String},)) do s noninlined_dce_new(s) nothing end @@ -1820,6 +1819,26 @@ let ir = Base.code_ircode(big_tuple_test1, Tuple{})[1][1] @test length(ir.stmts) == 1 end +# inlineable but removable call should be eligible for DCE +Base.@assume_effects :removable @inline function inlineable_effect_free(a::Float64) + a == Inf && return zero(a) + return sin(a) + cos(a) +end +@test fully_eliminated((Float64,)) do a + b = inlineable_effect_free(a) + c = inlineable_effect_free(b) + nothing +end + +# https://github.com/JuliaLang/julia/issues/47374 +function f47374(x) + [f47374(i, x) for i in 1:1] +end +function f47374(i::Int, x) + return 1.0 +end +@test f47374(rand(1)) == Float64[1.0] + # compiler should recognize effectful :static_parameter # https://github.com/JuliaLang/julia/issues/45490 issue45490_1(x::Union{T, Nothing}, y::Union{T, Nothing}) where {T} = T