53
53
function abstract_call_gf_by_type (interp:: AbstractInterpreter , @nospecialize (f),
54
54
arginfo:: ArgInfo , si:: StmtInfo , @nospecialize (atype),
55
55
sv:: InferenceState , max_methods:: Int )
56
- ⊑ ᵢ = ⊑ (typeinf_lattice (interp))
56
+ ⊑ ₚ = ⊑ (ipo_lattice (interp))
57
57
if ! should_infer_this_call (sv)
58
58
add_remark! (interp, sv, " Skipped call in throw block" )
59
59
nonoverlayed = false
@@ -133,7 +133,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
133
133
result, f, this_arginfo, si, match, sv)
134
134
const_result = nothing
135
135
if const_call_result != = nothing
136
- if const_call_result. rt ⊑ ᵢ rt
136
+ if const_call_result. rt ⊑ ₚ rt
137
137
rt = const_call_result. rt
138
138
(; effects, const_result, edge) = const_call_result
139
139
end
@@ -166,7 +166,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
166
166
this_const_rt = widenwrappedconditional (const_call_result. rt)
167
167
# return type of const-prop' inference can be wider than that of non const-prop' inference
168
168
# e.g. in cases when there are cycles but cached result is still accurate
169
- if this_const_rt ⊑ ᵢ this_rt
169
+ if this_const_rt ⊑ ₚ this_rt
170
170
this_conditional = this_const_conditional
171
171
this_rt = this_const_rt
172
172
(; effects, const_result, edge) = const_call_result
@@ -2422,19 +2422,52 @@ function abstract_eval_ssavalue(s::SSAValue, ssavaluetypes::Vector{Any})
2422
2422
return typ
2423
2423
end
2424
2424
2425
- function widenreturn (ipo_lattice:: AbstractLattice , @nospecialize (rt), @nospecialize (bestguess), nargs:: Int , slottypes:: Vector{Any} , changes:: VarTable )
2426
- ⊑ ₚ = ⊑ (ipo_lattice)
2427
- inner_lattice = widenlattice (ipo_lattice)
2428
- ⊑ ᵢ = ⊑ (inner_lattice)
2429
- if ! (bestguess ⊑ ₚ Bool) || bestguess === Bool
2425
+ struct BestguessInfo{Interp<: AbstractInterpreter }
2426
+ interp:: Interp
2427
+ bestguess
2428
+ nargs:: Int
2429
+ slottypes:: Vector{Any}
2430
+ changes:: VarTable
2431
+ function BestguessInfo (interp:: Interp , @nospecialize (bestguess), nargs:: Int ,
2432
+ slottypes:: Vector{Any} , changes:: VarTable ) where Interp<: AbstractInterpreter
2433
+ new {Interp} (interp, bestguess, nargs, slottypes, changes)
2434
+ end
2435
+ end
2436
+
2437
+ """
2438
+ widenreturn(@nospecialize(rt), info::BestguessInfo) -> new_bestguess
2439
+
2440
+ Appropriately converts inferred type of a return value `rt` to such a type
2441
+ that we know we can store in the cache and is valid and good inter-procedurally,
2442
+ E.g. if `rt isa Conditional` then `rt` should be converted to `InterConditional`
2443
+ or the other cachable lattice element.
2444
+
2445
+ External lattice `𝕃ₑ::ExternalLattice` may overload:
2446
+ - `widenreturn(𝕃ₑ::ExternalLattice, @nospecialize(rt), info::BestguessInfo)`
2447
+ - `widenreturn_noslotwrapper(𝕃ₑ::ExternalLattice, @nospecialize(rt), info::BestguessInfo)`
2448
+ """
2449
+ function widenreturn (@nospecialize (rt), info:: BestguessInfo )
2450
+ return widenreturn (typeinf_lattice (info. interp), rt, info)
2451
+ end
2452
+
2453
+ function widenreturn (𝕃ᵢ:: AbstractLattice , @nospecialize (rt), info:: BestguessInfo )
2454
+ return widenreturn (widenlattice (𝕃ᵢ), rt, info)
2455
+ end
2456
+ function widenreturn_noslotwrapper (𝕃ᵢ:: AbstractLattice , @nospecialize (rt), info:: BestguessInfo )
2457
+ return widenreturn_noslotwrapper (widenlattice (𝕃ᵢ), rt, info)
2458
+ end
2459
+
2460
+ function widenreturn (𝕃ᵢ:: ConditionalsLattice , @nospecialize (rt), info:: BestguessInfo )
2461
+ ⊑ ᵢ = ⊑ (𝕃ᵢ)
2462
+ if ! (⊑ (ipo_lattice (info. interp), info. bestguess, Bool)) || info. bestguess === Bool
2430
2463
# give up inter-procedural constraint back-propagation
2431
2464
# when tmerge would widen the result anyways (as an optimization)
2432
2465
rt = widenconditional (rt)
2433
2466
else
2434
2467
if isa (rt, Conditional)
2435
2468
id = rt. slot
2436
- if 1 ≤ id ≤ nargs
2437
- old_id_type = widenconditional (slottypes[id]) # same as `(states[1]::VarTable)[id].typ`
2469
+ if 1 ≤ id ≤ info . nargs
2470
+ old_id_type = widenconditional (info . slottypes[id]) # same as `(states[1]::VarTable)[id].typ`
2438
2471
if (! (rt. thentype ⊑ ᵢ old_id_type) || old_id_type ⊑ ᵢ rt. thentype) &&
2439
2472
(! (rt. elsetype ⊑ ᵢ old_id_type) || old_id_type ⊑ ᵢ rt. elsetype)
2440
2473
# discard this `Conditional` since it imposes
@@ -2451,44 +2484,69 @@ function widenreturn(ipo_lattice::AbstractLattice, @nospecialize(rt), @nospecial
2451
2484
end
2452
2485
if isa (rt, Conditional)
2453
2486
rt = InterConditional (rt. slot, rt. thentype, rt. elsetype)
2454
- elseif is_lattice_bool (ipo_lattice, rt)
2455
- if isa (bestguess, InterConditional)
2456
- # if the bestguess so far is already `Conditional`, try to convert
2457
- # this `rt` into `Conditional` on the slot to avoid overapproximation
2458
- # due to conflict of different slots
2459
- rt = bool_rt_to_conditional (rt, slottypes, changes, bestguess. slot)
2460
- else
2461
- # pick up the first "interesting" slot, convert `rt` to its `Conditional`
2462
- # TODO : ideally we want `Conditional` and `InterConditional` to convey
2463
- # constraints on multiple slots
2464
- for slot_id in 1 : nargs
2465
- rt = bool_rt_to_conditional (rt, slottypes, changes, slot_id)
2466
- rt isa InterConditional && break
2467
- end
2468
- end
2487
+ elseif is_lattice_bool (𝕃ᵢ, rt)
2488
+ rt = bool_rt_to_conditional (rt, info)
2469
2489
end
2470
2490
end
2471
-
2472
- # only propagate information we know we can store
2473
- # and is valid and good inter-procedurally
2474
2491
isa (rt, Conditional) && return InterConditional (rt)
2475
2492
isa (rt, InterConditional) && return rt
2476
- return widenreturn_noconditional (widenlattice (ipo_lattice), rt)
2493
+ return widenreturn (widenlattice (𝕃ᵢ), rt, info)
2494
+ end
2495
+ function bool_rt_to_conditional (@nospecialize (rt), info:: BestguessInfo )
2496
+ bestguess = info. bestguess
2497
+ if isa (bestguess, InterConditional)
2498
+ # if the bestguess so far is already `Conditional`, try to convert
2499
+ # this `rt` into `Conditional` on the slot to avoid overapproximation
2500
+ # due to conflict of different slots
2501
+ rt = bool_rt_to_conditional (rt, bestguess. slot, info)
2502
+ else
2503
+ # pick up the first "interesting" slot, convert `rt` to its `Conditional`
2504
+ # TODO : ideally we want `Conditional` and `InterConditional` to convey
2505
+ # constraints on multiple slots
2506
+ for slot_id = 1 : info. nargs
2507
+ rt = bool_rt_to_conditional (rt, slot_id, info)
2508
+ rt isa InterConditional && break
2509
+ end
2510
+ end
2511
+ return rt
2512
+ end
2513
+ function bool_rt_to_conditional (@nospecialize (rt), slot_id:: Int , info:: BestguessInfo )
2514
+ ⊑ ᵢ = ⊑ (typeinf_lattice (info. interp))
2515
+ old = info. slottypes[slot_id]
2516
+ new = widenconditional (info. changes[slot_id]. typ) # avoid nested conditional
2517
+ if new ⊑ ᵢ old && ! (old ⊑ ᵢ new)
2518
+ if isa (rt, Const)
2519
+ val = rt. val
2520
+ if val === true
2521
+ return InterConditional (slot_id, new, Bottom)
2522
+ elseif val === false
2523
+ return InterConditional (slot_id, Bottom, new)
2524
+ end
2525
+ elseif rt === Bool
2526
+ return InterConditional (slot_id, new, new)
2527
+ end
2528
+ end
2529
+ return rt
2477
2530
end
2478
2531
2479
- function widenreturn_noconditional (inner_lattice:: AbstractLattice , @nospecialize (rt))
2480
- isa (rt, Const) && return rt
2481
- isa (rt, Type) && return rt
2532
+ function widenreturn (𝕃ᵢ:: PartialsLattice , @nospecialize (rt), info:: BestguessInfo )
2533
+ return widenreturn_partials (𝕃ᵢ, rt, info)
2534
+ end
2535
+ function widenreturn_noslotwrapper (𝕃ᵢ:: PartialsLattice , @nospecialize (rt), info:: BestguessInfo )
2536
+ return widenreturn_partials (𝕃ᵢ, rt, info)
2537
+ end
2538
+ function widenreturn_partials (𝕃ᵢ:: PartialsLattice , @nospecialize (rt), info:: BestguessInfo )
2482
2539
if isa (rt, PartialStruct)
2483
2540
fields = copy (rt. fields)
2484
2541
local anyrefine = false
2542
+ 𝕃 = typeinf_lattice (info. interp)
2485
2543
for i in 1 : length (fields)
2486
2544
a = fields[i]
2487
- a = isvarargtype (a) ? a : widenreturn_noconditional (inner_lattice , a)
2545
+ a = isvarargtype (a) ? a : widenreturn_noslotwrapper (𝕃 , a, info )
2488
2546
if ! anyrefine
2489
2547
# TODO : consider adding && const_prop_profitable(a) here?
2490
2548
anyrefine = has_const_info (a) ||
2491
- ⊏ (inner_lattice , a, fieldtype (rt. typ, i))
2549
+ ⊏ (𝕃 , a, fieldtype (rt. typ, i))
2492
2550
end
2493
2551
fields[i] = a
2494
2552
end
@@ -2497,6 +2555,24 @@ function widenreturn_noconditional(inner_lattice::AbstractLattice, @nospecialize
2497
2555
if isa (rt, PartialOpaque)
2498
2556
return rt # XXX : this case was missed in #39512
2499
2557
end
2558
+ return widenreturn (widenlattice (𝕃ᵢ), rt, info)
2559
+ end
2560
+
2561
+ function widenreturn (:: ConstsLattice , @nospecialize (rt), :: BestguessInfo )
2562
+ return widenreturn_consts (rt)
2563
+ end
2564
+ function widenreturn_noslotwrapper (:: ConstsLattice , @nospecialize (rt), :: BestguessInfo )
2565
+ return widenreturn_consts (rt)
2566
+ end
2567
+ function widenreturn_consts (@nospecialize (rt))
2568
+ isa (rt, Const) && return rt
2569
+ return widenconst (rt)
2570
+ end
2571
+
2572
+ function widenreturn (:: JLTypeLattice , @nospecialize (rt), :: BestguessInfo )
2573
+ return widenconst (rt)
2574
+ end
2575
+ function widenreturn_noslotwrapper (:: JLTypeLattice , @nospecialize (rt), :: BestguessInfo )
2500
2576
return widenconst (rt)
2501
2577
end
2502
2578
@@ -2560,15 +2636,15 @@ end
2560
2636
end
2561
2637
end
2562
2638
2563
- function update_bbstate! (lattice :: AbstractLattice , frame:: InferenceState , bb:: Int , vartable:: VarTable )
2639
+ function update_bbstate! (𝕃ᵢ :: AbstractLattice , frame:: InferenceState , bb:: Int , vartable:: VarTable )
2564
2640
bbtable = frame. bb_vartables[bb]
2565
2641
if bbtable === nothing
2566
2642
# if a basic block hasn't been analyzed yet,
2567
2643
# we can update its state a bit more aggressively
2568
2644
frame. bb_vartables[bb] = copy (vartable)
2569
2645
return true
2570
2646
else
2571
- return stupdate! (lattice , bbtable, vartable)
2647
+ return stupdate! (𝕃ᵢ , bbtable, vartable)
2572
2648
end
2573
2649
end
2574
2650
@@ -2590,6 +2666,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
2590
2666
ssavaluetypes = frame. ssavaluetypes
2591
2667
bbs = frame. cfg. blocks
2592
2668
nbbs = length (bbs)
2669
+ 𝕃ₚ, 𝕃ᵢ = ipo_lattice (interp), typeinf_lattice (interp)
2593
2670
2594
2671
currbb = frame. currbb
2595
2672
if currbb != 1
@@ -2659,19 +2736,19 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
2659
2736
# We continue with the true branch, but process the false
2660
2737
# branch here.
2661
2738
if isa (condt, Conditional)
2662
- else_change = conditional_change (currstate, condt. elsetype, condt. slot)
2739
+ else_change = conditional_change (𝕃ᵢ, currstate, condt. elsetype, condt. slot)
2663
2740
if else_change != = nothing
2664
2741
false_vartable = stoverwrite1! (copy (currstate), else_change)
2665
2742
else
2666
2743
false_vartable = currstate
2667
2744
end
2668
- changed = update_bbstate! (typeinf_lattice (interp) , frame, falsebb, false_vartable)
2669
- then_change = conditional_change (currstate, condt. thentype, condt. slot)
2745
+ changed = update_bbstate! (𝕃ᵢ , frame, falsebb, false_vartable)
2746
+ then_change = conditional_change (𝕃ᵢ, currstate, condt. thentype, condt. slot)
2670
2747
if then_change != = nothing
2671
2748
stoverwrite1! (currstate, then_change)
2672
2749
end
2673
2750
else
2674
- changed = update_bbstate! (typeinf_lattice (interp) , frame, falsebb, currstate)
2751
+ changed = update_bbstate! (𝕃ᵢ , frame, falsebb, currstate)
2675
2752
end
2676
2753
if changed
2677
2754
handle_control_backedge! (interp, frame, currpc, stmt. dest)
@@ -2683,7 +2760,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
2683
2760
elseif isa (stmt, ReturnNode)
2684
2761
bestguess = frame. bestguess
2685
2762
rt = abstract_eval_value (interp, stmt. val, currstate, frame)
2686
- rt = widenreturn (ipo_lattice (interp), rt, bestguess, nargs, slottypes, currstate)
2763
+ rt = widenreturn (rt, BestguessInfo (interp, bestguess, nargs, slottypes, currstate) )
2687
2764
# narrow representation of bestguess slightly to prepare for tmerge with rt
2688
2765
if rt isa InterConditional && bestguess isa Const
2689
2766
let slot_id = rt. slot
@@ -2703,9 +2780,9 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
2703
2780
if ! isempty (frame. limitations)
2704
2781
rt = LimitedAccuracy (rt, copy (frame. limitations))
2705
2782
end
2706
- if tchanged (ipo_lattice (interp) , rt, bestguess)
2783
+ if tchanged (𝕃ₚ , rt, bestguess)
2707
2784
# new (wider) return type for frame
2708
- bestguess = tmerge (ipo_lattice (interp) , bestguess, rt)
2785
+ bestguess = tmerge (𝕃ₚ , bestguess, rt)
2709
2786
# TODO : if bestguess isa InterConditional && !interesting(bestguess); bestguess = widenconditional(bestguess); end
2710
2787
frame. bestguess = bestguess
2711
2788
for (caller, caller_pc) in frame. cycle_backedges
@@ -2721,7 +2798,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
2721
2798
# Propagate entry info to exception handler
2722
2799
l = stmt. args[1 ]:: Int
2723
2800
catchbb = block_for_inst (frame. cfg, l)
2724
- if update_bbstate! (typeinf_lattice (interp) , frame, catchbb, currstate)
2801
+ if update_bbstate! (𝕃ᵢ , frame, catchbb, currstate)
2725
2802
push! (W, catchbb)
2726
2803
end
2727
2804
ssavaluetypes[currpc] = Any
@@ -2746,7 +2823,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
2746
2823
# propagate new type info to exception handler
2747
2824
# the handling for Expr(:enter) propagates all changes from before the try/catch
2748
2825
# so this only needs to propagate any changes
2749
- if stupdate1! (typeinf_lattice (interp) , states[exceptbb]:: VarTable , changes)
2826
+ if stupdate1! (𝕃ᵢ , states[exceptbb]:: VarTable , changes)
2750
2827
push! (W, exceptbb)
2751
2828
end
2752
2829
cur_hand = frame. handler_at[cur_hand]
@@ -2758,7 +2835,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
2758
2835
continue
2759
2836
end
2760
2837
if ! isempty (frame. ssavalue_uses[currpc])
2761
- record_ssa_assign! (currpc, type, frame)
2838
+ record_ssa_assign! (𝕃ᵢ, currpc, type, frame)
2762
2839
else
2763
2840
ssavaluetypes[currpc] = type
2764
2841
end
@@ -2771,7 +2848,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
2771
2848
2772
2849
# Case 2: Directly branch to a different BB
2773
2850
begin @label branch
2774
- if update_bbstate! (typeinf_lattice (interp) , frame, nextbb, currstate)
2851
+ if update_bbstate! (𝕃ᵢ , frame, nextbb, currstate)
2775
2852
push! (W, nextbb)
2776
2853
end
2777
2854
end
@@ -2795,13 +2872,13 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
2795
2872
nothing
2796
2873
end
2797
2874
2798
- function conditional_change (state:: VarTable , @nospecialize (typ), slot:: Int )
2875
+ function conditional_change (𝕃ᵢ :: AbstractLattice , state:: VarTable , @nospecialize (typ), slot:: Int )
2799
2876
vtype = state[slot]
2800
2877
oldtyp = vtype. typ
2801
2878
if iskindtype (typ)
2802
2879
# this code path corresponds to the special handling for `isa(x, iskindtype)` check
2803
2880
# implemented within `abstract_call_builtin`
2804
- elseif ignorelimited (typ) ⊑ ignorelimited (oldtyp)
2881
+ elseif ⊑ (𝕃ᵢ, ignorelimited (typ), ignorelimited (oldtyp) )
2805
2882
# approximate test for `typ ∩ oldtyp` being better than `oldtyp`
2806
2883
# since we probably formed these types with `typesubstract`,
2807
2884
# the comparison is likely simple
@@ -2811,29 +2888,11 @@ function conditional_change(state::VarTable, @nospecialize(typ), slot::Int)
2811
2888
if oldtyp isa LimitedAccuracy
2812
2889
# typ is better unlimited, but we may still need to compute the tmeet with the limit
2813
2890
# "causes" since we ignored those in the comparison
2814
- typ = tmerge (typ, LimitedAccuracy (Bottom, oldtyp. causes))
2891
+ typ = tmerge (𝕃ᵢ, typ, LimitedAccuracy (Bottom, oldtyp. causes))
2815
2892
end
2816
2893
return StateUpdate (SlotNumber (slot), VarState (typ, vtype. undef), state, true )
2817
2894
end
2818
2895
2819
- function bool_rt_to_conditional (@nospecialize (rt), slottypes:: Vector{Any} , state:: VarTable , slot_id:: Int )
2820
- old = slottypes[slot_id]
2821
- new = widenconditional (state[slot_id]. typ) # avoid nested conditional
2822
- if new ⊑ old && ! (old ⊑ new)
2823
- if isa (rt, Const)
2824
- val = rt. val
2825
- if val === true
2826
- return InterConditional (slot_id, new, Bottom)
2827
- elseif val === false
2828
- return InterConditional (slot_id, Bottom, new)
2829
- end
2830
- elseif rt === Bool
2831
- return InterConditional (slot_id, new, new)
2832
- end
2833
- end
2834
- return rt
2835
- end
2836
-
2837
2896
# make as much progress on `frame` as possible (by handling cycles)
2838
2897
function typeinf_nocycle (interp:: AbstractInterpreter , frame:: InferenceState )
2839
2898
typeinf_local (interp, frame)
0 commit comments