1 ! Copyright (C) 2011 Erik Charlebois
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: bootstrap.image.private kernel kernel.private namespaces
4 system cpu.ppc.assembler compiler.units compiler.constants math
5 math.private math.ranges layouts words vocabs slots.private
6 locals locals.backend generic.single.private fry sequences
7 threads.private strings.private ;
8 FROM: cpu.ppc.assembler => B ;
11 : jit-call ( string -- )
18 : jit-call-quot ( -- )
19 4 quot-entry-point-offset LI
24 : jit-jump-quot ( -- )
25 4 quot-entry-point-offset LI
30 : stack-frame ( -- n )
31 reserved-size factor-area-size + 16 align ;
33 : save-at ( m -- n ) reserved-size + param-size + ;
35 : save-int ( reg off -- ) [ 1 ] dip save-at jit-save-int ;
36 : save-fp ( reg off -- ) [ 1 ] dip save-at STFD ;
37 : save-vec ( reg offt -- ) save-at 11 swap LI 11 1 STVXL ;
38 : restore-int ( reg off -- ) [ 1 ] dip save-at jit-load-int ;
39 : restore-fp ( reg off -- ) [ 1 ] dip save-at LFD ;
40 : restore-vec ( reg offt -- ) save-at 11 swap LI 11 1 LVXL ;
42 ! Stop using intervals here.
43 : nv-fp-regs ( -- seq ) 14 31 [a..b] ;
44 : nv-vec-regs ( -- seq ) 20 31 [a..b] ;
46 : saved-fp-regs-size ( -- n ) 144 ;
47 : saved-vec-regs-size ( -- n ) 192 ;
49 : callback-frame-size ( -- n )
57 : old-context-save-offset ( -- n )
58 cell-size 20 * saved-fp-regs-size + saved-vec-regs-size + save-at ;
61 ! Save old stack pointer
64 0 MFLR ! Get return address
65 0 1 lr-save jit-save-cell ! Stash return address
66 1 1 callback-frame-size neg jit-save-cell-update ! Bump stack pointer and set back chain
68 ! Save all non-volatile registers
69 nv-int-regs [ cell-size * save-int ] each-index
70 nv-fp-regs [ 8 * saved-int-regs-size + save-fp ] each-index
71 ! nv-vec-regs [ 16 * saved-int-regs-size saved-fp-regs-size + + save-vec ] each-index
73 ! Stick old stack pointer in the frame register so callbacks
74 ! can access their arguments
78 vm-reg jit-load-vm-arg
81 0 vm-reg vm-context-offset jit-load-cell
82 0 1 old-context-save-offset jit-save-cell
84 ! Switch over to the spare context
85 11 vm-reg vm-spare-context-offset jit-load-cell
86 11 vm-reg vm-context-offset jit-save-cell
88 ! Save C callstack pointer and load Factor callstack
89 1 11 context-callstack-save-offset jit-save-cell
90 1 11 context-callstack-bottom-offset jit-load-cell
92 ! Load new data and retain stacks
93 rs-reg 11 context-retainstack-offset jit-load-cell
94 ds-reg 11 context-datastack-offset jit-load-cell
96 ! Call into Factor code
97 0 jit-load-entry-point-arg
101 ! Load VM again, pointlessly
102 vm-reg jit-load-vm-arg
104 ! Load C callstack pointer
105 11 vm-reg vm-context-offset jit-load-cell
106 1 11 context-callstack-save-offset jit-load-cell
109 0 1 old-context-save-offset jit-load-cell
110 0 vm-reg vm-context-offset jit-save-cell
112 ! Restore non-volatile registers
113 ! nv-vec-regs [ 16 * saved-int-regs-size saved-float-regs-size + + restore-vec ] each-index
114 nv-fp-regs [ 8 * saved-int-regs-size + restore-fp ] each-index
115 nv-int-regs [ cell-size * restore-int ] each-index
117 1 1 callback-frame-size ADDI ! Bump stack back up
118 0 1 lr-save jit-load-cell ! Fetch return address
119 0 MTLR ! Set up return
121 ] CALLBACK-STUB jit-define
123 : jit-conditional* ( test-quot false-quot -- )
124 [ '[ 4 + @ ] ] dip jit-conditional ; inline
126 : jit-load-context ( -- )
127 ctx-reg vm-reg vm-context-offset jit-load-cell ;
129 : jit-save-context ( -- )
131 1 ctx-reg context-callstack-top-offset jit-save-cell
132 ds-reg ctx-reg context-datastack-offset jit-save-cell
133 rs-reg ctx-reg context-retainstack-offset jit-save-cell ;
135 : jit-restore-context ( -- )
136 ds-reg ctx-reg context-datastack-offset jit-load-cell
137 rs-reg ctx-reg context-retainstack-offset jit-load-cell ;
141 0 1 lr-save jit-save-cell
143 0 1 cell-size 2 * neg jit-save-cell
145 0 1 cell-size 1 * neg jit-save-cell
146 1 1 stack-frame neg jit-save-cell-update
147 ] JIT-PROLOG jit-define
150 3 jit-load-literal-arg
151 3 ds-reg cell-size jit-save-cell-update
152 ] JIT-PUSH-LITERAL jit-define
159 jit-load-dlsym-toc-arg ! Restore the TOC/GOT
162 ] JIT-PRIMITIVE jit-define
165 0 BL rc-relative-ppc-3-pc rt-entry-point-pic jit-rel
166 ] JIT-WORD-CALL jit-define
170 0 B rc-relative-ppc-3-pc rt-entry-point-pic-tail jit-rel
171 ] JIT-WORD-JUMP jit-define
174 3 ds-reg 0 jit-load-cell
175 ds-reg dup cell-size SUBI
176 0 3 \ f type-number jit-compare-cell-imm
177 [ 0 swap BEQ ] [ 0 B rc-relative-ppc-3-pc rt-entry-point jit-rel ] jit-conditional*
178 0 B rc-relative-ppc-3-pc rt-entry-point jit-rel
182 4 ds-reg 0 jit-load-cell
183 ds-reg dup cell-size SUBI
184 4 rs-reg cell-size jit-save-cell-update ;
187 4 ds-reg 0 jit-load-cell
188 5 ds-reg cell-size neg jit-load-cell
189 ds-reg dup 2 cell-size * SUBI
190 rs-reg dup 2 cell-size * ADDI
191 4 rs-reg 0 jit-save-cell
192 5 rs-reg cell-size neg jit-save-cell ;
195 4 ds-reg 0 jit-load-cell
196 5 ds-reg cell-size neg jit-load-cell
197 6 ds-reg cell-size neg 2 * jit-load-cell
198 ds-reg dup 3 cell-size * SUBI
199 rs-reg dup 3 cell-size * ADDI
200 4 rs-reg 0 jit-save-cell
201 5 rs-reg cell-size neg jit-save-cell
202 6 rs-reg cell-size neg 2 * jit-save-cell ;
205 4 rs-reg 0 jit-load-cell
206 rs-reg dup cell-size SUBI
207 4 ds-reg cell-size jit-save-cell-update ;
210 4 rs-reg 0 jit-load-cell
211 5 rs-reg cell-size neg jit-load-cell
212 rs-reg dup 2 cell-size * SUBI
213 ds-reg dup 2 cell-size * ADDI
214 4 ds-reg 0 jit-save-cell
215 5 ds-reg cell-size neg jit-save-cell ;
218 4 rs-reg 0 jit-load-cell
219 5 rs-reg cell-size neg jit-load-cell
220 6 rs-reg cell-size neg 2 * jit-load-cell
221 rs-reg dup 3 cell-size * SUBI
222 ds-reg dup 3 cell-size * ADDI
223 4 ds-reg 0 jit-save-cell
224 5 ds-reg cell-size neg jit-save-cell
225 6 ds-reg cell-size neg 2 * jit-save-cell ;
229 0 BL rc-relative-ppc-3-pc rt-entry-point jit-rel
235 0 BL rc-relative-ppc-3-pc rt-entry-point jit-rel
237 ] JIT-2DIP jit-define
241 0 BL rc-relative-ppc-3-pc rt-entry-point jit-rel
243 ] JIT-3DIP jit-define
247 0 1 lr-save jit-load-cell
249 ] JIT-EPILOG jit-define
251 [ BLR ] JIT-RETURN jit-define
253 ! ! ! Polymorphic inline caches
255 ! Don't touch r6 here; it's used to pass the tail call site
256 ! address for tail PICs
258 ! Load a value from a stack position
260 4 ds-reg 0 jit-load-cell rc-absolute-ppc-2 rt-untagged jit-rel
261 ] PIC-LOAD jit-define
263 [ 4 4 tag-mask get ANDI. ] PIC-TAG jit-define
267 4 4 tag-mask get ANDI.
268 0 4 tuple type-number jit-compare-cell-imm
270 [ 4 tuple-class-offset LI 4 3 4 jit-load-cell-x ]
272 ] PIC-TUPLE jit-define
275 0 4 0 jit-compare-cell-imm rc-absolute-ppc-2 rt-untagged jit-rel
276 ] PIC-CHECK-TAG jit-define
279 5 jit-load-literal-arg
280 0 4 5 jit-compare-cell
281 ] PIC-CHECK-TUPLE jit-define
284 [ 0 swap BNE ] [ 0 B rc-relative-ppc-3-pc rt-entry-point jit-rel ] jit-conditional*
287 ! Inline cache miss entry points
288 : jit-load-return-address ( -- ) 6 MFLR ;
290 ! These are always in tail position with an existing stack
291 ! frame, and the stack. The frame setup takes this into account.
292 : jit-inline-cache-miss ( -- )
297 "inline_cache_miss" jit-call
300 jit-restore-context ;
302 [ jit-load-return-address jit-inline-cache-miss ]
305 \ inline-cache-miss define-combinator-primitive
307 [ jit-inline-cache-miss ]
310 \ inline-cache-miss-tail define-combinator-primitive
312 ! ! ! Megamorphic caches
317 4 4 tag-mask get ANDI. ! Mask and...
318 4 4 tag-bits get jit-shift-left-logical-imm ! shift tag bits to fixnum
319 0 4 tuple type-number tag-fixnum jit-compare-cell-imm
321 [ 4 tuple-class-offset LI 4 3 4 jit-load-cell-x ]
324 3 jit-load-literal-arg
325 ! key = hashcode(class)
326 5 4 jit-class-hashcode
327 ! key &= cache.length - 1
328 5 5 mega-cache-size get 1 - 4 * ANDI.
329 ! cache += array-start-offset
330 3 3 array-start-offset ADDI
333 ! if(get(cache) == class)
335 0 6 4 jit-compare-cell
338 ! megamorphic_cache_hits++
339 4 jit-load-megamorphic-cache-arg
343 ! ... goto get(cache + cell-size)
344 5 word-entry-point-offset LI
345 3 3 cell-size jit-load-cell
346 3 3 5 jit-load-cell-x
351 ! fall-through on miss
352 ] MEGA-LOOKUP jit-define
356 ! Quotations and words
358 3 ds-reg 0 jit-load-cell
359 ds-reg dup cell-size SUBI
362 [ jit-jump-quot ] \ (call) define-combinator-primitive
365 3 ds-reg 0 jit-load-cell
366 ds-reg dup cell-size SUBI
367 4 word-entry-point-offset LI
368 4 3 4 jit-load-cell-x
371 [ 4 MTCTR BCTR ] \ (execute) define-combinator-primitive
374 3 ds-reg 0 jit-load-cell
375 ds-reg dup cell-size SUBI
376 4 word-entry-point-offset LI
377 4 3 4 jit-load-cell-x
379 ] JIT-EXECUTE jit-define
384 "lazy_jit_compile" jit-call
388 \ lazy-jit-compile define-combinator-primitive
391 : jit-compare ( insn -- )
393 3 jit-load-literal-arg
394 4 ds-reg 0 jit-load-cell
395 5 ds-reg cell-size neg jit-load-cell-update
396 0 5 4 jit-compare-cell
397 [ 0 8 ] dip execute( cr offset -- )
399 3 ds-reg 0 jit-save-cell ;
401 : jit-math ( insn -- )
402 3 ds-reg 0 jit-load-cell
403 4 ds-reg cell-size neg jit-load-cell-update
404 [ 5 3 4 ] dip execute( dst src1 src2 -- )
405 5 ds-reg 0 jit-save-cell ;
407 ! Overflowing fixnum arithmetic
408 :: jit-overflow ( insn func -- )
409 ds-reg ds-reg cell-size SUBI
411 3 ds-reg 0 jit-load-cell
412 4 ds-reg cell-size jit-load-cell
415 6 4 3 insn call( d a s -- )
416 6 ds-reg 0 jit-save-cell
425 :: jit-switch-context ( reg -- )
427 7 1 lr-save jit-save-cell
429 ! Make the new context the current one
431 ctx-reg vm-reg vm-context-offset jit-save-cell
433 ! Load new stack pointer
434 1 ctx-reg context-callstack-top-offset jit-load-cell
436 ! Load new ds, rs registers
437 jit-restore-context ;
439 : jit-pop-context-and-param ( -- )
440 3 ds-reg 0 jit-load-cell
442 3 3 4 jit-load-cell-x
443 4 ds-reg cell-size neg jit-load-cell
444 ds-reg ds-reg cell-size 2 * SUBI ;
446 : jit-push-param ( -- )
447 ds-reg ds-reg cell-size ADDI
448 4 ds-reg 0 jit-save-cell ;
450 : jit-set-context ( -- )
451 jit-pop-context-and-param
456 : jit-pop-quot-and-param ( -- )
457 3 ds-reg 0 jit-load-cell
458 4 ds-reg cell-size neg jit-load-cell
459 ds-reg ds-reg cell-size 2 * SUBI ;
461 : jit-start-context ( -- )
462 ! Create the new context in return-reg. Have to save context
463 ! twice, first before calling new_context() which may GC,
464 ! and again after popping the two parameters from the stack.
467 "new_context" jit-call
470 jit-pop-quot-and-param
476 : jit-delete-current-context ( -- )
479 "delete_context" jit-call ;
481 : jit-start-context-and-delete ( -- )
485 "reset_context" jit-call
487 ctx-reg jit-switch-context
489 ! Pops the quotation from the stack and puts it in register 3
490 3 ds-reg 0 jit-load-cell
491 ds-reg ds-reg cell-size SUBI
494 ! # All ppc subprimitives
497 { (set-context) [ jit-set-context ] }
498 { (set-context-and-delete) [
499 jit-delete-current-context
502 { (start-context) [ jit-start-context ] }
503 { (start-context-and-delete) [
504 jit-start-context-and-delete
512 "begin_callback" jit-call
524 "end_callback" jit-call
526 { unwind-native-frames [
527 ! Unwind stack frames
530 ! Load VM pointer into vm-reg, since we're entering from
534 ! Load ds and rs registers
538 ! We have changed the stack; load return address again
539 0 1 lr-save jit-load-cell
549 { fixnum+ [ [ ADDO. ] "overflow_fixnum_add" jit-overflow ] }
550 { fixnum+fast [ \ ADD jit-math ] }
553 { fixnum-bitand [ \ AND jit-math ] }
555 3 ds-reg 0 jit-load-cell
557 3 3 tag-mask get XORI
558 3 ds-reg 0 jit-save-cell
560 { fixnum-bitor [ \ OR jit-math ] }
561 { fixnum-bitxor [ \ XOR jit-math ] }
562 { fixnum-shift-fast [
563 3 ds-reg 0 jit-load-cell ! Load amount to shift
564 3 3 jit-shift-tag-bits ! Shift out tag bits
565 ds-reg ds-reg cell-size SUBI
566 4 ds-reg 0 jit-load-cell ! Load value to shift
567 5 4 3 jit-shift-left-logical ! Shift left
568 6 3 NEG ! Negate shift amount
569 7 4 6 jit-shift-right-algebraic ! Shift right
570 7 7 jit-mask-tag-bits ! Mask out tag bits
571 0 3 0 jit-compare-cell-imm
572 [ 0 swap BGT ] [ 5 7 MR ] jit-conditional*
573 5 ds-reg 0 jit-save-cell
578 3 ds-reg 0 jit-load-cell
579 ds-reg ds-reg cell-size SUBI
580 4 ds-reg 0 jit-load-cell
582 3 3 tag-mask get ANDI.
584 0 3 0 jit-compare-cell-imm
585 [ 0 swap BNE ] [ 4 1 tag-fixnum LI ] jit-conditional*
586 4 ds-reg 0 jit-save-cell
588 { eq? [ \ BEQ jit-compare ] }
589 { fixnum> [ \ BGT jit-compare ] }
590 { fixnum>= [ \ BGE jit-compare ] }
591 { fixnum< [ \ BLT jit-compare ] }
592 { fixnum<= [ \ BLE jit-compare ] }
596 3 ds-reg 0 jit-load-cell
597 ds-reg ds-reg cell-size SUBI
598 4 ds-reg 0 jit-load-cell
600 6 5 3 jit-multiply-low
602 7 ds-reg 0 jit-save-cell
605 3 ds-reg 0 jit-load-cell
606 ds-reg ds-reg cell-size SUBI
607 4 ds-reg 0 jit-load-cell
609 5 5 tag-bits get jit-shift-left-logical-imm
610 5 ds-reg 0 jit-save-cell
613 3 ds-reg 0 jit-load-cell
614 4 ds-reg cell-size neg jit-load-cell
616 6 5 3 jit-multiply-low
618 5 5 tag-bits get jit-shift-left-logical-imm
619 5 ds-reg cell-size neg jit-save-cell
620 7 ds-reg 0 jit-save-cell
625 ds-reg ds-reg cell-size SUBI
627 3 ds-reg 0 jit-load-cell
628 3 3 jit-shift-tag-bits
629 4 ds-reg cell-size jit-load-cell
632 6 3 4 jit-multiply-low-ov-rc
633 6 ds-reg 0 jit-save-cell
636 4 4 jit-shift-tag-bits
638 "overflow_fixnum_multiply" jit-call
643 3 ds-reg 0 jit-load-cell
644 4 ds-reg cell-size neg jit-load-cell-update
645 4 4 jit-shift-tag-bits
646 5 3 4 jit-multiply-low
647 5 ds-reg 0 jit-save-cell
651 { fixnum- [ [ SUBFO. ] "overflow_fixnum_subtract" jit-overflow ] }
652 { fixnum-fast [ \ SUBF jit-math ] }
656 3 ds-reg 0 jit-load-cell
657 ds-reg ds-reg cell-size SUBI
658 3 3 jit-shift-fixnum-slot
662 3 ds-reg 0 jit-load-cell
663 3 3 jit-shift-fixnum-slot
664 3 rs-reg 3 jit-load-cell-x
665 3 ds-reg 0 jit-save-cell
667 { load-local [ jit->r ] }
672 7 1 lr-save jit-save-cell
674 ! Load callstack object
675 6 ds-reg 0 jit-load-cell
676 ds-reg ds-reg cell-size SUBI
677 ! Get ctx->callstack_bottom
679 3 ctx-reg context-callstack-bottom-offset jit-load-cell
680 ! Get top of callstack object -- 'src' for memcpy
681 4 6 callstack-top-offset ADDI
682 ! Get callstack length, in bytes --- 'len' for memcpy
683 7 callstack-length-offset LI
684 5 6 7 jit-load-cell-x
685 5 5 jit-shift-tag-bits
686 ! Compute new stack pointer -- 'dst' for memcpy
688 ! Install new stack pointer
690 ! Call memcpy; arguments are now in the correct registers
691 1 1 -16 cell-size * jit-save-cell-update
692 "factor_memcpy" jit-call
694 ! Return with new callstack
695 0 1 lr-save jit-load-cell
702 3 ds-reg 0 jit-load-cell ! Load m
703 4 ds-reg cell-size neg jit-load-cell-update ! Load obj
704 3 3 jit-shift-fixnum-slot ! Shift to a cell-size multiple
705 4 4 jit-mask-tag-bits ! Clear tag bits on obj
706 3 4 3 jit-load-cell-x ! Load cell at &obj[m]
707 3 ds-reg 0 jit-save-cell ! Push the result to the stack
710 ! load string index from stack
711 3 ds-reg cell-size neg jit-load-cell
712 3 3 jit-shift-tag-bits
713 ! load string from stack
714 4 ds-reg 0 jit-load-cell
716 4 4 string-offset ADDI
718 3 3 tag-bits get jit-shift-left-logical-imm
719 ! store character to stack
720 ds-reg ds-reg cell-size SUBI
721 3 ds-reg 0 jit-save-cell
724 3 ds-reg 0 jit-load-cell
725 3 3 tag-mask get ANDI.
726 3 3 tag-bits get jit-shift-left-logical-imm
727 3 ds-reg 0 jit-save-cell
733 { drop [ ds-reg dup cell-size SUBI ] }
734 { 2drop [ ds-reg dup 2 cell-size * SUBI ] }
735 { 3drop [ ds-reg dup 3 cell-size * SUBI ] }
739 3 ds-reg 0 jit-load-cell
740 3 ds-reg cell-size jit-save-cell-update
743 3 ds-reg 0 jit-load-cell
744 4 ds-reg cell-size neg jit-load-cell
745 ds-reg dup 2 cell-size * ADDI
746 3 ds-reg 0 jit-save-cell
747 4 ds-reg cell-size neg jit-save-cell
750 3 ds-reg 0 jit-load-cell
751 4 ds-reg cell-size neg jit-load-cell
752 5 ds-reg cell-size neg 2 * jit-load-cell
753 ds-reg dup cell-size 3 * ADDI
754 3 ds-reg 0 jit-save-cell
755 4 ds-reg cell-size neg jit-save-cell
756 5 ds-reg cell-size neg 2 * jit-save-cell
759 3 ds-reg 0 jit-load-cell
760 4 ds-reg cell-size neg jit-load-cell
761 4 ds-reg 0 jit-save-cell
762 3 ds-reg cell-size jit-save-cell-update
767 3 ds-reg cell-size neg jit-load-cell
768 3 ds-reg cell-size jit-save-cell-update
771 3 ds-reg cell-size neg 2 * jit-load-cell
772 3 ds-reg cell-size jit-save-cell-update
777 3 ds-reg 0 jit-load-cell
778 ds-reg dup cell-size SUBI
779 3 ds-reg 0 jit-save-cell
782 3 ds-reg 0 jit-load-cell
783 ds-reg dup cell-size 2 * SUBI
784 3 ds-reg 0 jit-save-cell
789 3 ds-reg 0 jit-load-cell
790 4 ds-reg cell-size neg jit-load-cell
791 5 ds-reg cell-size neg 2 * jit-load-cell
792 3 ds-reg cell-size neg 2 * jit-save-cell
793 5 ds-reg cell-size neg jit-save-cell
794 4 ds-reg 0 jit-save-cell
797 3 ds-reg 0 jit-load-cell
798 4 ds-reg cell-size neg jit-load-cell
799 5 ds-reg cell-size neg 2 * jit-load-cell
800 4 ds-reg cell-size neg 2 * jit-save-cell
801 3 ds-reg cell-size neg jit-save-cell
802 5 ds-reg 0 jit-save-cell
805 3 ds-reg 0 jit-load-cell
806 4 ds-reg cell-size neg jit-load-cell
807 3 ds-reg cell-size neg jit-save-cell
808 4 ds-reg 0 jit-save-cell
811 3 ds-reg cell-size neg jit-load-cell
812 4 ds-reg cell-size neg 2 * jit-load-cell
813 3 ds-reg cell-size neg 2 * jit-save-cell
814 4 ds-reg cell-size neg jit-save-cell
816 } define-sub-primitives
818 [ "bootstrap.ppc" forget-vocab ] with-compilation-unit