• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaLang / julia / #37527

pending completion
#37527

push

local

web-flow
make `IRShow.method_name` inferrable (#49607)

18 of 18 new or added lines in 3 files covered. (100.0%)

68710 of 81829 relevant lines covered (83.97%)

33068903.12 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.63
/base/compiler/ssair/inlining.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
struct Signature
4
    f::Any
5
    ft::Any
6
    argtypes::Vector{Any}
7
    Signature(@nospecialize(f), @nospecialize(ft), argtypes::Vector{Any}) = new(f, ft, argtypes)
25,515,990✔
8
end
9

10
struct InliningTodo
11
    # The MethodInstance to be inlined
12
    mi::MethodInstance
14,362,112✔
13
    # The IR of the inlinee
14
    ir::IRCode
15
    # If the function being inlined is a single basic block we can use a
16
    # simpler inlining algorithm. This flag determines whether that's allowed
17
    linear_inline_eligible::Bool
18
    # Effects of the call statement
19
    effects::Effects
20
end
21
function InliningTodo(mi::MethodInstance, ir::IRCode, effects::Effects)
10,575✔
22
    return InliningTodo(mi, ir, linear_inline_eligible(ir), effects)
14,367,067✔
23
end
24

25
struct ConstantCase
26
    val::Any
27
    ConstantCase(@nospecialize val) = new(val)
1,610,438✔
28
end
29

30
struct SomeCase
31
    val::Any
32
    SomeCase(@nospecialize val) = new(val)
2,472,432✔
33
end
34

35
struct InvokeCase
36
    invoke::MethodInstance
799,943✔
37
    effects::Effects
38
    info::CallInfo
39
end
40

41
struct InliningCase
42
    sig  # Type
43
    item # Union{InliningTodo, InvokeCase, ConstantCase}
44
    function InliningCase(@nospecialize(sig), @nospecialize(item))
10,750✔
45
        @assert isa(item, Union{InliningTodo, InvokeCase, ConstantCase}) "invalid inlining item"
14,409,036✔
46
        return new(sig, item)
16,768,533✔
47
    end
48
end
49

50
struct UnionSplit
51
    fully_covered::Bool
52
    atype::DataType
53
    cases::Vector{InliningCase}
54
    bbs::Vector{Int}
55
    UnionSplit(fully_covered::Bool, atype::DataType, cases::Vector{InliningCase}) =
158,676✔
56
        new(fully_covered, atype, cases, Int[])
57
end
58

59
struct InliningEdgeTracker
60
    et::Union{Nothing,EdgeTracker}
14,819,439✔
61
    invokesig::Union{Nothing,Vector{Any}}
62
end
63
InliningEdgeTracker(et::Union{Nothing,EdgeTracker}) = InliningEdgeTracker(et, nothing)
507✔
64

65
function add_inlining_backedge!((; et, invokesig)::InliningEdgeTracker, mi::MethodInstance)
14,444,293✔
66
    if et !== nothing
14,444,293✔
67
        if invokesig === nothing
14,444,292✔
68
            add_backedge!(et, mi)
14,441,240✔
69
        else
70
            add_invoke_backedge!(et, invoke_signature(invokesig), mi)
3,052✔
71
        end
72
    end
73
    return nothing
14,444,293✔
74
end
75

76
function ssa_inlining_pass!(ir::IRCode, state::InliningState, propagate_inbounds::Bool)
6,928✔
77
    # Go through the function, performing simple inlining (e.g. replacing call by constants
78
    # and analyzing legality of inlining).
79
    @timeit "analysis" todo = assemble_inline_todo!(ir, state)
5,016,404✔
80
    isempty(todo) && return ir
5,016,404✔
81
    # Do the actual inlining for every call we identified
82
    @timeit "execution" ir = batch_inline!(ir, todo, propagate_inbounds, OptimizationParams(state.interp))
3,188,064✔
83
    return ir
3,188,064✔
84
end
85

86
mutable struct CFGInliningState
87
    new_cfg_blocks::Vector{BasicBlock}
3,188,064✔
88
    todo_bbs::Vector{Tuple{Int, Int}}
89
    first_bb::Int
90
    bb_rename::Vector{Int}
91
    dead_blocks::Vector{Int}
92
    split_targets::BitSet
93
    merged_orig_blocks::BitSet
94
    cfg::CFG
95
end
96

97
function CFGInliningState(ir::IRCode)
3,188,064✔
98
    CFGInliningState(
3,188,064✔
99
        BasicBlock[],
100
        Tuple{Int, Int}[],
101
        0,
102
        zeros(Int, length(ir.cfg.blocks)),
103
        Vector{Int}(),
104
        BitSet(),
105
        BitSet(),
106
        ir.cfg
107
    )
108
end
109

110
# Tells the inliner that we're now inlining into block `block`, meaning
111
# all previous blocks have been processed and can be added to the new cfg
112
function inline_into_block!(state::CFGInliningState, block::Int)
2,815,853✔
113
    if state.first_bb != block
2,815,853✔
114
        new_range = state.first_bb+1:block
1,926,041✔
115
        l = length(state.new_cfg_blocks)
1,926,041✔
116
        state.bb_rename[new_range] = (l+1:l+length(new_range))
4,289,532✔
117
        append!(state.new_cfg_blocks, (copy(block) for block in state.cfg.blocks[new_range]))
1,926,041✔
118
        push!(state.merged_orig_blocks, last(new_range))
1,926,041✔
119
    end
120
    state.first_bb = block
2,815,853✔
121
    return
2,815,853✔
122
end
123

124
function cfg_inline_item!(ir::IRCode, idx::Int, todo::InliningTodo, state::CFGInliningState, from_unionsplit::Bool=false)
2,657,177✔
125
    inlinee_cfg = todo.ir.cfg
2,657,177✔
126
    # Figure out if we need to split the BB
127
    need_split_before = false
×
128
    need_split = true
×
129
    block = block_for_inst(ir, idx)
2,657,177✔
130
    inline_into_block!(state, block)
2,657,177✔
131

132
    if !isempty(inlinee_cfg.blocks[1].preds)
2,657,177✔
133
        need_split_before = true
×
134
    end
135

136
    last_block_idx = last(state.cfg.blocks[block].stmts)
2,657,177✔
137
    if false # TODO: ((idx+1) == last_block_idx && isa(ir[SSAValue(last_block_idx)], GotoNode))
×
138
        need_split = false
×
139
        post_bb_id = -ir[SSAValue(last_block_idx)][:inst].label
×
140
    else
141
        post_bb_id = length(state.new_cfg_blocks) + length(inlinee_cfg.blocks) + (need_split_before ? 1 : 0)
2,657,177✔
142
        need_split = true #!(idx == last_block_idx)
×
143
    end
144

145
    need_split || delete!(state.merged_orig_blocks, last(new_range))
×
146

147
    push!(state.todo_bbs, (length(state.new_cfg_blocks) - 1 + (need_split_before ? 1 : 0), post_bb_id))
2,657,177✔
148

149
    from_unionsplit || delete!(state.split_targets, length(state.new_cfg_blocks))
5,278,820✔
150
    local orig_succs
×
151
    need_split && (orig_succs = copy(state.new_cfg_blocks[end].succs))
2,657,177✔
152
    empty!(state.new_cfg_blocks[end].succs)
2,657,177✔
153
    if need_split_before
2,657,177✔
154
        l = length(state.new_cfg_blocks)
135✔
155
        bb_rename_range = (1+l:length(inlinee_cfg.blocks)+l)
135✔
156
        push!(state.new_cfg_blocks[end].succs, length(state.new_cfg_blocks)+1)
135✔
157
        append!(state.new_cfg_blocks, inlinee_cfg.blocks)
135✔
158
    else
159
        # Merge the last block that was already there with the first block we're adding
160
        l = length(state.new_cfg_blocks)
2,657,042✔
161
        bb_rename_range = (l:length(inlinee_cfg.blocks)+l-1)
2,657,042✔
162
        append!(state.new_cfg_blocks[end].succs, inlinee_cfg.blocks[1].succs)
2,657,042✔
163
        append!(state.new_cfg_blocks, inlinee_cfg.blocks[2:end])
2,657,042✔
164
    end
165
    if need_split
2,657,177✔
166
        push!(state.new_cfg_blocks, BasicBlock(state.cfg.blocks[block].stmts,
2,657,177✔
167
            Int[], orig_succs))
168
        from_unionsplit || push!(state.split_targets, length(state.new_cfg_blocks))
5,278,820✔
169
    end
170
    new_block_range = (length(state.new_cfg_blocks)-length(inlinee_cfg.blocks)+1):length(state.new_cfg_blocks)
2,657,177✔
171

172
    # Fixup the edges of the newely added blocks
173
    for (old_block, new_block) in enumerate(bb_rename_range)
5,314,354✔
174
        if old_block != 1 || need_split_before
34,403,124✔
175
            p = state.new_cfg_blocks[new_block].preds
29,088,905✔
176
            let bb_rename_range = bb_rename_range
×
177
                map!(p, p) do old_pred_block
35,356,958✔
178
                    return old_pred_block == 0 ? 0 : bb_rename_range[old_pred_block]
70,211,581✔
179
                end
180
            end
181
        end
182
        if new_block != last(new_block_range)
31,745,947✔
183
            s = state.new_cfg_blocks[new_block].succs
31,745,947✔
184
            let bb_rename_range = bb_rename_range
×
185
                map!(s, s) do old_succ_block
41,109,221✔
186
                    return bb_rename_range[old_succ_block]
35,105,790✔
187
                end
188
            end
189
        end
190
    end
60,834,717✔
191

192
    if need_split_before
2,657,177✔
193
        push!(state.new_cfg_blocks[first(bb_rename_range)].preds, first(bb_rename_range)-1)
135✔
194
    end
195

196
    any_edges = false
×
197
    for (old_block, new_block) in enumerate(bb_rename_range)
5,314,354✔
198
        if (length(state.new_cfg_blocks[new_block].succs) == 0)
31,745,947✔
199
            terminator_idx = last(inlinee_cfg.blocks[old_block].stmts)
6,003,431✔
200
            terminator = todo.ir[SSAValue(terminator_idx)][:inst]
6,003,431✔
201
            if isa(terminator, ReturnNode) && isdefined(terminator, :val)
6,003,431✔
202
                any_edges = true
×
203
                push!(state.new_cfg_blocks[new_block].succs, post_bb_id)
3,867,616✔
204
                if need_split
3,867,616✔
205
                    push!(state.new_cfg_blocks[post_bb_id].preds, new_block)
3,867,616✔
206
                end
207
            end
208
        end
209
    end
60,834,717✔
210
    any_edges || push!(state.dead_blocks, post_bb_id)
2,664,437✔
211

212
    return nothing
2,657,177✔
213
end
214

215
function cfg_inline_unionsplit!(ir::IRCode, idx::Int,
158,676✔
216
                                (; fully_covered, #=atype,=# cases, bbs)::UnionSplit,
217
                                state::CFGInliningState,
218
                                params::OptimizationParams)
219
    inline_into_block!(state, block_for_inst(ir, idx))
158,676✔
220
    from_bbs = Int[]
158,676✔
221
    delete!(state.split_targets, length(state.new_cfg_blocks))
260,875✔
222
    orig_succs = copy(state.new_cfg_blocks[end].succs)
158,676✔
223
    empty!(state.new_cfg_blocks[end].succs)
158,676✔
224
    for i in 1:length(cases)
317,352✔
225
        # The condition gets sunk into the previous block
226
        # Add a block for the union-split body
227
        push!(state.new_cfg_blocks, BasicBlock(StmtRange(idx, idx)))
295,099✔
228
        cond_bb = length(state.new_cfg_blocks)-1
295,099✔
229
        push!(state.new_cfg_blocks[end].preds, cond_bb)
295,099✔
230
        push!(state.new_cfg_blocks[cond_bb].succs, cond_bb+1)
295,099✔
231
        case = cases[i].item
295,099✔
232
        if isa(case, InliningTodo)
295,099✔
233
            if !case.linear_inline_eligible
203,724✔
234
                cfg_inline_item!(ir, idx, case, state, true)
35,534✔
235
            end
236
        end
237
        push!(from_bbs, length(state.new_cfg_blocks))
295,099✔
238
        # TODO: Right now we unconditionally generate a fallback block
239
        # in case of subtyping errors - This is probably unnecessary.
240
        if i != length(cases) || (!fully_covered || (!params.trust_inference))
453,775✔
241
            # This block will have the next condition or the final else case
242
            push!(state.new_cfg_blocks, BasicBlock(StmtRange(idx, idx)))
295,099✔
243
            push!(state.new_cfg_blocks[cond_bb].succs, length(state.new_cfg_blocks))
295,099✔
244
            push!(state.new_cfg_blocks[end].preds, cond_bb)
295,099✔
245
            push!(bbs, length(state.new_cfg_blocks))
295,099✔
246
        end
247
    end
431,522✔
248
    # The edge from the fallback block.
249
    fully_covered || push!(from_bbs, length(state.new_cfg_blocks))
233,737✔
250
    # This block will be the block everyone returns to
251
    push!(state.new_cfg_blocks, BasicBlock(StmtRange(idx, idx), from_bbs, orig_succs))
158,676✔
252
    join_bb = length(state.new_cfg_blocks)
158,676✔
253
    push!(state.split_targets, join_bb)
159,107✔
254
    push!(bbs, join_bb)
158,676✔
255
    for bb in from_bbs
158,676✔
256
        push!(state.new_cfg_blocks[bb].succs, join_bb)
370,160✔
257
    end
370,160✔
258
end
259

260
function finish_cfg_inline!(state::CFGInliningState)
3,188,064✔
261
    new_range = (state.first_bb + 1):length(state.cfg.blocks)
3,875,705✔
262
    state.bb_rename[new_range] = let
×
263
        l = length(state.new_cfg_blocks)
3,188,064✔
264
        l+1:l+length(new_range)
5,308,644✔
265
    end
266
    append!(state.new_cfg_blocks, state.cfg.blocks[new_range])
3,188,064✔
267

268
    # Rename edges original bbs
269
    for (orig_bb, bb) in pairs(state.bb_rename)
6,376,128✔
270
        p, s = state.new_cfg_blocks[bb].preds, state.new_cfg_blocks[bb].succs
8,910,535✔
271
        map!(p, p) do pred_bb
10,368,612✔
272
            pred_bb == length(state.bb_rename) && return length(state.new_cfg_blocks)
7,181,101✔
273
            return state.bb_rename[pred_bb + 1] - 1
7,180,352✔
274
        end
275
        if !(orig_bb in state.merged_orig_blocks)
12,504,226✔
276
            map!(s, s) do succ_bb
8,329,982✔
277
                return state.bb_rename[succ_bb]
5,179,037✔
278
            end
279
        end
280
    end
14,633,006✔
281

282
    for bb in collect(state.split_targets)
5,319,748✔
283
        s = state.new_cfg_blocks[bb].succs
1,926,041✔
284
        map!(s, s) do succ_bb
2,728,728✔
285
            return state.bb_rename[succ_bb]
1,963,674✔
286
        end
287
    end
2,982,421✔
288

289
    # Rename any annotated original bb references
290
    for bb in 1:length(state.new_cfg_blocks)
6,376,128✔
291
        s = state.new_cfg_blocks[bb].succs
41,405,491✔
292
        map!(s, s) do succ_bb
53,212,039✔
293
            return succ_bb < 0 ? state.bb_rename[-succ_bb] : succ_bb
94,153,220✔
294
        end
295
    end
79,622,918✔
296

297
    # Kill dead blocks
298
    for block in state.dead_blocks
6,369,234✔
299
        for succ in state.new_cfg_blocks[block].succs
13,181✔
300
            kill_edge!(state.new_cfg_blocks, block, succ)
1,339✔
301
        end
2,678✔
302
    end
7,260✔
303
end
304

305
# duplicated from IRShow
306
function normalize_method_name(m)
×
307
    if m isa Method
28,698,876✔
308
        return m.name
×
309
    elseif m isa MethodInstance
28,698,876✔
310
        return (m.def::Method).name
14,349,438✔
311
    elseif m isa Symbol
14,349,438✔
312
        return m
14,349,438✔
313
    else
314
        return Symbol("")
×
315
    end
316
end
317
@noinline method_name(m::LineInfoNode) = normalize_method_name(m.method)
28,698,876✔
318

319
inline_node_is_duplicate(topline::LineInfoNode, line::LineInfoNode) =
14,349,492✔
320
    topline.module === line.module &&
321
    method_name(topline) === method_name(line) &&
322
    topline.file === line.file &&
323
    topline.line === line.line
324

325
function ir_inline_linetable!(linetable::Vector{LineInfoNode}, inlinee_ir::IRCode,
14,349,481✔
326
                              inlinee::MethodInstance,
327
                              inlined_at::Int32)
328
    inlinee_def = inlinee.def::Method
14,349,481✔
329
    coverage = coverage_enabled(inlinee_def.module)
14,349,481✔
330
    linetable_offset::Int32 = length(linetable)
14,349,481✔
331
    # Append the linetable of the inlined function to our line table
332
    topline::Int32 = linetable_offset + Int32(1)
14,349,481✔
333
    coverage_by_path = JLOptions().code_coverage == 3
14,349,481✔
334
    push!(linetable, LineInfoNode(inlinee_def.module, inlinee, inlinee_def.file, inlinee_def.line, inlined_at))
14,349,481✔
335
    oldlinetable = inlinee_ir.linetable
14,349,481✔
336
    extra_coverage_line = zero(Int32)
×
337
    for oldline in eachindex(oldlinetable)
28,698,962✔
338
        entry = oldlinetable[oldline]
292,714,074✔
339
        if !coverage && coverage_by_path && is_file_tracked(entry.file)
292,714,074✔
340
            # include topline coverage entry if in path-specific coverage mode, and any file falls under path
341
            coverage = true
×
342
        end
343
        newentry = LineInfoNode(entry.module, entry.method, entry.file, entry.line,
292,714,074✔
344
            (entry.inlined_at > 0 ? entry.inlined_at + linetable_offset + (oldline == 1) : inlined_at))
345
        if oldline == 1
292,714,074✔
346
            # check for a duplicate on the first iteration (likely true)
347
            if inline_node_is_duplicate(linetable[topline], newentry)
14,349,492✔
348
                continue
11,903,334✔
349
            else
350
                linetable_offset += 1
2,446,147✔
351
            end
352
        end
353
        push!(linetable, newentry)
280,810,740✔
354
    end
571,078,667✔
355
    if coverage && inlinee_ir.stmts[1][:line] + linetable_offset != topline
14,349,481✔
356
        extra_coverage_line = topline
×
357
    end
358
    return linetable_offset, extra_coverage_line
14,349,481✔
359
end
360

361
function ir_prepare_inlining!(insert_node!::Inserter, inline_target::Union{IRCode, IncrementalCompact},
14,349,481✔
362
        linetable::Vector{LineInfoNode}, ir′::IRCode, sparam_vals::SimpleVector,
363
        mi::MethodInstance, inlined_at::Int32, argexprs::Vector{Any})
364
    def = mi.def::Method
14,349,481✔
365
    topline::Int32 = length(linetable) + Int32(1)
14,349,481✔
366
    linetable_offset, extra_coverage_line = ir_inline_linetable!(linetable, ir′, mi, inlined_at)
14,349,481✔
367
    if extra_coverage_line != 0
14,349,481✔
368
        insert_node!(NewInstruction(Expr(:code_coverage_effect), Nothing, extra_coverage_line))
3,949,327✔
369
    end
370
    sp_ssa = nothing
×
371
    if !validate_sparams(sparam_vals)
19,166,975✔
372
        # N.B. This works on the caller-side argexprs, (i.e. before the va fixup below)
373
        sp_ssa = insert_node!(
17,576✔
374
            effect_free(NewInstruction(Expr(:call, Core._compute_sparams, def, argexprs...), SimpleVector, topline)))
375
    end
376
    if def.isva
14,349,481✔
377
        nargs_def = Int(def.nargs::Int32)
1,248,252✔
378
        if nargs_def > 0
1,248,252✔
379
            argexprs = fix_va_argexprs!(insert_node!, inline_target, argexprs, nargs_def, topline)
1,248,252✔
380
        end
381
    end
382
    if def.is_for_opaque_closure
14,349,481✔
383
        # Replace the first argument by a load of the capture environment
384
        argexprs[1] = insert_node!(
10✔
385
            NewInstruction(Expr(:call, GlobalRef(Core, :getfield), argexprs[1], QuoteNode(:captures)),
386
            ir′.argtypes[1], topline))
387
    end
388
    return (Pair{Union{Nothing, SSAValue}, Vector{Any}}(sp_ssa, argexprs), linetable_offset)
14,349,481✔
389
end
390

391
function ir_inline_item!(compact::IncrementalCompact, idx::Int, argexprs::Vector{Any},
14,349,481✔
392
                         linetable::Vector{LineInfoNode}, item::InliningTodo,
393
                         boundscheck::Symbol, todo_bbs::Vector{Tuple{Int, Int}})
394
    # Ok, do the inlining here
395
    sparam_vals = item.mi.sparam_vals
14,349,481✔
396
    inlined_at = compact.result[idx][:line]
14,349,481✔
397

398
    ((sp_ssa, argexprs), linetable_offset) = ir_prepare_inlining!(InsertHere(compact),
14,349,481✔
399
        compact, linetable, item.ir, sparam_vals, item.mi, inlined_at, argexprs)
400

401
    if boundscheck === :default || boundscheck === :propagate
28,469,074✔
402
        if (compact.result[idx][:flag] & IR_FLAG_INBOUNDS) != 0
243,603✔
403
            boundscheck = :off
×
404
        end
405
    end
406
    # If the iterator already moved on to the next basic block,
407
    # temporarily re-open in again.
408
    local return_value
×
409
    def = item.mi.def::Method
14,349,481✔
410
    sig = def.sig
14,349,481✔
411
    # Special case inlining that maintains the current basic block if there's only one BB in the target
412
    new_new_offset = length(compact.new_new_nodes)
14,349,481✔
413
    late_fixup_offset = length(compact.late_fixup)
14,349,481✔
414
    if item.linear_inline_eligible
14,349,481✔
415
        #compact[idx] = nothing
416
        inline_compact = IncrementalCompact(compact, item.ir, compact.result_idx)
11,692,304✔
417
        for ((_, idx′), stmt′) in inline_compact
23,384,608✔
418
            # This dance is done to maintain accurate usage counts in the
419
            # face of rename_arguments! mutating in place - should figure out
420
            # something better eventually.
421
            inline_compact[idx′] = nothing
79,210,916✔
422
            stmt′ = ssa_substitute!(InsertBefore(inline_compact, SSAValue(idx′)), inline_compact[SSAValue(idx′)], stmt′, argexprs, sig, sparam_vals, sp_ssa, linetable_offset, boundscheck)
79,312,839✔
423
            if isa(stmt′, ReturnNode)
79,210,916✔
424
                val = stmt′.val
11,692,304✔
425
                return_value = SSAValue(idx′)
11,692,304✔
426
                inline_compact[idx′] = val
11,692,304✔
427
                inline_compact.result[idx′][:type] =
23,141,338✔
428
                    argextype(val, isa(val, Argument) || isa(val, Expr) ? compact : inline_compact)
429
                # Everything legal in value position is guaranteed to be effect free in stmt position
430
                inline_compact.result[idx′][:flag] = IR_FLAG_EFFECT_FREE
11,692,304✔
431
                break
11,692,304✔
432
            end
433
            inline_compact[idx′] = stmt′
67,518,612✔
434
        end
67,518,612✔
435
        just_fixup!(inline_compact, new_new_offset, late_fixup_offset)
11,692,304✔
436
        compact.result_idx = inline_compact.result_idx
11,692,304✔
437
    else
438
        bb_offset, post_bb_id = popfirst!(todo_bbs)
2,657,177✔
439
        # This implements the need_split_before flag above
440
        need_split_before = !isempty(item.ir.cfg.blocks[1].preds)
2,657,177✔
441
        if need_split_before
2,657,177✔
442
            finish_current_bb!(compact, 0)
135✔
443
        end
444
        pn = PhiNode()
2,657,177✔
445
        #compact[idx] = nothing
446
        inline_compact = IncrementalCompact(compact, item.ir, compact.result_idx)
2,657,177✔
447
        for ((_, idx′), stmt′) in inline_compact
5,314,354✔
448
            inline_compact[idx′] = nothing
169,712,242✔
449
            stmt′ = ssa_substitute!(InsertBefore(inline_compact, SSAValue(idx′)), inline_compact[SSAValue(idx′)], stmt′, argexprs, sig, sparam_vals, sp_ssa, linetable_offset, boundscheck)
170,121,707✔
450
            if isa(stmt′, ReturnNode)
169,712,242✔
451
                if isdefined(stmt′, :val)
5,985,904✔
452
                    val = stmt′.val
3,867,616✔
453
                    @assert !isa(val, Expr) # GlobalRefs with side-effects are disallowed in value position in IRCode
3,867,616✔
454
                    push!(pn.edges, inline_compact.active_result_bb-1)
3,867,616✔
455
                    push!(pn.values, val)
3,867,616✔
456
                    stmt′ = GotoNode(post_bb_id)
3,867,616✔
457
                end
458
            elseif isa(stmt′, GotoNode)
163,726,338✔
459
                stmt′ = GotoNode(stmt′.label + bb_offset)
14,749,430✔
460
            elseif isa(stmt′, Expr) && stmt′.head === :enter
148,976,908✔
461
                stmt′ = Expr(:enter, stmt′.args[1]::Int + bb_offset)
1✔
462
            elseif isa(stmt′, GotoIfNot)
148,976,907✔
463
                stmt′ = GotoIfNot(stmt′.cond, stmt′.dest + bb_offset)
9,363,273✔
464
            elseif isa(stmt′, PhiNode)
139,613,634✔
465
                stmt′ = PhiNode(Int32[edge+bb_offset for edge in stmt′.edges], stmt′.values)
5,634,847✔
466
            end
467
            inline_compact[idx′] = stmt′
169,712,242✔
468
        end
336,767,307✔
469
        just_fixup!(inline_compact, new_new_offset, late_fixup_offset)
2,657,177✔
470
        compact.result_idx = inline_compact.result_idx
2,657,177✔
471
        compact.active_result_bb = inline_compact.active_result_bb
2,657,177✔
472
        if length(pn.edges) == 1
2,657,177✔
473
            return_value = pn.values[1]
1,662,797✔
474
        else
475
            return_value = insert_node_here!(compact,
994,380✔
476
                NewInstruction(pn, argextype(SSAValue(idx), compact), compact.result[idx][:line]))
477
        end
478
    end
479
    return_value
14,349,481✔
480
end
481

482
function fix_va_argexprs!(insert_node!::Inserter, inline_target::Union{IRCode, IncrementalCompact},
1,248,252✔
483
    argexprs::Vector{Any}, nargs_def::Int, line_idx::Int32)
484
    newargexprs = argexprs[1:(nargs_def-1)]
1,248,252✔
485
    tuple_call = Expr(:call, TOP_TUPLE)
1,248,252✔
486
    tuple_typs = Any[]
1,248,252✔
487
    for i in nargs_def:length(argexprs)
1,995,861✔
488
        arg = argexprs[i]
1,357,007✔
489
        push!(tuple_call.args, arg)
1,357,007✔
490
        push!(tuple_typs, argextype(arg, inline_target))
1,357,007✔
491
    end
1,966,405✔
492
    tuple_typ = tuple_tfunc(OptimizerLattice(), tuple_typs)
1,248,252✔
493
    tuple_inst = NewInstruction(tuple_call, tuple_typ, line_idx)
1,248,252✔
494
    push!(newargexprs, insert_node!(tuple_inst))
1,248,252✔
495
    return newargexprs
1,248,252✔
496
end
497

498
const FATAL_TYPE_BOUND_ERROR = ErrorException("fatal error in type inference (type bound)")
499

500
"""
501
    ir_inline_unionsplit!
502

503
The core idea of this function is to simulate the dispatch semantics by generating
504
(flat) `isa`-checks corresponding to the signatures of union-split dispatch candidates,
505
and then inline their bodies into each `isa`-conditional block.
506
This `isa`-based virtual dispatch requires few pre-conditions to hold in order to simulate
507
the actual semantics correctly.
508

509
The first one is that these dispatch candidates need to be processed in order of their specificity,
510
and the corresponding `isa`-checks should reflect the method specificities, since now their
511
signatures are not necessarily concrete.
512
For example, given the following definitions:
513

514
    f(x::Int)    = ...
515
    f(x::Number) = ...
516
    f(x::Any)    = ...
517

518
and a callsite:
519

520
    f(x::Any)
521

522
then a correct `isa`-based virtual dispatch would be:
523

524
    if isa(x, Int)
525
        [inlined/resolved f(x::Int)]
526
    elseif isa(x, Number)
527
        [inlined/resolved f(x::Number)]
528
    else # implies `isa(x, Any)`, which fully covers this call signature,
529
         # otherwise we need to insert a fallback dynamic dispatch case also
530
        [inlined/resolved f(x::Any)]
531
    end
532

533
Fortunately, `ml_matches` should already sorted them in that way, except cases when there is
534
any ambiguity, from which we already bail out at this point.
535

536
Another consideration is type equality constraint from type variables: the `isa`-checks are
537
not enough to simulate the dispatch semantics in cases like:
538
Given a definition:
539

540
    g(x::T, y::T) where T<:Integer = ...
541

542
transform a callsite:
543

544
    g(x::Any, y::Any)
545

546
into the optimized form:
547

548
    if isa(x, Integer) && isa(y, Integer)
549
        [inlined/resolved g(x::Integer, y::Integer)]
550
    else
551
        g(x, y) # fallback dynamic dispatch
552
    end
553

554
But again, we should already bail out from such cases at this point, essentially by
555
excluding cases where `case.sig::UnionAll`.
556

557
In short, here we can process the dispatch candidates in order, assuming we haven't changed
558
their order somehow somewhere up to this point.
559
"""
560
function ir_inline_unionsplit!(compact::IncrementalCompact, idx::Int,
158,676✔
561
                               argexprs::Vector{Any}, linetable::Vector{LineInfoNode},
562
                               (; fully_covered, atype, cases, bbs)::UnionSplit,
563
                               boundscheck::Symbol, todo_bbs::Vector{Tuple{Int, Int}},
564
                               params::OptimizationParams)
565
    stmt, typ, line = compact.result[idx][:inst], compact.result[idx][:type], compact.result[idx][:line]
158,676✔
566
    join_bb = bbs[end]
158,676✔
567
    pn = PhiNode()
158,676✔
568
    local bb = compact.active_result_bb
158,676✔
569
    ncases = length(cases)
158,676✔
570
    @assert length(bbs) >= ncases
158,676✔
571
    for i = 1:ncases
317,352✔
572
        ithcase = cases[i]
295,099✔
573
        mtype = ithcase.sig::DataType # checked within `handle_cases!`
295,099✔
574
        case = ithcase.item
295,099✔
575
        next_cond_bb = bbs[i]
295,099✔
576
        cond = true
×
577
        nparams = fieldcount(atype)
295,099✔
578
        @assert nparams == fieldcount(mtype)
295,099✔
579
        if i != ncases || !fully_covered || !params.trust_inference
453,775✔
580
            for i = 1:nparams
590,198✔
581
                a, m = fieldtype(atype, i), fieldtype(mtype, i)
903,713✔
582
                # If this is always true, we don't need to check for it
583
                a <: m && continue
903,713✔
584
                # Generate isa check
585
                isa_expr = Expr(:call, isa, argexprs[i], m)
300,280✔
586
                ssa = insert_node_here!(compact, NewInstruction(isa_expr, Bool, line))
300,280✔
587
                if cond === true
300,280✔
588
                    cond = ssa
278,475✔
589
                else
590
                    and_expr = Expr(:call, and_int, cond, ssa)
43,610✔
591
                    cond = insert_node_here!(compact, NewInstruction(and_expr, Bool, line))
21,805✔
592
                end
593
            end
1,512,327✔
594
            insert_node_here!(compact, NewInstruction(GotoIfNot(cond, next_cond_bb), Union{}, line))
573,574✔
595
        end
596
        bb = next_cond_bb - 1
295,099✔
597
        finish_current_bb!(compact, 0)
295,099✔
598
        argexprs′ = argexprs
×
599
        if !isa(case, ConstantCase)
295,099✔
600
            argexprs′ = copy(argexprs)
276,979✔
601
            for i = 1:nparams
553,958✔
602
                argex = argexprs[i]
858,913✔
603
                (isa(argex, SSAValue) || isa(argex, Argument)) || continue
1,125,136✔
604
                a, m = fieldtype(atype, i), fieldtype(mtype, i)
762,680✔
605
                if !(a <: m)
762,680✔
606
                    argexprs′[i] = insert_node_here!(compact,
494,230✔
607
                        NewInstruction(PiNode(argex, m), m, line))
608
                end
609
            end
1,440,847✔
610
        end
611
        if isa(case, InliningTodo)
295,099✔
612
            val = ir_inline_item!(compact, idx, argexprs′, linetable, case, boundscheck, todo_bbs)
203,724✔
613
        elseif isa(case, InvokeCase)
91,375✔
614
            inst = Expr(:invoke, case.invoke, argexprs′...)
73,255✔
615
            flag = flags_for_effects(case.effects)
146,376✔
616
            val = insert_node_here!(compact, NewInstruction(inst, typ, case.info, line, flag))
73,255✔
617
        else
618
            case = case::ConstantCase
18,120✔
619
            val = case.val
18,120✔
620
        end
621
        if !isempty(compact.cfg_transform.result_bbs[bb].preds)
295,099✔
622
            push!(pn.edges, bb)
293,760✔
623
            push!(pn.values, val)
293,760✔
624
            insert_node_here!(compact,
293,760✔
625
                NewInstruction(GotoNode(join_bb), Union{}, line))
626
        else
627
            insert_node_here!(compact,
1,339✔
628
                NewInstruction(ReturnNode(), Union{}, line))
629
        end
630
        finish_current_bb!(compact, 0)
295,099✔
631
    end
431,522✔
632
    bb += 1
158,676✔
633
    # We're now in the fall through block, decide what to do
634
    if fully_covered
158,676✔
635
        if !params.trust_inference
83,615✔
636
            e = Expr(:call, GlobalRef(Core, :throw), FATAL_TYPE_BOUND_ERROR)
83,615✔
637
            insert_node_here!(compact, NewInstruction(e, Union{}, line))
83,615✔
638
            insert_node_here!(compact, NewInstruction(ReturnNode(), Union{}, line))
83,615✔
639
            finish_current_bb!(compact, 0)
83,615✔
640
        end
641
    else
642
        ssa = insert_node_here!(compact, NewInstruction(stmt, typ, line))
75,061✔
643
        push!(pn.edges, bb)
75,061✔
644
        push!(pn.values, ssa)
75,061✔
645
        insert_node_here!(compact, NewInstruction(GotoNode(join_bb), Union{}, line))
75,061✔
646
        finish_current_bb!(compact, 0)
75,061✔
647
    end
648

649
    # We're now in the join block.
650
    return insert_node_here!(compact, NewInstruction(pn, typ, line))
158,676✔
651
end
652

653
function batch_inline!(ir::IRCode, todo::Vector{Pair{Int,Any}}, propagate_inbounds::Bool, params::OptimizationParams)
3,188,064✔
654
    # Compute the new CFG first (modulo statement ranges, which will be computed below)
655
    state = CFGInliningState(ir)
3,188,064✔
656
    for (idx, item) in todo
3,188,064✔
657
        if isa(item, UnionSplit)
14,304,433✔
658
            cfg_inline_unionsplit!(ir, idx, item, state, params)
158,676✔
659
        else
660
            item = item::InliningTodo
14,145,757✔
661
            # A linear inline does not modify the CFG
662
            item.linear_inline_eligible && continue
14,145,757✔
663
            cfg_inline_item!(ir, idx, item, state, false)
2,621,643✔
664
        end
665
    end
17,492,497✔
666
    finish_cfg_inline!(state)
3,188,064✔
667

668
    boundscheck = inbounds_option()
6,327,953✔
669
    if boundscheck === :default && propagate_inbounds
3,188,064✔
670
        boundscheck = :propagate
×
671
    end
672

673
    let compact = IncrementalCompact(ir, CFGTransformState!(state.new_cfg_blocks, false))
3,188,064✔
674
        # This needs to be a minimum and is more of a size hint
675
        nn = 0
×
676
        for (_, item) in todo
3,188,064✔
677
            if isa(item, InliningTodo)
14,304,433✔
678
                nn += (length(item.ir.stmts) + length(item.ir.new_nodes))
14,145,757✔
679
            end
680
        end
17,492,497✔
681
        nnewnodes = length(compact.result) + nn
3,188,064✔
682
        resize!(compact, nnewnodes)
3,188,064✔
683
        (inline_idx, item) = popfirst!(todo)
3,188,064✔
684
        for ((old_idx, idx), stmt) in compact
6,376,128✔
685
            if old_idx == inline_idx
40,678,119✔
686
                stmt = stmt::Expr
14,304,433✔
687
                if stmt.head === :invoke
14,304,433✔
688
                    argexprs = stmt.args[2:end]
1✔
689
                else
690
                    @assert stmt.head === :call
14,304,432✔
691
                    argexprs = copy(stmt.args)
14,304,432✔
692
                end
693
                refinish = false
14,304,433✔
694
                if compact.result_idx == first(compact.cfg_transform.result_bbs[compact.active_result_bb].stmts)
14,304,433✔
695
                    compact.active_result_bb -= 1
303,432✔
696
                    refinish = true
×
697
                end
698
                # It is possible for GlobalRefs and Exprs to be in argument position
699
                # at this point in the IR, though in that case they are required
700
                # to be effect-free. However, we must still move them out of argument
701
                # position, since `Argument` is allowed in PhiNodes, but `GlobalRef`
702
                # and `Expr` are not, so a substitution could anger the verifier.
703
                for aidx in 1:length(argexprs)
28,608,866✔
704
                    aexpr = argexprs[aidx]
41,974,185✔
705
                    if isa(aexpr, Expr) || isa(aexpr, GlobalRef)
83,948,370✔
706
                        ninst = effect_free(NewInstruction(aexpr, argextype(aexpr, compact), compact.result[idx][:line]))
28,177,324✔
707
                        argexprs[aidx] = insert_node_here!(compact, ninst)
14,088,662✔
708
                    end
709
                end
69,643,937✔
710
                if isa(item, InliningTodo)
14,304,433✔
711
                    compact.ssa_rename[old_idx] = ir_inline_item!(compact, idx, argexprs, ir.linetable, item, boundscheck, state.todo_bbs)
14,145,757✔
712
                elseif isa(item, UnionSplit)
158,676✔
713
                    compact.ssa_rename[old_idx] = ir_inline_unionsplit!(compact, idx, argexprs, ir.linetable, item, boundscheck, state.todo_bbs, params)
158,676✔
714
                end
715
                compact[idx] = nothing
14,304,433✔
716
                refinish && finish_current_bb!(compact, 0)
14,304,433✔
717
                if !isempty(todo)
14,304,433✔
718
                    (inline_idx, item) = popfirst!(todo)
11,116,369✔
719
                else
720
                    inline_idx = -1
14,304,433✔
721
                end
722
            elseif isa(stmt, GotoNode)
26,373,686✔
723
                compact[idx] = GotoNode(state.bb_rename[stmt.label])
865,261✔
724
            elseif isa(stmt, Expr) && stmt.head === :enter
25,508,425✔
725
                compact[idx] = Expr(:enter, state.bb_rename[stmt.args[1]::Int])
38,390✔
726
            elseif isa(stmt, GotoIfNot)
25,470,035✔
727
                compact[idx] = GotoIfNot(stmt.cond, state.bb_rename[stmt.dest])
2,109,785✔
728
            elseif isa(stmt, PhiNode)
23,360,250✔
729
                compact[idx] = PhiNode(Int32[edge == length(state.bb_rename) ? length(state.new_cfg_blocks) : state.bb_rename[edge+1]-1 for edge in stmt.edges], stmt.values)
1,250,392✔
730
            end
731
        end
78,168,174✔
732

733
        ir = finish(compact)
3,188,064✔
734
    end
735
    return ir
3,188,064✔
736
end
737

738
# This assumes the caller has verified that all arguments to the _apply_iterate call are Tuples.
739
function rewrite_apply_exprargs!(todo::Vector{Pair{Int,Any}},
819,200✔
740
    ir::IRCode, idx::Int, stmt::Expr, argtypes::Vector{Any},
741
    arginfos::Vector{MaybeAbstractIterationInfo}, arg_start::Int, istate::InliningState)
742
    flag = ir.stmts[idx][:flag]
819,200✔
743
    argexprs = stmt.args
819,200✔
744
    new_argexprs = Any[argexprs[arg_start]]
819,200✔
745
    new_argtypes = Any[argtypes[arg_start]]
819,200✔
746
    # loop over original arguments and flatten any known iterators
747
    for i in (arg_start+1):length(argexprs)
1,638,400✔
748
        def = argexprs[i]
1,411,789✔
749
        def_type = argtypes[i]
1,411,789✔
750
        thisarginfo = arginfos[i-arg_start]
1,411,789✔
751
        if thisarginfo === nothing || !thisarginfo.complete
1,412,241✔
752
            if def_type isa PartialStruct
1,411,337✔
753
                # def_type.typ <: Tuple is assumed
754
                def_argtypes = def_type.fields
299,122✔
755
            else
756
                def_argtypes = Any[]
1,112,215✔
757
                if isa(def_type, Const) # && isa(def_type.val, Union{Tuple, SimpleVector}) is implied
1,112,215✔
758
                    for p in def_type.val
264,297✔
759
                        push!(def_argtypes, Const(p))
378,285✔
760
                    end
378,285✔
761
                else
762
                    ti = widenconst(def_type)::DataType # checked by `is_valid_type_for_apply_rewrite`
847,918✔
763
                    if ti.name === _NAMEDTUPLE_NAME
847,918✔
764
                        ti = ti.parameters[2]::DataType # checked by `is_valid_type_for_apply_rewrite`
118✔
765
                    end
766
                    for p in ti.parameters
1,655,086✔
767
                        if isa(p, DataType) && isdefined(p, :instance)
1,318,191✔
768
                            # replace singleton types with their equivalent Const object
769
                            p = Const(p.instance)
97,152✔
770
                        elseif isconstType(p)
1,221,039✔
771
                            p = Const(p.parameters[1])
×
772
                        end
773
                        push!(def_argtypes, p)
1,318,191✔
774
                    end
1,318,191✔
775
                end
776
            end
777
            # now push flattened types into new_argtypes and getfield exprs into new_argexprs
778
            for j in 1:length(def_argtypes)
2,739,940✔
779
                def_atype = def_argtypes[j]
2,307,451✔
780
                if isa(def_atype, Const) && is_inlineable_constant(def_atype.val)
2,307,451✔
781
                    new_argexpr = quoted(def_atype.val)
747,602✔
782
                else
783
                    new_call = Expr(:call, GlobalRef(Core, :getfield), def, j)
1,734,578✔
784
                    new_argexpr = insert_node!(ir, idx, NewInstruction(new_call, def_atype))
1,734,578✔
785
                end
786
                push!(new_argexprs, new_argexpr)
2,307,451✔
787
                push!(new_argtypes, def_atype)
2,307,451✔
788
            end
3,286,299✔
789
        else
790
            state = Core.svec()
452✔
791
            for i = 1:length(thisarginfo.each)
904✔
792
                call = thisarginfo.each[i]
1,792✔
793
                new_stmt = Expr(:call, argexprs[2], def, state...)
1,792✔
794
                state1 = insert_node!(ir, idx, NewInstruction(new_stmt, call.rt))
1,792✔
795
                new_sig = call_sig(ir, new_stmt)::Signature
1,792✔
796
                new_info = call.info
1,792✔
797
                # See if we can inline this call to `iterate`
798
                handle_call!(todo, ir, state1.id, new_stmt, new_info, flag, new_sig, istate)
3,584✔
799
                if i != length(thisarginfo.each)
1,792✔
800
                    valT = getfield_tfunc(optimizer_lattice(istate.interp), call.rt, Const(1))
1,340✔
801
                    val_extracted = insert_node!(ir, idx, NewInstruction(
1,340✔
802
                        Expr(:call, GlobalRef(Core, :getfield), state1, 1),
803
                        valT))
804
                    push!(new_argexprs, val_extracted)
1,340✔
805
                    push!(new_argtypes, valT)
1,340✔
806
                    state_extracted = insert_node!(ir, idx, NewInstruction(
1,340✔
807
                        Expr(:call, GlobalRef(Core, :getfield), state1, 2),
808
                        getfield_tfunc(optimizer_lattice(istate.interp), call.rt, Const(2))))
809
                    state = Core.svec(state_extracted)
1,340✔
810
                end
811
            end
1,792✔
812
        end
813
    end
2,004,378✔
814
    stmt.args = new_argexprs
819,200✔
815
    return new_argtypes
819,200✔
816
end
817

818
function compileable_specialization(mi::MethodInstance, effects::Effects,
2,350,180✔
819
        et::InliningEdgeTracker, @nospecialize(info::CallInfo); compilesig_invokes::Bool=true)
820
    mi_invoke = mi
×
821
    if compilesig_invokes
1,175,090✔
822
        method, atype, sparams = mi.def::Method, mi.specTypes, mi.sparam_vals
1,175,087✔
823
        new_atype = get_compileable_sig(method, atype, sparams)
2,349,771✔
824
        new_atype === nothing && return nothing
1,175,087✔
825
        if atype !== new_atype
799,940✔
826
            sp_ = ccall(:jl_type_intersection_with_env, Any, (Any, Any), new_atype, method.sig)::SimpleVector
97,586✔
827
            if sparams === sp_[2]::SimpleVector
97,586✔
828
                mi_invoke = specialize_method(method, new_atype, sparams)
97,586✔
829
                mi_invoke === nothing && return nothing
799,940✔
830
            end
831
        end
832
    else
833
        # If this caller does not want us to optimize calls to use their
834
        # declared compilesig, then it is also likely they would handle sparams
835
        # incorrectly if there were any unknown typevars, so we conservatively return nothing
836
        if any(@nospecialize(t)->isa(t, TypeVar), mi.sparam_vals)
3✔
837
            return nothing
×
838
        end
839
    end
840
    add_inlining_backedge!(et, mi)
799,943✔
841
    return InvokeCase(mi_invoke, effects, info)
799,943✔
842
end
843

844
function compileable_specialization(match::MethodMatch, effects::Effects,
507✔
845
        et::InliningEdgeTracker, @nospecialize(info::CallInfo); compilesig_invokes::Bool=true)
846
    mi = specialize_method(match)
507✔
847
    return compileable_specialization(mi, effects, et, info; compilesig_invokes)
507✔
848
end
849

850
struct CachedResult
851
    src::Any
852
    effects::Effects
853
    CachedResult(@nospecialize(src), effects::Effects) = new(src, effects)
6,199✔
854
end
855
@inline function get_cached_result(state::InliningState, mi::MethodInstance)
6,221✔
856
    code = get(code_cache(state), mi, nothing)
20,412,394✔
857
    if code isa CodeInstance
10,235,756✔
858
        if use_const_api(code)
10,176,638✔
859
            # in this case function can be inlined to a constant
860
            return ConstantCase(quoted(code.rettype_const))
871,926✔
861
        else
862
            src = @atomic :monotonic code.inferred
9,486,600✔
863
        end
864
        effects = decode_effects(code.ipo_purity_bits)
9,486,600✔
865
        return CachedResult(src, effects)
9,486,600✔
866
    end
867
    return CachedResult(nothing, Effects())
59,118✔
868
end
869

870
# the general resolver for usual and const-prop'ed calls
871
function resolve_todo(mi::MethodInstance, result::Union{MethodMatch,InferenceResult},
29,573,760✔
872
        argtypes::Vector{Any}, @nospecialize(info::CallInfo), flag::UInt8,
873
        state::InliningState; invokesig::Union{Nothing,Vector{Any}}=nothing)
874
    et = InliningEdgeTracker(state.et, invokesig)
29,573,760✔
875

876
    #XXX: update_valid_age!(min_valid[1], max_valid[1], sv)
877
    if isa(result, InferenceResult)
10,827✔
878
        src = result.src
4,551,125✔
879
        effects = result.ipo_effects
4,551,125✔
880
        if is_foldable_nothrow(effects)
9,084,312✔
881
            res = result.result
2,622✔
882
            if isa(res, Const) && is_inlineable_constant(res.val)
2,622✔
883
                # use constant calling convention
884
                add_inlining_backedge!(et, mi)
230✔
885
                return ConstantCase(quoted(res.val))
230✔
886
            end
887
        end
888
    else
889
        cached_result = get_cached_result(state, mi)
10,417,643✔
890
        if cached_result isa ConstantCase
10,235,755✔
891
            add_inlining_backedge!(et, mi)
690,038✔
892
            return cached_result
690,038✔
893
        end
894
        (; src, effects) = cached_result
6,215✔
895
    end
896

897
    # the duplicated check might have been done already within `analyze_method!`, but still
898
    # we need it here too since we may come here directly using a constant-prop' result
899
    if !OptimizationParams(state.interp).inlining || is_stmt_noinline(flag)
28,193,224✔
900
        return compileable_specialization(mi, effects, et, info;
447✔
901
            compilesig_invokes=OptimizationParams(state.interp).compilesig_invokes)
902
    end
903

904
    src = inlining_policy(state.interp, src, info, flag, mi, argtypes)
14,096,170✔
905
    src === nothing && return compileable_specialization(mi, effects, et, info;
14,096,165✔
906
        compilesig_invokes=OptimizationParams(state.interp).compilesig_invokes)
907

908
    add_inlining_backedge!(et, mi)
12,954,081✔
909
    return InliningTodo(mi, retrieve_ir_for_inlining(mi, src), effects)
12,954,081✔
910
end
911

912
# the special resolver for :invoke-d call
913
function resolve_todo(mi::MethodInstance, argtypes::Vector{Any},
1✔
914
    @nospecialize(info::CallInfo), flag::UInt8, state::InliningState)
915
    if !OptimizationParams(state.interp).inlining || is_stmt_noinline(flag)
2✔
916
        return nothing
×
917
    end
918

919
    et = InliningEdgeTracker(state.et, nothing)
1✔
920

921
    cached_result = get_cached_result(state, mi)
1✔
922
    if cached_result isa ConstantCase
1✔
923
        add_inlining_backedge!(et, mi)
×
924
        return cached_result
×
925
    end
926
    (; src, effects) = cached_result
×
927

928
    src = inlining_policy(state.interp, src, info, flag, mi, argtypes)
1✔
929

930
    src === nothing && return nothing
1✔
931

932
    add_inlining_backedge!(et, mi)
1✔
933
    return InliningTodo(mi, retrieve_ir_for_inlining(mi, src), effects)
1✔
934
end
935

936
function validate_sparams(sparams::SimpleVector)
24,818✔
937
    for i = 1:length(sparams)
60,962,104✔
938
        spᵢ = sparams[i]
15,916,756✔
939
        (isa(spᵢ, TypeVar) || isvarargtype(spᵢ)) && return false
31,590,803✔
940
    end
18,228,678✔
941
    return true
47,357,270✔
942
end
943

944
function may_have_fcalls(m::Method)
×
945
    isdefined(m, :source) || return true
97,470✔
946
    src = m.source
97,464✔
947
    isa(src, CodeInfo) || isa(src, Vector{UInt8}) || return true
194,928✔
948
    return ccall(:jl_ir_flag_has_fcall, Bool, (Any,), src)
97,464✔
949
end
950

951
function analyze_method!(match::MethodMatch, argtypes::Vector{Any},
20,479,042✔
952
    @nospecialize(info::CallInfo), flag::UInt8, state::InliningState;
953
    allow_typevars::Bool, invokesig::Union{Nothing,Vector{Any}}=nothing)
954
    method = match.method
10,239,521✔
955
    spec_types = match.spec_types
10,239,521✔
956

957
    # Check that we have the correct number of arguments
958
    na = Int(method.nargs)
10,239,521✔
959
    npassedargs = length(argtypes)
10,239,521✔
960
    if na != npassedargs && !(na > 0 && method.isva)
10,239,521✔
961
        # we have a method match only because an earlier
962
        # inference step shortened our call args list, even
963
        # though we have too many arguments to actually
964
        # call this function
965
        return nothing
×
966
    end
967
    if !match.fully_covers
10,239,521✔
968
        # type-intersection was not able to give us a simple list of types, so
969
        # ir_inline_unionsplit won't be able to deal with inlining this
970
        if !(spec_types isa DataType && length(spec_types.parameters) == length(argtypes) && !isvarargtype(spec_types.parameters[end]))
173,590✔
971
            return nothing
2,868✔
972
        end
973
    end
974

975
    if !validate_sparams(match.sparams)
13,636,415✔
976
        (allow_typevars && !may_have_fcalls(match.method)) || return nothing
70,107✔
977
    end
978

979
    # Get the specialization for this method signature
980
    # (later we will decide what to do with it)
981
    mi = specialize_method(match)
10,235,755✔
982
    return resolve_todo(mi, match, argtypes, info, flag, state; invokesig)
10,235,755✔
983
end
984

985
function retrieve_ir_for_inlining(mi::MethodInstance, src::Array{UInt8, 1})
5,976✔
986
    src = ccall(:jl_uncompress_ir, Any, (Any, Ptr{Cvoid}, Any), mi.def, C_NULL, src::Vector{UInt8})::CodeInfo
8,485,434✔
987
    return inflate_ir!(src, mi)
8,485,434✔
988
end
989
retrieve_ir_for_inlining(mi::MethodInstance, src::CodeInfo) = inflate_ir(src, mi)
4,468,648✔
990
retrieve_ir_for_inlining(mi::MethodInstance, ir::IRCode) = copy(ir)
1,408,030✔
991

992
function flags_for_effects(effects::Effects)
×
993
    flags::UInt8 = 0
×
994
    if is_consistent(effects)
5,993,738✔
995
        flags |= IR_FLAG_CONSISTENT
×
996
    end
997
    if is_removable_if_unused(effects)
6,011,187✔
998
        flags |= IR_FLAG_EFFECT_FREE | IR_FLAG_NOTHROW
4,962,593✔
999
    elseif is_nothrow(effects)
1,031,145✔
1000
        flags |= IR_FLAG_NOTHROW
204,255✔
1001
    end
1002
    return flags
5,993,738✔
1003
end
1004

1005
function handle_single_case!(todo::Vector{Pair{Int,Any}},
16,461,575✔
1006
    ir::IRCode, idx::Int, stmt::Expr, @nospecialize(case), params::OptimizationParams,
1007
    isinvoke::Bool = false)
1008
    if isa(case, ConstantCase)
32,919,224✔
1009
        ir[SSAValue(idx)][:inst] = case.val
1,592,311✔
1010
    elseif isa(case, InvokeCase)
14,870,444✔
1011
        is_foldable_nothrow(case.effects) && inline_const_if_inlineable!(ir[SSAValue(idx)]) && return nothing
724,566✔
1012
        isinvoke && rewrite_invoke_exprargs!(stmt)
724,562✔
1013
        stmt.head = :invoke
724,562✔
1014
        pushfirst!(stmt.args, case.invoke)
724,562✔
1015
        ir[SSAValue(idx)][:flag] |= flags_for_effects(case.effects)
724,562✔
1016
    elseif case === nothing
14,145,878✔
1017
        # Do, well, nothing
1018
    else
1019
        isinvoke && rewrite_invoke_exprargs!(stmt)
14,145,756✔
1020
        push!(todo, idx=>(case::InliningTodo))
14,145,756✔
1021
    end
1022
    return nothing
16,461,571✔
1023
end
1024

1025
rewrite_invoke_exprargs!(expr::Expr) = (expr.args = invoke_rewrite(expr.args); expr)
6,092✔
1026

1027
function is_valid_type_for_apply_rewrite(@nospecialize(typ), params::OptimizationParams)
1,473,782✔
1028
    if isa(typ, Const) && (v = typ.val; isa(v, SimpleVector))
1,746,228✔
1029
        length(v) > params.max_tuple_splat && return false
645✔
1030
        for p in v
1,268✔
1031
            is_inlineable_constant(p) || return false
1,861✔
1032
        end
3,099✔
1033
        return true
645✔
1034
    end
1035
    typ = widenconst(typ)
1,473,137✔
1036
    if isa(typ, DataType) && typ.name === _NAMEDTUPLE_NAME
1,473,137✔
1037
        typ = typ.parameters[2]
126✔
1038
        typ = unwraptv(typ)
126✔
1039
    end
1040
    isa(typ, DataType) || return false
1,476,178✔
1041
    if typ.name === Tuple.name
1,470,096✔
1042
        return !isvatuple(typ) && length(typ.parameters) <= params.max_tuple_splat
1,454,412✔
1043
    else
1044
        return false
15,684✔
1045
    end
1046
end
1047

1048
function inline_splatnew!(ir::IRCode, idx::Int, stmt::Expr, @nospecialize(rt), state::InliningState)
12,809✔
1049
    𝕃ₒ = optimizer_lattice(state.interp)
25✔
1050
    nf = nfields_tfunc(𝕃ₒ, rt)
12,809✔
1051
    if nf isa Const
12,809✔
1052
        eargs = stmt.args
12,784✔
1053
        tup = eargs[2]
12,784✔
1054
        tt = argextype(tup, ir)
12,784✔
1055
        tnf = nfields_tfunc(𝕃ₒ, tt)
12,784✔
1056
        # TODO: hoisting this tnf.val === nf.val check into codegen
1057
        # would enable us to almost always do this transform
1058
        if tnf isa Const && tnf.val === nf.val
12,784✔
1059
            n = tnf.val::Int
12,781✔
1060
            new_argexprs = Any[eargs[1]]
12,781✔
1061
            for j = 1:n
25,561✔
1062
                atype = getfield_tfunc(𝕃ₒ, tt, Const(j))
24,747✔
1063
                new_call = Expr(:call, Core.getfield, tup, j)
24,747✔
1064
                new_argexpr = insert_node!(ir, idx, NewInstruction(new_call, atype))
24,747✔
1065
                push!(new_argexprs, new_argexpr)
24,747✔
1066
            end
36,714✔
1067
            stmt.head = :new
12,781✔
1068
            stmt.args = new_argexprs
12,781✔
1069
        end
1070
    end
1071
    return nothing
12,809✔
1072
end
1073

1074
function call_sig(ir::IRCode, stmt::Expr)
24,698,055✔
1075
    isempty(stmt.args) && return nothing
24,698,055✔
1076
    if stmt.head === :call
24,698,055✔
1077
        offset = 1
24,698,054✔
1078
    elseif stmt.head === :invoke
1✔
1079
        offset = 2
1✔
1080
    else
1081
        return nothing
×
1082
    end
1083
    ft = argextype(stmt.args[offset], ir)
24,698,055✔
1084
    has_free_typevars(ft) && return nothing
24,698,055✔
1085
    f = singleton_type(ft)
24,992,660✔
1086
    f === Core.Intrinsics.llvmcall && return nothing
24,698,055✔
1087
    f === Core.Intrinsics.cglobal && return nothing
24,697,483✔
1088
    argtypes = Vector{Any}(undef, length(stmt.args))
24,696,775✔
1089
    argtypes[1] = ft
24,696,775✔
1090
    for i = (offset+1):length(stmt.args)
49,132,398✔
1091
        a = argextype(stmt.args[i], ir)
48,738,903✔
1092
        (a === Bottom || isvarargtype(a)) && return nothing
48,738,903✔
1093
        argtypes[i] = a
48,738,903✔
1094
    end
73,042,183✔
1095
    return Signature(f, ft, argtypes)
24,696,775✔
1096
end
1097

1098
function inline_apply!(todo::Vector{Pair{Int,Any}},
24,692,702✔
1099
    ir::IRCode, idx::Int, stmt::Expr, sig::Signature, state::InliningState)
1100
    while sig.f === Core._apply_iterate
25,511,698✔
1101
        info = ir.stmts[idx][:info]
920,668✔
1102
        if isa(info, UnionSplitApplyCallInfo)
920,668✔
1103
            if length(info.infos) != 1
918,449✔
1104
                # TODO: Handle union split applies?
1105
                new_info = info = NoCallInfo()
1,353✔
1106
            else
1107
                info = info.infos[1]
917,096✔
1108
                new_info = info.call
1,835,545✔
1109
            end
1110
        else
1111
            @assert info === NoCallInfo()
2,219✔
1112
            new_info = info = NoCallInfo()
×
1113
        end
1114
        arg_start = 3
920,668✔
1115
        argtypes = sig.argtypes
920,668✔
1116
        if arg_start > length(argtypes)
920,668✔
1117
            return nothing
×
1118
        end
1119
        ft = argtypes[arg_start]
920,668✔
1120
        if ft isa Const && ft.val === Core.tuple
920,668✔
1121
            # if one argument is a tuple already, and the rest are empty, we can just return it
1122
            # e.g. rewrite `((t::Tuple)...,)` to `t`
1123
            nonempty_idx = 0
7✔
1124
            𝕃ₒ = optimizer_lattice(state.interp)
7✔
1125
            for i = (arg_start + 1):length(argtypes)
402,474✔
1126
                ti = argtypes[i]
395,708✔
1127
                ⊑(𝕃ₒ, ti, Tuple{}) && continue
791,416✔
1128
                if ⊑(𝕃ₒ, ti, Tuple) && nonempty_idx == 0
665,078✔
1129
                    nonempty_idx = i
5✔
1130
                    continue
194,325✔
1131
                end
1132
                nonempty_idx = 0
×
1133
                break
138,214✔
1134
            end
451,965✔
1135
            if nonempty_idx != 0
201,237✔
1136
                ir.stmts[idx][:inst] = stmt.args[nonempty_idx]
62,485✔
1137
                return nothing
62,485✔
1138
            end
1139
        end
1140
        # Try to figure out the signature of the function being called
1141
        # and if rewrite_apply_exprargs can deal with this form
1142
        arginfos = MaybeAbstractIterationInfo[]
858,183✔
1143
        for i = (arg_start + 1):length(argtypes)
1,716,366✔
1144
            thisarginfo = nothing
270✔
1145
            if !is_valid_type_for_apply_rewrite(argtypes[i], OptimizationParams(state.interp))
1,473,782✔
1146
                isa(info, ApplyCallInfo) || return nothing
41,289✔
1147
                thisarginfo = info.arginfo[i-arg_start]
37,595✔
1148
                if thisarginfo === nothing || !thisarginfo.complete
38,941✔
1149
                    return nothing
37,136✔
1150
                end
1151
            end
1152
            push!(arginfos, thisarginfo)
1,435,258✔
1153
        end
2,050,398✔
1154
        # Independent of whether we can inline, the above analysis allows us to rewrite
1155
        # this apply call to a regular call
1156
        argtypes = rewrite_apply_exprargs!(todo,
819,200✔
1157
            ir, idx, stmt, argtypes, arginfos, arg_start, state)
1158
        ir.stmts[idx][:info] = new_info
819,200✔
1159
        has_free_typevars(ft) && return nothing
819,200✔
1160
        f = singleton_type(ft)
824,489✔
1161
        sig = Signature(f, ft, argtypes)
819,200✔
1162
    end
819,200✔
1163
    sig
24,591,234✔
1164
end
1165

1166
# TODO: this test is wrong if we start to handle Unions of function types later
1167
function is_builtin(𝕃ₒ::AbstractLattice, s::Signature)
16,726✔
1168
    isa(s.f, IntrinsicFunction) && return true
22,022,407✔
1169
    ⊑(𝕃ₒ, s.ft, IntrinsicFunction) && return true
42,950,483✔
1170
    isa(s.f, Builtin) && return true
21,475,232✔
1171
    ⊑(𝕃ₒ, s.ft, Builtin) && return true
34,689,083✔
1172
    return false
17,344,542✔
1173
end
1174

1175
function handle_invoke_call!(todo::Vector{Pair{Int,Any}},
3,932✔
1176
    ir::IRCode, idx::Int, stmt::Expr, info::InvokeCallInfo, flag::UInt8,
1177
    sig::Signature, state::InliningState)
1178
    match = info.match
3,932✔
1179
    if !match.fully_covers
3,932✔
1180
        # TODO: We could union split out the signature check and continue on
1181
        return nothing
6✔
1182
    end
1183
    result = info.result
3,926✔
1184
    invokesig = sig.argtypes
3,926✔
1185
    if isa(result, ConcreteResult)
3,926✔
1186
        item = concrete_result_item(result, info, state; invokesig)
753✔
1187
    else
1188
        argtypes = invoke_rewrite(sig.argtypes)
3,173✔
1189
        if isa(result, ConstPropResult)
3,173✔
1190
            mi = result.result.linfo
1,950✔
1191
            validate_sparams(mi.sparam_vals) || return nothing
1,950✔
1192
            if Union{} !== argtypes_to_type(argtypes) <: mi.def.sig
1,950✔
1193
                item = resolve_todo(mi, result.result, argtypes, info, flag, state; invokesig)
1,950✔
1194
                handle_single_case!(todo, ir, idx, stmt, item, OptimizationParams(state.interp), true)
1,950✔
1195
                return nothing
1,950✔
1196
            end
1197
        end
1198
        item = analyze_method!(match, argtypes, info, flag, state; allow_typevars=false, invokesig)
1,223✔
1199
    end
1200
    handle_single_case!(todo, ir, idx, stmt, item, OptimizationParams(state.interp), true)
1,976✔
1201
    return nothing
1,976✔
1202
end
1203

1204
function invoke_signature(argtypes::Vector{Any})
3,052✔
1205
    ft, argtyps = widenconst(argtypes[2]), instanceof_tfunc(widenconst(argtypes[3]))[1]
3,052✔
1206
    return rewrap_unionall(Tuple{ft, unwrap_unionall(argtyps).parameters...}, argtyps)
3,052✔
1207
end
1208

1209
function narrow_opaque_closure!(ir::IRCode, stmt::Expr, @nospecialize(info::CallInfo), state::InliningState)
28✔
1210
    if isa(info, OpaqueClosureCreateInfo)
28✔
1211
        lbt = argextype(stmt.args[2], ir)
28✔
1212
        lb, exact = instanceof_tfunc(lbt)
28✔
1213
        exact || return
28✔
1214
        ubt = argextype(stmt.args[3], ir)
28✔
1215
        ub, exact = instanceof_tfunc(ubt)
28✔
1216
        exact || return
28✔
1217
        # Narrow opaque closure type
1218
        𝕃ₒ = optimizer_lattice(state.interp)
×
1219
        newT = widenconst(tmeet(𝕃ₒ, tmerge(𝕃ₒ, lb, info.unspec.rt), ub))
28✔
1220
        if newT != ub
28✔
1221
            # N.B.: Narrowing the ub requires a backedge on the mi whose type
1222
            # information we're using, since a change in that function may
1223
            # invalidate ub result.
1224
            stmt.args[3] = newT
13✔
1225
        end
1226
    end
1227
end
1228

1229
# As a matter of convenience, this pass also computes effect-freenes.
1230
# For primitives, we do that right here. For proper calls, we will
1231
# discover this when we consult the caches.
1232
function check_effect_free!(ir::IRCode, idx::Int, @nospecialize(stmt), @nospecialize(rt), state::InliningState)
37,566✔
1233
    return check_effect_free!(ir, idx, stmt, rt, optimizer_lattice(state.interp))
88,198,079✔
1234
end
1235
function check_effect_free!(ir::IRCode, idx::Int, @nospecialize(stmt), @nospecialize(rt), 𝕃ₒ::AbstractLattice)
43,865✔
1236
    (consistent, effect_free_and_nothrow, nothrow) = stmt_effect_flags(𝕃ₒ, stmt, rt, ir)
49,843,742✔
1237
    if consistent
49,843,742✔
1238
        ir.stmts[idx][:flag] |= IR_FLAG_CONSISTENT
20,225,177✔
1239
    end
1240
    if effect_free_and_nothrow
49,843,742✔
1241
        ir.stmts[idx][:flag] |= IR_FLAG_EFFECT_FREE | IR_FLAG_NOTHROW
11,478,154✔
1242
    elseif nothrow
38,365,588✔
1243
        ir.stmts[idx][:flag] |= IR_FLAG_NOTHROW
8,792,647✔
1244
    end
1245
    return effect_free_and_nothrow
49,843,742✔
1246
end
1247

1248
# Handles all analysis and inlining of intrinsics and builtins. In particular,
1249
# this method does not access the method table or otherwise process generic
1250
# functions.
1251
function process_simple!(todo::Vector{Pair{Int,Any}}, ir::IRCode, idx::Int, state::InliningState)
52,261,432✔
1252
    stmt = ir.stmts[idx][:inst]
52,261,432✔
1253
    rt = ir.stmts[idx][:type]
52,261,432✔
1254
    if !(stmt isa Expr)
52,261,432✔
1255
        check_effect_free!(ir, idx, stmt, rt, state)
24,026,169✔
1256
        return nothing
15,255,941✔
1257
    end
1258
    head = stmt.head
37,005,491✔
1259
    if head !== :call
37,005,491✔
1260
        if head === :splatnew
12,311,511✔
1261
            inline_splatnew!(ir, idx, stmt, rt, state)
12,809✔
1262
        elseif head === :new_opaque_closure
12,298,702✔
1263
            narrow_opaque_closure!(ir, stmt, ir.stmts[idx][:info], state)
28✔
1264
        elseif head === :invoke
12,298,674✔
1265
            sig = call_sig(ir, stmt)
1✔
1266
            sig === nothing && return nothing
1✔
1267
            return stmt, sig
1✔
1268
        end
1269
        check_effect_free!(ir, idx, stmt, rt, state)
24,034,867✔
1270
        return nothing
12,311,510✔
1271
    end
1272

1273
    sig = call_sig(ir, stmt)
24,693,980✔
1274
    sig === nothing && return nothing
24,693,980✔
1275

1276
    # Handle _apply_iterate
1277
    sig = inline_apply!(todo, ir, idx, stmt, sig, state)
24,692,702✔
1278
    sig === nothing && return nothing
24,692,702✔
1279

1280
    # Check if we match any of the early inliners
1281
    earlyres = early_inline_special_case(ir, stmt, rt, sig, state)
24,591,234✔
1282
    if isa(earlyres, SomeCase)
24,591,234✔
1283
        ir.stmts[idx][:inst] = earlyres.val
2,396,837✔
1284
        return nothing
2,396,837✔
1285
    end
1286

1287
    if check_effect_free!(ir, idx, stmt, rt, state)
40,044,937✔
1288
        if sig.f === typeassert || ⊑(optimizer_lattice(state.interp), sig.ft, typeof(typeassert))
12,693,081✔
1289
            # typeassert is a no-op if effect free
1290
            ir.stmts[idx][:inst] = stmt.args[2]
169,245✔
1291
            return nothing
169,245✔
1292
        end
1293
    end
1294

1295
    if (sig.f !== Core.invoke && sig.f !== Core.finalizer && sig.f !== modifyfield!) &&
43,498,152✔
1296
        is_builtin(optimizer_lattice(state.interp), sig)
1297
        # No inlining for builtins (other invoke/apply/typeassert/finalizer)
1298
        return nothing
4,677,051✔
1299
    end
1300

1301
    # Special case inliners for regular functions
1302
    lateres = late_inline_special_case!(ir, idx, stmt, rt, sig, state)
17,348,101✔
1303
    if isa(lateres, SomeCase)
17,348,101✔
1304
        ir[SSAValue(idx)][:inst] = lateres.val
75,595✔
1305
        check_effect_free!(ir, idx, lateres.val, rt, state)
92,106✔
1306
        return nothing
75,595✔
1307
    end
1308

1309
    return stmt, sig
17,272,506✔
1310
end
1311

1312
function handle_any_const_result!(cases::Vector{InliningCase},
34,295,012✔
1313
    @nospecialize(result), match::MethodMatch, argtypes::Vector{Any},
1314
    @nospecialize(info::CallInfo), flag::UInt8, state::InliningState;
1315
    allow_abstract::Bool, allow_typevars::Bool)
1316
    if isa(result, ConcreteResult)
17,147,506✔
1317
        return handle_concrete_result!(cases, result, info, state)
951,455✔
1318
    end
1319
    if isa(result, SemiConcreteResult)
16,196,051✔
1320
        result = inlining_policy(state.interp, result, info, flag, result.mi, argtypes)
2,816,898✔
1321
        if isa(result, SemiConcreteResult)
1,408,449✔
1322
            return handle_semi_concrete_result!(cases, result, info, flag, state; allow_abstract)
1,408,449✔
1323
        end
1324
    end
1325
    if isa(result, ConstPropResult)
14,787,602✔
1326
        return handle_const_prop_result!(cases, result, argtypes, info, flag, state; allow_abstract, allow_typevars)
4,549,309✔
1327
    else
1328
        @assert result === nothing
10,238,293✔
1329
        return handle_match!(cases, match, argtypes, info, flag, state; allow_abstract, allow_typevars)
10,238,293✔
1330
    end
1331
end
1332

1333
function info_effects(@nospecialize(result), match::MethodMatch, state::InliningState)
10,792✔
1334
    if isa(result, ConcreteResult)
17,055,414✔
1335
        return result.effects
951,454✔
1336
    elseif isa(result, SemiConcreteResult)
16,103,960✔
1337
        return result.effects
1,408,449✔
1338
    elseif isa(result, ConstPropResult)
14,695,511✔
1339
        return result.result.ipo_effects
4,546,073✔
1340
    else
1341
        mi = specialize_method(match; preexisting=true)
10,149,438✔
1342
        if isa(mi, MethodInstance)
10,149,438✔
1343
            code = get(code_cache(state), mi, nothing)
20,232,599✔
1344
            if code isa CodeInstance
10,140,023✔
1345
                return decode_effects(code.ipo_purity_bits)
10,092,576✔
1346
            end
1347
        end
1348
        return Effects()
56,862✔
1349
    end
1350
end
1351

1352
function compute_inlining_cases(@nospecialize(info::CallInfo), flag::UInt8, sig::Signature,
16,845,868✔
1353
    state::InliningState)
1354
    nunion = nsplit(info)
16,845,868✔
1355
    nunion === nothing && return nothing
16,845,868✔
1356
    cases = InliningCase[]
16,845,868✔
1357
    argtypes = sig.argtypes
16,845,868✔
1358
    local handled_all_cases::Bool = true
16,845,868✔
1359
    local revisit_idx = nothing
10,755✔
1360
    local only_method = nothing
10,755✔
1361
    local meth::MethodLookupResult
×
1362
    local all_result_count = 0
10,755✔
1363
    local joint_effects::Effects = EFFECTS_TOTAL
10,755✔
1364
    local fully_covered::Bool = true
16,845,868✔
1365
    for i = 1:nunion
33,691,736✔
1366
        meth = getsplit(info, i)
16,943,181✔
1367
        if meth.ambig
16,943,181✔
1368
            # Too many applicable methods
1369
            # Or there is a (partial?) ambiguity
1370
            return nothing
558✔
1371
        elseif length(meth) == 0
16,942,623✔
1372
            # No applicable methods; try next union split
1373
            handled_all_cases = false
9,325✔
1374
            continue
9,325✔
1375
        else
1376
            if length(meth) == 1 && only_method !== false
16,933,298✔
1377
                if only_method === nothing
16,826,633✔
1378
                    only_method = meth[1].method
16,742,689✔
1379
                elseif only_method !== meth[1].method
83,944✔
1380
                    only_method = false
16,826,636✔
1381
                end
1382
            else
1383
                only_method = false
16✔
1384
            end
1385
        end
1386
        local split_fully_covered::Bool = false
16,933,298✔
1387
        for (j, match) in enumerate(meth)
33,866,596✔
1388
            all_result_count += 1
17,055,414✔
1389
            result = getresult(info, all_result_count)
17,055,414✔
1390
            joint_effects = merge_effects(joint_effects, info_effects(result, match, state))
34,014,699✔
1391
            split_fully_covered |= match.fully_covers
17,055,414✔
1392
            if !validate_sparams(match.sparams)
22,717,049✔
1393
                if !match.fully_covers
129,498✔
1394
                    handled_all_cases = false
23,793✔
1395
                    continue
23,793✔
1396
                end
1397
                if revisit_idx === nothing
105,705✔
1398
                    revisit_idx = (i, j, all_result_count)
104,153✔
1399
                else
1400
                    handled_all_cases = false
1,552✔
1401
                    revisit_idx = nothing
105,705✔
1402
                end
1403
            else
1404
                handled_all_cases &= handle_any_const_result!(cases,
16,925,916✔
1405
                    result, match, argtypes, info, flag, state; allow_abstract=true, allow_typevars=false)
1406
            end
1407
        end
17,177,530✔
1408
        fully_covered &= split_fully_covered
16,933,298✔
1409
    end
17,039,936✔
1410

1411
    joint_effects = Effects(joint_effects; nothrow=fully_covered)
16,845,310✔
1412

1413
    if handled_all_cases && revisit_idx !== nothing
16,845,310✔
1414
        # we handled everything except one match with unmatched sparams,
1415
        # so try to handle it by bypassing validate_sparams
1416
        (i, j, k) = revisit_idx
×
1417
        match = getsplit(info, i)[j]
97,228✔
1418
        result = getresult(info, k)
97,228✔
1419
        handled_all_cases &= handle_any_const_result!(cases,
97,228✔
1420
            result, match, argtypes, info, flag, state; allow_abstract=true, allow_typevars=true)
1421
    elseif length(cases) == 0 && only_method isa Method
16,748,082✔
1422
        # if the signature is fully covered and there is only one applicable method,
1423
        # we can try to inline it even in the presence of unmatched sparams
1424
        # -- But don't try it if we already tried to handle the match in the revisit_idx
1425
        # case, because that'll (necessarily) be the same method.
1426
        if nsplit(info)::Int > 1
124,362✔
1427
            atype = argtypes_to_type(argtypes)
1,912✔
1428
            (metharg, methsp) = ccall(:jl_type_intersection_with_env, Any, (Any, Any), atype, only_method.sig)::SimpleVector
3,824✔
1429
            match = MethodMatch(metharg, methsp::SimpleVector, only_method, true)
1,912✔
1430
            result = nothing
1,912✔
1431
        else
1432
            @assert length(meth) == 1
122,450✔
1433
            match = meth[1]
122,450✔
1434
            result = getresult(info, 1)
122,450✔
1435
        end
1436
        handle_any_const_result!(cases,
124,362✔
1437
            result, match, argtypes, info, flag, state; allow_abstract=true, allow_typevars=true)
1438
        fully_covered = handled_all_cases = match.fully_covers
124,362✔
1439
    elseif !handled_all_cases
16,623,720✔
1440
        # if we've not seen all candidates, union split is valid only for dispatch tuples
1441
        filter!(case::InliningCase->isdispatchtuple(case.sig), cases)
94,811✔
1442
    end
1443

1444
    return cases, (handled_all_cases & fully_covered), joint_effects
16,845,310✔
1445
end
1446

1447
function handle_call!(todo::Vector{Pair{Int,Any}},
10,755✔
1448
    ir::IRCode, idx::Int, stmt::Expr, @nospecialize(info::CallInfo), flag::UInt8, sig::Signature,
1449
    state::InliningState)
1450
    cases = compute_inlining_cases(info, flag, sig, state)
16,845,853✔
1451
    cases === nothing && return nothing
16,845,853✔
1452
    cases, all_covered, joint_effects = cases
16,845,295✔
1453
    handle_cases!(todo, ir, idx, stmt, argtypes_to_type(sig.argtypes), cases,
16,845,295✔
1454
        all_covered, joint_effects, OptimizationParams(state.interp))
1455
end
1456

1457
function handle_match!(cases::Vector{InliningCase},
20,476,586✔
1458
    match::MethodMatch, argtypes::Vector{Any}, @nospecialize(info::CallInfo), flag::UInt8,
1459
    state::InliningState;
1460
    allow_abstract::Bool, allow_typevars::Bool)
1461
    spec_types = match.spec_types
10,238,293✔
1462
    allow_abstract || isdispatchtuple(spec_types) || return false
10,238,293✔
1463
    # We may see duplicated dispatch signatures here when a signature gets widened
1464
    # during abstract interpretation: for the purpose of inlining, we can just skip
1465
    # processing this dispatch candidate (unless unmatched type parameters are present)
1466
    !allow_typevars && _any(case->case.sig === spec_types, cases) && return true
10,640,663✔
1467
    item = analyze_method!(match, argtypes, info, flag, state; allow_typevars)
10,238,291✔
1468
    item === nothing && return false
10,238,291✔
1469
    push!(cases, InliningCase(spec_types, item))
9,888,383✔
1470
    return true
9,888,383✔
1471
end
1472

1473
function handle_const_prop_result!(cases::Vector{InliningCase},
9,098,618✔
1474
    result::ConstPropResult, argtypes::Vector{Any}, @nospecialize(info::CallInfo),
1475
    flag::UInt8, state::InliningState;
1476
    allow_abstract::Bool, allow_typevars::Bool)
1477
    mi = result.result.linfo
4,549,309✔
1478
    spec_types = mi.specTypes
4,549,309✔
1479
    allow_abstract || isdispatchtuple(spec_types) || return false
4,549,309✔
1480
    if !validate_sparams(mi.sparam_vals)
5,800,497✔
1481
        (allow_typevars && !may_have_fcalls(mi.def::Method)) || return false
28,396✔
1482
    end
1483
    item = resolve_todo(mi, result.result, argtypes, info, flag, state)
4,549,171✔
1484
    item === nothing && return false
4,549,171✔
1485
    push!(cases, InliningCase(spec_types, item))
4,520,653✔
1486
    return true
4,520,653✔
1487
end
1488

1489
function semiconcrete_result_item(result::SemiConcreteResult,
14✔
1490
        @nospecialize(info::CallInfo), flag::UInt8, state::InliningState)
1491
    mi = result.mi
1,408,044✔
1492
    if !OptimizationParams(state.interp).inlining || is_stmt_noinline(flag)
2,816,088✔
1493
        et = InliningEdgeTracker(state.et, nothing)
28✔
1494
        return compileable_specialization(mi, result.effects, et, info;
14✔
1495
            compilesig_invokes=OptimizationParams(state.interp).compilesig_invokes)
1496
    else
1497
        return InliningTodo(mi, retrieve_ir_for_inlining(mi, result.ir), result.effects)
1,408,030✔
1498
    end
1499
end
1500

1501
function handle_semi_concrete_result!(cases::Vector{InliningCase}, result::SemiConcreteResult,
2,816,898✔
1502
        @nospecialize(info::CallInfo), flag::UInt8, state::InliningState;
1503
        allow_abstract::Bool)
1504
    mi = result.mi
1,408,449✔
1505
    spec_types = mi.specTypes
1,408,449✔
1506
    allow_abstract || isdispatchtuple(spec_types) || return false
1,408,449✔
1507
    validate_sparams(mi.sparam_vals) || return false
1,408,854✔
1508
    item = semiconcrete_result_item(result, info, flag, state)
1,408,058✔
1509
    item === nothing && return false
1,408,044✔
1510
    push!(cases, InliningCase(spec_types, item))
1,408,058✔
1511
    return true
1,408,044✔
1512
end
1513

1514
function handle_concrete_result!(cases::Vector{InliningCase}, result::ConcreteResult, @nospecialize(info::CallInfo), state::InliningState)
12✔
1515
    case = concrete_result_item(result, info, state)
951,455✔
1516
    case === nothing && return false
951,455✔
1517
    push!(cases, InliningCase(result.mi.specTypes, case))
983,489✔
1518
    return true
951,453✔
1519
end
1520

1521
may_inline_concrete_result(result::ConcreteResult) =
964,572✔
1522
    isdefined(result, :result) && is_inlineable_constant(result.result)
1523

1524
function concrete_result_item(result::ConcreteResult, @nospecialize(info::CallInfo), state::InliningState;
1,904,416✔
1525
    invokesig::Union{Nothing,Vector{Any}}=nothing)
1526
    if !may_inline_concrete_result(result)
964,572✔
1527
        et = InliningEdgeTracker(state.et, invokesig)
64,076✔
1528
        return compileable_specialization(result.mi, result.effects, et, info;
32,038✔
1529
            compilesig_invokes=OptimizationParams(state.interp).compilesig_invokes)
1530
    end
1531
    @assert result.effects === EFFECTS_TOTAL
920,170✔
1532
    return ConstantCase(quoted(result.result))
920,170✔
1533
end
1534

1535
function handle_cases!(todo::Vector{Pair{Int,Any}}, ir::IRCode, idx::Int, stmt::Expr,
16,845,295✔
1536
    @nospecialize(atype), cases::Vector{InliningCase}, fully_covered::Bool,
1537
    joint_effects::Effects, params::OptimizationParams)
1538
    # If we only have one case and that case is fully covered, we may either
1539
    # be able to do the inlining now (for constant cases), or push it directly
1540
    # onto the todo list
1541
    if fully_covered && length(cases) == 1
16,845,295✔
1542
        handle_single_case!(todo, ir, idx, stmt, cases[1].item, params)
16,457,638✔
1543
    elseif length(cases) > 0
387,657✔
1544
        isa(atype, DataType) || return nothing
158,866✔
1545
        for case in cases
158,866✔
1546
            isa(case.sig, DataType) || return nothing
295,480✔
1547
        end
453,776✔
1548
        push!(todo, idx=>UnionSplit(fully_covered, atype, cases))
158,676✔
1549
    else
1550
        ir[SSAValue(idx)][:flag] |= flags_for_effects(joint_effects)
228,791✔
1551
    end
1552
    return nothing
16,845,105✔
1553
end
1554

1555
function handle_opaque_closure_call!(todo::Vector{Pair{Int,Any}},
11✔
1556
    ir::IRCode, idx::Int, stmt::Expr, info::OpaqueClosureCallInfo,
1557
    flag::UInt8, sig::Signature, state::InliningState)
1558
    result = info.result
11✔
1559
    if isa(result, ConstPropResult)
11✔
1560
        mi = result.result.linfo
4✔
1561
        validate_sparams(mi.sparam_vals) || return nothing
4✔
1562
        item = resolve_todo(mi, result.result, sig.argtypes, info, flag, state)
4✔
1563
    elseif isa(result, ConcreteResult)
7✔
1564
        item = concrete_result_item(result, info, state)
×
1565
    else
1566
        if isa(result, SemiConcreteResult)
7✔
1567
            result = inlining_policy(state.interp, result, info, flag, result.mi, sig.argtypes)
×
1568
        end
1569
        if isa(result, SemiConcreteResult)
7✔
1570
            item = semiconcrete_result_item(result, info, flag, state)
×
1571
        else
1572
            item = analyze_method!(info.match, sig.argtypes, info, flag, state; allow_typevars=false)
7✔
1573
        end
1574
    end
1575
    handle_single_case!(todo, ir, idx, stmt, item, OptimizationParams(state.interp))
11✔
1576
    return nothing
11✔
1577
end
1578

1579
function handle_modifyfield!_call!(ir::IRCode, idx::Int, stmt::Expr, info::ModifyFieldInfo, state::InliningState)
579✔
1580
    info = info.info
579✔
1581
    info isa MethodResultPure && (info = info.info)
579✔
1582
    info isa ConstCallInfo && (info = info.call)
579✔
1583
    info isa MethodMatchInfo || return nothing
651✔
1584
    length(info.results) == 1 || return nothing
507✔
1585
    match = info.results[1]::MethodMatch
507✔
1586
    match.fully_covers || return nothing
507✔
1587
    case = compileable_specialization(match, Effects(), InliningEdgeTracker(state.et), info;
1,014✔
1588
        compilesig_invokes=OptimizationParams(state.interp).compilesig_invokes)
1589
    case === nothing && return nothing
507✔
1590
    stmt.head = :invoke_modify
144✔
1591
    pushfirst!(stmt.args, case.invoke)
144✔
1592
    ir.stmts[idx][:inst] = stmt
144✔
1593
    return nothing
144✔
1594
end
1595

1596
function handle_finalizer_call!(ir::IRCode, idx::Int, stmt::Expr, info::FinalizerInfo,
480✔
1597
    state::InliningState)
1598

1599
    # Finalizers don't return values, so if their execution is not observable,
1600
    # we can just not register them
1601
    if is_removable_if_unused(info.effects)
480✔
1602
        ir[SSAValue(idx)] = nothing
×
1603
        return nothing
×
1604
    end
1605

1606
    # Only inline finalizers that are known nothrow and notls.
1607
    # This avoids having to set up state for finalizer isolation
1608
    is_finalizer_inlineable(info.effects) || return nothing
945✔
1609

1610
    ft = argextype(stmt.args[2], ir)
15✔
1611
    has_free_typevars(ft) && return nothing
15✔
1612
    f = singleton_type(ft)
17✔
1613
    argtypes = Vector{Any}(undef, 2)
15✔
1614
    argtypes[1] = ft
15✔
1615
    argtypes[2] = argextype(stmt.args[3], ir)
15✔
1616
    sig = Signature(f, ft, argtypes)
15✔
1617

1618
    cases = compute_inlining_cases(info.info, #=flag=#UInt8(0), sig, state)
15✔
1619
    cases === nothing && return nothing
15✔
1620
    cases, all_covered, _ = cases
15✔
1621
    if all_covered && length(cases) == 1
15✔
1622
        # NOTE we don't append `item1` to `stmt` here so that we don't serialize
1623
        # `Core.Compiler` data structure into the global cache
1624
        item1 = cases[1].item
15✔
1625
        if isa(item1, InliningTodo)
15✔
1626
            push!(stmt.args, true)
14✔
1627
            push!(stmt.args, item1.mi)
14✔
1628
        elseif isa(item1, InvokeCase)
1✔
1629
            push!(stmt.args, false)
1✔
1630
            push!(stmt.args, item1.invoke)
1✔
1631
        elseif isa(item1, ConstantCase)
×
1632
            push!(stmt.args, nothing)
×
1633
            push!(stmt.args, item1.val)
×
1634
        end
1635
    end
1636
    return nothing
15✔
1637
end
1638

1639
function handle_invoke_expr!(todo::Vector{Pair{Int,Any}},
×
1640
    idx::Int, stmt::Expr, @nospecialize(info::CallInfo), flag::UInt8, sig::Signature, state::InliningState)
1641
    mi = stmt.args[1]::MethodInstance
1✔
1642
    case = resolve_todo(mi, sig.argtypes, info, flag, state)
1✔
1643
    if case !== nothing
1✔
1644
        push!(todo, idx=>(case::InliningTodo))
1✔
1645
    end
1646
    return nothing
1✔
1647
end
1648

1649
function inline_const_if_inlineable!(inst::Instruction)
×
1650
    rt = inst[:type]
22,910✔
1651
    if rt isa Const && is_inlineable_constant(rt.val)
22,910✔
1652
        inst[:inst] = quoted(rt.val)
4✔
1653
        return true
4✔
1654
    end
1655
    inst[:flag] |= IR_FLAG_EFFECT_FREE
22,906✔
1656
    return false
22,906✔
1657
end
1658

1659
function assemble_inline_todo!(ir::IRCode, state::InliningState)
5,016,404✔
1660
    todo = Pair{Int, Any}[]
5,016,404✔
1661

1662
    for idx in 1:length(ir.stmts)
10,032,808✔
1663
        simpleres = process_simple!(todo, ir, idx, state)
52,261,432✔
1664
        simpleres === nothing && continue
52,261,432✔
1665
        stmt, sig = simpleres
17,272,507✔
1666

1667
        flag = ir.stmts[idx][:flag]
17,272,507✔
1668
        info = ir.stmts[idx][:info]
17,272,507✔
1669

1670
        # `NativeInterpreter` won't need this, but provide a support for `:invoke` exprs here
1671
        # for external `AbstractInterpreter`s that may run the inlining pass multiple times
1672
        if isexpr(stmt, :invoke)
17,272,507✔
1673
            handle_invoke_expr!(todo, idx, stmt, info, flag, sig, state)
1✔
1674
            continue
1✔
1675
        end
1676

1677
        # Check whether this call was @pure and evaluates to a constant
1678
        if info isa MethodResultPure
17,272,506✔
1679
            inline_const_if_inlineable!(ir[SSAValue(idx)]) && continue
569✔
1680
            info = info.info
569✔
1681
        end
1682
        if info === NoCallInfo()
17,272,506✔
1683
            # Inference determined this couldn't be analyzed. Don't question it.
1684
            continue
423,443✔
1685
        end
1686

1687
        # handle special cased builtins
1688
        if isa(info, OpaqueClosureCallInfo)
16,849,063✔
1689
            handle_opaque_closure_call!(todo, ir, idx, stmt, info, flag, sig, state)
11✔
1690
        elseif isa(info, ModifyFieldInfo)
16,849,052✔
1691
            handle_modifyfield!_call!(ir, idx, stmt, info, state)
579✔
1692
        elseif isa(info, InvokeCallInfo)
16,848,473✔
1693
            handle_invoke_call!(todo, ir, idx, stmt, info, flag, sig, state)
3,932✔
1694
        elseif isa(info, FinalizerInfo)
16,844,541✔
1695
            handle_finalizer_call!(ir, idx, stmt, info, state)
480✔
1696
        else
1697
            # cascade to the generic (and extendable) handler
1698
            handle_call!(todo, ir, idx, stmt, info, flag, sig, state)
16,844,061✔
1699
        end
1700
    end
99,506,460✔
1701

1702
    return todo
5,016,404✔
1703
end
1704

1705
function linear_inline_eligible(ir::IRCode)
×
1706
    length(ir.cfg.blocks) == 1 || return false
17,016,321✔
1707
    terminator = ir[SSAValue(last(ir.cfg.blocks[1].stmts))][:inst]
11,707,903✔
1708
    isa(terminator, ReturnNode) || return false
11,707,903✔
1709
    isdefined(terminator, :val) || return false
11,712,858✔
1710
    return true
11,702,948✔
1711
end
1712

1713
function early_inline_special_case(
24,591,234✔
1714
    ir::IRCode, stmt::Expr, @nospecialize(type), sig::Signature,
1715
    state::InliningState)
1716
    OptimizationParams(state.interp).inlining || return nothing
24,591,234✔
1717
    (; f, ft, argtypes) = sig
24,591,234✔
1718

1719
    if isa(type, Const) # || isconstType(type)
24,591,234✔
1720
        val = type.val
6,338,401✔
1721
        is_inlineable_constant(val) || return nothing
6,396,683✔
1722
        if isa(f, IntrinsicFunction)
6,280,119✔
1723
            if is_pure_intrinsic_infer(f) && intrinsic_nothrow(f, argtypes[2:end])
59,274✔
1724
                return SomeCase(quoted(val))
59,258✔
1725
            end
1726
        elseif contains_is(_PURE_BUILTINS, f)
34,694,447✔
1727
            return SomeCase(quoted(val))
812,615✔
1728
        elseif contains_is(_EFFECT_FREE_BUILTINS, f)
75,203,706✔
1729
            if _builtin_nothrow(optimizer_lattice(state.interp), f, argtypes[2:end], type)
1,548,470✔
1730
                return SomeCase(quoted(val))
1,522,514✔
1731
            end
1732
        elseif f === Core.get_binding_type
3,859,760✔
1733
            length(argtypes) == 3 || return nothing
1✔
1734
            if get_binding_type_effect_free(argtypes[2], argtypes[3])
1✔
1735
                return SomeCase(quoted(val))
1✔
1736
            end
1737
        end
1738
    end
1739
    if f === compilerbarrier
22,138,564✔
1740
        # check if this `compilerbarrier` has already imposed a barrier on abstract interpretation
1741
        # so that it can be eliminated here
1742
        length(argtypes) == 3 || return nothing
2,009✔
1743
        setting = argtypes[2]
2,009✔
1744
        isa(setting, Const) || return nothing
2,009✔
1745
        setting = setting.val
2,009✔
1746
        isa(setting, Symbol) || return nothing
2,009✔
1747
        setting === :const || setting === :conditional || setting === :type || return nothing
4,018✔
1748
        # barriered successfully already, eliminate it
1749
        return SomeCase(stmt.args[3])
2,009✔
1750
    elseif f === Core.ifelse && length(argtypes) == 4
22,136,555✔
1751
        cond = argtypes[2]
1,464✔
1752
        if isa(cond, Const)
1,464✔
1753
            if cond.val === true
440✔
1754
                return SomeCase(stmt.args[3])
171✔
1755
            elseif cond.val === false
269✔
1756
                return SomeCase(stmt.args[4])
269✔
1757
            end
1758
        end
1759
    end
1760
    return nothing
22,136,115✔
1761
end
1762

1763
# special-case some regular method calls whose results are not folded within `abstract_call_known`
1764
# (and thus `early_inline_special_case` doesn't handle them yet)
1765
# NOTE we manually inline the method bodies, and so the logic here needs to precisely sync with their definitions
1766
function late_inline_special_case!(
17,348,101✔
1767
    ir::IRCode, idx::Int, stmt::Expr, @nospecialize(type), sig::Signature,
1768
    state::InliningState)
1769
    OptimizationParams(state.interp).inlining || return nothing
17,348,101✔
1770
    (; f, ft, argtypes) = sig
17,348,101✔
1771
    if length(argtypes) == 3 && istopfunction(f, :!==)
17,348,101✔
1772
        # special-case inliner for !== that precedes _methods_by_ftype union splitting
1773
        # and that works, even though inference generally avoids inferring the `!==` Method
1774
        if isa(type, Const)
23,231✔
1775
            return SomeCase(quoted(type.val))
1,305✔
1776
        end
1777
        cmp_call = Expr(:call, GlobalRef(Core, :(===)), stmt.args[2], stmt.args[3])
21,926✔
1778
        cmp_call_ssa = insert_node!(ir, idx, effect_free(NewInstruction(cmp_call, Bool)))
21,926✔
1779
        not_call = Expr(:call, GlobalRef(Core.Intrinsics, :not_int), cmp_call_ssa)
21,926✔
1780
        return SomeCase(not_call)
21,926✔
1781
    elseif length(argtypes) == 3 && istopfunction(f, :(>:))
17,324,870✔
1782
        # special-case inliner for issupertype
1783
        # that works, even though inference generally avoids inferring the `>:` Method
1784
        if isa(type, Const) && _builtin_nothrow(optimizer_lattice(state.interp), <:, Any[argtypes[3], argtypes[2]], type)
106✔
1785
            return SomeCase(quoted(type.val))
38✔
1786
        end
1787
        subtype_call = Expr(:call, GlobalRef(Core, :(<:)), stmt.args[3], stmt.args[2])
29✔
1788
        return SomeCase(subtype_call)
29✔
1789
    elseif f === TypeVar && 2 <= length(argtypes) <= 4 && ⊑(optimizer_lattice(state.interp), argtypes[2], Symbol)
17,338,181✔
1790
        typevar_call = Expr(:call, GlobalRef(Core, :_typevar), stmt.args[2],
26,001✔
1791
            length(stmt.args) < 4 ? Bottom : stmt.args[3],
1792
            length(stmt.args) == 2 ? Any : stmt.args[end])
1793
        return SomeCase(typevar_call)
13,378✔
1794
    elseif f === UnionAll && length(argtypes) == 3 && ⊑(optimizer_lattice(state.interp), argtypes[2], TypeVar)
17,328,134✔
1795
        unionall_call = Expr(:foreigncall, QuoteNode(:jl_type_unionall), Any, svec(Any, Any),
14,662✔
1796
            0, QuoteNode(:ccall), stmt.args[2], stmt.args[3])
1797
        return SomeCase(unionall_call)
14,662✔
1798
    elseif is_return_type(f)
17,296,763✔
1799
        if isconstType(type)
26,368✔
1800
            return SomeCase(quoted(type.parameters[1]))
×
1801
        elseif isa(type, Const)
26,368✔
1802
            return SomeCase(quoted(type.val))
24,257✔
1803
        end
1804
    end
1805
    return nothing
17,272,506✔
1806
end
1807

1808
function ssa_substitute!(insert_node!::Inserter,
511,388✔
1809
                         subst_inst::Instruction, @nospecialize(val), arg_replacements::Vector{Any},
1810
                         @nospecialize(spsig), spvals::SimpleVector,
1811
                         spvals_ssa::Union{Nothing, SSAValue},
1812
                         linetable_offset::Int32, boundscheck::Symbol)
1813
    subst_inst[:flag] &= ~IR_FLAG_INBOUNDS
248,923,158✔
1814
    subst_inst[:line] += linetable_offset
248,923,158✔
1815
    return ssa_substitute_op!(insert_node!, subst_inst,
248,923,158✔
1816
        val, arg_replacements, spsig, spvals, spvals_ssa, boundscheck)
1817
end
1818

1819
function insert_spval!(insert_node!::Inserter, spvals_ssa::SSAValue, spidx::Int, do_isdefined::Bool)
10,425✔
1820
    ret = insert_node!(
10,425✔
1821
        effect_free(NewInstruction(Expr(:call, Core._svec_ref, false, spvals_ssa, spidx), Any)))
1822
    tcheck_not = nothing
×
1823
    if do_isdefined
10,425✔
1824
        tcheck = insert_node!(
7,087✔
1825
            effect_free(NewInstruction(Expr(:call, Core.isa, ret, Core.TypeVar), Bool)))
1826
        tcheck_not = insert_node!(
7,087✔
1827
            effect_free(NewInstruction(Expr(:call, not_int, tcheck), Bool)))
1828
    end
1829
    return (ret, tcheck_not)
10,425✔
1830
end
1831

1832
function ssa_substitute_op!(insert_node!::Inserter, subst_inst::Instruction,
532,886,589✔
1833
                            @nospecialize(val), arg_replacements::Vector{Any},
1834
                            @nospecialize(spsig), spvals::SimpleVector,
1835
                            spvals_ssa::Union{Nothing, SSAValue},
1836
                            boundscheck::Symbol)
1837
    if isa(val, Argument)
532,886,589✔
1838
        return arg_replacements[val.n]
31,911,685✔
1839
    end
1840
    if isa(val, Expr)
500,974,904✔
1841
        e = val::Expr
200,867,384✔
1842
        head = e.head
200,867,384✔
1843
        if head === :static_parameter
200,867,384✔
1844
            spidx = e.args[1]::Int
15,671✔
1845
            val = spvals[spidx]
15,671✔
1846
            if !isa(val, TypeVar) && val !== Vararg
15,671✔
1847
                return quoted(val)
5,293✔
1848
            else
1849
                flag = subst_inst[:flag]
10,378✔
1850
                maybe_undef = (flag & IR_FLAG_NOTHROW) == 0 && isa(val, TypeVar)
10,378✔
1851
                (ret, tcheck_not) = insert_spval!(insert_node!, spvals_ssa::SSAValue, spidx, maybe_undef)
10,378✔
1852
                if maybe_undef
10,378✔
1853
                    insert_node!(
14,080✔
1854
                        non_effect_free(NewInstruction(Expr(:throw_undef_if_not, val.name, tcheck_not), Nothing)))
1855
                end
1856
                return ret
10,378✔
1857
            end
1858
        elseif head === :isdefined && isa(e.args[1], Expr) && e.args[1].head === :static_parameter
200,851,713✔
1859
            spidx = (e.args[1]::Expr).args[1]::Int
47✔
1860
            val = spvals[spidx]
47✔
1861
            if !isa(val, TypeVar)
47✔
1862
                return true
×
1863
            else
1864
                (_, tcheck_not) = insert_spval!(insert_node!, spvals_ssa::SSAValue, spidx, true)
47✔
1865
                return tcheck_not
47✔
1866
            end
1867
        elseif head === :cfunction && spvals_ssa === nothing
200,851,666✔
1868
            @assert !isa(spsig, UnionAll) || !isempty(spvals)
44✔
1869
            e.args[3] = ccall(:jl_instantiate_type_in_env, Any, (Any, Any, Ptr{Any}), e.args[3], spsig, spvals)
42✔
1870
            e.args[4] = svec(Any[
179✔
1871
                ccall(:jl_instantiate_type_in_env, Any, (Any, Any, Ptr{Any}), argt, spsig, spvals)
1872
                for argt in e.args[4]::SimpleVector ]...)
1873
        elseif head === :foreigncall && spvals_ssa === nothing
200,851,624✔
1874
            @assert !isa(spsig, UnionAll) || !isempty(spvals)
1,651,409✔
1875
            for i = 1:length(e.args)
2,523,816✔
1876
                if i == 2
8,987,656✔
1877
                    e.args[2] = ccall(:jl_instantiate_type_in_env, Any, (Any, Any, Ptr{Any}), e.args[2], spsig, spvals)
1,261,908✔
1878
                elseif i == 3
7,725,748✔
1879
                    e.args[3] = svec(Any[
1,261,908✔
1880
                        ccall(:jl_instantiate_type_in_env, Any, (Any, Any, Ptr{Any}), argt, spsig, spvals)
1881
                        for argt in e.args[3]::SimpleVector ]...)
1882
                end
1883
            end
8,987,656✔
1884
        elseif head === :boundscheck
199,589,716✔
1885
            if boundscheck === :off # inbounds == true
1,580,925✔
1886
                return false
10,440✔
1887
            elseif boundscheck === :propagate
1,570,485✔
1888
                return e
4,962✔
1889
            else # on or default
1890
                return true
1,565,523✔
1891
            end
1892
        end
1893
    end
1894
    isa(val, Union{SSAValue, NewSSAValue}) && return val # avoid infinite loop
499,378,261✔
1895
    urs = userefs(val)
719,932,290✔
1896
    for op in urs
506,997,632✔
1897
        op[] = ssa_substitute_op!(insert_node!, subst_inst, op[], arg_replacements, spsig, spvals, spvals_ssa, boundscheck)
283,963,431✔
1898
    end
459,652,873✔
1899
    return urs[]
398,723,643✔
1900
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc