Skip to content

Commit 82655a2

Browse files
authored
Merge branch 'master' into oneto-inval
2 parents 03533fd + 4690323 commit 82655a2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+1983
-613
lines changed

base/compiler/abstractinterpretation.jl

Lines changed: 258 additions & 153 deletions
Large diffs are not rendered by default.

base/compiler/abstractlattice.jl

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
abstract type AbstractLattice; end
2+
function widenlattice end
3+
4+
"""
5+
struct JLTypeLattice
6+
7+
A singleton type representing the lattice of Julia types, without any inference
8+
extensions.
9+
"""
10+
struct JLTypeLattice <: AbstractLattice; end
11+
widenlattice(::JLTypeLattice) = error("Type lattice is the least-precise lattice available")
12+
is_valid_lattice(::JLTypeLattice, @nospecialize(elem)) = isa(elem, Type)
13+
14+
"""
15+
struct ConstsLattice
16+
17+
A lattice extending `JLTypeLattice` and adjoining `Const` and `PartialTypeVar`.
18+
"""
19+
struct ConstsLattice <: AbstractLattice; end
20+
widenlattice(::ConstsLattice) = JLTypeLattice()
21+
is_valid_lattice(lattice::ConstsLattice, @nospecialize(elem)) =
22+
is_valid_lattice(widenlattice(lattice), elem) || isa(elem, Const) || isa(elem, PartialTypeVar)
23+
24+
"""
25+
struct PartialsLattice{L}
26+
27+
A lattice extending lattice `L` and adjoining `PartialStruct` and `PartialOpaque`.
28+
"""
29+
struct PartialsLattice{L <: AbstractLattice} <: AbstractLattice
30+
parent::L
31+
end
32+
widenlattice(L::PartialsLattice) = L.parent
33+
is_valid_lattice(lattice::PartialsLattice, @nospecialize(elem)) =
34+
is_valid_lattice(widenlattice(lattice), elem) ||
35+
isa(elem, PartialStruct) || isa(elem, PartialOpaque)
36+
37+
"""
38+
struct ConditionalsLattice{L}
39+
40+
A lattice extending lattice `L` and adjoining `Conditional`.
41+
"""
42+
struct ConditionalsLattice{L <: AbstractLattice} <: AbstractLattice
43+
parent::L
44+
end
45+
widenlattice(L::ConditionalsLattice) = L.parent
46+
is_valid_lattice(lattice::ConditionalsLattice, @nospecialize(elem)) =
47+
is_valid_lattice(widenlattice(lattice), elem) || isa(elem, Conditional)
48+
49+
struct InterConditionalsLattice{L <: AbstractLattice} <: AbstractLattice
50+
parent::L
51+
end
52+
widenlattice(L::InterConditionalsLattice) = L.parent
53+
is_valid_lattice(lattice::InterConditionalsLattice, @nospecialize(elem)) =
54+
is_valid_lattice(widenlattice(lattice), elem) || isa(elem, InterConditional)
55+
56+
const AnyConditionalsLattice{L} = Union{ConditionalsLattice{L}, InterConditionalsLattice{L}}
57+
const BaseInferenceLattice = typeof(ConditionalsLattice(PartialsLattice(ConstsLattice())))
58+
const IPOResultLattice = typeof(InterConditionalsLattice(PartialsLattice(ConstsLattice())))
59+
60+
"""
61+
struct InferenceLattice{L}
62+
63+
The full lattice used for abstract interpration during inference. Takes
64+
a base lattice and adjoins `LimitedAccuracy`.
65+
"""
66+
struct InferenceLattice{L} <: AbstractLattice
67+
parent::L
68+
end
69+
widenlattice(L::InferenceLattice) = L.parent
70+
is_valid_lattice(lattice::InferenceLattice, @nospecialize(elem)) =
71+
is_valid_lattice(widenlattice(lattice), elem) || isa(elem, LimitedAccuracy)
72+
73+
"""
74+
struct OptimizerLattice
75+
76+
The lattice used by the optimizer. Extends
77+
`BaseInferenceLattice` with `MaybeUndef`.
78+
"""
79+
struct OptimizerLattice <: AbstractLattice; end
80+
widenlattice(L::OptimizerLattice) = BaseInferenceLattice.instance
81+
is_valid_lattice(lattice::OptimizerLattice, @nospecialize(elem)) =
82+
is_valid_lattice(widenlattice(lattice), elem) || isa(elem, MaybeUndef)
83+
84+
"""
85+
tmeet(lattice, a, b::Type)
86+
87+
Compute the lattice meet of lattice elements `a` and `b` over the lattice
88+
`lattice`. If `lattice` is `JLTypeLattice`, this is equiavalent to type
89+
intersection. Note that currently `b` is restricted to being a type (interpreted
90+
as a lattice element in the JLTypeLattice sub-lattice of `lattice`).
91+
"""
92+
function tmeet end
93+
94+
function tmeet(::JLTypeLattice, @nospecialize(a::Type), @nospecialize(b::Type))
95+
ti = typeintersect(a, b)
96+
valid_as_lattice(ti) || return Bottom
97+
return ti
98+
end
99+
100+
"""
101+
tmerge(lattice, a, b)
102+
103+
Compute a lattice join of elements `a` and `b` over the lattice `lattice`.
104+
Note that the computed element need not be the least upper bound of `a` and
105+
`b`, but rather, we impose additional limitations on the complexity of the
106+
joined element, ideally without losing too much precision in common cases and
107+
remaining mostly associative and commutative.
108+
"""
109+
function tmerge end
110+
111+
"""
112+
⊑(lattice, a, b)
113+
114+
Compute the lattice ordering (i.e. less-than-or-equal) relationship between
115+
lattice elements `a` and `b` over the lattice `lattice`. If `lattice` is
116+
`JLTypeLattice`, this is equiavalent to subtyping.
117+
"""
118+
function end
119+
120+
(::JLTypeLattice, @nospecialize(a::Type), @nospecialize(b::Type)) = a <: b
121+
122+
"""
123+
⊏(lattice, a, b) -> Bool
124+
125+
The strict partial order over the type inference lattice.
126+
This is defined as the irreflexive kernel of `⊑`.
127+
"""
128+
(lattice::AbstractLattice, @nospecialize(a), @nospecialize(b)) = (lattice, a, b) && !(lattice, b, a)
129+
130+
"""
131+
⋤(lattice, a, b) -> Bool
132+
133+
This order could be used as a slightly more efficient version of the strict order `⊏`,
134+
where we can safely assume `a ⊑ b` holds.
135+
"""
136+
(lattice::AbstractLattice, @nospecialize(a), @nospecialize(b)) = !(lattice, b, a)
137+
138+
"""
139+
is_lattice_equal(lattice, a, b) -> Bool
140+
141+
Check if two lattice elements are partial order equivalent.
142+
This is basically `a ⊑ b && b ⊑ a` but (optionally) with extra performance optimizations.
143+
"""
144+
function is_lattice_equal(lattice::AbstractLattice, @nospecialize(a), @nospecialize(b))
145+
a === b && return true
146+
(lattice, a, b) && (lattice, b, a)
147+
end
148+
149+
"""
150+
has_nontrivial_const_info(lattice, t) -> Bool
151+
152+
Determine whether the given lattice element `t` of `lattice` has non-trivial
153+
constant information that would not be available from the type itself.
154+
"""
155+
has_nontrivial_const_info(lattice::AbstractLattice, @nospecialize t) =
156+
has_nontrivial_const_info(widenlattice(lattice), t)
157+
has_nontrivial_const_info(::JLTypeLattice, @nospecialize(t)) = false
158+
159+
# Curried versions
160+
(lattice::AbstractLattice) = (@nospecialize(a), @nospecialize(b)) -> (lattice, a, b)
161+
(lattice::AbstractLattice) = (@nospecialize(a), @nospecialize(b)) -> (lattice, a, b)
162+
(lattice::AbstractLattice) = (@nospecialize(a), @nospecialize(b)) -> (lattice, a, b)
163+
164+
# Fallbacks for external packages using these methods
165+
const fallback_lattice = InferenceLattice(BaseInferenceLattice.instance)
166+
const fallback_ipo_lattice = InferenceLattice(IPOResultLattice.instance)
167+
168+
(@nospecialize(a), @nospecialize(b)) = (fallback_lattice, a, b)
169+
tmeet(@nospecialize(a), @nospecialize(b)) = tmeet(fallback_lattice, a, b)
170+
tmerge(@nospecialize(a), @nospecialize(b)) = tmerge(fallback_lattice, a, b)
171+
(@nospecialize(a), @nospecialize(b)) = (fallback_lattice, a, b)
172+
(@nospecialize(a), @nospecialize(b)) = (fallback_lattice, a, b)
173+
is_lattice_equal(@nospecialize(a), @nospecialize(b)) = is_lattice_equal(fallback_lattice, a, b)

