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
@@ -2447,19 +2447,52 @@ function abstract_eval_ssavalue(s::SSAValue, ssavaluetypes::Vector{Any})
2447
2447
return typ
2448
2448
end
2449
2449
2450
- function widenreturn (ipo_lattice:: AbstractLattice , @nospecialize (rt), @nospecialize (bestguess), nargs:: Int , slottypes:: Vector{Any} , changes:: VarTable )
2451
- ⊑ ₚ = ⊑ (ipo_lattice)
2452
- inner_lattice = widenlattice (ipo_lattice)
2453
- ⊑ ᵢ = ⊑ (inner_lattice)
2454
- if ! (bestguess ⊑ ₚ Bool) || bestguess === Bool
2450
+ struct BestguessInfo{Interp<: AbstractInterpreter }
2451
+ interp:: Interp
2452
+ bestguess
2453
+ nargs:: Int
2454
+ slottypes:: Vector{Any}
2455
+ changes:: VarTable
2456
+ function BestguessInfo (interp:: Interp , @nospecialize (bestguess), nargs:: Int ,
2457
+ slottypes:: Vector{Any} , changes:: VarTable ) where Interp<: AbstractInterpreter
2458
+ new {Interp} (interp, bestguess, nargs, slottypes, changes)
2459
+ end
2460
+ end
2461
+
2462
+ """
2463
+ widenreturn(@nospecialize(rt), info::BestguessInfo) -> new_bestguess
2464
+
2465
+ Appropriately converts inferred type of a return value `rt` to such a type
2466
+ that we know we can store in the cache and is valid and good inter-procedurally,
2467
+ E.g. if `rt isa Conditional` then `rt` should be converted to `InterConditional`
2468
+ or the other cachable lattice element.
2469
+
2470
+ External lattice `𝕃ₑ::ExternalLattice` may overload:
2471
+ - `widenreturn(𝕃ₑ::ExternalLattice, @nospecialize(rt), info::BestguessInfo)`
2472
+ - `widenreturn_noslotwrapper(𝕃ₑ::ExternalLattice, @nospecialize(rt), info::BestguessInfo)`
2473
+ """
2474
+ function widenreturn (@nospecialize (rt), info:: BestguessInfo )
2475
+ return widenreturn (typeinf_lattice (info. interp), rt, info)
2476
+ end
2477
+
2478
+ function widenreturn (𝕃ᵢ:: AbstractLattice , @nospecialize (rt), info:: BestguessInfo )
2479
+ return widenreturn (widenlattice (𝕃ᵢ), rt, info)
2480
+ end
2481
+ function widenreturn_noslotwrapper (𝕃ᵢ:: AbstractLattice , @nospecialize (rt), info:: BestguessInfo )
2482
+ return widenreturn_noslotwrapper (widenlattice (𝕃ᵢ), rt, info)
2483
+ end
2484
+
2485
+ function widenreturn (𝕃ᵢ:: ConditionalsLattice , @nospecialize (rt), info:: BestguessInfo )
2486
+ ⊑ ᵢ = ⊑ (𝕃ᵢ)
2487
+ if ! (⊑ (ipo_lattice (info. interp), info. bestguess, Bool)) || info. bestguess === Bool
2455
2488
# give up inter-procedural constraint back-propagation
2456
2489
# when tmerge would widen the result anyways (as an optimization)
2457
2490
rt = widenconditional (rt)
2458
2491
else
2459
2492
if isa (rt, Conditional)
2460
2493
id = rt. slot
2461
- if 1 ≤ id ≤ nargs
2462
- old_id_type = widenconditional (slottypes[id]) # same as `(states[1]::VarTable)[id].typ`
2494
+ if 1 ≤ id ≤ info . nargs
2495
+ old_id_type = widenconditional (info . slottypes[id]) # same as `(states[1]::VarTable)[id].typ`
2463
2496
if (! (rt. thentype ⊑ ᵢ old_id_type) || old_id_type ⊑ ᵢ rt. thentype) &&
2464
2497
(! (rt. elsetype ⊑ ᵢ old_id_type) || old_id_type ⊑ ᵢ rt. elsetype)
2465
2498
# discard this `Conditional` since it imposes
@@ -2476,44 +2509,69 @@ function widenreturn(ipo_lattice::AbstractLattice, @nospecialize(rt), @nospecial
2476
2509
end
2477
2510
if isa (rt, Conditional)
2478
2511
rt = InterConditional (rt. slot, rt. thentype, rt. elsetype)
2479
- elseif is_lattice_bool (ipo_lattice, rt)
2480
- if isa (bestguess, InterConditional)
2481
- # if the bestguess so far is already `Conditional`, try to convert
2482
- # this `rt` into `Conditional` on the slot to avoid overapproximation
2483
- # due to conflict of different slots
2484
- rt = bool_rt_to_conditional (rt, slottypes, changes, bestguess. slot)
2485
- else
2486
- # pick up the first "interesting" slot, convert `rt` to its `Conditional`
2487
- # TODO : ideally we want `Conditional` and `InterConditional` to convey
2488
- # constraints on multiple slots
2489
- for slot_id in 1 : nargs
2490
- rt = bool_rt_to_conditional (rt, slottypes, changes, slot_id)
2491
- rt isa InterConditional && break
2492
- end
2493
- end
2512
+ elseif is_lattice_bool (𝕃ᵢ, rt)
2513
+ rt = bool_rt_to_conditional (rt, info)
2494
2514
end
2495
2515
end
2496
-
2497
- # only propagate information we know we can store
2498
- # and is valid and good inter-procedurally
2499
2516
isa (rt, Conditional) && return InterConditional (rt)
2500
2517
isa (rt, InterConditional) && return rt
2501
- return widenreturn_noconditional (widenlattice (ipo_lattice), rt)
2518
+ return widenreturn (widenlattice (𝕃ᵢ), rt, info)
2519
+ end
2520
+ function bool_rt_to_conditional (@nospecialize (rt), info:: BestguessInfo )
2521
+ bestguess = info. bestguess
2522
+ if isa (bestguess, InterConditional)
2523
+ # if the bestguess so far is already `Conditional`, try to convert
2524
+ # this `rt` into `Conditional` on the slot to avoid overapproximation
2525
+ # due to conflict of different slots
2526
+ rt = bool_rt_to_conditional (rt, bestguess. slot, info)
2527
+ else
2528
+ # pick up the first "interesting" slot, convert `rt` to its `Conditional`
2529
+ # TODO : ideally we want `Conditional` and `InterConditional` to convey
2530
+ # constraints on multiple slots
2531
+ for slot_id = 1 : info. nargs
2532
+ rt = bool_rt_to_conditional (rt, slot_id, info)
2533
+ rt isa InterConditional && break
2534
+ end
2535
+ end
2536
+ return rt
2537
+ end
2538
+ function bool_rt_to_conditional (@nospecialize (rt), slot_id:: Int , info:: BestguessInfo )
2539
+ ⊑ ᵢ = ⊑ (typeinf_lattice (info. interp))
2540
+ old = info. slottypes[slot_id]
2541
+ new = widenconditional (info. changes[slot_id]. typ) # avoid nested conditional
2542
+ if new ⊑ ᵢ old && ! (old ⊑ ᵢ new)
2543
+ if isa (rt, Const)
2544
+ val = rt. val
2545
+ if val === true
2546
+ return InterConditional (slot_id, new, Bottom)
2547
+ elseif val === false
2548
+ return InterConditional (slot_id, Bottom, new)
2549
+ end
2550
+ elseif rt === Bool
2551
+ return InterConditional (slot_id, new, new)
2552
+ end
2553
+ end
2554
+ return rt
2502
2555
end
2503
2556
2504
- function widenreturn_noconditional (inner_lattice:: AbstractLattice , @nospecialize (rt))
2505
- isa (rt, Const) && return rt
2506
- isa (rt, Type) && return rt
2557
+ function widenreturn (𝕃ᵢ:: PartialsLattice , @nospecialize (rt), info:: BestguessInfo )
2558
+ return widenreturn_partials (𝕃ᵢ, rt, info)
2559
+ end
2560
+ function widenreturn_noslotwrapper (𝕃ᵢ:: PartialsLattice , @nospecialize (rt), info:: BestguessInfo )
2561
+ return widenreturn_partials (𝕃ᵢ, rt, info)
2562
+ end
2563
+ function widenreturn_partials (𝕃ᵢ:: PartialsLattice , @nospecialize (rt), info:: BestguessInfo )
2507
2564
if isa (rt, PartialStruct)
2508
2565
fields = copy (rt. fields)
2509
2566
local anyrefine = false
2567
+ 𝕃 = typeinf_lattice (info. interp)
2510
2568
for i in 1 : length (fields)
2511
2569
a = fields[i]
2512
- a = isvarargtype (a) ? a : widenreturn_noconditional (inner_lattice , a)
2570
+ a = isvarargtype (a) ? a : widenreturn_noslotwrapper (𝕃 , a, info )
2513
2571
if ! anyrefine
2514
2572
# TODO : consider adding && const_prop_profitable(a) here?
2515
2573
anyrefine = has_const_info (a) ||
2516
- ⊏ (inner_lattice , a, fieldtype (rt. typ, i))
2574
+ ⊏ (𝕃 , a, fieldtype (rt. typ, i))
2517
2575
end
2518
2576
fields[i] = a
2519
2577
end
@@ -2522,6 +2580,24 @@ function widenreturn_noconditional(inner_lattice::AbstractLattice, @nospecialize
2522
2580
if isa (rt, PartialOpaque)
2523
2581
return rt # XXX : this case was missed in #39512
2524
2582
end
2583
+ return widenreturn (widenlattice (𝕃ᵢ), rt, info)
2584
+ end
2585
+
2586
+ function widenreturn (:: ConstsLattice , @nospecialize (rt), :: BestguessInfo )
2587
+ return widenreturn_consts (rt)
2588
+ end
2589
+ function widenreturn_noslotwrapper (:: ConstsLattice , @nospecialize (rt), :: BestguessInfo )
2590
+ return widenreturn_consts (rt)
2591
+ end
2592
+ function widenreturn_consts (@nospecialize (rt))
2593
+ isa (rt, Const) && return rt
2594
+ return widenconst (rt)
2595
+ end
2596
+
2597
+ function widenreturn (:: JLTypeLattice , @nospecialize (rt), :: BestguessInfo )
2598
+ return widenconst (rt)
2599
+ end
2600
+ function widenreturn_noslotwrapper (:: JLTypeLattice , @nospecialize (rt), :: BestguessInfo )
2525
2601
return widenconst (rt)
2526
2602
end
2527
2603
@@ -2585,15 +2661,15 @@ end
2585
2661
end
2586
2662
end
2587
2663
2588
- function update_bbstate! (lattice :: AbstractLattice , frame:: InferenceState , bb:: Int , vartable:: VarTable )
2664
+ function update_bbstate! (𝕃ᵢ :: AbstractLattice , frame:: InferenceState , bb:: Int , vartable:: VarTable )
2589
2665
bbtable = frame. bb_vartables[bb]
2590
2666
if bbtable === nothing
2591
2667
# if a basic block hasn't been analyzed yet,
2592
2668
# we can update its state a bit more aggressively
2593
2669
frame. bb_vartables[bb] = copy (vartable)
2594
2670
return true
2595
2671
else
2596
- return stupdate! (lattice , bbtable, vartable)
2672
+ return stupdate! (𝕃ᵢ , bbtable, vartable)
2597
2673
end
2598
2674
end
2599
2675
@@ -2615,6 +2691,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
2615
2691
ssavaluetypes = frame. ssavaluetypes
2616
2692
bbs = frame. cfg. blocks
2617
2693
nbbs = length (bbs)
2694
+ 𝕃ₚ, 𝕃ᵢ = ipo_lattice (interp), typeinf_lattice (interp)
2618
2695
2619
2696
currbb = frame. currbb
2620
2697
if currbb != 1
@@ -2693,19 +2770,19 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
2693
2770
# We continue with the true branch, but process the false
2694
2771
# branch here.
2695
2772
if isa (condt, Conditional)
2696
- else_change = conditional_change (currstate, condt. elsetype, condt. slot)
2773
+ else_change = conditional_change (𝕃ᵢ, currstate, condt. elsetype, condt. slot)
2697
2774
if else_change != = nothing
2698
2775
false_vartable = stoverwrite1! (copy (currstate), else_change)
2699
2776
else
2700
2777
false_vartable = currstate
2701
2778
end
2702
- changed = update_bbstate! (typeinf_lattice (interp) , frame, falsebb, false_vartable)
2703
- then_change = conditional_change (currstate, condt. thentype, condt. slot)
2779
+ changed = update_bbstate! (𝕃ᵢ , frame, falsebb, false_vartable)
2780
+ then_change = conditional_change (𝕃ᵢ, currstate, condt. thentype, condt. slot)
2704
2781
if then_change != = nothing
2705
2782
stoverwrite1! (currstate, then_change)
2706
2783
end
2707
2784
else
2708
- changed = update_bbstate! (typeinf_lattice (interp) , frame, falsebb, currstate)
2785
+ changed = update_bbstate! (𝕃ᵢ , frame, falsebb, currstate)
2709
2786
end
2710
2787
if changed
2711
2788
handle_control_backedge! (interp, frame, currpc, stmt. dest)
@@ -2717,7 +2794,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
2717
2794
elseif isa (stmt, ReturnNode)
2718
2795
bestguess = frame. bestguess
2719
2796
rt = abstract_eval_value (interp, stmt. val, currstate, frame)
2720
- rt = widenreturn (ipo_lattice (interp), rt, bestguess, nargs, slottypes, currstate)
2797
+ rt = widenreturn (rt, BestguessInfo (interp, bestguess, nargs, slottypes, currstate) )
2721
2798
# narrow representation of bestguess slightly to prepare for tmerge with rt
2722
2799
if rt isa InterConditional && bestguess isa Const
2723
2800
let slot_id = rt. slot
@@ -2737,9 +2814,9 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
2737
2814
if ! isempty (frame. limitations)
2738
2815
rt = LimitedAccuracy (rt, copy (frame. limitations))
2739
2816
end
2740
- if tchanged (ipo_lattice (interp) , rt, bestguess)
2817
+ if tchanged (𝕃ₚ , rt, bestguess)
2741
2818
# new (wider) return type for frame
2742
- bestguess = tmerge (ipo_lattice (interp) , bestguess, rt)
2819
+ bestguess = tmerge (𝕃ₚ , bestguess, rt)
2743
2820
# TODO : if bestguess isa InterConditional && !interesting(bestguess); bestguess = widenconditional(bestguess); end
2744
2821
frame. bestguess = bestguess
2745
2822
for (caller, caller_pc) in frame. cycle_backedges
@@ -2755,7 +2832,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
2755
2832
# Propagate entry info to exception handler
2756
2833
l = stmt. args[1 ]:: Int
2757
2834
catchbb = block_for_inst (frame. cfg, l)
2758
- if update_bbstate! (typeinf_lattice (interp) , frame, catchbb, currstate)
2835
+ if update_bbstate! (𝕃ᵢ , frame, catchbb, currstate)
2759
2836
push! (W, catchbb)
2760
2837
end
2761
2838
ssavaluetypes[currpc] = Any
@@ -2780,7 +2857,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
2780
2857
# propagate new type info to exception handler
2781
2858
# the handling for Expr(:enter) propagates all changes from before the try/catch
2782
2859
# so this only needs to propagate any changes
2783
- if stupdate1! (typeinf_lattice (interp) , states[exceptbb]:: VarTable , changes)
2860
+ if stupdate1! (𝕃ᵢ , states[exceptbb]:: VarTable , changes)
2784
2861
push! (W, exceptbb)
2785
2862
end
2786
2863
cur_hand = frame. handler_at[cur_hand]
@@ -2792,7 +2869,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
2792
2869
continue
2793
2870
end
2794
2871
if ! isempty (frame. ssavalue_uses[currpc])
2795
- record_ssa_assign! (currpc, type, frame)
2872
+ record_ssa_assign! (𝕃ᵢ, currpc, type, frame)
2796
2873
else
2797
2874
ssavaluetypes[currpc] = type
2798
2875
end
@@ -2805,7 +2882,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
2805
2882
2806
2883
# Case 2: Directly branch to a different BB
2807
2884
begin @label branch
2808
- if update_bbstate! (typeinf_lattice (interp) , frame, nextbb, currstate)
2885
+ if update_bbstate! (𝕃ᵢ , frame, nextbb, currstate)
2809
2886
push! (W, nextbb)
2810
2887
end
2811
2888
end
@@ -2829,13 +2906,13 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
2829
2906
nothing
2830
2907
end
2831
2908
2832
- function conditional_change (state:: VarTable , @nospecialize (typ), slot:: Int )
2909
+ function conditional_change (𝕃ᵢ :: AbstractLattice , state:: VarTable , @nospecialize (typ), slot:: Int )
2833
2910
vtype = state[slot]
2834
2911
oldtyp = vtype. typ
2835
2912
if iskindtype (typ)
2836
2913
# this code path corresponds to the special handling for `isa(x, iskindtype)` check
2837
2914
# implemented within `abstract_call_builtin`
2838
- elseif ignorelimited (typ) ⊑ ignorelimited (oldtyp)
2915
+ elseif ⊑ (𝕃ᵢ, ignorelimited (typ), ignorelimited (oldtyp) )
2839
2916
# approximate test for `typ ∩ oldtyp` being better than `oldtyp`
2840
2917
# since we probably formed these types with `typesubstract`,
2841
2918
# the comparison is likely simple
@@ -2845,29 +2922,11 @@ function conditional_change(state::VarTable, @nospecialize(typ), slot::Int)
2845
2922
if oldtyp isa LimitedAccuracy
2846
2923
# typ is better unlimited, but we may still need to compute the tmeet with the limit
2847
2924
# "causes" since we ignored those in the comparison
2848
- typ = tmerge (typ, LimitedAccuracy (Bottom, oldtyp. causes))
2925
+ typ = tmerge (𝕃ᵢ, typ, LimitedAccuracy (Bottom, oldtyp. causes))
2849
2926
end
2850
2927
return StateUpdate (SlotNumber (slot), VarState (typ, vtype. undef), state, true )
2851
2928
end
2852
2929
2853
- function bool_rt_to_conditional (@nospecialize (rt), slottypes:: Vector{Any} , state:: VarTable , slot_id:: Int )
2854
- old = slottypes[slot_id]
2855
- new = widenconditional (state[slot_id]. typ) # avoid nested conditional
2856
- if new ⊑ old && ! (old ⊑ new)
2857
- if isa (rt, Const)
2858
- val = rt. val
2859
- if val === true
2860
- return InterConditional (slot_id, new, Bottom)
2861
- elseif val === false
2862
- return InterConditional (slot_id, Bottom, new)
2863
- end
2864
- elseif rt === Bool
2865
- return InterConditional (slot_id, new, new)
2866
- end
2867
- end
2868
- return rt
2869
- end
2870
-
2871
2930
# make as much progress on `frame` as possible (by handling cycles)
2872
2931
function typeinf_nocycle (interp:: AbstractInterpreter , frame:: InferenceState )
2873
2932
typeinf_local (interp, frame)
0 commit comments