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