1
1
# # Instruction and TapedFunction
2
2
3
+ # TODO add an introduction of the impl, caveats
4
+ # caveates:
5
+ # 1. global references are cached out (info msg)
6
+ # 2. QuoteNode is evaluated at tape-recording time (compile time) (info msg)
7
+ # 3. One allocation in each Instruction
8
+
3
9
abstract type AbstractInstruction end
4
10
const RawTape = Vector{AbstractInstruction}
5
11
@@ -18,6 +24,7 @@ mutable struct TapedFunction{F, TapeType}
18
24
tape:: TapeType
19
25
counter:: Int
20
26
bindings:: Bindings
27
+ slots:: Dict{Int, Int} # slots indices in bindings
21
28
retval:: Int # 0 indicates the function has not returned
22
29
23
30
function TapedFunction {F, T} (f:: F , args... ; cache= false ) where {F, T}
@@ -31,9 +38,9 @@ mutable struct TapedFunction{F, TapeType}
31
38
return tf
32
39
end
33
40
ir = _infer (f, args_type)
34
- bindings, tape = translate! (RawTape (), ir)
41
+ bindings, slots, tape = translate! (RawTape (), ir)
35
42
36
- tf = new {F, T} (f, length (args), ir, tape, 1 , bindings, 0 )
43
+ tf = new {F, T} (f, length (args), ir, tape, 1 , bindings, slots, 0 )
37
44
TRCache[cache_key] = tf # set cache
38
45
return tf
39
46
end
@@ -43,7 +50,7 @@ mutable struct TapedFunction{F, TapeType}
43
50
44
51
function TapedFunction {F, T0} (tf:: TapedFunction{F, T1} ) where {F, T0, T1}
45
52
new {F, T0} (tf. func, tf. arity, tf. ir, tf. tape,
46
- tf. counter, tf. bindings, 0 )
53
+ tf. counter, tf. bindings, tf . slots , 0 )
47
54
end
48
55
49
56
TapedFunction (tf:: TapedFunction{F, T} ) where {F, T} = TapedFunction {F, T} (tf)
@@ -104,10 +111,10 @@ function (tf::TapedFunction)(args...; callback=nothing, continuation=false)
104
111
# set args
105
112
if tf. counter <= 1
106
113
# The first slot in `bindings` is assumed to be `tf.func`.
107
- _update_var! (tf, 1 , tf. func)
114
+ haskey (tf . slots, 1 ) && _update_var! (tf, tf . slots[ 1 ] , tf. func)
108
115
for i in 1 : length (args) # the subsequent slots are arguments
109
116
slot = i + 1
110
- _update_var! (tf, slot, args[i])
117
+ haskey (tf . slots, slot) && _update_var! (tf, tf . slots[ slot] , args[i])
111
118
end
112
119
end
113
120
@@ -218,128 +225,132 @@ end
218
225
219
226
220
227
# # Translation: CodeInfo -> Tape
221
- #=
222
- Now, we use a Vector{Any} as the bindings to store all the
223
- variables used in a taped function. These variables are categorized
224
- into 3 kinds: 1. slot values, 2. literal data, 3. ssa values.
225
-
226
- - bindings[1:CNT_SLOT-1] is for slot values
227
- - bindings[CNT_SLOT] holds the current used maximum literal index
228
- - bindings[CNT_SLOT+1:CNT_SLOT+CNT_LITE] is for literal data
229
- - bindings[CNT_SLOT+CNT_LITE+1:end] is for ssa values
230
- =#
231
- const CNT_SLOT = 200
232
- const CNT_LITE = 1000
233
- const OFFSET_VAR = CNT_SLOT + CNT_LITE
234
-
235
- function bind_var! (var_literal, bindings:: Bindings , ir:: Core.CodeInfo ) # for literal constants
236
- last_idx = bindings[CNT_SLOT]
237
- idx = last_idx + 1
238
- @assert idx < OFFSET_VAR
239
- bindings[CNT_SLOT] = idx
240
- bindings[idx] = var_literal
228
+
229
+ struct TempBindings
230
+ data:: Bindings
231
+ book:: Dict{Any, Int}
232
+ end
233
+
234
+ function bind_var! (var_literal, tbind:: TempBindings , ir:: Core.CodeInfo )
235
+ # for literal constants
236
+ push! (tbind. data, var_literal)
237
+ idx = length (tbind. data)
241
238
return idx
242
239
end
243
- bind_var! (var:: GlobalRef , bindings:: Bindings , ir:: Core.CodeInfo ) =
244
- bind_var! (getproperty (var. mod, var. name), bindings, ir)
245
- bind_var! (var:: QuoteNode , bindings:: Bindings , ir:: Core.CodeInfo ) =
246
- bind_var! (eval (var), bindings, ir) # staging out value of `var::QuoteNode`
247
- bind_var! (var:: Core.TypedSlot , bindings:: Bindings , ir:: Core.CodeInfo ) =
248
- (@assert var. id < CNT_SLOT; bind_var! (var. id, bindings, ir. slottypes[var. id]))
249
- bind_var! (var:: Core.SlotNumber , bindings:: Bindings , ir:: Core.CodeInfo ) =
250
- (@assert var. id < CNT_SLOT; bind_var! (var. id, bindings, ir. slottypes[var. id]))
251
- bind_var! (var:: Core.SSAValue , bindings:: Bindings , ir:: Core.CodeInfo ) =
252
- bind_var! (var. id + OFFSET_VAR, bindings, ir. ssavaluetypes[var. id])
253
- bind_var! (var:: Int , boxes:: Bindings , c:: Core.Const ) =
254
- bind_var! (var, boxes, _loose_type (Type{c. val}))
255
- bind_var! (var:: Int , boxes:: Bindings , c:: Core.PartialStruct ) =
256
- bind_var! (var, boxes, _loose_type (c. typ))
257
- function bind_var! (var:: Int , bindings:: Bindings , :: Type{T} ) where T
258
- # here var is the unified index
259
- var > length (bindings) && resize! (bindings, var + 10 )
260
- return var
240
+ function bind_var! (var:: GlobalRef , tbind:: TempBindings , ir:: Core.CodeInfo )
241
+ in (var. mod, (Base, Core)) ||
242
+ @info " evaluating GlobalRef $var at compile time"
243
+ bind_var! (getproperty (var. mod, var. name), tbind, ir)
244
+ end
245
+ function bind_var! (var:: QuoteNode , tbind:: TempBindings , ir:: Core.CodeInfo )
246
+ @info " evaluating QuoteNode $var at compile time"
247
+ bind_var! (eval (var), tbind, ir)
248
+ end
249
+ function bind_var! (var:: Core.TypedSlot , tbind:: TempBindings , ir:: Core.CodeInfo )
250
+ get! (tbind. book, var, allocate_binding! (var, tbind, ir. slottypes[var. id]))
251
+ end
252
+ function bind_var! (var:: Core.SlotNumber , tbind:: TempBindings , ir:: Core.CodeInfo )
253
+ get! (tbind. book, var, allocate_binding! (var, tbind, ir. slottypes[var. id]))
254
+ end
255
+ function bind_var! (var:: Core.SSAValue , tbind:: TempBindings , ir:: Core.CodeInfo )
256
+ get! (tbind. book, var, allocate_binding! (var, tbind, ir. ssavaluetypes[var. id]))
257
+ end
258
+
259
+ allocate_binding! (var, tbind:: TempBindings , c:: Core.Const ) =
260
+ allocate_binding! (var, tbind, _loose_type (Type{c. val}))
261
+ allocate_binding! (var, tbind:: TempBindings , c:: Core.PartialStruct ) =
262
+ allocate_binding! (var, tbind, _loose_type (c. typ))
263
+ function allocate_binding! (var, tbind:: TempBindings , :: Type{T} ) where T
264
+ # we may use the type info (T) here
265
+ push! (tbind. data, nothing )
266
+ idx = length (tbind. data)
267
+ return idx
261
268
end
262
269
263
270
function translate! (tape:: RawTape , ir:: Core.CodeInfo )
264
271
bindings = Bindings ()
265
- resize! (bindings, OFFSET_VAR + 10 )
266
- bindings[CNT_SLOT] = CNT_SLOT
272
+ bcache = Dict {Any, Int} ()
273
+ tbind = TempBindings (bindings, bcache)
274
+ slots = Dict {Int, Int} ()
267
275
268
276
for (idx, line) in enumerate (ir. code)
269
277
isa (line, Core. Const) && (line = line. val) # unbox Core.Const
270
278
isconst = isa (ir. ssavaluetypes[idx], Core. Const)
271
- ins = translate!! (Core. SSAValue (idx), line, bindings , isconst, ir)
279
+ ins = translate!! (Core. SSAValue (idx), line, tbind , isconst, ir)
272
280
push! (tape, ins)
273
281
end
274
- return (bindings, tape)
282
+ for (k, v) in bcache
283
+ isa (k, Union{Core. TypedSlot, Core. SlotNumber}) && (slots[k. id] = v)
284
+ end
285
+ return (bindings, slots, tape)
275
286
end
276
287
277
288
const IRVar = Union{Core. SSAValue, Core. SlotNumber}
278
289
279
- function _const_instruction (var:: IRVar , v, bindings :: Bindings , ir)
290
+ function _const_instruction (var:: IRVar , v, tbind :: TempBindings , ir)
280
291
if isa (var, Core. SSAValue)
281
- box = bind_var! (var, bindings , ir)
282
- bindings [box] = v
292
+ box = bind_var! (var, tbind , ir)
293
+ tbind . data [box] = v
283
294
return NOOPInstruction ()
284
295
end
285
- return Instruction (identity, (bind_var! (v, bindings , ir),), bind_var! (var, bindings , ir))
296
+ return Instruction (identity, (bind_var! (v, tbind , ir),), bind_var! (var, tbind , ir))
286
297
end
287
298
288
299
function translate!! (var:: IRVar , line:: Core.NewvarNode ,
289
- bindings :: Bindings , isconst:: Bool , @nospecialize (ir))
300
+ tbind :: TempBindings , isconst:: Bool , @nospecialize (ir))
290
301
# use a no-op to ensure the 1-to-1 mapping from ir.code to instructions on tape.
291
302
return NOOPInstruction ()
292
303
end
293
304
294
305
function translate!! (var:: IRVar , line:: GlobalRef ,
295
- bindings :: Bindings , isconst:: Bool , ir)
306
+ tbind :: TempBindings , isconst:: Bool , ir)
296
307
if isconst
297
308
v = ir. ssavaluetypes[var. id]. val
298
- return _const_instruction (var, v, bindings , ir)
309
+ return _const_instruction (var, v, tbind , ir)
299
310
end
300
311
func () = getproperty (line. mod, line. name)
301
- return Instruction (func, (), bind_var! (var, bindings , ir))
312
+ return Instruction (func, (), bind_var! (var, tbind , ir))
302
313
end
303
314
304
315
function translate!! (var:: IRVar , line:: Core.SlotNumber ,
305
- bindings :: Bindings , isconst:: Bool , ir)
316
+ tbind :: TempBindings , isconst:: Bool , ir)
306
317
if isconst
307
318
v = ir. ssavaluetypes[var. id]. val
308
- return _const_instruction (var, v, bindings , ir)
319
+ return _const_instruction (var, v, tbind , ir)
309
320
end
310
321
func = identity
311
- input = (bind_var! (line, bindings , ir),)
312
- output = bind_var! (var, bindings , ir)
322
+ input = (bind_var! (line, tbind , ir),)
323
+ output = bind_var! (var, tbind , ir)
313
324
return Instruction (func, input, output)
314
325
end
315
326
316
327
function translate!! (var:: IRVar , line:: Core.TypedSlot ,
317
- bindings :: Bindings , isconst:: Bool , ir)
318
- input_box = bind_var! (Core. SlotNumber (line. id), bindings , ir)
319
- return Instruction (identity, (input_box,), bind_var! (var, bindings , ir))
328
+ tbind :: TempBindings , isconst:: Bool , ir)
329
+ input_box = bind_var! (Core. SlotNumber (line. id), tbind , ir)
330
+ return Instruction (identity, (input_box,), bind_var! (var, tbind , ir))
320
331
end
321
332
322
333
function translate!! (var:: IRVar , line:: Core.GotoIfNot ,
323
- bindings :: Bindings , isconst:: Bool , ir)
324
- cond = bind_var! (line. cond, bindings , ir)
334
+ tbind :: TempBindings , isconst:: Bool , ir)
335
+ cond = bind_var! (line. cond, tbind , ir)
325
336
return CondGotoInstruction (cond, line. dest)
326
337
end
327
338
328
339
function translate!! (var:: IRVar , line:: Core.GotoNode ,
329
- bindings :: Bindings , isconst:: Bool , @nospecialize (ir))
340
+ tbind :: TempBindings , isconst:: Bool , @nospecialize (ir))
330
341
return GotoInstruction (line. label)
331
342
end
332
343
333
344
function translate!! (var:: IRVar , line:: Core.ReturnNode ,
334
- bindings :: Bindings , isconst:: Bool , ir)
335
- return ReturnInstruction (bind_var! (line. val, bindings , ir))
345
+ tbind :: TempBindings , isconst:: Bool , ir)
346
+ return ReturnInstruction (bind_var! (line. val, tbind , ir))
336
347
end
337
348
338
349
_canbeoptimized (v) = isa (v, DataType) || isprimitivetype (typeof (v))
339
350
function translate!! (var:: IRVar , line:: Expr ,
340
- bindings :: Bindings , isconst:: Bool , ir:: Core.CodeInfo )
351
+ tbind :: TempBindings , isconst:: Bool , ir:: Core.CodeInfo )
341
352
head = line. head
342
- _bind_fn = (x) -> bind_var! (x, bindings , ir)
353
+ _bind_fn = (x) -> bind_var! (x, tbind , ir)
343
354
if head === :new
344
355
args = map (_bind_fn, line. args)
345
356
return Instruction (__new__, args |> Tuple, _bind_fn (var))
@@ -349,7 +360,7 @@ function translate!!(var::IRVar, line::Expr,
349
360
# optimised function calls, we will evaluate the function at compile-time and cache results.
350
361
if isconst
351
362
v = ir. ssavaluetypes[var. id]. val
352
- _canbeoptimized (v) && return _const_instruction (var, v, bindings , ir)
363
+ _canbeoptimized (v) && return _const_instruction (var, v, tbind , ir)
353
364
end
354
365
args = map (_bind_fn, line. args)
355
366
# args[1] is the function
@@ -367,7 +378,7 @@ function translate!!(var::IRVar, line::Expr,
367
378
lhs = line. args[1 ]
368
379
rhs = line. args[2 ] # the right hand side, maybe a Expr, or a var, or ...
369
380
if Meta. isexpr (rhs, (:new , :call ))
370
- return translate!! (lhs, rhs, bindings , false , ir)
381
+ return translate!! (lhs, rhs, tbind , false , ir)
371
382
else # rhs is a single value
372
383
if isconst
373
384
v = ir. ssavaluetypes[var. id]. val
@@ -381,7 +392,7 @@ function translate!!(var::IRVar, line::Expr,
381
392
end
382
393
end
383
394
384
- function translate!! (var, line, bindings , ir)
395
+ function translate!! (var, line, tbind , ir)
385
396
@error " Unknown IR code: " typeof (var) var typeof (line) line
386
397
throw (ErrorException (" Unknown IR code" ))
387
398
end
0 commit comments