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
@@ -134,7 +134,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
134
134
result, f, this_arginfo, si, match, sv)
135
135
const_result = nothing
136
136
if const_call_result != = nothing
137
- if const_call_result. rt ⊑ ᵢ rt
137
+ if const_call_result. rt ⊑ ₚ rt
138
138
rt = const_call_result. rt
139
139
(; effects, const_result, edge) = const_call_result
140
140
end
@@ -167,7 +167,7 @@ function abstract_call_gf_by_type(interp::AbstractInterpreter, @nospecialize(f),
167
167
this_const_rt = widenwrappedconditional (const_call_result. rt)
168
168
# return type of const-prop' inference can be wider than that of non const-prop' inference
169
169
# e.g. in cases when there are cycles but cached result is still accurate
170
- if this_const_rt ⊑ ᵢ this_rt
170
+ if this_const_rt ⊑ ₚ this_rt
171
171
this_conditional = this_const_conditional
172
172
this_rt = this_const_rt
173
173
(; effects, const_result, edge) = const_call_result
@@ -2399,19 +2399,52 @@ function abstract_eval_ssavalue(s::SSAValue, ssavaluetypes::Vector{Any})
2399
2399
return typ
2400
2400
end
2401
2401
2402
- function widenreturn (ipo_lattice:: AbstractLattice , @nospecialize (rt), @nospecialize (bestguess), nargs:: Int , slottypes:: Vector{Any} , changes:: VarTable )
2403
- ⊑ ₚ = ⊑ (ipo_lattice)
2404
- inner_lattice = widenlattice (ipo_lattice)
2405
- ⊑ ᵢ = ⊑ (inner_lattice)
2406
- if ! (bestguess ⊑ ₚ Bool) || bestguess === Bool
2402
+ struct BestguessInfo{Interp<: AbstractInterpreter }
2403
+ interp:: Interp
2404
+ bestguess
2405
+ nargs:: Int
2406
+ slottypes:: Vector{Any}
2407
+ changes:: VarTable
2408
+ function BestguessInfo (interp:: Interp , @nospecialize (bestguess), nargs:: Int ,
2409
+ slottypes:: Vector{Any} , changes:: VarTable ) where Interp<: AbstractInterpreter
2410
+ new {Interp} (interp, bestguess, nargs, slottypes, changes)
2411
+ end
2412
+ end
2413
+
2414
+ """
2415
+ widenreturn(@nospecialize(rt), info::BestguessInfo) -> new_bestguess
2416
+
2417
+ Appropriately converts inferred type of a return value `rt` to such a type
2418
+ that we know we can store in the cache and is valid and good inter-procedurally,
2419
+ E.g. if `rt isa Conditional` then `rt` should be converted to `InterConditional`
2420
+ or the other cachable lattice element.
2421
+
2422
+ External lattice `𝕃ₑ::ExternalLattice` may overload:
2423
+ - `widenreturn(𝕃ₑ::ExternalLattice, @nospecialize(rt), info::BestguessInfo)`
2424
+ - `widenreturn_noslotwrapper(𝕃ₑ::ExternalLattice, @nospecialize(rt), info::BestguessInfo)`
2425
+ """
2426
+ function widenreturn (@nospecialize (rt), info:: BestguessInfo )
2427
+ return widenreturn (typeinf_lattice (info. interp), rt, info)
2428
+ end
2429
+
2430
+ function widenreturn (𝕃ᵢ:: AbstractLattice , @nospecialize (rt), info:: BestguessInfo )
2431
+ return widenreturn (widenlattice (𝕃ᵢ), rt, info)
2432
+ end
2433
+ function widenreturn_noslotwrapper (𝕃ᵢ:: AbstractLattice , @nospecialize (rt), info:: BestguessInfo )
2434
+ return widenreturn_noslotwrapper (widenlattice (𝕃ᵢ), rt, info)
2435
+ end
2436
+
2437
+ function widenreturn (𝕃ᵢ:: ConditionalsLattice , @nospecialize (rt), info:: BestguessInfo )
2438
+ ⊑ ᵢ = ⊑ (𝕃ᵢ)
2439
+ if ! (⊑ (ipo_lattice (info. interp), info. bestguess, Bool)) || info. bestguess === Bool
2407
2440
# give up inter-procedural constraint back-propagation
2408
2441
# when tmerge would widen the result anyways (as an optimization)
2409
2442
rt = widenconditional (rt)
2410
2443
else
2411
2444
if isa (rt, Conditional)
2412
2445
id = rt. slot
2413
- if 1 ≤ id ≤ nargs
2414
- old_id_type = widenconditional (slottypes[id]) # same as `(states[1]::VarTable)[id].typ`
2446
+ if 1 ≤ id ≤ info . nargs
2447
+ old_id_type = widenconditional (info . slottypes[id]) # same as `(states[1]::VarTable)[id].typ`
2415
2448
if (! (rt. thentype ⊑ ᵢ old_id_type) || old_id_type ⊑ ᵢ rt. thentype) &&
2416
2449
(! (rt. elsetype ⊑ ᵢ old_id_type) || old_id_type ⊑ ᵢ rt. elsetype)
2417
2450
# discard this `Conditional` since it imposes
@@ -2428,44 +2461,69 @@ function widenreturn(ipo_lattice::AbstractLattice, @nospecialize(rt), @nospecial
2428
2461
end
2429
2462
if isa (rt, Conditional)
2430
2463
rt = InterConditional (rt. slot, rt. thentype, rt. elsetype)
2431
- elseif is_lattice_bool (ipo_lattice, rt)
2432
- if isa (bestguess, InterConditional)
2433
- # if the bestguess so far is already `Conditional`, try to convert
2434
- # this `rt` into `Conditional` on the slot to avoid overapproximation
2435
- # due to conflict of different slots
2436
- rt = bool_rt_to_conditional (rt, slottypes, changes, bestguess. slot)
2437
- else
2438
- # pick up the first "interesting" slot, convert `rt` to its `Conditional`
2439
- # TODO : ideally we want `Conditional` and `InterConditional` to convey
2440
- # constraints on multiple slots
2441
- for slot_id in 1 : nargs
2442
- rt = bool_rt_to_conditional (rt, slottypes, changes, slot_id)
2443
- rt isa InterConditional && break
2444
- end
2445
- end
2464
+ elseif is_lattice_bool (𝕃ᵢ, rt)
2465
+ rt = bool_rt_to_conditional (rt, info)
2446
2466
end
2447
2467
end
2448
-
2449
- # only propagate information we know we can store
2450
- # and is valid and good inter-procedurally
2451
2468
isa (rt, Conditional) && return InterConditional (rt)
2452
2469
isa (rt, InterConditional) && return rt
2453
- return widenreturn_noconditional (widenlattice (ipo_lattice), rt)
2470
+ return widenreturn (widenlattice (𝕃ᵢ), rt, info)
2471
+ end
2472
+ function bool_rt_to_conditional (@nospecialize (rt), info:: BestguessInfo )
2473
+ bestguess = info. bestguess
2474
+ if isa (bestguess, InterConditional)
2475
+ # if the bestguess so far is already `Conditional`, try to convert
2476
+ # this `rt` into `Conditional` on the slot to avoid overapproximation
2477
+ # due to conflict of different slots
2478
+ rt = bool_rt_to_conditional (rt, bestguess. slot, info)
2479
+ else
2480
+ # pick up the first "interesting" slot, convert `rt` to its `Conditional`
2481
+ # TODO : ideally we want `Conditional` and `InterConditional` to convey
2482
+ # constraints on multiple slots
2483
+ for slot_id = 1 : info. nargs
2484
+ rt = bool_rt_to_conditional (rt, slot_id, info)
2485
+ rt isa InterConditional && break
2486
+ end
2487
+ end
2488
+ return rt
2489
+ end
2490
+ function bool_rt_to_conditional (@nospecialize (rt), slot_id:: Int , info:: BestguessInfo )
2491
+ ⊑ ᵢ = ⊑ (typeinf_lattice (info. interp))
2492
+ old = info. slottypes[slot_id]
2493
+ new = widenconditional (info. changes[slot_id]. typ) # avoid nested conditional
2494
+ if new ⊑ ᵢ old && ! (old ⊑ ᵢ new)
2495
+ if isa (rt, Const)
2496
+ val = rt. val
2497
+ if val === true
2498
+ return InterConditional (slot_id, new, Bottom)
2499
+ elseif val === false
2500
+ return InterConditional (slot_id, Bottom, new)
2501
+ end
2502
+ elseif rt === Bool
2503
+ return InterConditional (slot_id, new, new)
2504
+ end
2505
+ end
2506
+ return rt
2454
2507
end
2455
2508
2456
- function widenreturn_noconditional (inner_lattice:: AbstractLattice , @nospecialize (rt))
2457
- isa (rt, Const) && return rt
2458
- isa (rt, Type) && return rt
2509
+ function widenreturn (𝕃ᵢ:: PartialsLattice , @nospecialize (rt), info:: BestguessInfo )
2510
+ return widenreturn_partials (𝕃ᵢ, rt, info)
2511
+ end
2512
+ function widenreturn_noslotwrapper (𝕃ᵢ:: PartialsLattice , @nospecialize (rt), info:: BestguessInfo )
2513
+ return widenreturn_partials (𝕃ᵢ, rt, info)
2514
+ end
2515
+ function widenreturn_partials (𝕃ᵢ:: PartialsLattice , @nospecialize (rt), info:: BestguessInfo )
2459
2516
if isa (rt, PartialStruct)
2460
2517
fields = copy (rt. fields)
2461
2518
local anyrefine = false
2519
+ 𝕃 = typeinf_lattice (info. interp)
2462
2520
for i in 1 : length (fields)
2463
2521
a = fields[i]
2464
- a = isvarargtype (a) ? a : widenreturn_noconditional (inner_lattice , a)
2522
+ a = isvarargtype (a) ? a : widenreturn_noslotwrapper (𝕃 , a, info )
2465
2523
if ! anyrefine
2466
2524
# TODO : consider adding && const_prop_profitable(a) here?
2467
2525
anyrefine = has_const_info (a) ||
2468
- ⊏ (inner_lattice , a, fieldtype (rt. typ, i))
2526
+ ⊏ (𝕃 , a, fieldtype (rt. typ, i))
2469
2527
end
2470
2528
fields[i] = a
2471
2529
end
@@ -2474,6 +2532,24 @@ function widenreturn_noconditional(inner_lattice::AbstractLattice, @nospecialize
2474
2532
if isa (rt, PartialOpaque)
2475
2533
return rt # XXX : this case was missed in #39512
2476
2534
end
2535
+ return widenreturn (widenlattice (𝕃ᵢ), rt, info)
2536
+ end
2537
+
2538
+ function widenreturn (:: ConstsLattice , @nospecialize (rt), :: BestguessInfo )
2539
+ return widenreturn_consts (rt)
2540
+ end
2541
+ function widenreturn_noslotwrapper (:: ConstsLattice , @nospecialize (rt), :: BestguessInfo )
2542
+ return widenreturn_consts (rt)
2543
+ end
2544
+ function widenreturn_consts (@nospecialize (rt))
2545
+ isa (rt, Const) && return rt
2546
+ return widenconst (rt)
2547
+ end
2548
+
2549
+ function widenreturn (:: JLTypeLattice , @nospecialize (rt), :: BestguessInfo )
2550
+ return widenconst (rt)
2551
+ end
2552
+ function widenreturn_noslotwrapper (:: JLTypeLattice , @nospecialize (rt), :: BestguessInfo )
2477
2553
return widenconst (rt)
2478
2554
end
2479
2555
@@ -2537,15 +2613,15 @@ end
2537
2613
end
2538
2614
end
2539
2615
2540
- function update_bbstate! (lattice :: AbstractLattice , frame:: InferenceState , bb:: Int , vartable:: VarTable )
2616
+ function update_bbstate! (𝕃ᵢ :: AbstractLattice , frame:: InferenceState , bb:: Int , vartable:: VarTable )
2541
2617
bbtable = frame. bb_vartables[bb]
2542
2618
if bbtable === nothing
2543
2619
# if a basic block hasn't been analyzed yet,
2544
2620
# we can update its state a bit more aggressively
2545
2621
frame. bb_vartables[bb] = copy (vartable)
2546
2622
return true
2547
2623
else
2548
- return stupdate! (lattice , bbtable, vartable)
2624
+ return stupdate! (𝕃ᵢ , bbtable, vartable)
2549
2625
end
2550
2626
end
2551
2627
@@ -2567,6 +2643,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
2567
2643
ssavaluetypes = frame. ssavaluetypes
2568
2644
bbs = frame. cfg. blocks
2569
2645
nbbs = length (bbs)
2646
+ 𝕃ₚ, 𝕃ᵢ = ipo_lattice (interp), typeinf_lattice (interp)
2570
2647
2571
2648
currbb = frame. currbb
2572
2649
if currbb != 1
@@ -2636,19 +2713,19 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
2636
2713
# We continue with the true branch, but process the false
2637
2714
# branch here.
2638
2715
if isa (condt, Conditional)
2639
- else_change = conditional_change (currstate, condt. elsetype, condt. slot)
2716
+ else_change = conditional_change (𝕃ᵢ, currstate, condt. elsetype, condt. slot)
2640
2717
if else_change != = nothing
2641
2718
false_vartable = stoverwrite1! (copy (currstate), else_change)
2642
2719
else
2643
2720
false_vartable = currstate
2644
2721
end
2645
- changed = update_bbstate! (typeinf_lattice (interp) , frame, falsebb, false_vartable)
2646
- then_change = conditional_change (currstate, condt. thentype, condt. slot)
2722
+ changed = update_bbstate! (𝕃ᵢ , frame, falsebb, false_vartable)
2723
+ then_change = conditional_change (𝕃ᵢ, currstate, condt. thentype, condt. slot)
2647
2724
if then_change != = nothing
2648
2725
stoverwrite1! (currstate, then_change)
2649
2726
end
2650
2727
else
2651
- changed = update_bbstate! (typeinf_lattice (interp) , frame, falsebb, currstate)
2728
+ changed = update_bbstate! (𝕃ᵢ , frame, falsebb, currstate)
2652
2729
end
2653
2730
if changed
2654
2731
handle_control_backedge! (interp, frame, currpc, stmt. dest)
@@ -2660,7 +2737,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
2660
2737
elseif isa (stmt, ReturnNode)
2661
2738
bestguess = frame. bestguess
2662
2739
rt = abstract_eval_value (interp, stmt. val, currstate, frame)
2663
- rt = widenreturn (ipo_lattice (interp), rt, bestguess, nargs, slottypes, currstate)
2740
+ rt = widenreturn (rt, BestguessInfo (interp, bestguess, nargs, slottypes, currstate) )
2664
2741
# narrow representation of bestguess slightly to prepare for tmerge with rt
2665
2742
if rt isa InterConditional && bestguess isa Const
2666
2743
let slot_id = rt. slot
@@ -2680,9 +2757,9 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
2680
2757
if ! isempty (frame. limitations)
2681
2758
rt = LimitedAccuracy (rt, copy (frame. limitations))
2682
2759
end
2683
- if tchanged (ipo_lattice (interp) , rt, bestguess)
2760
+ if tchanged (𝕃ₚ , rt, bestguess)
2684
2761
# new (wider) return type for frame
2685
- bestguess = tmerge (ipo_lattice (interp) , bestguess, rt)
2762
+ bestguess = tmerge (𝕃ₚ , bestguess, rt)
2686
2763
# TODO : if bestguess isa InterConditional && !interesting(bestguess); bestguess = widenconditional(bestguess); end
2687
2764
frame. bestguess = bestguess
2688
2765
for (caller, caller_pc) in frame. cycle_backedges
@@ -2698,7 +2775,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
2698
2775
# Propagate entry info to exception handler
2699
2776
l = stmt. args[1 ]:: Int
2700
2777
catchbb = block_for_inst (frame. cfg, l)
2701
- if update_bbstate! (typeinf_lattice (interp) , frame, catchbb, currstate)
2778
+ if update_bbstate! (𝕃ᵢ , frame, catchbb, currstate)
2702
2779
push! (W, catchbb)
2703
2780
end
2704
2781
ssavaluetypes[currpc] = Any
@@ -2723,7 +2800,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
2723
2800
# propagate new type info to exception handler
2724
2801
# the handling for Expr(:enter) propagates all changes from before the try/catch
2725
2802
# so this only needs to propagate any changes
2726
- if stupdate1! (typeinf_lattice (interp) , states[exceptbb]:: VarTable , changes)
2803
+ if stupdate1! (𝕃ᵢ , states[exceptbb]:: VarTable , changes)
2727
2804
push! (W, exceptbb)
2728
2805
end
2729
2806
cur_hand = frame. handler_at[cur_hand]
@@ -2735,7 +2812,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
2735
2812
continue
2736
2813
end
2737
2814
if ! isempty (frame. ssavalue_uses[currpc])
2738
- record_ssa_assign! (currpc, type, frame)
2815
+ record_ssa_assign! (𝕃ᵢ, currpc, type, frame)
2739
2816
else
2740
2817
ssavaluetypes[currpc] = type
2741
2818
end
@@ -2748,7 +2825,7 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
2748
2825
2749
2826
# Case 2: Directly branch to a different BB
2750
2827
begin @label branch
2751
- if update_bbstate! (typeinf_lattice (interp) , frame, nextbb, currstate)
2828
+ if update_bbstate! (𝕃ᵢ , frame, nextbb, currstate)
2752
2829
push! (W, nextbb)
2753
2830
end
2754
2831
end
@@ -2772,13 +2849,13 @@ function typeinf_local(interp::AbstractInterpreter, frame::InferenceState)
2772
2849
nothing
2773
2850
end
2774
2851
2775
- function conditional_change (state:: VarTable , @nospecialize (typ), slot:: Int )
2852
+ function conditional_change (𝕃ᵢ :: AbstractLattice , state:: VarTable , @nospecialize (typ), slot:: Int )
2776
2853
vtype = state[slot]
2777
2854
oldtyp = vtype. typ
2778
2855
if iskindtype (typ)
2779
2856
# this code path corresponds to the special handling for `isa(x, iskindtype)` check
2780
2857
# implemented within `abstract_call_builtin`
2781
- elseif ignorelimited (typ) ⊑ ignorelimited (oldtyp)
2858
+ elseif ⊑ (𝕃ᵢ, ignorelimited (typ), ignorelimited (oldtyp) )
2782
2859
# approximate test for `typ ∩ oldtyp` being better than `oldtyp`
2783
2860
# since we probably formed these types with `typesubstract`,
2784
2861
# the comparison is likely simple
@@ -2788,29 +2865,11 @@ function conditional_change(state::VarTable, @nospecialize(typ), slot::Int)
2788
2865
if oldtyp isa LimitedAccuracy
2789
2866
# typ is better unlimited, but we may still need to compute the tmeet with the limit
2790
2867
# "causes" since we ignored those in the comparison
2791
- typ = tmerge (typ, LimitedAccuracy (Bottom, oldtyp. causes))
2868
+ typ = tmerge (𝕃ᵢ, typ, LimitedAccuracy (Bottom, oldtyp. causes))
2792
2869
end
2793
2870
return StateUpdate (SlotNumber (slot), VarState (typ, vtype. undef), state, true )
2794
2871
end
2795
2872
2796
- function bool_rt_to_conditional (@nospecialize (rt), slottypes:: Vector{Any} , state:: VarTable , slot_id:: Int )
2797
- old = slottypes[slot_id]
2798
- new = widenconditional (state[slot_id]. typ) # avoid nested conditional
2799
- if new ⊑ old && ! (old ⊑ new)
2800
- if isa (rt, Const)
2801
- val = rt. val
2802
- if val === true
2803
- return InterConditional (slot_id, new, Bottom)
2804
- elseif val === false
2805
- return InterConditional (slot_id, Bottom, new)
2806
- end
2807
- elseif rt === Bool
2808
- return InterConditional (slot_id, new, new)
2809
- end
2810
- end
2811
- return rt
2812
- end
2813
-
2814
2873
# make as much progress on `frame` as possible (by handling cycles)
2815
2874
function typeinf_nocycle (interp:: AbstractInterpreter , frame:: InferenceState )
2816
2875
typeinf_local (interp, frame)
0 commit comments