@@ -675,24 +675,17 @@ function rewrite_apply_exprargs!(ir::IRCode, todo::Vector{Pair{Int, Any}}, idx::
675
675
new_stmt = Expr (:call , argexprs[2 ], def, state... )
676
676
state1 = insert_node! (ir, idx, NewInstruction (new_stmt, call. rt))
677
677
new_sig = with_atype (call_sig (ir, new_stmt):: Signature )
678
- info = call. info
679
- handled = false
680
- if isa (info, ConstCallInfo)
681
- if maybe_handle_const_call! (
682
- ir, state1. id, new_stmt, info, new_sig,
683
- istate, false , todo)
684
- handled = true
685
- else
686
- info = info. call
687
- end
688
- end
689
- if ! handled && (isa (info, MethodMatchInfo) || isa (info, UnionSplitInfo))
690
- info = isa (info, MethodMatchInfo) ?
691
- MethodMatchInfo[info] : info. matches
678
+ new_info = call. info
679
+ if isa (new_info, ConstCallInfo)
680
+ handle_const_call! (
681
+ ir, state1. id, new_stmt, new_info,
682
+ new_sig, istate, todo)
683
+ elseif isa (new_info, MethodMatchInfo) || isa (new_info, UnionSplitInfo)
684
+ new_infos = isa (new_info, MethodMatchInfo) ? MethodMatchInfo[new_info] : new_info. matches
692
685
# See if we can inline this call to `iterate`
693
686
analyze_single_call! (
694
687
ir, todo, state1. id, new_stmt,
695
- new_sig, info , istate)
688
+ new_sig, new_infos , istate)
696
689
end
697
690
if i != length (thisarginfo. each)
698
691
valT = getfield_tfunc (call. rt, Const (1 ))
@@ -910,7 +903,9 @@ function iterate(split::UnionSplitSignature, state::Vector{Int}...)
910
903
return (sig, state)
911
904
end
912
905
913
- function handle_single_case! (ir:: IRCode , stmt:: Expr , idx:: Int , @nospecialize (case), isinvoke:: Bool , todo:: Vector{Pair{Int, Any}} )
906
+ function handle_single_case! (
907
+ ir:: IRCode , stmt:: Expr , idx:: Int , @nospecialize (case),
908
+ todo:: Vector{Pair{Int, Any}} , isinvoke:: Bool = false )
914
909
if isa (case, ConstantCase)
915
910
ir[SSAValue (idx)] = case. val
916
911
elseif isa (case, MethodInstance)
@@ -1086,13 +1081,13 @@ function inline_invoke!(ir::IRCode, idx::Int, sig::Signature, (; match, result):
1086
1081
validate_sparams (mi. sparam_vals) || return nothing
1087
1082
if argtypes_to_type (atypes) <: mi.def.sig
1088
1083
state. mi_cache != = nothing && (item = resolve_todo (item, state))
1089
- handle_single_case! (ir, stmt, idx, item, true , todo )
1084
+ handle_single_case! (ir, stmt, idx, item, todo, true )
1090
1085
return nothing
1091
1086
end
1092
1087
end
1093
1088
1094
1089
result = analyze_method! (match, atypes, state)
1095
- handle_single_case! (ir, stmt, idx, result, true , todo )
1090
+ handle_single_case! (ir, stmt, idx, result, todo, true )
1096
1091
return nothing
1097
1092
end
1098
1093
@@ -1200,49 +1195,39 @@ function process_simple!(ir::IRCode, todo::Vector{Pair{Int, Any}}, idx::Int, sta
1200
1195
return sig
1201
1196
end
1202
1197
1203
- # TODO inline non-`isdispatchtuple`, union-split callsites
1198
+ # TODO inline non-`isdispatchtuple`, union-split callsites?
1204
1199
function analyze_single_call! (
1205
1200
ir:: IRCode , todo:: Vector{Pair{Int, Any}} , idx:: Int , @nospecialize (stmt),
1206
- (; atypes, atype):: Signature , infos:: Vector{MethodMatchInfo} , state:: InliningState )
1201
+ sig:: Signature , infos:: Vector{MethodMatchInfo} , state:: InliningState )
1202
+ (; atypes, atype) = sig
1207
1203
cases = InliningCase[]
1208
1204
local signature_union = Bottom
1209
1205
local only_method = nothing # keep track of whether there is one matching method
1210
- local meth
1206
+ local meth:: MethodLookupResult
1211
1207
local fully_covered = true
1212
1208
for i in 1 : length (infos)
1213
- info = infos[i]
1214
- meth = info. results
1209
+ meth = infos[i]. results
1215
1210
if meth. ambig
1216
1211
# Too many applicable methods
1217
1212
# Or there is a (partial?) ambiguity
1218
- return
1213
+ return nothing
1219
1214
elseif length (meth) == 0
1220
1215
# No applicable methods; try next union split
1221
1216
continue
1222
- elseif length (meth) == 1 && only_method != = false
1223
- if only_method === nothing
1224
- only_method = meth[1 ]. method
1225
- elseif only_method != = meth[1 ]. method
1217
+ else
1218
+ if length (meth) == 1 && only_method != = false
1219
+ if only_method === nothing
1220
+ only_method = meth[1 ]. method
1221
+ elseif only_method != = meth[1 ]. method
1222
+ only_method = false
1223
+ end
1224
+ else
1226
1225
only_method = false
1227
1226
end
1228
- else
1229
- only_method = false
1230
1227
end
1231
1228
for match in meth
1232
- spec_types = match. spec_types
1233
- signature_union = Union{signature_union, spec_types}
1234
- if ! isdispatchtuple (spec_types)
1235
- fully_covered = false
1236
- continue
1237
- end
1238
- item = analyze_method! (match, atypes, state)
1239
- if item === nothing
1240
- fully_covered = false
1241
- continue
1242
- elseif _any (case-> case. sig === spec_types, cases)
1243
- continue
1244
- end
1245
- push! (cases, InliningCase (spec_types, item))
1229
+ signature_union = Union{signature_union, match. spec_types}
1230
+ fully_covered &= handle_match! (match, atypes, state, cases)
1246
1231
end
1247
1232
end
1248
1233
@@ -1253,9 +1238,8 @@ function analyze_single_call!(
1253
1238
if length (infos) > 1
1254
1239
(metharg, methsp) = ccall (:jl_type_intersection_with_env , Any, (Any, Any),
1255
1240
atype, only_method. sig):: SimpleVector
1256
- match = MethodMatch (metharg, methsp, only_method, true )
1241
+ match = MethodMatch (metharg, methsp:: SimpleVector , only_method, true )
1257
1242
else
1258
- meth = meth:: MethodLookupResult
1259
1243
@assert length (meth) == 1
1260
1244
match = meth[1 ]
1261
1245
end
@@ -1268,46 +1252,41 @@ function analyze_single_call!(
1268
1252
fully_covered = false
1269
1253
end
1270
1254
1271
- # If we only have one case and that case is fully covered, we may either
1272
- # be able to do the inlining now (for constant cases), or push it directly
1273
- # onto the todo list
1274
- if fully_covered && length (cases) == 1
1275
- handle_single_case! (ir, stmt, idx, cases[1 ]. item, false , todo)
1276
- elseif length (cases) > 0
1277
- push! (todo, idx=> UnionSplit (fully_covered, atype, cases))
1278
- end
1279
- return nothing
1255
+ handle_cases! (ir, idx, stmt, sig, cases, fully_covered, todo)
1280
1256
end
1281
1257
1282
- # try to create `InliningCase`s using constant-prop'ed results
1283
- # currently it works only when constant-prop' succeeded for all (union-split) signatures
1284
- # TODO use any of constant-prop'ed results, and leave the other unhandled cases to later
1285
- # TODO this function contains a lot of duplications with `analyze_single_call!`, factor them out
1286
- function maybe_handle_const_call! (
1287
- ir :: IRCode , idx :: Int , stmt :: Expr , (; results):: ConstCallInfo , (; atypes, atype) :: Signature ,
1288
- state :: InliningState , isinvoke :: Bool , todo :: Vector{Pair{Int, Any}} )
1289
- cases = InliningCase[] # TODO avoid this allocation for single cases ?
1258
+ # similar to `analyze_single_call!`, but with constant results
1259
+ function handle_const_call! (
1260
+ ir :: IRCode , idx :: Int , stmt :: Expr , cinfo :: ConstCallInfo ,
1261
+ sig :: Signature , state :: InliningState , todo :: Vector{Pair{Int, Any}} )
1262
+ (; atypes, atype) = sig
1263
+ (; call, results) = cinfo
1264
+ infos = isa (call, MethodMatchInfo) ? MethodMatchInfo[call] : call . matches
1265
+ cases = InliningCase[]
1290
1266
local fully_covered = true
1291
1267
local signature_union = Bottom
1292
- for result in results
1293
- isa (result, InferenceResult) || return false
1294
- (; mi) = item = InliningTodo (result, atypes)
1295
- spec_types = mi. specTypes
1296
- signature_union = Union{signature_union, spec_types}
1297
- if ! isdispatchtuple (spec_types)
1298
- fully_covered = false
1299
- continue
1300
- end
1301
- if ! validate_sparams (mi. sparam_vals)
1302
- fully_covered = false
1268
+ local j = 0
1269
+ for i in 1 : length (infos)
1270
+ meth = infos[i]. results
1271
+ if meth. ambig
1272
+ # Too many applicable methods
1273
+ # Or there is a (partial?) ambiguity
1274
+ return nothing
1275
+ elseif length (meth) == 0
1276
+ # No applicable methods; try next union split
1303
1277
continue
1304
1278
end
1305
- state. mi_cache != = nothing && (item = resolve_todo (item, state))
1306
- if item === nothing
1307
- fully_covered = false
1308
- continue
1279
+ for match in meth
1280
+ j += 1
1281
+ result = results[j]
1282
+ if result === nothing
1283
+ signature_union = Union{signature_union, match. spec_types}
1284
+ fully_covered &= handle_match! (match, atypes, state, cases)
1285
+ else
1286
+ signature_union = Union{signature_union, result. linfo. specTypes}
1287
+ fully_covered &= handle_const_result! (result, atypes, state, cases)
1288
+ end
1309
1289
end
1310
- push! (cases, InliningCase (spec_types, item))
1311
1290
end
1312
1291
1313
1292
# if the signature is fully covered and there is only one applicable method,
@@ -1316,25 +1295,54 @@ function maybe_handle_const_call!(
1316
1295
if length (cases) == 0 && length (results) == 1
1317
1296
(; mi) = item = InliningTodo (results[1 ]:: InferenceResult , atypes)
1318
1297
state. mi_cache != = nothing && (item = resolve_todo (item, state))
1319
- validate_sparams (mi. sparam_vals) || return true
1320
- item === nothing && return true
1298
+ validate_sparams (mi. sparam_vals) || return nothing
1299
+ item === nothing && return nothing
1321
1300
push! (cases, InliningCase (mi. specTypes, item))
1322
1301
fully_covered = true
1323
1302
end
1324
1303
else
1325
1304
fully_covered = false
1326
1305
end
1327
1306
1307
+ handle_cases! (ir, idx, stmt, sig, cases, fully_covered, todo)
1308
+ end
1309
+
1310
+ function handle_match! (
1311
+ match:: MethodMatch , argtypes:: Vector{Any} , state:: InliningState ,
1312
+ cases:: Vector{InliningCase} )
1313
+ spec_types = match. spec_types
1314
+ isdispatchtuple (spec_types) || return false
1315
+ item = analyze_method! (match, argtypes, state)
1316
+ item === nothing && return false
1317
+ _any (case-> case. sig === spec_types, cases) && return true
1318
+ push! (cases, InliningCase (spec_types, item))
1319
+ return true
1320
+ end
1321
+
1322
+ function handle_const_result! (
1323
+ result:: InferenceResult , argtypes:: Vector{Any} , state:: InliningState ,
1324
+ cases:: Vector{InliningCase} )
1325
+ (; mi) = item = InliningTodo (result, argtypes)
1326
+ spec_types = mi. specTypes
1327
+ isdispatchtuple (spec_types) || return false
1328
+ validate_sparams (mi. sparam_vals) || return false
1329
+ state. mi_cache != = nothing && (item = resolve_todo (item, state))
1330
+ item === nothing && return false
1331
+ push! (cases, InliningCase (spec_types, item))
1332
+ return true
1333
+ end
1334
+
1335
+ function handle_cases! (ir:: IRCode , idx:: Int , stmt:: Expr , sig:: Signature ,
1336
+ cases:: Vector{InliningCase} , fully_covered:: Bool , todo:: Vector{Pair{Int, Any}} )
1328
1337
# If we only have one case and that case is fully covered, we may either
1329
1338
# be able to do the inlining now (for constant cases), or push it directly
1330
1339
# onto the todo list
1331
1340
if fully_covered && length (cases) == 1
1332
- handle_single_case! (ir, stmt, idx, cases[1 ]. item, isinvoke, todo)
1341
+ handle_single_case! (ir, stmt, idx, cases[1 ]. item, todo)
1333
1342
elseif length (cases) > 0
1334
- isinvoke && rewrite_invoke_exprargs! (stmt)
1335
- push! (todo, idx=> UnionSplit (fully_covered, atype, cases))
1343
+ push! (todo, idx=> UnionSplit (fully_covered, sig. atype, cases))
1336
1344
end
1337
- return true
1345
+ return nothing
1338
1346
end
1339
1347
1340
1348
function handle_const_opaque_closure_call! (
@@ -1346,7 +1354,7 @@ function handle_const_opaque_closure_call!(
1346
1354
isdispatchtuple (item. mi. specTypes) || return
1347
1355
validate_sparams (item. mi. sparam_vals) || return
1348
1356
state. mi_cache != = nothing && (item = resolve_todo (item, state))
1349
- handle_single_case! (ir, stmt, idx, item, false , todo)
1357
+ handle_single_case! (ir, stmt, idx, item, todo)
1350
1358
return nothing
1351
1359
end
1352
1360
@@ -1371,9 +1379,8 @@ function assemble_inline_todo!(ir::IRCode, state::InliningState)
1371
1379
ir. stmts[idx][:flag ] |= IR_FLAG_EFFECT_FREE
1372
1380
info = info. info
1373
1381
end
1374
-
1375
- # Inference determined this couldn't be analyzed. Don't question it.
1376
1382
if info === false
1383
+ # Inference determined this couldn't be analyzed. Don't question it.
1377
1384
continue
1378
1385
end
1379
1386
@@ -1386,16 +1393,15 @@ function assemble_inline_todo!(ir::IRCode, state::InliningState)
1386
1393
sig, state, todo)
1387
1394
continue
1388
1395
else
1389
- maybe_handle_const_call ! (
1396
+ handle_const_call ! (
1390
1397
ir, idx, stmt, info, sig,
1391
- state, sig . f === Core . invoke, todo) && continue
1398
+ state, todo)
1392
1399
end
1393
- info = info. call # cascade to the non-constant handling
1394
1400
end
1395
1401
1396
1402
if isa (info, OpaqueClosureCallInfo)
1397
1403
item = analyze_method! (info. match, sig. atypes, state)
1398
- handle_single_case! (ir, stmt, idx, item, false , todo)
1404
+ handle_single_case! (ir, stmt, idx, item, todo)
1399
1405
continue
1400
1406
end
1401
1407
0 commit comments