33
33
pass to apply its own inlining policy decisions.
34
34
"""
35
35
struct DelayedInliningSpec
36
- match:: MethodMatch
36
+ match:: Union{ MethodMatch, InferenceResult}
37
37
atypes:: Vector{Any}
38
38
stmttype:: Any
39
39
end
@@ -44,7 +44,11 @@ struct InliningTodo
44
44
spec:: Union{ResolvedInliningSpec, DelayedInliningSpec}
45
45
end
46
46
47
- InliningTodo (mi:: MethodInstance , match:: MethodMatch , atypes:: Vector{Any} , @nospecialize (stmttype)) = InliningTodo (mi, DelayedInliningSpec (match, atypes, stmttype))
47
+ InliningTodo (mi:: MethodInstance , match:: MethodMatch ,
48
+ atypes:: Vector{Any} , @nospecialize (stmttype)) = InliningTodo (mi, DelayedInliningSpec (match, atypes, stmttype))
49
+
50
+ InliningTodo (result:: InferenceResult , atypes:: Vector{Any} , @nospecialize (stmttype)) =
51
+ InliningTodo (result. linfo, DelayedInliningSpec (result, atypes, stmttype))
48
52
49
53
struct ConstantCase
50
54
val:: Any
@@ -631,7 +635,10 @@ function rewrite_apply_exprargs!(ir::IRCode, todo::Vector{Pair{Int, Any}}, idx::
631
635
new_stmt = Expr (:call , argexprs[2 ], def, state... )
632
636
state1 = insert_node! (ir, idx, call. rt, new_stmt)
633
637
new_sig = with_atype (call_sig (ir, new_stmt):: Signature )
634
- if isa (call. info, MethodMatchInfo) || isa (call. info, UnionSplitInfo)
638
+ if isa (call. info, ConstCallInfo)
639
+ handle_const_call! (ir, state1. id, new_stmt, call. info, new_sig,
640
+ call. rt, et, caches, false , todo)
641
+ elseif isa (call. info, MethodMatchInfo) || isa (call. info, UnionSplitInfo)
635
642
info = isa (call. info, MethodMatchInfo) ?
636
643
MethodMatchInfo[call. info] : call. info. matches
637
644
# See if we can inline this call to `iterate`
@@ -676,9 +683,31 @@ function compileable_specialization(et::Union{EdgeTracker, Nothing}, match::Meth
676
683
return mi
677
684
end
678
685
686
+ function compileable_specialization (et:: Union{EdgeTracker, Nothing} , result:: InferenceResult )
687
+ mi = specialize_method (result. linfo. def, result. argtypes, result. linfo. sparam_vals, false , true )
688
+ mi != = nothing && et != = nothing && push! (et, mi:: MethodInstance )
689
+ return mi
690
+ end
691
+
679
692
function resolve_todo (todo:: InliningTodo , et:: Union{EdgeTracker, Nothing} , caches:: InferenceCaches )
680
693
spec = todo. spec:: DelayedInliningSpec
681
- isconst, src = find_inferred (todo. mi, spec. atypes, caches, spec. stmttype)
694
+
695
+ # XXX : update_valid_age!(min_valid[1], max_valid[1], sv)
696
+ isconst, src = false , nothing
697
+ if isa (spec. match, InferenceResult)
698
+ let inferred_src = spec. match. src
699
+ if isa (inferred_src, CodeInfo)
700
+ isconst, src = false , inferred_src
701
+ elseif isa (inferred_src, Const)
702
+ if ! is_inlineable_constant (inferred_src. val)
703
+ return compileable_specialization (et, spec. match)
704
+ end
705
+ isconst, src = true , quoted (inferred_src. val)
706
+ end
707
+ end
708
+ else
709
+ isconst, src = find_inferred (todo. mi, spec. atypes, caches, spec. stmttype)
710
+ end
682
711
683
712
if isconst && et != = nothing
684
713
push! (et, todo. mi)
@@ -717,6 +746,13 @@ function resolve_todo!(todo::Vector{Pair{Int, Any}}, et::Union{EdgeTracker, Noth
717
746
todo
718
747
end
719
748
749
+ function validate_sparams (sparams:: SimpleVector )
750
+ for i = 1 : length (sparams)
751
+ (isa (sparams[i], TypeVar) || isa (sparams[i], Core. TypeofVararg)) && return false
752
+ end
753
+ return true
754
+ end
755
+
720
756
function analyze_method! (match:: MethodMatch , atypes:: Vector{Any} ,
721
757
et:: Union{EdgeTracker, Nothing} ,
722
758
caches:: Union{InferenceCaches, Nothing} ,
@@ -737,9 +773,8 @@ function analyze_method!(match::MethodMatch, atypes::Vector{Any},
737
773
738
774
# Bail out if any static parameters are left as TypeVar
739
775
ok = true
740
- for i = 1 : length (match. sparams)
741
- (isa (match. sparams[i], TypeVar) || isa (match. sparams[i], Core. TypeofVararg)) && return nothing
742
- end
776
+ validate_sparams (match. sparams) || return nothing
777
+
743
778
744
779
if ! params. inlining
745
780
return compileable_specialization (et, match)
@@ -1146,6 +1181,28 @@ function analyze_single_call!(ir::IRCode, todo::Vector{Pair{Int, Any}}, idx::Int
1146
1181
return nothing
1147
1182
end
1148
1183
1184
+ function handle_const_call! (ir:: IRCode , idx:: Int , stmt:: Expr ,
1185
+ info:: ConstCallInfo , sig:: Signature , @nospecialize (calltype),
1186
+ et:: Union{EdgeTracker, Nothing} , caches:: Union{InferenceCaches, Nothing} ,
1187
+ isinvoke:: Bool , todo:: Vector{Pair{Int, Any}} )
1188
+ item = InliningTodo (info. result, sig. atypes, calltype)
1189
+ validate_sparams (item. mi. sparam_vals) || return
1190
+ mthd_sig = item. mi. def. sig
1191
+ mistypes = item. mi. specTypes
1192
+ caches != = nothing && (item = resolve_todo (item, et, caches))
1193
+ if sig. atype <: mthd_sig
1194
+ return handle_single_case! (ir, stmt, idx, item, isinvoke, todo)
1195
+ else
1196
+ item === nothing && return
1197
+ # Union split out the error case
1198
+ item = UnionSplit (false , sig. atype, Pair{Any, Any}[mistypes => item])
1199
+ if isinvoke
1200
+ stmt. args = rewrite_invoke_exprargs! (stmt. args)
1201
+ end
1202
+ push! (todo, idx=> item)
1203
+ end
1204
+ end
1205
+
1149
1206
function assemble_inline_todo! (ir:: IRCode , state:: InliningState )
1150
1207
# todo = (inline_idx, (isva, isinvoke, na), method, spvals, inline_linetable, inline_ir, lie)
1151
1208
todo = Pair{Int, Any}[]
@@ -1173,6 +1230,15 @@ function assemble_inline_todo!(ir::IRCode, state::InliningState)
1173
1230
end
1174
1231
end
1175
1232
1233
+ # If inference arrived at this result by using constant propagation,
1234
+ # it'll performed a specialized analysis for just this case. Use its
1235
+ # result.
1236
+ if isa (info, ConstCallInfo)
1237
+ handle_const_call! (ir, idx, stmt, info, sig, calltype, state. et,
1238
+ state. caches, invoke_data != = nothing , todo)
1239
+ continue
1240
+ end
1241
+
1176
1242
# Ok, now figure out what method to call
1177
1243
if invoke_data != = nothing
1178
1244
inline_invoke! (ir, idx, sig, invoke_data, state, todo)
@@ -1387,35 +1453,6 @@ function ssa_substitute_op!(@nospecialize(val), arg_replacements::Vector{Any},
1387
1453
end
1388
1454
1389
1455
function find_inferred (mi:: MethodInstance , atypes:: Vector{Any} , caches:: InferenceCaches , @nospecialize (rettype))
1390
- if caches. inf_cache != = nothing
1391
- # see if the method has a InferenceResult in the current cache
1392
- # or an existing inferred code info store in `.inferred`
1393
- haveconst = false
1394
- for i in 1 : length (atypes)
1395
- if has_nontrivial_const_info (atypes[i])
1396
- # have new information from argtypes that wasn't available from the signature
1397
- haveconst = true
1398
- break
1399
- end
1400
- end
1401
- if haveconst || improvable_via_constant_propagation (rettype)
1402
- inf_result = cache_lookup (mi, atypes, caches. inf_cache) # Union{Nothing, InferenceResult}
1403
- else
1404
- inf_result = nothing
1405
- end
1406
- # XXX : update_valid_age!(min_valid[1], max_valid[1], sv)
1407
- if isa (inf_result, InferenceResult)
1408
- let inferred_src = inf_result. src
1409
- if isa (inferred_src, CodeInfo)
1410
- return svec (false , inferred_src)
1411
- end
1412
- if isa (inferred_src, Const) && is_inlineable_constant (inferred_src. val)
1413
- return svec (true , quoted (inferred_src. val),)
1414
- end
1415
- end
1416
- end
1417
- end
1418
-
1419
1456
linfo = get (caches. mi_cache, mi, nothing )
1420
1457
if linfo isa CodeInstance
1421
1458
if invoke_api (linfo) == 2
0 commit comments