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,32 @@ 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. linfo. specTypes,
688
+ result. linfo. sparam_vals, false , true )
689
+ mi != = nothing && et != = nothing && push! (et, mi:: MethodInstance )
690
+ return mi
691
+ end
692
+
679
693
function resolve_todo (todo:: InliningTodo , et:: Union{EdgeTracker, Nothing} , caches:: InferenceCaches )
680
694
spec = todo. spec:: DelayedInliningSpec
681
- isconst, src = find_inferred (todo. mi, spec. atypes, caches, spec. stmttype)
695
+
696
+ # XXX : update_valid_age!(min_valid[1], max_valid[1], sv)
697
+ isconst, src = false , nothing
698
+ if isa (spec. match, InferenceResult)
699
+ let inferred_src = spec. match. src
700
+ if isa (inferred_src, CodeInfo)
701
+ isconst, src = false , inferred_src
702
+ elseif isa (inferred_src, Const)
703
+ if ! is_inlineable_constant (inferred_src. val)
704
+ return compileable_specialization (et, spec. match)
705
+ end
706
+ isconst, src = true , quoted (inferred_src. val)
707
+ end
708
+ end
709
+ else
710
+ isconst, src = find_inferred (todo. mi, spec. atypes, caches, spec. stmttype)
711
+ end
682
712
683
713
if isconst && et != = nothing
684
714
push! (et, todo. mi)
@@ -717,6 +747,13 @@ function resolve_todo!(todo::Vector{Pair{Int, Any}}, et::Union{EdgeTracker, Noth
717
747
todo
718
748
end
719
749
750
+ function validate_sparams (sparams:: SimpleVector )
751
+ for i = 1 : length (sparams)
752
+ (isa (sparams[i], TypeVar) || isa (sparams[i], Core. TypeofVararg)) && return false
753
+ end
754
+ return true
755
+ end
756
+
720
757
function analyze_method! (match:: MethodMatch , atypes:: Vector{Any} ,
721
758
et:: Union{EdgeTracker, Nothing} ,
722
759
caches:: Union{InferenceCaches, Nothing} ,
@@ -737,9 +774,8 @@ function analyze_method!(match::MethodMatch, atypes::Vector{Any},
737
774
738
775
# Bail out if any static parameters are left as TypeVar
739
776
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
777
+ validate_sparams (match. sparams) || return nothing
778
+
743
779
744
780
if ! params. inlining
745
781
return compileable_specialization (et, match)
@@ -1146,6 +1182,28 @@ function analyze_single_call!(ir::IRCode, todo::Vector{Pair{Int, Any}}, idx::Int
1146
1182
return nothing
1147
1183
end
1148
1184
1185
+ function handle_const_call! (ir:: IRCode , idx:: Int , stmt:: Expr ,
1186
+ info:: ConstCallInfo , sig:: Signature , @nospecialize (calltype),
1187
+ et:: Union{EdgeTracker, Nothing} , caches:: Union{InferenceCaches, Nothing} ,
1188
+ isinvoke:: Bool , todo:: Vector{Pair{Int, Any}} )
1189
+ item = InliningTodo (info. result, sig. atypes, calltype)
1190
+ validate_sparams (item. mi. sparam_vals) || return
1191
+ mthd_sig = item. mi. def. sig
1192
+ mistypes = item. mi. specTypes
1193
+ caches != = nothing && (item = resolve_todo (item, et, caches))
1194
+ if sig. atype <: mthd_sig
1195
+ return handle_single_case! (ir, stmt, idx, item, isinvoke, todo)
1196
+ else
1197
+ item === nothing && return
1198
+ # Union split out the error case
1199
+ item = UnionSplit (false , sig. atype, Pair{Any, Any}[mistypes => item])
1200
+ if isinvoke
1201
+ stmt. args = rewrite_invoke_exprargs! (stmt. args)
1202
+ end
1203
+ push! (todo, idx=> item)
1204
+ end
1205
+ end
1206
+
1149
1207
function assemble_inline_todo! (ir:: IRCode , state:: InliningState )
1150
1208
# todo = (inline_idx, (isva, isinvoke, na), method, spvals, inline_linetable, inline_ir, lie)
1151
1209
todo = Pair{Int, Any}[]
@@ -1173,6 +1231,15 @@ function assemble_inline_todo!(ir::IRCode, state::InliningState)
1173
1231
end
1174
1232
end
1175
1233
1234
+ # If inference arrived at this result by using constant propagation,
1235
+ # it'll performed a specialized analysis for just this case. Use its
1236
+ # result.
1237
+ if isa (info, ConstCallInfo)
1238
+ handle_const_call! (ir, idx, stmt, info, sig, calltype, state. et,
1239
+ state. caches, invoke_data != = nothing , todo)
1240
+ continue
1241
+ end
1242
+
1176
1243
# Ok, now figure out what method to call
1177
1244
if invoke_data != = nothing
1178
1245
inline_invoke! (ir, idx, sig, invoke_data, state, todo)
@@ -1387,35 +1454,6 @@ function ssa_substitute_op!(@nospecialize(val), arg_replacements::Vector{Any},
1387
1454
end
1388
1455
1389
1456
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
1457
linfo = get (caches. mi_cache, mi, nothing )
1420
1458
if linfo isa CodeInstance
1421
1459
if invoke_api (linfo) == 2
0 commit comments