Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit74334f1

Browse files
committed
Very WIP: Eager finalizer insertion
This is a variant of the eager-finalization idea(e.g. as seen in#44056), but with a focus on the mechanismof finalizer insertion, since I need a similar pass downstream.Integration of EscapeAnalysis is left to#44056.My motivation for this change is somewhat different. In particular,I want to be able to insert finalize call such that I cansubsequently SROA the mutable object. This requires a coupledesign points that are more stringent than the pass from#44056,so I decided to prototype them as an independent PR. The primarythings I need here that are not seen in#44056 are:- The ability to forgo finalizer registration with the runtime entirely (requires additional legality analyis)- The ability to inline the registered finalizer at the deallocation point (to enable subsequent SROA)To this end, adding a finalizer is promoted to a builtinthat is recognized by inference and inlining (such that inferencecan produce an inferred version of the finalizer for inlining).The current status is that this fixes the minimal example I wantedto have work, but does not yet extend to the motivating case I had.Nevertheless, I felt that this was a good checkpoint to synchronizewith other efforts along these lines.Currently working demo:```julia> const total_deallocations = Ref{Int}(0)Base.RefValue{Int64}(0)julia> mutable struct DoAlloc function DoAlloc() this = new() Core._add_finalizer(this, function(this) global total_deallocations[] += 1 end) return this end endjulia> function foo() for i = 1:1000 DoAlloc() end endfoo (generic function with 1 method)julia> @code_llvm foo(); @ REPL[3]:1 within `foo`define void @julia_foo_111() #0 {top: %.promoted = load i64, i64* inttoptr (i64 140370001753968 to i64*), align 16; @ REPL[3]:2 within `foo` %0 = add i64 %.promoted, 1000; @ REPL[3] within `foo` store i64 %0, i64* inttoptr (i64 140370001753968 to i64*), align 16; @ REPL[3]:4 within `foo` ret void}```
1 parent94ddc17 commit74334f1

File tree

13 files changed

+267
-55
lines changed

13 files changed

+267
-55
lines changed

‎base/compiler/abstractinterpretation.jl

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1590,6 +1590,16 @@ function invoke_rewrite(xs::Vector{Any})
15901590
return newxs
15911591
end
15921592

1593+
functionabstract_add_finalizer(interp::AbstractInterpreter, argtypes::Vector{Any}, sv::InferenceState)
1594+
iflength(argtypes)==3
1595+
tt= argtypes[3]
1596+
finalizer_argvec= Any[argtypes[3], argtypes[2]]
1597+
call=abstract_call(interp,ArgInfo(nothing, finalizer_argvec), sv,1)
1598+
returnCallMeta(Nothing,FinalizerInfo(call.info))
1599+
end
1600+
returnCallMeta(Nothing,false)
1601+
end
1602+
15931603
# call where the function is known exactly
15941604
functionabstract_call_known(interp::AbstractInterpreter,@nospecialize(f),
15951605
arginfo::ArgInfo, sv::InferenceState,
@@ -1607,6 +1617,8 @@ function abstract_call_known(interp::AbstractInterpreter, @nospecialize(f),
16071617
elseif f=== modifyfield!
16081618
tristate_merge!(sv,Effects())#TODO
16091619
returnabstract_modifyfield!(interp, argtypes, sv)
1620+
elseif f=== Core._add_finalizer
1621+
returnabstract_add_finalizer(interp, argtypes, sv)
16101622
end
16111623
rt=abstract_call_builtin(interp, f, arginfo, sv, max_methods)
16121624
tristate_merge!(sv,builtin_effects(f, argtypes, rt))

‎base/compiler/optimize.jl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ const IR_FLAG_THROW_BLOCK = 0x01 << 3
2727
# This statement may be removed if its result is unused. In particular it must
2828
# thus be both pure and effect free.
2929
const IR_FLAG_EFFECT_FREE=0x01<<4
30+
# This statement was proven not to throw
31+
const IR_FLAG_NOTHROW=0x01<<5
32+
3033

3134
const TOP_TUPLE=GlobalRef(Core,:tuple)
3235

@@ -543,7 +546,7 @@ function run_passes(ci::CodeInfo, sv::OptimizationState, caller::InferenceResult
543546
@timeit"Inlining" ir=ssa_inlining_pass!(ir, ir.linetable, sv.inlining, ci.propagate_inbounds)
544547
# @timeit "verify 2" verify_ir(ir)
545548
@timeit"compact 2" ir=compact!(ir)
546-
@timeit"SROA" ir=sroa_pass!(ir)
549+
@timeit"SROA" ir=sroa_pass!(ir, sv.inlining)
547550
@timeit"ADCE" ir=adce_pass!(ir)
548551
@timeit"type lift" ir=type_lift_pass!(ir)
549552
@timeit"compact 3" ir=compact!(ir)

‎base/compiler/ssair/inlining.jl

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -874,7 +874,8 @@ function validate_sparams(sparams::SimpleVector)
874874
end
875875

876876
functionanalyze_method!(match::MethodMatch, argtypes::Vector{Any},
877-
flag::UInt8, state::InliningState)
877+
flag::UInt8, state::InliningState,
878+
do_resolve::Bool=true)
878879
method= match.method
879880
spec_types= match.spec_types
880881

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

@@ -1206,7 +1207,7 @@ function process_simple!(ir::IRCode, idx::Int, state::InliningState, todo::Vecto
12061207
end
12071208
end
12081209

1209-
if sig.f!== Core.invoke&&is_builtin(sig)
1210+
if sig.f!== Core.invoke&&sig.f!== Core._add_finalizer&&is_builtin(sig)
12101211
# No inlining for builtins (other invoke/apply/typeassert)
12111212
returnnothing
12121213
end
@@ -1226,9 +1227,10 @@ function process_simple!(ir::IRCode, idx::Int, state::InliningState, todo::Vecto
12261227
end
12271228

12281229
#TODO inline non-`isdispatchtuple`, union-split callsites?
1229-
functionanalyze_single_call!(
1230-
ir::IRCode, idx::Int, stmt::Expr, infos::Vector{MethodMatchInfo}, flag::UInt8,
1231-
sig::Signature, state::InliningState, todo::Vector{Pair{Int, Any}})
1230+
functioncompute_inlining_cases(
1231+
infos::Vector{MethodMatchInfo}, flag::UInt8,
1232+
sig::Signature, state::InliningState,
1233+
do_resolve::Bool=true)
12321234
argtypes= sig.argtypes
12331235
cases= InliningCase[]
12341236
local any_fully_covered=false
@@ -1245,7 +1247,7 @@ function analyze_single_call!(
12451247
continue
12461248
end
12471249
for matchin meth
1248-
handled_all_cases&=handle_match!(match, argtypes, flag, state, cases,true)
1250+
handled_all_cases&=handle_match!(match, argtypes, flag, state, cases,true, do_resolve)
12491251
any_fully_covered|= match.fully_covers
12501252
end
12511253
end
@@ -1255,8 +1257,18 @@ function analyze_single_call!(
12551257
filter!(case::InliningCase->isdispatchtuple(case.sig), cases)
12561258
end
12571259

1258-
handle_cases!(ir, idx, stmt,argtypes_to_type(argtypes), cases,
1259-
handled_all_cases& any_fully_covered, todo, state.params)
1260+
return cases, handled_all_cases& any_fully_covered
1261+
end
1262+
1263+
functionanalyze_single_call!(
1264+
ir::IRCode, idx::Int, stmt::Expr, infos::Vector{MethodMatchInfo}, flag::UInt8,
1265+
sig::Signature, state::InliningState, todo::Vector{Pair{Int, Any}})
1266+
1267+
r=compute_inlining_cases(infos, flag, sig, state)
1268+
r===nothing&&returnnothing
1269+
cases, all_covered= r
1270+
handle_cases!(ir, idx, stmt,argtypes_to_type(sig.argtypes), cases,
1271+
all_covered, todo, state.params)
12601272
end
12611273

12621274
# similar to `analyze_single_call!`, but with constant results
@@ -1308,14 +1320,15 @@ end
13081320

13091321
functionhandle_match!(
13101322
match::MethodMatch, argtypes::Vector{Any}, flag::UInt8, state::InliningState,
1311-
cases::Vector{InliningCase}, allow_abstract::Bool=false)
1323+
cases::Vector{InliningCase}, allow_abstract::Bool=false,
1324+
do_resolve::Bool=true)
13121325
spec_types= match.spec_types
13131326
allow_abstract||isdispatchtuple(spec_types)||returnfalse
13141327
# we may see duplicated dispatch signatures here when a signature gets widened
13151328
# during abstract interpretation: for the purpose of inlining, we can just skip
13161329
# processing this dispatch candidate
13171330
_any(case->case.sig=== spec_types, cases)&&returntrue
1318-
item=analyze_method!(match, argtypes, flag, state)
1331+
item=analyze_method!(match, argtypes, flag, state, do_resolve)
13191332
item===nothing&&returnfalse
13201333
push!(cases,InliningCase(spec_types, item))
13211334
returntrue
@@ -1430,6 +1443,40 @@ function assemble_inline_todo!(ir::IRCode, state::InliningState)
14301443
continue
14311444
end
14321445

1446+
# Handle finalizer
1447+
if sig.f=== Core._add_finalizer
1448+
ifisa(info, FinalizerInfo)
1449+
info= info.info
1450+
ifisa(info, MethodMatchInfo)
1451+
infos= MethodMatchInfo[info]
1452+
elseifisa(info, UnionSplitInfo)
1453+
infos= info.matches
1454+
else
1455+
continue
1456+
end
1457+
1458+
ft=argextype(stmt.args[3], ir)
1459+
has_free_typevars(ft)&&returnnothing
1460+
f=singleton_type(ft)
1461+
argtypes=Vector{Any}(undef,2)
1462+
argtypes[1]= ft
1463+
argtypes[2]=argextype(stmt.args[2], ir)
1464+
sig=Signature(f, ft, argtypes)
1465+
1466+
cases, all_covered=compute_inlining_cases(infos,UInt8(0), sig, state,false)
1467+
length(cases)==0&&continue
1468+
if all_covered&&length(cases)==1
1469+
ifisa(cases[1], InliningCase)
1470+
case1= cases[1].item
1471+
ifisa(case1, InliningTodo)
1472+
push!(stmt.args, case1.mi)
1473+
end
1474+
end
1475+
end
1476+
continue
1477+
end
1478+
end
1479+
14331480
# if inference arrived here with constant-prop'ed result(s),
14341481
# we can perform a specialized analysis for just this case
14351482
ifisa(info, ConstCallInfo)

‎base/compiler/ssair/ir.jl

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -166,36 +166,6 @@ const AnySSAValue = Union{SSAValue, OldSSAValue, NewSSAValue}
166166

167167

168168
# SSA-indexed nodes
169-
170-
struct NewInstruction
171-
stmt::Any
172-
type::Any
173-
info::Any
174-
# If nothing, copy the line from previous statement
175-
# in the insertion location
176-
line::Union{Int32, Nothing}
177-
flag::UInt8
178-
179-
## Insertion options
180-
181-
# The IR_FLAG_EFFECT_FREE flag has already been computed (or forced).
182-
# Don't bother redoing so on insertion.
183-
effect_free_computed::Bool
184-
NewInstruction(@nospecialize(stmt),@nospecialize(type),@nospecialize(info),
185-
line::Union{Int32, Nothing}, flag::UInt8, effect_free_computed::Bool)=
186-
new(stmt, type, info, line, flag, effect_free_computed)
187-
end
188-
NewInstruction(@nospecialize(stmt),@nospecialize(type))=
189-
NewInstruction(stmt, type,nothing)
190-
NewInstruction(@nospecialize(stmt),@nospecialize(type), line::Union{Nothing, Int32})=
191-
NewInstruction(stmt, type,nothing, line, IR_FLAG_NULL,false)
192-
193-
effect_free(inst::NewInstruction)=
194-
NewInstruction(inst.stmt, inst.type, inst.info, inst.line, inst.flag| IR_FLAG_EFFECT_FREE,true)
195-
non_effect_free(inst::NewInstruction)=
196-
NewInstruction(inst.stmt, inst.type, inst.info, inst.line, inst.flag&~IR_FLAG_EFFECT_FREE,true)
197-
198-
199169
struct InstructionStream
200170
inst::Vector{Any}
201171
type::Vector{Any}
@@ -295,6 +265,36 @@ function add!(new::NewNodeStream, pos::Int, attach_after::Bool)
295265
end
296266
copy(nns::NewNodeStream)=NewNodeStream(copy(nns.stmts),copy(nns.info))
297267

268+
struct NewInstruction
269+
stmt::Any
270+
type::Any
271+
info::Any
272+
# If nothing, copy the line from previous statement
273+
# in the insertion location
274+
line::Union{Int32, Nothing}
275+
flag::UInt8
276+
277+
## Insertion options
278+
279+
# The IR_FLAG_EFFECT_FREE flag has already been computed (or forced).
280+
# Don't bother redoing so on insertion.
281+
effect_free_computed::Bool
282+
NewInstruction(@nospecialize(stmt),@nospecialize(type),@nospecialize(info),
283+
line::Union{Int32, Nothing}, flag::UInt8, effect_free_computed::Bool)=
284+
new(stmt, type, info, line, flag, effect_free_computed)
285+
end
286+
NewInstruction(@nospecialize(stmt),@nospecialize(type))=
287+
NewInstruction(stmt, type,nothing)
288+
NewInstruction(@nospecialize(stmt),@nospecialize(type), line::Union{Nothing, Int32})=
289+
NewInstruction(stmt, type,nothing, line, IR_FLAG_NULL,false)
290+
NewInstruction(@nospecialize(stmt), meta::Instruction)=
291+
NewInstruction(stmt, meta[:type], meta[:info], meta[:line], meta[:flag],true)
292+
293+
effect_free(inst::NewInstruction)=
294+
NewInstruction(inst.stmt, inst.type, inst.info, inst.line, inst.flag| IR_FLAG_EFFECT_FREE,true)
295+
non_effect_free(inst::NewInstruction)=
296+
NewInstruction(inst.stmt, inst.type, inst.info, inst.line, inst.flag&~IR_FLAG_EFFECT_FREE,true)
297+
298298
struct IRCode
299299
stmts::InstructionStream
300300
argtypes::Vector{Any}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp