@@ -308,21 +308,17 @@ function finish_cfg_inline!(state::CFGInliningState)
308
308
end
309
309
end
310
310
311
- function ir_inline_item! (compact:: IncrementalCompact , idx:: Int , argexprs:: Vector{Any} ,
312
- linetable:: Vector{LineInfoNode} , item:: InliningTodo ,
313
- boundscheck:: Symbol , todo_bbs:: Vector{Tuple{Int, Int}} )
314
- # Ok, do the inlining here
315
- spec = item. spec:: ResolvedInliningSpec
316
- sparam_vals = item. mi. sparam_vals
317
- def = item. mi. def:: Method
311
+ function ir_inline_linetable! (linetable:: Vector{LineInfoNode} , inlinee_ir:: IRCode ,
312
+ inlinee:: Method ,
313
+ inlined_at:: Int32 )
314
+ coverage = coverage_enabled (inlinee. module)
318
315
linetable_offset:: Int32 = length (linetable)
319
316
# Append the linetable of the inlined function to our line table
320
- inlined_at = compact. result[idx][:line ]
321
317
topline:: Int32 = linetable_offset + Int32 (1 )
322
- coverage = coverage_enabled (def. module)
323
318
coverage_by_path = JLOptions (). code_coverage == 3
324
- push! (linetable, LineInfoNode (def. module, def. name, def. file, def. line, inlined_at))
325
- oldlinetable = spec. ir. linetable
319
+ push! (linetable, LineInfoNode (inlinee. module, inlinee. name, inlinee. file, inlinee. line, inlined_at))
320
+ oldlinetable = inlinee_ir. linetable
321
+ extra_coverage_line = 0
326
322
for oldline in 1 : length (oldlinetable)
327
323
entry = oldlinetable[oldline]
328
324
if ! coverage && coverage_by_path && is_file_tracked (entry. file)
@@ -341,8 +337,25 @@ function ir_inline_item!(compact::IncrementalCompact, idx::Int, argexprs::Vector
341
337
end
342
338
push! (linetable, newentry)
343
339
end
344
- if coverage && spec. ir. stmts[1 ][:line ] + linetable_offset != topline
345
- insert_node_here! (compact, NewInstruction (Expr (:code_coverage_effect ), Nothing, topline))
340
+ if coverage && inlinee_ir. stmts[1 ][:line ] + linetable_offset != topline
341
+ extra_coverage_line = topline
342
+ end
343
+ return linetable_offset, extra_coverage_line
344
+ end
345
+
346
+ function ir_inline_item! (compact:: IncrementalCompact , idx:: Int , argexprs:: Vector{Any} ,
347
+ linetable:: Vector{LineInfoNode} , item:: InliningTodo ,
348
+ boundscheck:: Symbol , todo_bbs:: Vector{Tuple{Int, Int}} )
349
+ # Ok, do the inlining here
350
+ spec = item. spec:: ResolvedInliningSpec
351
+ sparam_vals = item. mi. sparam_vals
352
+ def = item. mi. def:: Method
353
+ inlined_at = compact. result[idx][:line ]
354
+ linetable_offset:: Int32 = length (linetable)
355
+ topline:: Int32 = linetable_offset + Int32 (1 )
356
+ linetable_offset, extra_coverage_line = ir_inline_linetable! (linetable, item. spec. ir, def, inlined_at)
357
+ if extra_coverage_line != 0
358
+ insert_node_here! (compact, NewInstruction (Expr (:code_coverage_effect ), Nothing, extra_coverage_line))
346
359
end
347
360
if def. isva
348
361
nargs_def = Int (def. nargs:: Int32 )
@@ -839,7 +852,7 @@ function resolve_todo(todo::InliningTodo, state::InliningState, flag::UInt8)
839
852
src === nothing && return compileable_specialization (et, match, effects)
840
853
841
854
et != = nothing && push! (et, mi)
842
- return InliningTodo (mi, src, effects)
855
+ return InliningTodo (mi, retrieve_ir_for_inlining (mi, src) , effects)
843
856
end
844
857
845
858
function resolve_todo ((; fully_covered, atype, cases, #= bbs=# ):: UnionSplit , state:: InliningState , flag:: UInt8 )
@@ -861,7 +874,8 @@ function validate_sparams(sparams::SimpleVector)
861
874
end
862
875
863
876
function analyze_method! (match:: MethodMatch , argtypes:: Vector{Any} ,
864
- flag:: UInt8 , state:: InliningState )
877
+ flag:: UInt8 , state:: InliningState ,
878
+ do_resolve:: Bool = true )
865
879
method = match. method
866
880
spec_types = match. spec_types
867
881
@@ -895,7 +909,7 @@ function analyze_method!(match::MethodMatch, argtypes::Vector{Any},
895
909
todo = InliningTodo (mi, match, argtypes)
896
910
# If we don't have caches here, delay resolving this MethodInstance
897
911
# until the batch inlining step (or an external post-processing pass)
898
- state. mi_cache === nothing && return todo
912
+ do_resolve && state. mi_cache === nothing && return todo
899
913
return resolve_todo (todo, state, flag)
900
914
end
901
915
@@ -904,17 +918,12 @@ function InliningTodo(mi::MethodInstance, ir::IRCode, effects::Effects)
904
918
return InliningTodo (mi, ResolvedInliningSpec (ir, effects))
905
919
end
906
920
907
- function InliningTodo (mi:: MethodInstance , src:: Union{CodeInfo, Vector{UInt8}} , effects:: Effects )
908
- if ! isa (src, CodeInfo)
909
- src = ccall (:jl_uncompress_ir , Any, (Any, Ptr{Cvoid}, Any), mi. def, C_NULL , src:: Vector{UInt8} ):: CodeInfo
910
- else
911
- src = copy (src)
912
- end
913
- @timeit " inline IR inflation" begin
914
- ir = inflate_ir! (src, mi):: IRCode
915
- return InliningTodo (mi, ResolvedInliningSpec (ir, effects))
916
- end
921
+ function retrieve_ir_for_inlining (mi:: MethodInstance , src:: Array{UInt8, 1} )
922
+ src = ccall (:jl_uncompress_ir , Any, (Any, Ptr{Cvoid}, Any), mi. def, C_NULL , src:: Vector{UInt8} ):: CodeInfo
923
+ return inflate_ir! (src, mi)
917
924
end
925
+ retrieve_ir_for_inlining (mi:: MethodInstance , src:: CodeInfo ) = inflate_ir (src, mi):: IRCode
926
+ retrieve_ir_for_inlining (mi:: MethodInstance , ir:: IRCode ) = copy (ir)
918
927
919
928
function handle_single_case! (
920
929
ir:: IRCode , idx:: Int , stmt:: Expr ,
@@ -1196,7 +1205,7 @@ function process_simple!(ir::IRCode, idx::Int, state::InliningState, todo::Vecto
1196
1205
end
1197
1206
end
1198
1207
1199
- if sig. f != = Core. invoke && is_builtin (sig)
1208
+ if sig. f != = Core. invoke && sig . f != = Core . finalizer && is_builtin (sig)
1200
1209
# No inlining for builtins (other invoke/apply/typeassert)
1201
1210
return nothing
1202
1211
end
@@ -1213,9 +1222,10 @@ function process_simple!(ir::IRCode, idx::Int, state::InliningState, todo::Vecto
1213
1222
end
1214
1223
1215
1224
# TODO inline non-`isdispatchtuple`, union-split callsites?
1216
- function analyze_single_call! (
1217
- ir:: IRCode , idx:: Int , stmt:: Expr , infos:: Vector{MethodMatchInfo} , flag:: UInt8 ,
1218
- sig:: Signature , state:: InliningState , todo:: Vector{Pair{Int, Any}} )
1225
+ function compute_inlining_cases (
1226
+ infos:: Vector{MethodMatchInfo} , flag:: UInt8 ,
1227
+ sig:: Signature , state:: InliningState ,
1228
+ do_resolve:: Bool = true )
1219
1229
argtypes = sig. argtypes
1220
1230
cases = InliningCase[]
1221
1231
local any_fully_covered = false
@@ -1232,7 +1242,7 @@ function analyze_single_call!(
1232
1242
continue
1233
1243
end
1234
1244
for match in meth
1235
- handled_all_cases &= handle_match! (match, argtypes, flag, state, cases, true )
1245
+ handled_all_cases &= handle_match! (match, argtypes, flag, state, cases, true , do_resolve )
1236
1246
any_fully_covered |= match. fully_covers
1237
1247
end
1238
1248
end
@@ -1242,8 +1252,18 @@ function analyze_single_call!(
1242
1252
filter! (case:: InliningCase -> isdispatchtuple (case. sig), cases)
1243
1253
end
1244
1254
1245
- handle_cases! (ir, idx, stmt, argtypes_to_type (argtypes), cases,
1246
- handled_all_cases & any_fully_covered, todo, state. params)
1255
+ return cases, handled_all_cases & any_fully_covered
1256
+ end
1257
+
1258
+ function analyze_single_call! (
1259
+ ir:: IRCode , idx:: Int , stmt:: Expr , infos:: Vector{MethodMatchInfo} , flag:: UInt8 ,
1260
+ sig:: Signature , state:: InliningState , todo:: Vector{Pair{Int, Any}} )
1261
+
1262
+ r = compute_inlining_cases (infos, flag, sig, state)
1263
+ r === nothing && return nothing
1264
+ cases, all_covered = r
1265
+ handle_cases! (ir, idx, stmt, argtypes_to_type (sig. argtypes), cases,
1266
+ all_covered, todo, state. params)
1247
1267
end
1248
1268
1249
1269
# similar to `analyze_single_call!`, but with constant results
@@ -1299,14 +1319,15 @@ end
1299
1319
1300
1320
function handle_match! (
1301
1321
match:: MethodMatch , argtypes:: Vector{Any} , flag:: UInt8 , state:: InliningState ,
1302
- cases:: Vector{InliningCase} , allow_abstract:: Bool = false )
1322
+ cases:: Vector{InliningCase} , allow_abstract:: Bool = false ,
1323
+ do_resolve:: Bool = true )
1303
1324
spec_types = match. spec_types
1304
1325
allow_abstract || isdispatchtuple (spec_types) || return false
1305
1326
# we may see duplicated dispatch signatures here when a signature gets widened
1306
1327
# during abstract interpretation: for the purpose of inlining, we can just skip
1307
1328
# processing this dispatch candidate
1308
1329
_any (case-> case. sig === spec_types, cases) && return true
1309
- item = analyze_method! (match, argtypes, flag, state)
1330
+ item = analyze_method! (match, argtypes, flag, state, do_resolve )
1310
1331
item === nothing && return false
1311
1332
push! (cases, InliningCase (spec_types, item))
1312
1333
return true
@@ -1419,6 +1440,48 @@ function assemble_inline_todo!(ir::IRCode, state::InliningState)
1419
1440
continue
1420
1441
end
1421
1442
1443
+ # Handle finalizer
1444
+ if sig. f === Core. finalizer
1445
+ if isa (info, FinalizerInfo)
1446
+ # Only inline finalizers that are known nothrow and notls.
1447
+ # This avoids having to set up state for finalizer isolation
1448
+ (is_nothrow (info. effects) && is_notaskstate (info. effects)) || continue
1449
+
1450
+ info = info. info
1451
+ if isa (info, MethodMatchInfo)
1452
+ infos = MethodMatchInfo[info]
1453
+ elseif isa (info, UnionSplitInfo)
1454
+ infos = info. matches
1455
+ else
1456
+ continue
1457
+ end
1458
+
1459
+ ft = argextype (stmt. args[2 ], ir)
1460
+ has_free_typevars (ft) && return nothing
1461
+ f = singleton_type (ft)
1462
+ argtypes = Vector {Any} (undef, 2 )
1463
+ argtypes[1 ] = ft
1464
+ argtypes[2 ] = argextype (stmt. args[3 ], ir)
1465
+ sig = Signature (f, ft, argtypes)
1466
+
1467
+ cases, all_covered = compute_inlining_cases (infos, UInt8 (0 ), sig, state, false )
1468
+ length (cases) == 0 && continue
1469
+ if all_covered && length (cases) == 1
1470
+ if isa (cases[1 ], InliningCase)
1471
+ case1 = cases[1 ]. item
1472
+ if isa (case1, InliningTodo)
1473
+ push! (stmt. args, true )
1474
+ push! (stmt. args, case1. mi)
1475
+ elseif isa (case1, InvokeCase)
1476
+ push! (stmt. args, false )
1477
+ push! (stmt. args, case1. invoke)
1478
+ end
1479
+ end
1480
+ end
1481
+ continue
1482
+ end
1483
+ end
1484
+
1422
1485
# if inference arrived here with constant-prop'ed result(s),
1423
1486
# we can perform a specialized analysis for just this case
1424
1487
if isa (info, ConstCallInfo)
0 commit comments