Skip to content

Commit 201d4f6

Browse files
authored
Merge pull request #45934 from JuliaLang/avi/follow-45272
inlining: follow #45272, improve the finalizer inlining implementation
2 parents c1d21e1 + 7bab5d5 commit 201d4f6

File tree

7 files changed

+247
-157
lines changed

7 files changed

+247
-157
lines changed

base/compiler/abstractinterpretation.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -496,13 +496,13 @@ function abstract_call_method(interp::AbstractInterpreter, method::Method, @nosp
496496
add_remark!(interp, sv, "Refusing to infer into `depwarn`")
497497
return MethodCallResult(Any, false, false, nothing, Effects())
498498
end
499-
topmost = nothing
499+
500500
# Limit argument type tuple growth of functions:
501501
# look through the parents list to see if there's a call to the same method
502502
# and from the same method.
503503
# Returns the topmost occurrence of that repeated edge.
504-
edgecycle = false
505-
edgelimited = false
504+
edgecycle = edgelimited = false
505+
topmost = nothing
506506

507507
for infstate in InfStackUnwind(sv)
508508
if method === infstate.linfo.def

base/compiler/optimize.jl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ const IR_FLAG_EFFECT_FREE = 0x01 << 4
3030
# This statement was proven not to throw
3131
const IR_FLAG_NOTHROW = 0x01 << 5
3232

33-
3433
const TOP_TUPLE = GlobalRef(Core, :tuple)
3534

3635
#####################

base/compiler/ssair/inlining.jl

Lines changed: 88 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -767,7 +767,7 @@ function rewrite_apply_exprargs!(
767767
elseif isa(new_info, MethodMatchInfo) || isa(new_info, UnionSplitInfo)
768768
new_infos = isa(new_info, MethodMatchInfo) ? MethodMatchInfo[new_info] : new_info.matches
769769
# See if we can inline this call to `iterate`
770-
analyze_single_call!(
770+
handle_call!(
771771
ir, state1.id, new_stmt, new_infos, flag,
772772
new_sig, istate, todo)
773773
end
@@ -874,8 +874,7 @@ function validate_sparams(sparams::SimpleVector)
874874
end
875875

876876
function analyze_method!(match::MethodMatch, argtypes::Vector{Any},
877-
flag::UInt8, state::InliningState,
878-
do_resolve::Bool = true)
877+
flag::UInt8, state::InliningState)
879878
method = match.method
880879
spec_types = match.spec_types
881880

@@ -909,7 +908,7 @@ function analyze_method!(match::MethodMatch, argtypes::Vector{Any},
909908
todo = InliningTodo(mi, match, argtypes)
910909
# If we don't have caches here, delay resolving this MethodInstance
911910
# until the batch inlining step (or an external post-processing pass)
912-
do_resolve && state.mi_cache === nothing && return todo
911+
state.mi_cache === nothing && return todo
913912
return resolve_todo(todo, state, flag)
914913
end
915914

@@ -921,7 +920,7 @@ function retrieve_ir_for_inlining(mi::MethodInstance, src::Array{UInt8, 1})
921920
src = ccall(:jl_uncompress_ir, Any, (Any, Ptr{Cvoid}, Any), mi.def, C_NULL, src::Vector{UInt8})::CodeInfo
922921
return inflate_ir!(src, mi)
923922
end
924-
retrieve_ir_for_inlining(mi::MethodInstance, src::CodeInfo) = inflate_ir(src, mi)::IRCode
923+
retrieve_ir_for_inlining(mi::MethodInstance, src::CodeInfo) = inflate_ir(src, mi)
925924
retrieve_ir_for_inlining(mi::MethodInstance, ir::IRCode) = copy(ir)
926925

927926
function handle_single_case!(
@@ -1225,10 +1224,8 @@ function process_simple!(ir::IRCode, idx::Int, state::InliningState, todo::Vecto
12251224
end
12261225

12271226
# TODO inline non-`isdispatchtuple`, union-split callsites?
1228-
function compute_inlining_cases(
1229-
infos::Vector{MethodMatchInfo}, flag::UInt8,
1230-
sig::Signature, state::InliningState,
1231-
do_resolve::Bool = true)
1227+
function compute_inlining_cases(infos::Vector{MethodMatchInfo},
1228+
flag::UInt8, sig::Signature, state::InliningState)
12321229
argtypes = sig.argtypes
12331230
cases = InliningCase[]
12341231
local any_fully_covered = false
@@ -1245,7 +1242,7 @@ function compute_inlining_cases(
12451242
continue
12461243
end
12471244
for match in meth
1248-
handled_all_cases &= handle_match!(match, argtypes, flag, state, cases, true, do_resolve)
1245+
handled_all_cases &= handle_match!(match, argtypes, flag, state, cases, #=allow_abstract=#true)
12491246
any_fully_covered |= match.fully_covers
12501247
end
12511248
end
@@ -1258,23 +1255,10 @@ function compute_inlining_cases(
12581255
return cases, handled_all_cases & any_fully_covered
12591256
end
12601257

1261-
function analyze_single_call!(
1262-
ir::IRCode, idx::Int, stmt::Expr, infos::Vector{MethodMatchInfo}, flag::UInt8,
1263-
sig::Signature, state::InliningState, todo::Vector{Pair{Int, Any}})
1264-
1265-
r = compute_inlining_cases(infos, flag, sig, state)
1266-
r === nothing && return nothing
1267-
cases, all_covered = r
1268-
handle_cases!(ir, idx, stmt, argtypes_to_type(sig.argtypes), cases,
1269-
all_covered, todo, state.params)
1270-
end
1271-
1272-
# similar to `analyze_single_call!`, but with constant results
1273-
function handle_const_call!(
1274-
ir::IRCode, idx::Int, stmt::Expr, cinfo::ConstCallInfo, flag::UInt8,
1275-
sig::Signature, state::InliningState, todo::Vector{Pair{Int, Any}})
1258+
function compute_inlining_cases(info::ConstCallInfo,
1259+
flag::UInt8, sig::Signature, state::InliningState)
12761260
argtypes = sig.argtypes
1277-
(; call, results) = cinfo
1261+
(; call, results) = info
12781262
infos = isa(call, MethodMatchInfo) ? MethodMatchInfo[call] : call.matches
12791263
cases = InliningCase[]
12801264
local any_fully_covered = false
@@ -1302,7 +1286,7 @@ function handle_const_call!(
13021286
handled_all_cases &= handle_const_prop_result!(result, argtypes, flag, state, cases, true)
13031287
else
13041288
@assert result === nothing
1305-
handled_all_cases &= handle_match!(match, argtypes, flag, state, cases, true)
1289+
handled_all_cases &= handle_match!(match, argtypes, flag, state, cases, #=allow_abstract=#true)
13061290
end
13071291
end
13081292
end
@@ -1312,21 +1296,39 @@ function handle_const_call!(
13121296
filter!(case::InliningCase->isdispatchtuple(case.sig), cases)
13131297
end
13141298

1315-
handle_cases!(ir, idx, stmt, argtypes_to_type(argtypes), cases,
1316-
handled_all_cases & any_fully_covered, todo, state.params)
1299+
return cases, handled_all_cases & any_fully_covered
1300+
end
1301+
1302+
function handle_call!(
1303+
ir::IRCode, idx::Int, stmt::Expr, infos::Vector{MethodMatchInfo}, flag::UInt8,
1304+
sig::Signature, state::InliningState, todo::Vector{Pair{Int, Any}})
1305+
cases = compute_inlining_cases(infos, flag, sig, state)
1306+
cases === nothing && return nothing
1307+
cases, all_covered = cases
1308+
handle_cases!(ir, idx, stmt, argtypes_to_type(sig.argtypes), cases,
1309+
all_covered, todo, state.params)
1310+
end
1311+
1312+
function handle_const_call!(
1313+
ir::IRCode, idx::Int, stmt::Expr, info::ConstCallInfo, flag::UInt8,
1314+
sig::Signature, state::InliningState, todo::Vector{Pair{Int, Any}})
1315+
cases = compute_inlining_cases(info, flag, sig, state)
1316+
cases === nothing && return nothing
1317+
cases, all_covered = cases
1318+
handle_cases!(ir, idx, stmt, argtypes_to_type(sig.argtypes), cases,
1319+
all_covered, todo, state.params)
13171320
end
13181321

13191322
function handle_match!(
13201323
match::MethodMatch, argtypes::Vector{Any}, flag::UInt8, state::InliningState,
1321-
cases::Vector{InliningCase}, allow_abstract::Bool = false,
1322-
do_resolve::Bool = true)
1324+
cases::Vector{InliningCase}, allow_abstract::Bool = false)
13231325
spec_types = match.spec_types
13241326
allow_abstract || isdispatchtuple(spec_types) || return false
13251327
# we may see duplicated dispatch signatures here when a signature gets widened
13261328
# during abstract interpretation: for the purpose of inlining, we can just skip
13271329
# processing this dispatch candidate
13281330
_any(case->case.sig === spec_types, cases) && return true
1329-
item = analyze_method!(match, argtypes, flag, state, do_resolve)
1331+
item = analyze_method!(match, argtypes, flag, state)
13301332
item === nothing && return false
13311333
push!(cases, InliningCase(spec_types, item))
13321334
return true
@@ -1384,6 +1386,54 @@ function handle_const_opaque_closure_call!(
13841386
return nothing
13851387
end
13861388

1389+
function handle_finalizer_call!(
1390+
ir::IRCode, stmt::Expr, info::FinalizerInfo, state::InliningState)
1391+
# Only inline finalizers that are known nothrow and notls.
1392+
# This avoids having to set up state for finalizer isolation
1393+
(is_nothrow(info.effects) && is_notaskstate(info.effects)) || return nothing
1394+
1395+
info = info.info
1396+
if isa(info, MethodMatchInfo)
1397+
infos = MethodMatchInfo[info]
1398+
elseif isa(info, UnionSplitInfo)
1399+
infos = info.matches
1400+
# elseif isa(info, ConstCallInfo)
1401+
# # NOTE currently this code path isn't active as constant propagation won't happen
1402+
# # for `Core.finalizer` call because inference currently isn't able to fold a mutable
1403+
# # object as a constant
1404+
else
1405+
return nothing
1406+
end
1407+
1408+
ft = argextype(stmt.args[2], ir)
1409+
has_free_typevars(ft) && return nothing
1410+
f = singleton_type(ft)
1411+
argtypes = Vector{Any}(undef, 2)
1412+
argtypes[1] = ft
1413+
argtypes[2] = argextype(stmt.args[3], ir)
1414+
sig = Signature(f, ft, argtypes)
1415+
1416+
cases = compute_inlining_cases(infos, #=flag=#UInt8(0), sig, state)
1417+
cases === nothing && return nothing
1418+
cases, all_covered = cases
1419+
if all_covered && length(cases) == 1
1420+
# NOTE we don't append `item1` to `stmt` here so that we don't serialize
1421+
# `Core.Compiler` data structure into the global cache
1422+
item1 = cases[1].item
1423+
if isa(item1, InliningTodo)
1424+
push!(stmt.args, true)
1425+
push!(stmt.args, item1.mi)
1426+
elseif isa(item1, InvokeCase)
1427+
push!(stmt.args, false)
1428+
push!(stmt.args, item1.invoke)
1429+
elseif isa(item1, ConstantCase)
1430+
push!(stmt.args, nothing)
1431+
push!(stmt.args, item1.val)
1432+
end
1433+
end
1434+
return nothing
1435+
end
1436+
13871437
function inline_const_if_inlineable!(inst::Instruction)
13881438
rt = inst[:type]
13891439
if rt isa Const && is_inlineable_constant(rt.val)
@@ -1434,53 +1484,15 @@ function assemble_inline_todo!(ir::IRCode, state::InliningState)
14341484
end
14351485

14361486
# Handle invoke
1437-
if sig.f === Core.invoke
1438-
if isa(info, InvokeCallInfo)
1439-
inline_invoke!(ir, idx, stmt, info, flag, sig, state, todo)
1440-
end
1487+
if isa(info, InvokeCallInfo)
1488+
inline_invoke!(ir, idx, stmt, info, flag, sig, state, todo)
14411489
continue
14421490
end
14431491

14441492
# Handle finalizer
1445-
if sig.f === Core.finalizer
1446-
if isa(info, FinalizerInfo)
1447-
# Only inline finalizers that are known nothrow and notls.
1448-
# This avoids having to set up state for finalizer isolation
1449-
(is_nothrow(info.effects) && is_notaskstate(info.effects)) || continue
1450-
1451-
info = info.info
1452-
if isa(info, MethodMatchInfo)
1453-
infos = MethodMatchInfo[info]
1454-
elseif isa(info, UnionSplitInfo)
1455-
infos = info.matches
1456-
else
1457-
continue
1458-
end
1459-
1460-
ft = argextype(stmt.args[2], ir)
1461-
has_free_typevars(ft) && return nothing
1462-
f = singleton_type(ft)
1463-
argtypes = Vector{Any}(undef, 2)
1464-
argtypes[1] = ft
1465-
argtypes[2] = argextype(stmt.args[3], ir)
1466-
sig = Signature(f, ft, argtypes)
1467-
1468-
cases, all_covered = compute_inlining_cases(infos, UInt8(0), sig, state, false)
1469-
length(cases) == 0 && continue
1470-
if all_covered && length(cases) == 1
1471-
if isa(cases[1], InliningCase)
1472-
case1 = cases[1].item
1473-
if isa(case1, InliningTodo)
1474-
push!(stmt.args, true)
1475-
push!(stmt.args, case1.mi)
1476-
elseif isa(case1, InvokeCase)
1477-
push!(stmt.args, false)
1478-
push!(stmt.args, case1.invoke)
1479-
end
1480-
end
1481-
end
1482-
continue
1483-
end
1493+
if isa(info, FinalizerInfo)
1494+
handle_finalizer_call!(ir, stmt, info, state)
1495+
continue
14841496
end
14851497

14861498
# if inference arrived here with constant-prop'ed result(s),
@@ -1501,7 +1513,7 @@ function assemble_inline_todo!(ir::IRCode, state::InliningState)
15011513
continue # isa(info, ReturnTypeCallInfo), etc.
15021514
end
15031515

1504-
analyze_single_call!(ir, idx, stmt, infos, flag, sig, state, todo)
1516+
handle_call!(ir, idx, stmt, infos, flag, sig, state, todo)
15051517
end
15061518

15071519
return todo

0 commit comments

Comments
 (0)