base/compiler/compiler.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,8 @@ import Core.Compiler.CoreDocs
121121
Core.atdoc!(CoreDocs.docm)
122122

123123
# sorting
124-
function sort end
125124
function sort! end
126125
function issorted end
127-
function sortperm end
128126
include("ordering.jl")
129127
using .Order
130128
include("sort.jl")
@@ -153,6 +151,8 @@ include("compiler/ssair/basicblock.jl")
153151
include("compiler/ssair/domtree.jl")
154152
include("compiler/ssair/ir.jl")
155153

154+
include("compiler/abstractlattice.jl")
155+
156156
include("compiler/inferenceresult.jl")
157157
include("compiler/inferencestate.jl")
158158

@@ -164,7 +164,7 @@ include("compiler/stmtinfo.jl")
164164

165165
include("compiler/abstractinterpretation.jl")
166166
include("compiler/typeinfer.jl")
167-
include("compiler/optimize.jl") # TODO: break this up further + extract utilities
167+
include("compiler/optimize.jl")
168168

169169
# required for bootstrap because sort.jl uses extrema
170170
# to decide whether to dispatch to counting sort.

base/compiler/inferenceresult.jl

Lines changed: 38 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
# This file is a part of Julia. License is MIT: https://julialang.org/license
22

3-
function is_argtype_match(@nospecialize(given_argtype),
3+
function is_argtype_match(lattice::AbstractLattice,
4+
@nospecialize(given_argtype),
45
@nospecialize(cache_argtype),
56
overridden_by_const::Bool)
67
if is_forwardable_argtype(given_argtype)
7-
return is_lattice_equal(given_argtype, cache_argtype)
8+
return is_lattice_equal(lattice, given_argtype, cache_argtype)
89
end
910
return !overridden_by_const
1011
end
@@ -16,6 +17,36 @@ function is_forwardable_argtype(@nospecialize x)
1617
isa(x, PartialOpaque)
1718
end
1819

20+
function va_process_argtypes(given_argtypes::Vector{Any}, mi::MethodInstance,
21+
condargs::Union{Vector{Tuple{Int,Int}}, Nothing}=nothing)
22+
isva = mi.def.isva
23+
nargs = Int(mi.def.nargs)
24+
if isva || isvarargtype(given_argtypes[end])
25+
isva_given_argtypes = Vector{Any}(undef, nargs)
26+
for i = 1:(nargs - isva)
27+
isva_given_argtypes[i] = argtype_by_index(given_argtypes, i)
28+
end
29+
if isva
30+
if length(given_argtypes) < nargs && isvarargtype(given_argtypes[end])
31+
last = length(given_argtypes)
32+
else
33+
last = nargs
34+
end
35+
isva_given_argtypes[nargs] = tuple_tfunc(given_argtypes[last:end])
36+
# invalidate `Conditional` imposed on varargs
37+
if condargs !== nothing
38+
for (slotid, i) in condargs
39+
if slotid last
40+
isva_given_argtypes[i] = widenconditional(isva_given_argtypes[i])
41+
end
42+
end
43+
end
44+
end
45+
return isva_given_argtypes
46+
end
47+
return given_argtypes
48+
end
49+
1950
# In theory, there could be a `cache` containing a matching `InferenceResult`
2051
# for the provided `linfo` and `given_argtypes`. The purpose of this function is
2152
# to return a valid value for `cache_lookup(linfo, argtypes, cache).argtypes`,
@@ -56,35 +87,12 @@ function matching_cache_argtypes(
5687
end
5788
given_argtypes[i] = widenconditional(argtype)
5889
end
59-
isva = def.isva
60-
if isva || isvarargtype(given_argtypes[end])
61-
isva_given_argtypes = Vector{Any}(undef, nargs)
62-
for i = 1:(nargs - isva)
63-
isva_given_argtypes[i] = argtype_by_index(given_argtypes, i)
64-
end
65-
if isva
66-
if length(given_argtypes) < nargs && isvarargtype(given_argtypes[end])
67-
last = length(given_argtypes)
68-
else
69-
last = nargs
70-
end
71-
isva_given_argtypes[nargs] = tuple_tfunc(given_argtypes[last:end])
72-
# invalidate `Conditional` imposed on varargs
73-
if condargs !== nothing
74-
for (slotid, i) in condargs
75-
if slotid last
76-
isva_given_argtypes[i] = widenconditional(isva_given_argtypes[i])
77-
end
78-
end
79-
end
80-
end
81-
given_argtypes = isva_given_argtypes
82-
end
90+
given_argtypes = va_process_argtypes(given_argtypes, linfo, condargs)
8391
@assert length(given_argtypes) == nargs
8492
for i in 1:nargs
8593
given_argtype = given_argtypes[i]
8694
cache_argtype = cache_argtypes[i]
87-
if !is_argtype_match(given_argtype, cache_argtype, false)
95+
if !is_argtype_match(fallback_lattice, given_argtype, cache_argtype, false)
8896
# prefer the argtype we were given over the one computed from `linfo`
8997
cache_argtypes[i] = given_argtype
9098
overridden_by_const[i] = true
@@ -200,7 +208,7 @@ function matching_cache_argtypes(linfo::MethodInstance, ::Nothing)
200208
return cache_argtypes, falses(length(cache_argtypes))
201209
end
202210

203-
function cache_lookup(linfo::MethodInstance, given_argtypes::Vector{Any}, cache::Vector{InferenceResult})
211+
function cache_lookup(lattice::AbstractLattice, linfo::MethodInstance, given_argtypes::Vector{Any}, cache::Vector{InferenceResult})
204212
method = linfo.def::Method
205213
nargs::Int = method.nargs
206214
method.isva && (nargs -= 1)
@@ -211,15 +219,15 @@ function cache_lookup(linfo::MethodInstance, given_argtypes::Vector{Any}, cache:
211219
cache_argtypes = cached_result.argtypes
212220
cache_overridden_by_const = cached_result.overridden_by_const
213221
for i in 1:nargs
214-
if !is_argtype_match(given_argtypes[i],
222+
if !is_argtype_match(lattice, given_argtypes[i],
215223
cache_argtypes[i],
216224
cache_overridden_by_const[i])
217225
cache_match = false
218226
break
219227
end
220228
end
221229
if method.isva && cache_match
222-
cache_match = is_argtype_match(tuple_tfunc(given_argtypes[(nargs + 1):end]),
230+
cache_match = is_argtype_match(lattice, tuple_tfunc(lattice, given_argtypes[(nargs + 1):end]),
223231
cache_argtypes[end],
224232
cache_overridden_by_const[end])
225233
end

base/compiler/inferencestate.jl

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,12 @@ function in(idx::Int, bsbmp::BitSetBoundedMinPrioritySet)
8080
return idx in bsbmp.elems
8181
end
8282

83+
function append!(bsbmp::BitSetBoundedMinPrioritySet, itr)
84+
for val in itr
85+
push!(bsbmp, val)
86+
end
87+
end
88+
8389
mutable struct InferenceState
8490
#= information about this method instance =#
8591
linfo::MethodInstance
@@ -209,8 +215,10 @@ Effects(state::InferenceState) = state.ipo_effects
209215
function merge_effects!(::AbstractInterpreter, caller::InferenceState, effects::Effects)
210216
caller.ipo_effects = merge_effects(caller.ipo_effects, effects)
211217
end
218+
212219
merge_effects!(interp::AbstractInterpreter, caller::InferenceState, callee::InferenceState) =
213220
merge_effects!(interp, caller, Effects(callee))
221+
merge_effects!(interp::AbstractInterpreter, caller::IRCode, effects::Effects) = nothing
214222

215223
is_effect_overridden(sv::InferenceState, effect::Symbol) = is_effect_overridden(sv.linfo, effect)
216224
function is_effect_overridden(linfo::MethodInstance, effect::Symbol)
@@ -226,15 +234,15 @@ function InferenceResult(
226234
return _InferenceResult(linfo, arginfo)
227235
end
228236

229-
add_remark!(::AbstractInterpreter, sv::InferenceState, remark) = return
237+
add_remark!(::AbstractInterpreter, sv::Union{InferenceState, IRCode}, remark) = return
230238

231-
function bail_out_toplevel_call(::AbstractInterpreter, @nospecialize(callsig), sv::InferenceState)
232-
return sv.restrict_abstract_call_sites && !isdispatchtuple(callsig)
239+
function bail_out_toplevel_call(::AbstractInterpreter, @nospecialize(callsig), sv::Union{InferenceState, IRCode})
240+
return isa(sv, InferenceState) && sv.restrict_abstract_call_sites && !isdispatchtuple(callsig)
233241
end
234-
function bail_out_call(::AbstractInterpreter, @nospecialize(rt), sv::InferenceState)
242+
function bail_out_call(::AbstractInterpreter, @nospecialize(rt), sv::Union{InferenceState, IRCode})
235243
return rt === Any
236244
end
237-
function bail_out_apply(::AbstractInterpreter, @nospecialize(rt), sv::InferenceState)
245+
function bail_out_apply(::AbstractInterpreter, @nospecialize(rt), sv::Union{InferenceState, IRCode})
238246
return rt === Any
239247
end
240248

0 commit comments

Comments
 (0)