factor/basis/bootstrap/assembler/ppc.factor

819 lines
22 KiB
Factor

! Copyright (C) 2011 Erik Charlebois
! See http://factorcode.org/license.txt for BSD license.
USING: bootstrap.image.private kernel kernel.private namespaces
system cpu.ppc.assembler compiler.units compiler.constants math
math.private math.ranges layouts words vocabs slots.private
locals locals.backend generic.single.private fry sequences
threads.private strings.private ;
FROM: cpu.ppc.assembler => B ;
IN: bootstrap.ppc
: jit-call ( string -- )
dup
0 swap jit-load-dlsym
0 MTLR
jit-load-dlsym-toc
BLRL ;
: jit-call-quot ( -- )
4 quot-entry-point-offset LI
4 3 4 jit-load-cell-x
4 MTLR
BLRL ;
: jit-jump-quot ( -- )
4 quot-entry-point-offset LI
4 3 4 jit-load-cell-x
4 MTCTR
BCTR ;
: stack-frame ( -- n )
reserved-size factor-area-size + 16 align ;
: save-at ( m -- n ) reserved-size + param-size + ;
: save-int ( reg off -- ) [ 1 ] dip save-at jit-save-int ;
: save-fp ( reg off -- ) [ 1 ] dip save-at STFD ;
: save-vec ( reg offt -- ) save-at 11 swap LI 11 1 STVXL ;
: restore-int ( reg off -- ) [ 1 ] dip save-at jit-load-int ;
: restore-fp ( reg off -- ) [ 1 ] dip save-at LFD ;
: restore-vec ( reg offt -- ) save-at 11 swap LI 11 1 LVXL ;
! Stop using intervals here.
: nv-fp-regs ( -- seq ) 14 31 [a,b] ;
: nv-vec-regs ( -- seq ) 20 31 [a,b] ;
: saved-fp-regs-size ( -- n ) 144 ;
: saved-vec-regs-size ( -- n ) 192 ;
: callback-frame-size ( -- n )
reserved-size
param-size +
saved-int-regs-size +
saved-fp-regs-size +
saved-vec-regs-size +
16 align ;
: old-context-save-offset ( -- n )
cell-size 20 * saved-fp-regs-size + saved-vec-regs-size + save-at ;
[
! Save old stack pointer
11 1 MR
0 MFLR ! Get return address
0 1 lr-save jit-save-cell ! Stash return address
1 1 callback-frame-size neg jit-save-cell-update ! Bump stack pointer and set back chain
! Save all non-volatile registers
nv-int-regs [ cell-size * save-int ] each-index
nv-fp-regs [ 8 * saved-int-regs-size + save-fp ] each-index
! nv-vec-regs [ 16 * saved-int-regs-size saved-fp-regs-size + + save-vec ] each-index
! Stick old stack pointer in the frame register so callbacks
! can access their arguments
frame-reg 11 MR
! Load VM into vm-reg
vm-reg jit-load-vm-arg
! Save old context
0 vm-reg vm-context-offset jit-load-cell
0 1 old-context-save-offset jit-save-cell
! Switch over to the spare context
11 vm-reg vm-spare-context-offset jit-load-cell
11 vm-reg vm-context-offset jit-save-cell
! Save C callstack pointer and load Factor callstack
1 11 context-callstack-save-offset jit-save-cell
1 11 context-callstack-bottom-offset jit-load-cell
! Load new data and retain stacks
rs-reg 11 context-retainstack-offset jit-load-cell
ds-reg 11 context-datastack-offset jit-load-cell
! Call into Factor code
0 jit-load-entry-point-arg
0 MTLR
BLRL
! Load VM again, pointlessly
vm-reg jit-load-vm-arg
! Load C callstack pointer
11 vm-reg vm-context-offset jit-load-cell
1 11 context-callstack-save-offset jit-load-cell
! Load old context
0 1 old-context-save-offset jit-load-cell
0 vm-reg vm-context-offset jit-save-cell
! Restore non-volatile registers
! nv-vec-regs [ 16 * saved-int-regs-size saved-float-regs-size + + restore-vec ] each-index
nv-fp-regs [ 8 * saved-int-regs-size + restore-fp ] each-index
nv-int-regs [ cell-size * restore-int ] each-index
1 1 callback-frame-size ADDI ! Bump stack back up
0 1 lr-save jit-load-cell ! Fetch return address
0 MTLR ! Set up return
BLR ! Branch back
] CALLBACK-STUB jit-define
: jit-conditional* ( test-quot false-quot -- )
[ '[ 4 + @ ] ] dip jit-conditional ; inline
: jit-load-context ( -- )
ctx-reg vm-reg vm-context-offset jit-load-cell ;
: jit-save-context ( -- )
jit-load-context
1 ctx-reg context-callstack-top-offset jit-save-cell
ds-reg ctx-reg context-datastack-offset jit-save-cell
rs-reg ctx-reg context-retainstack-offset jit-save-cell ;
: jit-restore-context ( -- )
ds-reg ctx-reg context-datastack-offset jit-load-cell
rs-reg ctx-reg context-retainstack-offset jit-load-cell ;
[
0 MFLR
0 1 lr-save jit-save-cell
0 jit-load-this-arg
0 1 cell-size 2 * neg jit-save-cell
0 stack-frame LI
0 1 cell-size 1 * neg jit-save-cell
1 1 stack-frame neg jit-save-cell-update
] JIT-PROLOG jit-define
[
3 jit-load-literal-arg
3 ds-reg cell-size jit-save-cell-update
] JIT-PUSH-LITERAL jit-define
[
jit-save-context
3 vm-reg MR
4 jit-load-dlsym-arg
4 MTLR
jit-load-dlsym-toc-arg ! Restore the TOC/GOT
BLRL
jit-restore-context
] JIT-PRIMITIVE jit-define
[
0 BL rc-relative-ppc-3-pc rt-entry-point-pic jit-rel
] JIT-WORD-CALL jit-define
[
6 jit-load-here-arg
0 B rc-relative-ppc-3-pc rt-entry-point-pic-tail jit-rel
] JIT-WORD-JUMP jit-define
[
3 ds-reg 0 jit-load-cell
ds-reg dup cell-size SUBI
0 3 \ f type-number jit-compare-cell-imm
[ 0 swap BEQ ] [ 0 B rc-relative-ppc-3-pc rt-entry-point jit-rel ] jit-conditional*
0 B rc-relative-ppc-3-pc rt-entry-point jit-rel
] JIT-IF jit-define
: jit->r ( -- )
4 ds-reg 0 jit-load-cell
ds-reg dup cell-size SUBI
4 rs-reg cell-size jit-save-cell-update ;
: jit-2>r ( -- )
4 ds-reg 0 jit-load-cell
5 ds-reg cell-size neg jit-load-cell
ds-reg dup 2 cell-size * SUBI
rs-reg dup 2 cell-size * ADDI
4 rs-reg 0 jit-save-cell
5 rs-reg cell-size neg jit-save-cell ;
: jit-3>r ( -- )
4 ds-reg 0 jit-load-cell
5 ds-reg cell-size neg jit-load-cell
6 ds-reg cell-size neg 2 * jit-load-cell
ds-reg dup 3 cell-size * SUBI
rs-reg dup 3 cell-size * ADDI
4 rs-reg 0 jit-save-cell
5 rs-reg cell-size neg jit-save-cell
6 rs-reg cell-size neg 2 * jit-save-cell ;
: jit-r> ( -- )
4 rs-reg 0 jit-load-cell
rs-reg dup cell-size SUBI
4 ds-reg cell-size jit-save-cell-update ;
: jit-2r> ( -- )
4 rs-reg 0 jit-load-cell
5 rs-reg cell-size neg jit-load-cell
rs-reg dup 2 cell-size * SUBI
ds-reg dup 2 cell-size * ADDI
4 ds-reg 0 jit-save-cell
5 ds-reg cell-size neg jit-save-cell ;
: jit-3r> ( -- )
4 rs-reg 0 jit-load-cell
5 rs-reg cell-size neg jit-load-cell
6 rs-reg cell-size neg 2 * jit-load-cell
rs-reg dup 3 cell-size * SUBI
ds-reg dup 3 cell-size * ADDI
4 ds-reg 0 jit-save-cell
5 ds-reg cell-size neg jit-save-cell
6 ds-reg cell-size neg 2 * jit-save-cell ;
[
jit->r
0 BL rc-relative-ppc-3-pc rt-entry-point jit-rel
jit-r>
] JIT-DIP jit-define
[
jit-2>r
0 BL rc-relative-ppc-3-pc rt-entry-point jit-rel
jit-2r>
] JIT-2DIP jit-define
[
jit-3>r
0 BL rc-relative-ppc-3-pc rt-entry-point jit-rel
jit-3r>
] JIT-3DIP jit-define
[
1 1 stack-frame ADDI
0 1 lr-save jit-load-cell
0 MTLR
] JIT-EPILOG jit-define
[ BLR ] JIT-RETURN jit-define
! ! ! Polymorphic inline caches
! Don't touch r6 here; it's used to pass the tail call site
! address for tail PICs
! Load a value from a stack position
[
4 ds-reg 0 jit-load-cell rc-absolute-ppc-2 rt-untagged jit-rel
] PIC-LOAD jit-define
[ 4 4 tag-mask get ANDI. ] PIC-TAG jit-define
[
3 4 MR
4 4 tag-mask get ANDI.
0 4 tuple type-number jit-compare-cell-imm
[ 0 swap BNE ]
[ 4 tuple-class-offset LI 4 3 4 jit-load-cell-x ]
jit-conditional*
] PIC-TUPLE jit-define
[
0 4 0 jit-compare-cell-imm rc-absolute-ppc-2 rt-untagged jit-rel
] PIC-CHECK-TAG jit-define
[
5 jit-load-literal-arg
0 4 5 jit-compare-cell
] PIC-CHECK-TUPLE jit-define
[
[ 0 swap BNE ] [ 0 B rc-relative-ppc-3-pc rt-entry-point jit-rel ] jit-conditional*
] PIC-HIT jit-define
! Inline cache miss entry points
: jit-load-return-address ( -- ) 6 MFLR ;
! These are always in tail position with an existing stack
! frame, and the stack. The frame setup takes this into account.
: jit-inline-cache-miss ( -- )
jit-save-context
3 6 MR
4 vm-reg MR
ctx-reg 6 MR
"inline_cache_miss" jit-call
6 ctx-reg MR
jit-load-context
jit-restore-context ;
[ jit-load-return-address jit-inline-cache-miss ]
[ 3 MTLR BLRL ]
[ 3 MTCTR BCTR ]
\ inline-cache-miss define-combinator-primitive
[ jit-inline-cache-miss ]
[ 3 MTLR BLRL ]
[ 3 MTCTR BCTR ]
\ inline-cache-miss-tail define-combinator-primitive
! ! ! Megamorphic caches
[
! class = ...
3 4 MR
4 4 tag-mask get ANDI. ! Mask and...
4 4 tag-bits get jit-shift-left-logical-imm ! shift tag bits to fixnum
0 4 tuple type-number tag-fixnum jit-compare-cell-imm
[ 0 swap BNE ]
[ 4 tuple-class-offset LI 4 3 4 jit-load-cell-x ]
jit-conditional*
! cache = ...
3 jit-load-literal-arg
! key = hashcode(class)
5 4 jit-class-hashcode
! key &= cache.length - 1
5 5 mega-cache-size get 1 - 4 * ANDI.
! cache += array-start-offset
3 3 array-start-offset ADDI
! cache += key
3 3 5 ADD
! if(get(cache) == class)
6 3 0 jit-load-cell
0 6 4 jit-compare-cell
[ 0 swap BNE ]
[
! megamorphic_cache_hits++
4 jit-load-megamorphic-cache-arg
5 4 0 jit-load-cell
5 5 1 ADDI
5 4 0 jit-save-cell
! ... goto get(cache + cell-size)
5 word-entry-point-offset LI
3 3 cell-size jit-load-cell
3 3 5 jit-load-cell-x
3 MTCTR
BCTR
]
jit-conditional*
! fall-through on miss
] MEGA-LOOKUP jit-define
! ! ! Sub-primitives
! Quotations and words
[
3 ds-reg 0 jit-load-cell
ds-reg dup cell-size SUBI
]
[ jit-call-quot ]
[ jit-jump-quot ] \ (call) define-combinator-primitive
[
3 ds-reg 0 jit-load-cell
ds-reg dup cell-size SUBI
4 word-entry-point-offset LI
4 3 4 jit-load-cell-x
]
[ 4 MTLR BLRL ]
[ 4 MTCTR BCTR ] \ (execute) define-combinator-primitive
[
3 ds-reg 0 jit-load-cell
ds-reg dup cell-size SUBI
4 word-entry-point-offset LI
4 3 4 jit-load-cell-x
4 MTCTR BCTR
] JIT-EXECUTE jit-define
[
jit-save-context
4 vm-reg MR
"lazy_jit_compile" jit-call
]
[ jit-call-quot ]
[ jit-jump-quot ]
\ lazy-jit-compile define-combinator-primitive
! Comparisons
: jit-compare ( insn -- )
t jit-literal
3 jit-load-literal-arg
4 ds-reg 0 jit-load-cell
5 ds-reg cell-size neg jit-load-cell-update
0 5 4 jit-compare-cell
[ 0 8 ] dip execute( cr offset -- )
3 \ f type-number LI
3 ds-reg 0 jit-save-cell ;
: jit-math ( insn -- )
3 ds-reg 0 jit-load-cell
4 ds-reg cell-size neg jit-load-cell-update
[ 5 3 4 ] dip execute( dst src1 src2 -- )
5 ds-reg 0 jit-save-cell ;
! Overflowing fixnum arithmetic
:: jit-overflow ( insn func -- )
ds-reg ds-reg cell-size SUBI
jit-save-context
3 ds-reg 0 jit-load-cell
4 ds-reg cell-size jit-load-cell
0 0 LI
0 MTXER
6 4 3 insn call( d a s -- )
6 ds-reg 0 jit-save-cell
[ 0 swap BNS ]
[
5 vm-reg MR
func jit-call
]
jit-conditional* ;
! Contexts
:: jit-switch-context ( reg -- )
7 0 LI
7 1 lr-save jit-save-cell
! Make the new context the current one
ctx-reg reg MR
ctx-reg vm-reg vm-context-offset jit-save-cell
! Load new stack pointer
1 ctx-reg context-callstack-top-offset jit-load-cell
! Load new ds, rs registers
jit-restore-context ;
: jit-pop-context-and-param ( -- )
3 ds-reg 0 jit-load-cell
4 alien-offset LI
3 3 4 jit-load-cell-x
4 ds-reg cell-size neg jit-load-cell
ds-reg ds-reg cell-size 2 * SUBI ;
: jit-push-param ( -- )
ds-reg ds-reg cell-size ADDI
4 ds-reg 0 jit-save-cell ;
: jit-set-context ( -- )
jit-pop-context-and-param
jit-save-context
3 jit-switch-context
jit-push-param ;
: jit-pop-quot-and-param ( -- )
3 ds-reg 0 jit-load-cell
4 ds-reg cell-size neg jit-load-cell
ds-reg ds-reg cell-size 2 * SUBI ;
: jit-start-context ( -- )
! Create the new context in return-reg. Have to save context
! twice, first before calling new_context() which may GC,
! and again after popping the two parameters from the stack.
jit-save-context
3 vm-reg MR
"new_context" jit-call
6 3 MR
jit-pop-quot-and-param
jit-save-context
6 jit-switch-context
jit-push-param
jit-jump-quot ;
: jit-delete-current-context ( -- )
jit-load-context
3 vm-reg MR
"delete_context" jit-call ;
: jit-start-context-and-delete ( -- )
jit-save-context
3 vm-reg MR
"reset_context" jit-call
ctx-reg jit-switch-context
! Pops the quotation from the stack and puts it in register 3
3 ds-reg 0 jit-load-cell
ds-reg ds-reg cell-size SUBI
jit-jump-quot ;
! # All ppc subprimitives
{
! ## Contexts
{ (set-context) [ jit-set-context ] }
{ (set-context-and-delete) [
jit-delete-current-context
jit-set-context
] }
{ (start-context) [ jit-start-context ] }
{ (start-context-and-delete) [
jit-start-context-and-delete
] }
! ## Entry points
{ c-to-factor [
frame-reg 3 MR
3 vm-reg MR
"begin_callback" jit-call
jit-load-context
jit-restore-context
! Call quotation
3 frame-reg MR
jit-call-quot
jit-save-context
3 vm-reg MR
"end_callback" jit-call
] }
{ unwind-native-frames [
! Unwind stack frames
1 4 MR
! Load VM pointer into vm-reg, since we're entering from
! C code
vm-reg jit-load-vm
! Load ds and rs registers
jit-load-context
jit-restore-context
! We have changed the stack; load return address again
0 1 lr-save jit-load-cell
0 MTLR
! Call quotation
jit-jump-quot
] }
! ## Fixnums
! ### Add
{ fixnum+ [ [ ADDO. ] "overflow_fixnum_add" jit-overflow ] }
{ fixnum+fast [ \ ADD jit-math ] }
! ### Bit stuff
{ fixnum-bitand [ \ AND jit-math ] }
{ fixnum-bitnot [
3 ds-reg 0 jit-load-cell
3 3 NOT
3 3 tag-mask get XORI
3 ds-reg 0 jit-save-cell
] }
{ fixnum-bitor [ \ OR jit-math ] }
{ fixnum-bitxor [ \ XOR jit-math ] }
{ fixnum-shift-fast [
3 ds-reg 0 jit-load-cell ! Load amount to shift
3 3 jit-shift-tag-bits ! Shift out tag bits
ds-reg ds-reg cell-size SUBI
4 ds-reg 0 jit-load-cell ! Load value to shift
5 4 3 jit-shift-left-logical ! Shift left
6 3 NEG ! Negate shift amount
7 4 6 jit-shift-right-algebraic ! Shift right
7 7 jit-mask-tag-bits ! Mask out tag bits
0 3 0 jit-compare-cell-imm
[ 0 swap BGT ] [ 5 7 MR ] jit-conditional*
5 ds-reg 0 jit-save-cell
] }
! ### Comparisons
{ both-fixnums? [
3 ds-reg 0 jit-load-cell
ds-reg ds-reg cell-size SUBI
4 ds-reg 0 jit-load-cell
3 3 4 OR
3 3 tag-mask get ANDI.
4 \ f type-number LI
0 3 0 jit-compare-cell-imm
[ 0 swap BNE ] [ 4 1 tag-fixnum LI ] jit-conditional*
4 ds-reg 0 jit-save-cell
] }
{ eq? [ \ BEQ jit-compare ] }
{ fixnum> [ \ BGT jit-compare ] }
{ fixnum>= [ \ BGE jit-compare ] }
{ fixnum< [ \ BLT jit-compare ] }
{ fixnum<= [ \ BLE jit-compare ] }
! ### Div/mod
{ fixnum-mod [
3 ds-reg 0 jit-load-cell
ds-reg ds-reg cell-size SUBI
4 ds-reg 0 jit-load-cell
5 4 3 jit-divide
6 5 3 jit-multiply-low
7 4 6 SUB
7 ds-reg 0 jit-save-cell
] }
{ fixnum/i-fast [
3 ds-reg 0 jit-load-cell
ds-reg ds-reg cell-size SUBI
4 ds-reg 0 jit-load-cell
5 4 3 jit-divide
5 5 tag-bits get jit-shift-left-logical-imm
5 ds-reg 0 jit-save-cell
] }
{ fixnum/mod-fast [
3 ds-reg 0 jit-load-cell
4 ds-reg cell-size neg jit-load-cell
5 4 3 jit-divide
6 5 3 jit-multiply-low
7 4 6 SUB
5 5 tag-bits get jit-shift-left-logical-imm
5 ds-reg cell-size neg jit-save-cell
7 ds-reg 0 jit-save-cell
] }
! ### Mul
{ fixnum* [
ds-reg ds-reg cell-size SUBI
jit-save-context
3 ds-reg 0 jit-load-cell
3 3 jit-shift-tag-bits
4 ds-reg cell-size jit-load-cell
0 0 LI
0 MTXER
6 3 4 jit-multiply-low-ov-rc
6 ds-reg 0 jit-save-cell
[ 0 swap BNS ]
[
4 4 jit-shift-tag-bits
5 vm-reg MR
"overflow_fixnum_multiply" jit-call
]
jit-conditional*
] }
{ fixnum*fast [
3 ds-reg 0 jit-load-cell
4 ds-reg cell-size neg jit-load-cell-update
4 4 jit-shift-tag-bits
5 3 4 jit-multiply-low
5 ds-reg 0 jit-save-cell
] }
! ### Sub
{ fixnum- [ [ SUBFO. ] "overflow_fixnum_subtract" jit-overflow ] }
{ fixnum-fast [ \ SUBF jit-math ] }
! ## Locals
{ drop-locals [
3 ds-reg 0 jit-load-cell
ds-reg ds-reg cell-size SUBI
3 3 jit-shift-fixnum-slot
rs-reg rs-reg 3 SUB
] }
{ get-local [
3 ds-reg 0 jit-load-cell
3 3 jit-shift-fixnum-slot
3 rs-reg 3 jit-load-cell-x
3 ds-reg 0 jit-save-cell
] }
{ load-local [ jit->r ] }
! ## Misc
{ set-callstack [
7 0 LI
7 1 lr-save jit-save-cell
! Load callstack object
6 ds-reg 0 jit-load-cell
ds-reg ds-reg cell-size SUBI
! Get ctx->callstack_bottom
jit-load-context
3 ctx-reg context-callstack-bottom-offset jit-load-cell
! Get top of callstack object -- 'src' for memcpy
4 6 callstack-top-offset ADDI
! Get callstack length, in bytes --- 'len' for memcpy
7 callstack-length-offset LI
5 6 7 jit-load-cell-x
5 5 jit-shift-tag-bits
! Compute new stack pointer -- 'dst' for memcpy
3 3 5 SUB
! Install new stack pointer
1 3 MR
! Call memcpy; arguments are now in the correct registers
1 1 -16 cell-size * jit-save-cell-update
"factor_memcpy" jit-call
1 1 0 jit-load-cell
! Return with new callstack
0 1 lr-save jit-load-cell
0 MTLR
BLR
] }
! ## Objects
{ slot [
3 ds-reg 0 jit-load-cell ! Load m
4 ds-reg cell-size neg jit-load-cell-update ! Load obj
3 3 jit-shift-fixnum-slot ! Shift to a cell-size multiple
4 4 jit-mask-tag-bits ! Clear tag bits on obj
3 4 3 jit-load-cell-x ! Load cell at &obj[m]
3 ds-reg 0 jit-save-cell ! Push the result to the stack
] }
{ string-nth-fast [
! load string index from stack
3 ds-reg cell-size neg jit-load-cell
3 3 jit-shift-tag-bits
! load string from stack
4 ds-reg 0 jit-load-cell
! load character
4 4 string-offset ADDI
3 3 4 LBZX
3 3 tag-bits get jit-shift-left-logical-imm
! store character to stack
ds-reg ds-reg cell-size SUBI
3 ds-reg 0 jit-save-cell
] }
{ tag [
3 ds-reg 0 jit-load-cell
3 3 tag-mask get ANDI.
3 3 tag-bits get jit-shift-left-logical-imm
3 ds-reg 0 jit-save-cell
] }
! ## Shufflers
! ### Drops
{ drop [ ds-reg dup cell-size SUBI ] }
{ 2drop [ ds-reg dup 2 cell-size * SUBI ] }
{ 3drop [ ds-reg dup 3 cell-size * SUBI ] }
! ### Dups
{ dup [
3 ds-reg 0 jit-load-cell
3 ds-reg cell-size jit-save-cell-update
] }
{ 2dup [
3 ds-reg 0 jit-load-cell
4 ds-reg cell-size neg jit-load-cell
ds-reg dup 2 cell-size * ADDI
3 ds-reg 0 jit-save-cell
4 ds-reg cell-size neg jit-save-cell
] }
{ 3dup [
3 ds-reg 0 jit-load-cell
4 ds-reg cell-size neg jit-load-cell
5 ds-reg cell-size neg 2 * jit-load-cell
ds-reg dup cell-size 3 * ADDI
3 ds-reg 0 jit-save-cell
4 ds-reg cell-size neg jit-save-cell
5 ds-reg cell-size neg 2 * jit-save-cell
] }
{ dupd [
3 ds-reg 0 jit-load-cell
4 ds-reg cell-size neg jit-load-cell
4 ds-reg 0 jit-save-cell
3 ds-reg cell-size jit-save-cell-update
] }
! ### Misc shufflers
{ over [
3 ds-reg cell-size neg jit-load-cell
3 ds-reg cell-size jit-save-cell-update
] }
{ pick [
3 ds-reg cell-size neg 2 * jit-load-cell
3 ds-reg cell-size jit-save-cell-update
] }
! ### Nips
{ nip [
3 ds-reg 0 jit-load-cell
ds-reg dup cell-size SUBI
3 ds-reg 0 jit-save-cell
] }
{ 2nip [
3 ds-reg 0 jit-load-cell
ds-reg dup cell-size 2 * SUBI
3 ds-reg 0 jit-save-cell
] }
! ### Swaps
{ -rot [
3 ds-reg 0 jit-load-cell
4 ds-reg cell-size neg jit-load-cell
5 ds-reg cell-size neg 2 * jit-load-cell
3 ds-reg cell-size neg 2 * jit-save-cell
5 ds-reg cell-size neg jit-save-cell
4 ds-reg 0 jit-save-cell
] }
{ rot [
3 ds-reg 0 jit-load-cell
4 ds-reg cell-size neg jit-load-cell
5 ds-reg cell-size neg 2 * jit-load-cell
4 ds-reg cell-size neg 2 * jit-save-cell
3 ds-reg cell-size neg jit-save-cell
5 ds-reg 0 jit-save-cell
] }
{ swap [
3 ds-reg 0 jit-load-cell
4 ds-reg cell-size neg jit-load-cell
3 ds-reg cell-size neg jit-save-cell
4 ds-reg 0 jit-save-cell
] }
{ swapd [
3 ds-reg cell-size neg jit-load-cell
4 ds-reg cell-size neg 2 * jit-load-cell
3 ds-reg cell-size neg 2 * jit-save-cell
4 ds-reg cell-size neg jit-save-cell
] }
} define-sub-primitives
[ "bootstrap.ppc" forget-vocab ] with-compilation-unit