370
370
371
371
function ir_inline_item! (compact:: IncrementalCompact , idx:: Int , argexprs:: Vector{Any} ,
372
372
linetable:: Vector{LineInfoNode} , item:: InliningTodo ,
373
- boundscheck:: Symbol , todo_bbs:: Vector{Tuple{Int, Int}} )
373
+ boundscheck:: Symbol , todo_bbs:: Vector{Tuple{Int, Int}} ,
374
+ extra_flags:: UInt8 = inlined_flags_for_effects (item. effects))
374
375
# Ok, do the inlining here
375
376
sparam_vals = item. mi. sparam_vals
376
377
def = item. mi. def:: Method
@@ -411,6 +412,7 @@ function ir_inline_item!(compact::IncrementalCompact, idx::Int, argexprs::Vector
411
412
break
412
413
end
413
414
inline_compact[idx′] = stmt′
415
+ inline_compact[SSAValue (idx′)][:flag ] |= extra_flags
414
416
end
415
417
just_fixup! (inline_compact, new_new_offset, late_fixup_offset)
416
418
compact. result_idx = inline_compact. result_idx
@@ -445,6 +447,14 @@ function ir_inline_item!(compact::IncrementalCompact, idx::Int, argexprs::Vector
445
447
stmt′ = PhiNode (Int32[edge+ bb_offset for edge in stmt′. edges], stmt′. values)
446
448
end
447
449
inline_compact[idx′] = stmt′
450
+ if extra_flags != 0 && ! isa (stmt′, Union{GotoNode, GotoIfNot})
451
+ if (extra_flags & IR_FLAG_NOTHROW) != 0 && inline_compact[SSAValue (idx′)][:type ] === Union{}
452
+ # Shown nothrow, but also guaranteed to throw => unreachable
453
+ inline_compact[idx′] = ReturnNode ()
454
+ else
455
+ inline_compact[SSAValue (idx′)][:flag ] |= extra_flags
456
+ end
457
+ end
448
458
end
449
459
just_fixup! (inline_compact, new_new_offset, late_fixup_offset)
450
460
compact. result_idx = inline_compact. result_idx
838
848
839
849
# the general resolver for usual and const-prop'ed calls
840
850
function resolve_todo (mi:: MethodInstance , result:: Union{MethodMatch,InferenceResult} ,
841
- argtypes:: Vector{Any} , @nospecialize (info:: CallInfo ), flag:: UInt8 ,
842
- state:: InliningState ; invokesig:: Union{Nothing,Vector{Any}} = nothing )
851
+ argtypes:: Vector{Any} , @nospecialize (info:: CallInfo ), flag:: UInt8 ,
852
+ state:: InliningState ; invokesig:: Union{Nothing,Vector{Any}} = nothing ,
853
+ override_effects:: Effects = EFFECTS_UNKNOWN′)
843
854
et = InliningEdgeTracker (state. et, invokesig)
844
855
845
856
# XXX : update_valid_age!(min_valid[1], max_valid[1], sv)
@@ -860,6 +871,10 @@ function resolve_todo(mi::MethodInstance, result::Union{MethodMatch,InferenceRes
860
871
(; src, effects) = cached_result
861
872
end
862
873
874
+ if override_effects != = EFFECTS_UNKNOWN′
875
+ effects = override_effects
876
+ end
877
+
863
878
# the duplicated check might have been done already within `analyze_method!`, but still
864
879
# we need it here too since we may come here directly using a constant-prop' result
865
880
if ! state. params. inlining || is_stmt_noinline (flag)
@@ -937,7 +952,8 @@ can_inline_typevars(m::MethodMatch, argtypes::Vector{Any}) = can_inline_typevars
937
952
938
953
function analyze_method! (match:: MethodMatch , argtypes:: Vector{Any} ,
939
954
@nospecialize (info:: CallInfo ), flag:: UInt8 , state:: InliningState ;
940
- allow_typevars:: Bool , invokesig:: Union{Nothing,Vector{Any}} = nothing )
955
+ allow_typevars:: Bool , invokesig:: Union{Nothing,Vector{Any}} = nothing ,
956
+ override_effects:: Effects = EFFECTS_UNKNOWN′)
941
957
method = match. method
942
958
spec_types = match. spec_types
943
959
@@ -967,11 +983,13 @@ function analyze_method!(match::MethodMatch, argtypes::Vector{Any},
967
983
mi = specialize_method (match; preexisting= true ) # Union{Nothing, MethodInstance}
968
984
if mi === nothing
969
985
et = InliningEdgeTracker (state. et, invokesig)
970
- return compileable_specialization (match, Effects (), et, info;
986
+ effects = override_effects
987
+ effects === EFFECTS_UNKNOWN′ && (effects = info_effects (nothing , match, state))
988
+ return compileable_specialization (match, effects, et, info;
971
989
compilesig_invokes= state. params. compilesig_invokes)
972
990
end
973
991
974
- return resolve_todo (mi, match, argtypes, info, flag, state; invokesig)
992
+ return resolve_todo (mi, match, argtypes, info, flag, state; invokesig, override_effects )
975
993
end
976
994
977
995
function retrieve_ir_for_inlining (mi:: MethodInstance , src:: Array{UInt8, 1} )
@@ -994,6 +1012,37 @@ function flags_for_effects(effects::Effects)
994
1012
return flags
995
1013
end
996
1014
1015
+ """
1016
+ inlined_flags_for_effects(effects::Effects)
1017
+
1018
+ This function answers the query:
1019
+
1020
+ Given a call site annotated as `effects`, what can we say about each inlined
1021
+ statement after the inlining?
1022
+
1023
+ Note that this is different from `flags_for_effects`, which just talks about
1024
+ the call site itself. Consider for example:
1025
+
1026
+ ````
1027
+ function foo()
1028
+ V = Any[]
1029
+ push!(V, 1)
1030
+ tuple(V...)
1031
+ end
1032
+ ```
1033
+
1034
+ This function is properly inferred effect_free, because it has no global effects.
1035
+ However, we may not inline each statement with an :effect_free flag, because
1036
+ that would incorrectly lose the `push!`.
1037
+ """
1038
+ function inlined_flags_for_effects (effects:: Effects )
1039
+ flags:: UInt8 = 0
1040
+ if is_nothrow (effects)
1041
+ flags |= IR_FLAG_NOTHROW
1042
+ end
1043
+ return flags
1044
+ end
1045
+
997
1046
function handle_single_case! (todo:: Vector{Pair{Int,Any}} ,
998
1047
ir:: IRCode , idx:: Int , stmt:: Expr , @nospecialize (case), params:: OptimizationParams ,
999
1048
isinvoke:: Bool = false )
@@ -1170,21 +1219,26 @@ function handle_invoke_call!(todo::Vector{Pair{Int,Any}},
1170
1219
end
1171
1220
result = info. result
1172
1221
invokesig = sig. argtypes
1173
- if isa (result, ConcreteResult) && may_inline_concrete_result (result)
1174
- item = concrete_result_item (result, state; invokesig)
1175
- else
1176
- argtypes = invoke_rewrite (sig. argtypes)
1177
- if isa (result, ConstPropResult)
1178
- mi = result. result. linfo
1179
- validate_sparams (mi. sparam_vals) || return nothing
1180
- if argtypes_to_type (argtypes) <: mi.def.sig
1181
- item = resolve_todo (mi, result. result, argtypes, info, flag, state; invokesig)
1182
- handle_single_case! (todo, ir, idx, stmt, item, state. params, true )
1183
- return nothing
1184
- end
1222
+ override_effects = EFFECTS_UNKNOWN′
1223
+ if isa (result, ConcreteResult)
1224
+ if may_inline_concrete_result (result)
1225
+ item = concrete_result_item (result, state; invokesig)
1226
+ handle_single_case! (todo, ir, idx, stmt, item, state. params, true )
1227
+ return nothing
1185
1228
end
1186
- item = analyze_method! (match, argtypes, info, flag, state; allow_typevars = false , invokesig)
1229
+ override_effects = result . effects
1187
1230
end
1231
+ argtypes = invoke_rewrite (sig. argtypes)
1232
+ if isa (result, ConstPropResult)
1233
+ mi = result. result. linfo
1234
+ validate_sparams (mi. sparam_vals) || return nothing
1235
+ if argtypes_to_type (argtypes) <: mi.def.sig
1236
+ item = resolve_todo (mi, result. result, argtypes, info, flag, state; invokesig, override_effects)
1237
+ handle_single_case! (todo, ir, idx, stmt, item, state. params, true )
1238
+ return nothing
1239
+ end
1240
+ end
1241
+ item = analyze_method! (match, argtypes, info, flag, state; allow_typevars= false , invokesig, override_effects)
1188
1242
handle_single_case! (todo, ir, idx, stmt, item, state. params, true )
1189
1243
return nothing
1190
1244
end
@@ -1296,10 +1350,12 @@ function handle_any_const_result!(cases::Vector{InliningCase},
1296
1350
@nospecialize (result), match:: MethodMatch , argtypes:: Vector{Any} ,
1297
1351
@nospecialize (info:: CallInfo ), flag:: UInt8 , state:: InliningState ;
1298
1352
allow_abstract:: Bool , allow_typevars:: Bool )
1353
+ override_effects = EFFECTS_UNKNOWN′
1299
1354
if isa (result, ConcreteResult)
1300
1355
if may_inline_concrete_result (result)
1301
1356
return handle_concrete_result! (cases, result, state)
1302
1357
else
1358
+ override_effects = result. effects
1303
1359
result = nothing
1304
1360
end
1305
1361
end
@@ -1313,7 +1369,7 @@ function handle_any_const_result!(cases::Vector{InliningCase},
1313
1369
return handle_const_prop_result! (cases, result, argtypes, info, flag, state; allow_abstract, allow_typevars)
1314
1370
else
1315
1371
@assert result === nothing
1316
- return handle_match! (cases, match, argtypes, info, flag, state; allow_abstract, allow_typevars)
1372
+ return handle_match! (cases, match, argtypes, info, flag, state; allow_abstract, allow_typevars, override_effects )
1317
1373
end
1318
1374
end
1319
1375
@@ -1444,14 +1500,14 @@ end
1444
1500
function handle_match! (cases:: Vector{InliningCase} ,
1445
1501
match:: MethodMatch , argtypes:: Vector{Any} , @nospecialize (info:: CallInfo ), flag:: UInt8 ,
1446
1502
state:: InliningState ;
1447
- allow_abstract:: Bool , allow_typevars:: Bool )
1503
+ allow_abstract:: Bool , allow_typevars:: Bool , override_effects :: Effects )
1448
1504
spec_types = match. spec_types
1449
1505
allow_abstract || isdispatchtuple (spec_types) || return false
1450
1506
# We may see duplicated dispatch signatures here when a signature gets widened
1451
1507
# during abstract interpretation: for the purpose of inlining, we can just skip
1452
1508
# processing this dispatch candidate (unless unmatched type parameters are present)
1453
1509
! allow_typevars && _any (case-> case. sig === spec_types, cases) && return true
1454
- item = analyze_method! (match, argtypes, info, flag, state; allow_typevars)
1510
+ item = analyze_method! (match, argtypes, info, flag, state; allow_typevars, override_effects )
1455
1511
item === nothing && return false
1456
1512
push! (cases, InliningCase (spec_types, item))
1457
1513
return true
@@ -1526,8 +1582,13 @@ function handle_opaque_closure_call!(todo::Vector{Pair{Int,Any}},
1526
1582
mi = result. result. linfo
1527
1583
validate_sparams (mi. sparam_vals) || return nothing
1528
1584
item = resolve_todo (mi, result. result, sig. argtypes, info, flag, state)
1529
- elseif isa (result, ConcreteResult) && may_inline_concrete_result (result)
1530
- item = concrete_result_item (result, state)
1585
+ elseif isa (result, ConcreteResult)
1586
+ if may_inline_concrete_result (result)
1587
+ item = concrete_result_item (result, state)
1588
+ else
1589
+ override_effects = result. effects
1590
+ item = analyze_method! (info. match, sig. argtypes, info, flag, state; allow_typevars= false , override_effects)
1591
+ end
1531
1592
else
1532
1593
item = analyze_method! (info. match, sig. argtypes, info, flag, state; allow_typevars= false )
1533
1594
end
0 commit comments