From 5b49d06dc031bdb03f6ed7688c5c24a64b751697 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki Date: Wed, 2 Aug 2023 15:31:41 -0400 Subject: [PATCH 1/2] ssair: `compact!` constant `PiNode` Currently the `compact!`-ion pass fails to fold constant `PiNode` like `PiNode(0.0, Float64)`. This commit fixes it up. --- base/compiler/ssair/ir.jl | 5 +++-- test/compiler/inline.jl | 2 +- test/compiler/irutils.jl | 7 +++++-- test/compiler/ssair.jl | 12 +++++++++++- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/base/compiler/ssair/ir.jl b/base/compiler/ssair/ir.jl index 33bf419ab56c9..4c287adaff251 100644 --- a/base/compiler/ssair/ir.jl +++ b/base/compiler/ssair/ir.jl @@ -1362,8 +1362,9 @@ function process_node!(compact::IncrementalCompact, result_idx::Int, inst::Instr return result_idx end elseif !isa(pi_val, AnySSAValue) && !isa(pi_val, GlobalRef) - valtyp = isa(pi_val, QuoteNode) ? typeof(pi_val.value) : typeof(pi_val) - if valtyp === stmt.typ + pi_val′ = isa(pi_val, QuoteNode) ? pi_val.value : pi_val + stmttyp = stmt.typ + if isa(stmttyp, Const) ? pi_val′ === stmttyp.val : typeof(pi_val′) === stmttyp ssa_rename[idx] = pi_val return result_idx end diff --git a/test/compiler/inline.jl b/test/compiler/inline.jl index 3bc7ab5ccbc82..638f7e0185568 100644 --- a/test/compiler/inline.jl +++ b/test/compiler/inline.jl @@ -1130,7 +1130,7 @@ function f44200() x44200 end let src = code_typed1(f44200) - @test_broken count(x -> isa(x, Core.PiNode), src.code) == 0 + @test count(x -> isa(x, Core.PiNode), src.code) == 0 end # Test that peeling off one case from (::Any) doesn't introduce diff --git a/test/compiler/irutils.jl b/test/compiler/irutils.jl index 00de9b2472de4..c2f6fd3314c1b 100644 --- a/test/compiler/irutils.jl +++ b/test/compiler/irutils.jl @@ -37,8 +37,11 @@ isinvoke(y) = @nospecialize(x) -> isinvoke(y, x) isinvoke(sym::Symbol, @nospecialize(x)) = isinvoke(mi->mi.def.name===sym, x) isinvoke(pred::Function, @nospecialize(x)) = isexpr(x, :invoke) && pred(x.args[1]::MethodInstance) -function fully_eliminated(@nospecialize args...; retval=(@__FILE__), kwargs...) - code = code_typed1(args...; kwargs...).code +fully_eliminated(@nospecialize args...; retval=(@__FILE__), kwargs...) = + fully_eliminated(code_typed1(args...; kwargs...); retval) +fully_eliminated(src::CodeInfo; retval=(@__FILE__)) = fully_eliminated(src.code; retval) +fully_eliminated(ir::IRCode; retval=(@__FILE__)) = fully_eliminated(ir.stmts.inst; retval) +function fully_eliminated(code::Vector{Any}; retval=(@__FILE__), kwargs...) if retval !== (@__FILE__) length(code) == 1 || return false code1 = code[1] diff --git a/test/compiler/ssair.jl b/test/compiler/ssair.jl index 98cab349b46ee..ea833fa4ce5ff 100644 --- a/test/compiler/ssair.jl +++ b/test/compiler/ssair.jl @@ -5,7 +5,7 @@ using Core.IR const Compiler = Core.Compiler using .Compiler: CFG, BasicBlock, NewSSAValue -include(normpath(@__DIR__, "irutils.jl")) +include("irutils.jl") make_bb(preds, succs) = BasicBlock(Compiler.StmtRange(0, 0), preds, succs) @@ -593,6 +593,16 @@ let ci = make_ci([ @test Core.Compiler.verify_ir(ir) === nothing end +# compact constant PiNode +let ci = make_ci(Any[ + PiNode(0.0, Const(0.0)) + ReturnNode(SSAValue(1)) + ]) + ir = Core.Compiler.inflate_ir(ci) + ir = Core.Compiler.compact!(ir) + @test fully_eliminated(ir) +end + # insert_node! with new instruction with flag computed let ir = Base.code_ircode((Int,Int); optimize_until="inlining") do a, b a^b From 40339ac1dbbde33f87457b7d5e84e0ab7b5d3bb9 Mon Sep 17 00:00:00 2001 From: Shuhei Kadowaki Date: Wed, 2 Aug 2023 15:07:09 -0400 Subject: [PATCH 2/2] optimizer: move inlineable constants into statement position during `compact!`-ion In code like below ```julia Base.@assume_effects :nothrow function erase_before_inlining(x, y) z = sin(y) if x return "julia" end return z end let y::Float64 length(erase_before_inlining(true, y)) end ``` the constant prop' can figure out the constant return type of `erase_before_inlining(true, y)` while it is profitable not to inline expand it since otherwise we left some `!:nothrow` callees there (xref: #47305). In order to workaround this problem, this commit makes `compact!`move inlineable constants into statement positions so that such "inlineable, but safe as a whole" calls to be erased during compaction. This should give us general compile-time performance improvement too as we no longer need to expand the IR for those calls. --- base/compiler/ssair/ir.jl | 7 ++++++- test/compiler/EscapeAnalysis/interprocedural.jl | 6 ++---- test/compiler/inline.jl | 17 +++++++++++++++++ 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/base/compiler/ssair/ir.jl b/base/compiler/ssair/ir.jl index 4c287adaff251..8839812957279 100644 --- a/base/compiler/ssair/ir.jl +++ b/base/compiler/ssair/ir.jl @@ -1341,7 +1341,12 @@ function process_node!(compact::IncrementalCompact, result_idx::Int, inst::Instr return result_idx end end - ssa_rename[idx] = SSAValue(result_idx) + typ = inst[:type] + if isa(typ, Const) && is_inlineable_constant(typ.val) + ssa_rename[idx] = quoted(typ.val) + else + ssa_rename[idx] = SSAValue(result_idx) + end result[result_idx][:inst] = stmt result_idx += 1 elseif isa(stmt, PiNode) diff --git a/test/compiler/EscapeAnalysis/interprocedural.jl b/test/compiler/EscapeAnalysis/interprocedural.jl index 756e5489ed637..15d2a878d253b 100644 --- a/test/compiler/EscapeAnalysis/interprocedural.jl +++ b/test/compiler/EscapeAnalysis/interprocedural.jl @@ -98,10 +98,8 @@ identity_if_string(x::SafeRef) = nothing let result = code_escapes((SafeRef{String},); optimize=false) do x identity_if_string(x) end - i = only(findall(iscall((result.ir, identity_if_string)), result.ir.stmts.inst)) - r = only(findall(isreturn, result.ir.stmts.inst)) - @test !has_thrown_escape(result.state[Argument(2)], i) - @test !has_return_escape(result.state[Argument(2)], r) + @test !has_thrown_escape(result.state[Argument(2)]) + @test !has_return_escape(result.state[Argument(2)]) end let result = code_escapes((Union{SafeRef{String},Vector{String}},); optimize=false) do x identity_if_string(x) diff --git a/test/compiler/inline.jl b/test/compiler/inline.jl index 638f7e0185568..be9a2e98e2dc3 100644 --- a/test/compiler/inline.jl +++ b/test/compiler/inline.jl @@ -2065,3 +2065,20 @@ end # https://github.com/JuliaLang/julia/issues/50612 f50612(x) = UInt32(x) @test all(!isinvoke(:UInt32),get_code(f50612,Tuple{Char})) + +# move inlineable constant values into statement position during `compact!`-ion +# so that we don't inline DCE-eligibile calls +Base.@assume_effects :nothrow function erase_before_inlining(x, y) + z = sin(y) + if x + return "julia" + end + return z +end +@test fully_eliminated((Float64,); retval=5) do y + length(erase_before_inlining(true, y)) +end +@test fully_eliminated((Float64,); retval=(5,5)) do y + z = erase_before_inlining(true, y) + return length(z), length(z) +end