-
-
Notifications
You must be signed in to change notification settings - Fork 5.4k
/
init.jl
268 lines (228 loc) · 7.77 KB
/
init.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
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
# This file is a part of Julia. License is MIT: https://julialang.org/license
using Core.Intrinsics
import Core: print, println, show, write, unsafe_write, STDOUT, STDERR,
_apply, svec, apply_type, Builtin, IntrinsicFunction, MethodInstance
ccall(:jl_set_istopmod, Cvoid, (Any, Bool), Compiler, false)
eval(x) = Core.eval(Compiler, x)
eval(m, x) = Core.eval(m, x)
include(x) = Core.include(Compiler, x)
include(mod, x) = Core.include(mod, x)
inlining_enabled() = (JLOptions().can_inline == 1)
coverage_enabled() = (JLOptions().code_coverage != 0)
function return_type end
#################################
# essential files and libraries #
#################################
include("../essentials.jl")
include("../ctypes.jl")
include("../generator.jl")
include("../reflection.jl")
include("../options.jl")
###########################
# core operations & types #
###########################
include("../promotion.jl")
include("../tuple.jl")
include("../pair.jl")
include("../traits.jl")
include("../range.jl")
include("../expr.jl")
include("../error.jl")
###################################
# core numeric operations & types #
###################################
include("../bool.jl")
include("../number.jl")
include("../int.jl")
include("../operators.jl")
include("../pointer.jl")
#########################
# core array operations #
#########################
include("../indices.jl")
include("../array.jl")
include("../abstractarray.jl")
########################
# map-reduce operators #
########################
macro simd(forloop)
esc(forloop)
end
include("../reduce.jl")
###################
# core structures #
###################
include("../bitarray.jl")
include("../bitset.jl")
include("../abstractdict.jl")
include("../iterators.jl")
include("../namedtuple.jl")
##################
# core docsystem #
##################
include("../docs/core.jl")
#############
# constants #
#############
const EMPTY_VECTOR = Vector{Any}()
const COMPILER_TEMP_SYM = Symbol("#temp#")
const CoreNumType = Union{Int32, Int64, Float32, Float64}
const isleaftype = _isleaftype
const getproperty = getfield
const setproperty! = setfield!
const checked_add = +
const checked_sub = -
###################
# InferenceResult #
###################
mutable struct InferenceResult
linfo::MethodInstance
args::Vector{Any}
result # ::Type, or InferenceState if WIP
src::Union{CodeInfo, Nothing} # if inferred copy is available
function InferenceResult(linfo::MethodInstance)
if isdefined(linfo, :inferred_const)
result = Const(linfo.inferred_const)
else
result = linfo.rettype
end
return new(linfo, EMPTY_VECTOR, result, nothing)
end
end
function get_argtypes(result::InferenceResult)
result.args === EMPTY_VECTOR || return result.args # already cached
linfo = result.linfo
toplevel = !isa(linfo.def, Method)
atypes::SimpleVector = unwrap_unionall(linfo.specTypes).parameters
nargs::Int = toplevel ? 0 : linfo.def.nargs
args = Vector{Any}(uninitialized, nargs)
if !toplevel && linfo.def.isva
if linfo.specTypes == Tuple
if nargs > 1
atypes = svec(Any[ Any for i = 1:(nargs - 1) ]..., Tuple.parameters[1])
end
vararg_type = Tuple
else
vararg_type = rewrap(tupleparam_tail(atypes, nargs), linfo.specTypes)
end
args[nargs] = vararg_type
nargs -= 1
end
laty = length(atypes)
if laty > 0
if laty > nargs
laty = nargs
end
local lastatype
atail = laty
for i = 1:laty
atyp = atypes[i]
if i == laty && isvarargtype(atyp)
atyp = unwrap_unionall(atyp).parameters[1]
atail -= 1
end
if isa(atyp, TypeVar)
atyp = atyp.ub
end
if isa(atyp, DataType) && isdefined(atyp, :instance)
# replace singleton types with their equivalent Const object
atyp = Const(atyp.instance)
elseif isconstType(atyp)
atyp = Const(atyp.parameters[1])
else
atyp = rewrap_unionall(atyp, linfo.specTypes)
end
i == laty && (lastatype = atyp)
args[i] = atyp
end
for i = (atail + 1):nargs
args[i] = lastatype
end
else
@assert nargs == 0 "invalid specialization of method" # wrong number of arguments
end
result.args = args
return args
end
function cache_lookup(code::MethodInstance, argtypes::Vector{Any}, cache::Vector{InferenceResult})
method = code.def::Method
nargs::Int = method.nargs
method.isva && (nargs -= 1)
for cache_code in cache
# try to search cache first
cache_args = cache_code.args
if cache_code.linfo === code && length(cache_args) >= nargs
cache_match = true
# verify that the trailing args (va) aren't Const
for i in (nargs + 1):length(cache_args)
if isa(cache_args[i], Const)
cache_match = false
break
end
end
cache_match || continue
for i in 1:nargs
a = argtypes[i]
ca = cache_args[i]
# verify that all Const argument types match between the call and cache
if (isa(a, Const) || isa(ca, Const)) && !(a === ca)
cache_match = false
break
end
end
cache_match || continue
return cache_code
end
end
return nothing
end
##########
# Params #
##########
struct Params
cache::Vector{InferenceResult}
world::UInt
# optimization
inlining::Bool
ipo_constant_propagation::Bool
aggressive_constant_propagation::Bool
inline_cost_threshold::Int # number of CPU cycles beyond which it's not worth inlining
inline_nonleaf_penalty::Int # penalty for dynamic dispatch
inline_tupleret_bonus::Int # extra willingness for non-isbits tuple return types
# don't consider more than N methods. this trades off between
# compiler performance and generated code performance.
# typically, considering many methods means spending lots of time
# obtaining poor type information.
# It is important for N to be >= the number of methods in the error()
# function, so we can still know that error() is always Bottom.
MAX_METHODS::Int
# the maximum number of union-tuples to swap / expand
# before computing the set of matching methods
MAX_UNION_SPLITTING::Int
# the maximum number of union-tuples to swap / expand
# when inferring a call to _apply
MAX_APPLY_UNION_ENUM::Int
# parameters limiting large types
MAX_TUPLETYPE_LEN::Int
MAX_TUPLE_DEPTH::Int
# when attempting to inlining _apply, abort the optimization if the tuple
# contains more than this many elements
MAX_TUPLE_SPLAT::Int
# reasonable defaults
function Params(world::UInt;
inlining::Bool = inlining_enabled(),
inline_cost_threshold::Int = 100,
inline_nonleaf_penalty::Int = 1000,
inline_tupleret_bonus::Int = 400,
max_methods::Int = 4,
tupletype_len::Int = 15,
tuple_depth::Int = 4,
tuple_splat::Int = 16,
union_splitting::Int = 4,
apply_union_enum::Int = 8)
return new(Vector{InferenceResult}(),
world, inlining, true, false, inline_cost_threshold, inline_nonleaf_penalty,
inline_tupleret_bonus, max_methods, union_splitting, apply_union_enum,
tupletype_len, tuple_depth, tuple_splat)
end
end