-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
/
stmtinfo.jl
225 lines (187 loc) · 6.86 KB
/
stmtinfo.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# This file is a part of Julia. License is MIT: https://julialang.org/license
@nospecialize
"""
call::CallMeta
A simple struct that captures both the return type (`call.rt`)
and any additional information (`call.info`) for a given generic call.
"""
struct CallMeta
rt::Any
effects::Effects
info::CallInfo
end
struct NoCallInfo <: CallInfo end
"""
info::MethodMatchInfo <: CallInfo
Captures the result of a `:jl_matching_methods` lookup for the given call (`info.results`).
This info may then be used by the optimizer to inline the matches, without having
to re-consult the method table. This info is illegal on any statement that is
not a call to a generic function.
"""
struct MethodMatchInfo <: CallInfo
results::MethodLookupResult
end
nsplit_impl(info::MethodMatchInfo) = 1
getsplit_impl(info::MethodMatchInfo, idx::Int) = (@assert idx == 1; info.results)
getresult_impl(::MethodMatchInfo, ::Int) = nothing
"""
info::UnionSplitInfo <: CallInfo
If inference decides to partition the method search space by splitting unions,
it will issue a method lookup query for each such partition. This info indicates
that such partitioning happened and wraps the corresponding `MethodMatchInfo` for
each partition (`info.matches::Vector{MethodMatchInfo}`).
This info is illegal on any statement that is not a call to a generic function.
"""
struct UnionSplitInfo <: CallInfo
matches::Vector{MethodMatchInfo}
end
nmatches(info::MethodMatchInfo) = length(info.results)
function nmatches(info::UnionSplitInfo)
n = 0
for mminfo in info.matches
n += nmatches(mminfo)
end
return n
end
nsplit_impl(info::UnionSplitInfo) = length(info.matches)
getsplit_impl(info::UnionSplitInfo, idx::Int) = getsplit_impl(info.matches[idx], 1)
getresult_impl(::UnionSplitInfo, ::Int) = nothing
struct ConstPropResult
result::InferenceResult
end
struct ConcreteResult
mi::MethodInstance
effects::Effects
result
ConcreteResult(mi::MethodInstance, effects::Effects) = new(mi, effects)
ConcreteResult(mi::MethodInstance, effects::Effects, @nospecialize val) = new(mi, effects, val)
end
struct SemiConcreteResult
mi::MethodInstance
ir::IRCode
effects::Effects
end
const ConstResult = Union{ConstPropResult, ConcreteResult, SemiConcreteResult}
"""
info::ConstCallInfo <: CallInfo
The precision of this call was improved using constant information.
In addition to the original call information `info.call`, this info also keeps the results
of constant inference `info.results::Vector{Union{Nothing,ConstResult}}`.
"""
struct ConstCallInfo <: CallInfo
call::Union{MethodMatchInfo,UnionSplitInfo}
results::Vector{Union{Nothing,ConstResult}}
end
nsplit_impl(info::ConstCallInfo) = nsplit(info.call)
getsplit_impl(info::ConstCallInfo, idx::Int) = getsplit(info.call, idx)
getresult_impl(info::ConstCallInfo, idx::Int) = info.results[idx]
"""
info::MethodResultPure <: CallInfo
This struct represents a method result constant was proven to be
effect-free, including being no-throw (typically because the value was computed
by calling an `@pure` function).
"""
struct MethodResultPure <: CallInfo
info::CallInfo
end
let instance = MethodResultPure(NoCallInfo())
global MethodResultPure
MethodResultPure() = instance
end
"""
ainfo::AbstractIterationInfo
Captures all the information for abstract iteration analysis of a single value.
Each (abstract) call to `iterate`, corresponds to one entry in `ainfo.each::Vector{CallMeta}`.
"""
struct AbstractIterationInfo
each::Vector{CallMeta}
complete::Bool
end
const MaybeAbstractIterationInfo = Union{Nothing, AbstractIterationInfo}
"""
info::ApplyCallInfo <: CallInfo
This info applies to any call of `_apply_iterate(...)` and captures both the
info of the actual call being applied and the info for any implicit call
to the `iterate` function. Note that it is possible for the call itself
to be yet another `_apply_iterate`, in which case the `info.call` field will
be another `ApplyCallInfo`. This info is illegal on any statement that is
not an `_apply_iterate` call.
"""
struct ApplyCallInfo <: CallInfo
# The info for the call itself
call::Any
# AbstractIterationInfo for each argument, if applicable
arginfo::Vector{MaybeAbstractIterationInfo}
end
"""
info::UnionSplitApplyCallInfo <: CallInfo
Like `UnionSplitInfo`, but for `ApplyCallInfo` rather than `MethodMatchInfo`.
This info is illegal on any statement that is not an `_apply_iterate` call.
"""
struct UnionSplitApplyCallInfo <: CallInfo
infos::Vector{ApplyCallInfo}
end
"""
info::InvokeCallInfo
Represents a resolved call to `Core.invoke`, carrying the `info.match::MethodMatch` of
the method that has been processed.
Optionally keeps `info.result::InferenceResult` that keeps constant information.
"""
struct InvokeCallInfo <: CallInfo
match::MethodMatch
result::Union{Nothing,ConstResult}
end
"""
info::OpaqueClosureCallInfo
Represents a resolved call of opaque closure, carrying the `info.match::MethodMatch` of
the method that has been processed.
Optionally keeps `info.result::InferenceResult` that keeps constant information.
"""
struct OpaqueClosureCallInfo <: CallInfo
match::MethodMatch
result::Union{Nothing,ConstResult}
end
"""
info::OpaqueClosureCreateInfo <: CallInfo
This info may be constructed upon opaque closure construction, with `info.unspec::CallMeta`
carrying out inference result of an unreal, partially specialized call (i.e. specialized on
the closure environment, but not on the argument types of the opaque closure) in order to
allow the optimizer to rewrite the return type parameter of the `OpaqueClosure` based on it.
"""
struct OpaqueClosureCreateInfo <: CallInfo
unspec::CallMeta
function OpaqueClosureCreateInfo(unspec::CallMeta)
@assert isa(unspec.info, OpaqueClosureCallInfo)
return new(unspec)
end
end
# Stmt infos that are used by external consumers, but not by optimization.
# These are not produced by default and must be explicitly opted into by
# the AbstractInterpreter.
"""
info::ReturnTypeCallInfo <: CallInfo
Represents a resolved call of `Core.Compiler.return_type`.
`info.call` wraps the info corresponding to the call that `Core.Compiler.return_type` call
was supposed to analyze.
"""
struct ReturnTypeCallInfo <: CallInfo
info::CallInfo
end
"""
info::FinalizerInfo <: CallInfo
Represents the information of a potential (later) call to the finalizer on the given
object type.
"""
struct FinalizerInfo <: CallInfo
info::CallInfo # the callinfo for the finalizer call
effects::Effects # the effects for the finalizer call
end
"""
info::ModifyFieldInfo <: CallInfo
Represents a resolved all of `modifyfield!(obj, name, op, x, [order])`.
`info.info` wraps the call information of `op(getfield(obj, name), x)`.
"""
struct ModifyFieldInfo <: CallInfo
info::CallInfo # the callinfo for the `op(getfield(obj, name), x)` call
end
@specialize