@@ -675,19 +675,16 @@ function rewrite_apply_exprargs!(
675
675
new_sig = with_atype (call_sig (ir, new_stmt):: Signature )
676
676
new_info = call. info
677
677
if isa (new_info, ConstCallInfo)
678
- maybe_handle_const_call ! (
678
+ handle_const_call ! (
679
679
ir, state1. id, new_stmt, new_info, flag,
680
- new_sig, istate, todo) && @goto analyzed
681
- new_info = new_info. call # cascade to the non-constant handling
682
- end
683
- if isa (new_info, MethodMatchInfo) || isa (new_info, UnionSplitInfo)
680
+ new_sig, istate, todo)
681
+ elseif isa (new_info, MethodMatchInfo) || isa (new_info, UnionSplitInfo)
684
682
new_infos = isa (new_info, MethodMatchInfo) ? MethodMatchInfo[new_info] : new_info. matches
685
683
# See if we can inline this call to `iterate`
686
684
analyze_single_call! (
687
685
ir, state1. id, new_stmt, new_infos, flag,
688
686
new_sig, istate, todo)
689
687
end
690
- @label analyzed
691
688
if i != length (thisarginfo. each)
692
689
valT = getfield_tfunc (call. rt, Const (1 ))
693
690
val_extracted = insert_node! (ir, idx, NewInstruction (
@@ -1129,139 +1126,150 @@ function process_simple!(ir::IRCode, idx::Int, state::InliningState, todo::Vecto
1129
1126
return stmt, sig
1130
1127
end
1131
1128
1132
- # TODO inline non-`isdispatchtuple`, union-split callsites
1129
+ # TODO inline non-`isdispatchtuple`, union-split callsites?
1133
1130
function analyze_single_call! (
1134
1131
ir:: IRCode , idx:: Int , stmt:: Expr , infos:: Vector{MethodMatchInfo} , flag:: UInt8 ,
1135
1132
sig:: Signature , state:: InliningState , todo:: Vector{Pair{Int, Any}} )
1136
1133
(; argtypes, atype) = sig
1137
1134
cases = InliningCase[]
1138
1135
local signature_union = Bottom
1139
1136
local only_method = nothing # keep track of whether there is one matching method
1140
- local meth
1137
+ local meth:: MethodLookupResult
1141
1138
local fully_covered = true
1142
1139
for i in 1 : length (infos)
1143
- info = infos[i]
1144
- meth = info. results
1140
+ meth = infos[i]. results
1145
1141
if meth. ambig
1146
1142
# Too many applicable methods
1147
1143
# Or there is a (partial?) ambiguity
1148
- return
1144
+ return nothing
1149
1145
elseif length (meth) == 0
1150
1146
# No applicable methods; try next union split
1151
1147
continue
1152
- elseif length (meth) == 1 && only_method != = false
1153
- if only_method === nothing
1154
- only_method = meth[1 ]. method
1155
- elseif only_method != = meth[1 ]. method
1148
+ else
1149
+ if length (meth) == 1 && only_method != = false
1150
+ if only_method === nothing
1151
+ only_method = meth[1 ]. method
1152
+ elseif only_method != = meth[1 ]. method
1153
+ only_method = false
1154
+ end
1155
+ else
1156
1156
only_method = false
1157
1157
end
1158
- else
1159
- only_method = false
1160
1158
end
1161
1159
for match in meth
1162
- spec_types = match. spec_types
1163
- signature_union = Union{signature_union, spec_types}
1164
- if ! isdispatchtuple (spec_types)
1165
- fully_covered = false
1166
- continue
1167
- end
1168
- item = analyze_method! (match, argtypes, flag, state)
1169
- if item === nothing
1170
- fully_covered = false
1171
- continue
1172
- elseif _any (case-> case. sig === spec_types, cases)
1173
- continue
1174
- end
1175
- push! (cases, InliningCase (spec_types, item))
1160
+ signature_union = Union{signature_union, match. spec_types}
1161
+ fully_covered &= handle_match! (match, argtypes, flag, state, cases)
1176
1162
end
1177
1163
end
1178
1164
1179
- # if the signature is fully or mostly covered and there is only one applicable method,
1165
+ # if the signature is fully covered and there is only one applicable method,
1180
1166
# we can try to inline it even if the signature is not a dispatch tuple
1181
1167
if length (cases) == 0 && only_method isa Method
1182
1168
if length (infos) > 1
1183
1169
(metharg, methsp) = ccall (:jl_type_intersection_with_env , Any, (Any, Any),
1184
1170
atype, only_method. sig):: SimpleVector
1185
1171
match = MethodMatch (metharg, methsp:: SimpleVector , only_method, true )
1186
1172
else
1187
- meth = meth:: MethodLookupResult
1188
1173
@assert length (meth) == 1
1189
1174
match = meth[1 ]
1190
1175
end
1191
1176
item = analyze_method! (match, argtypes, flag, state)
1192
- item === nothing && return
1177
+ item === nothing && return nothing
1193
1178
push! (cases, InliningCase (match. spec_types, item))
1194
1179
fully_covered = match. fully_covers
1195
1180
else
1196
1181
fully_covered &= atype <: signature_union
1197
1182
end
1198
1183
1199
- # If we only have one case and that case is fully covered, we may either
1200
- # be able to do the inlining now (for constant cases), or push it directly
1201
- # onto the todo list
1202
- if fully_covered && length (cases) == 1
1203
- handle_single_case! (ir, idx, stmt, cases[1 ]. item, todo)
1204
- elseif length (cases) > 0
1205
- push! (todo, idx=> UnionSplit (fully_covered, atype, cases))
1206
- end
1207
- return nothing
1184
+ handle_cases! (ir, idx, stmt, sig, cases, fully_covered, todo)
1208
1185
end
1209
1186
1210
- # try to create `InliningCase`s using constant-prop'ed results
1211
- # currently it works only when constant-prop' succeeded for all (union-split) signatures
1212
- # TODO use any of constant-prop'ed results, and leave the other unhandled cases to later
1213
- # TODO this function contains a lot of duplications with `analyze_single_call!`, factor them out
1214
- function maybe_handle_const_call! (
1215
- ir:: IRCode , idx:: Int , stmt:: Expr , info:: ConstCallInfo , flag:: UInt8 ,
1187
+ # similar to `analyze_single_call!`, but with constant results
1188
+ function handle_const_call! (
1189
+ ir:: IRCode , idx:: Int , stmt:: Expr , cinfo:: ConstCallInfo , flag:: UInt8 ,
1216
1190
sig:: Signature , state:: InliningState , todo:: Vector{Pair{Int, Any}} )
1217
1191
(; argtypes, atype) = sig
1218
- results = info. results
1219
- cases = InliningCase[] # TODO avoid this allocation for single cases ?
1192
+ (; call, results) = cinfo
1193
+ infos = isa (call, MethodMatchInfo) ? MethodMatchInfo[call] : call. matches
1194
+ cases = InliningCase[]
1220
1195
local fully_covered = true
1221
1196
local signature_union = Bottom
1222
- for result in results
1223
- isa (result, InferenceResult) || return false
1224
- (; mi) = item = InliningTodo (result, argtypes)
1225
- spec_types = mi. specTypes
1226
- signature_union = Union{signature_union, spec_types}
1227
- if ! isdispatchtuple (spec_types)
1228
- fully_covered = false
1229
- continue
1230
- end
1231
- if ! validate_sparams (mi. sparam_vals)
1232
- fully_covered = false
1197
+ local j = 0
1198
+ for i in 1 : length (infos)
1199
+ meth = infos[i]. results
1200
+ if meth. ambig
1201
+ # Too many applicable methods
1202
+ # Or there is a (partial?) ambiguity
1203
+ return nothing
1204
+ elseif length (meth) == 0
1205
+ # No applicable methods; try next union split
1233
1206
continue
1234
1207
end
1235
- state. mi_cache != = nothing && (item = resolve_todo (item, state, flag))
1236
- if item === nothing
1237
- fully_covered = false
1238
- continue
1208
+ for match in meth
1209
+ j += 1
1210
+ result = results[j]
1211
+ if result === nothing
1212
+ signature_union = Union{signature_union, match. spec_types}
1213
+ fully_covered &= handle_match! (match, argtypes, flag, state, cases)
1214
+ else
1215
+ signature_union = Union{signature_union, result. linfo. specTypes}
1216
+ fully_covered &= handle_const_result! (result, argtypes, flag, state, cases)
1217
+ end
1239
1218
end
1240
- push! (cases, InliningCase (spec_types, item))
1241
1219
end
1242
1220
1243
1221
# if the signature is fully covered and there is only one applicable method,
1244
1222
# we can try to inline it even if the signature is not a dispatch tuple
1245
1223
if length (cases) == 0 && length (results) == 1
1246
1224
(; mi) = item = InliningTodo (results[1 ]:: InferenceResult , argtypes)
1247
1225
state. mi_cache != = nothing && (item = resolve_todo (item, state, flag))
1248
- validate_sparams (mi. sparam_vals) || return true
1249
- item === nothing && return true
1226
+ validate_sparams (mi. sparam_vals) || return nothing
1227
+ item === nothing && return nothing
1250
1228
push! (cases, InliningCase (mi. specTypes, item))
1251
1229
fully_covered = atype <: mi.specTypes
1252
1230
else
1253
1231
fully_covered &= atype <: signature_union
1254
1232
end
1255
1233
1234
+ handle_cases! (ir, idx, stmt, sig, cases, fully_covered, todo)
1235
+ end
1236
+
1237
+ function handle_match! (
1238
+ match:: MethodMatch , argtypes:: Vector{Any} , flag:: UInt8 , state:: InliningState ,
1239
+ cases:: Vector{InliningCase} )
1240
+ spec_types = match. spec_types
1241
+ isdispatchtuple (spec_types) || return false
1242
+ item = analyze_method! (match, argtypes, flag, state)
1243
+ item === nothing && return false
1244
+ _any (case-> case. sig === spec_types, cases) && return true
1245
+ push! (cases, InliningCase (spec_types, item))
1246
+ return true
1247
+ end
1248
+
1249
+ function handle_const_result! (
1250
+ result:: InferenceResult , argtypes:: Vector{Any} , flag:: UInt8 , state:: InliningState ,
1251
+ cases:: Vector{InliningCase} )
1252
+ (; mi) = item = InliningTodo (result, argtypes)
1253
+ spec_types = mi. specTypes
1254
+ isdispatchtuple (spec_types) || return false
1255
+ validate_sparams (mi. sparam_vals) || return false
1256
+ state. mi_cache != = nothing && (item = resolve_todo (item, state, flag))
1257
+ item === nothing && return false
1258
+ push! (cases, InliningCase (spec_types, item))
1259
+ return true
1260
+ end
1261
+
1262
+ function handle_cases! (ir:: IRCode , idx:: Int , stmt:: Expr , sig:: Signature ,
1263
+ cases:: Vector{InliningCase} , fully_covered:: Bool , todo:: Vector{Pair{Int, Any}} )
1256
1264
# If we only have one case and that case is fully covered, we may either
1257
1265
# be able to do the inlining now (for constant cases), or push it directly
1258
1266
# onto the todo list
1259
1267
if fully_covered && length (cases) == 1
1260
1268
handle_single_case! (ir, idx, stmt, cases[1 ]. item, todo)
1261
1269
elseif length (cases) > 0
1262
- push! (todo, idx=> UnionSplit (fully_covered, atype, cases))
1270
+ push! (todo, idx=> UnionSplit (fully_covered, sig . atype, cases))
1263
1271
end
1264
- return true
1272
+ return nothing
1265
1273
end
1266
1274
1267
1275
function handle_const_opaque_closure_call! (
@@ -1327,10 +1335,10 @@ function assemble_inline_todo!(ir::IRCode, state::InliningState)
1327
1335
# if inference arrived here with constant-prop'ed result(s),
1328
1336
# we can perform a specialized analysis for just this case
1329
1337
if isa (info, ConstCallInfo)
1330
- maybe_handle_const_call ! (
1338
+ handle_const_call ! (
1331
1339
ir, idx, stmt, info, flag,
1332
- sig, state, todo) && continue
1333
- info = info . call # cascade to the non-constant handling
1340
+ sig, state, todo)
1341
+ continue
1334
1342
end
1335
1343
1336
1344
# Ok, now figure out what method to call
0 commit comments