1 ! Copyright (C) 2020 Doug Coleman.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: bootstrap.image.private compiler.codegen.relocation
4 compiler.constants compiler.units cpu.arm.assembler
5 cpu.arm.assembler.opcodes generic.single.private
6 kernel kernel.private layouts locals.backend
7 math math.private memory namespaces sequences slots.private
8 strings.private threads.private vocabs ;
9 IN: bootstrap.assembler.arm
16 ! https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling?view=vs-2019
18 ! x0 Volatile Parameter/scratch register 1, result register
19 ! x1-x7 Volatile Parameter/scratch register 2-8
20 ! x8-x15 Volatile Scratch registers
21 ! x16-x17 Volatile Intra-procedure-call scratch registers
22 ! x18 Non-volatile Platform register: in kernel mode, points to KPCR for the current processor;
23 ! in user mode, points to TEB
24 ! x19-x28 Non-volatile Scratch registers
25 ! x29/fp Non-volatile Frame pointer
26 ! x30/lr Non-volatile Link registers
28 : stack-frame-size ( -- n ) 4 bootstrap-cells ;
29 : volatile-regs ( -- seq ) { X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 } ;
30 : nv-regs ( -- seq ) { X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 } ;
32 ! callee-save = non-volatile aka call-preserved
34 ! x30 is the link register (used to return from subroutines)
35 ! x29 is the frame register
36 ! x19 to x29 are callee-saved
37 ! x18 is the 'platform register', used for some operating-system-specific special purpose,
38 ! or an additional caller-saved register
39 ! x16 and x17 are the Intra-Procedure-call scratch register
40 ! x9 to x15: used to hold local variables (caller saved)
41 ! x8: used to hold indirect return value address
42 ! x0 to x7: used to hold argument values passed to a subroutine, and also hold
43 ! results returned from a subroutine
46 ! https://en.wikichip.org/wiki/arm/aarch64
47 ! Generally, X0 through X18 can corrupt while X19-X29 must be preserved
48 ! Register Role Requirement
49 ! X0 - X7 Parameter/result registers Can Corrupt
50 ! X8 Indirect result location register
51 ! X9 - X15 Temporary registers
52 ! X16 - X17 Intra-procedure call temporary
53 ! X18 Platform register, otherwise temporary, DONT USE
55 ! X19 - X29 Callee-saved register Must preserve
56 ! X29 - frame pointer register, must always be valid
57 ! X30 Link Register Can Corrupt
58 ! 16-byte stack alignment
60 : arg1 ( -- reg ) X0 ;
61 : arg2 ( -- reg ) X1 ;
62 : arg3 ( -- reg ) X2 ;
63 : arg4 ( -- reg ) X3 ;
64 : red-zone-size ( -- n ) 128 ;
66 : shift-arg ( -- reg ) X1 ;
67 : div-arg ( -- reg ) X0 ;
68 : mod-arg ( -- reg ) X2 ;
70 ! caller-saved registers X9-X15
71 ! callee-saved registers X19-X29
72 : temp0 ( -- reg ) X9 ;
73 : temp1 ( -- reg ) X10 ;
74 : temp2 ( -- reg ) X11 ;
75 : temp3 ( -- reg ) X12 ;
79 ! : pic-tail-reg ( -- reg ) RBX ;
80 : return-reg ( -- reg ) X0 ;
81 : stack-reg ( -- reg ) SP ;
82 ! https://developer.arm.com/documentation/dui0801/a/Overview-of-AArch64-state/Link-registers
83 : link-reg ( -- reg ) X30 ; ! LR
84 ! : stack-frame-reg ( -- reg ) X29 ; ! FP
85 : vm-reg ( -- reg ) X28 ;
86 : ds-reg ( -- reg ) X27 ;
87 : rs-reg ( -- reg ) X26 ;
88 ! : ctx-reg ( -- reg ) R12 ;
89 ! : fixnum>slot@ ( -- ) temp0 1 SAR ;
90 ! : rex-length ( -- n ) 1 ;
92 ! rc-absolute-cell is just CONSTANT: 0
93 : jit-call ( name -- )
95 f rc-absolute-cell rel-dlsym
97 ! RAX 0 MOV f rc-absolute-cell rel-dlsym
100 :: jit-call-1arg ( arg1s name -- )
106 :: jit-call-2arg ( arg1s arg2s name -- )
115 ! pic-tail-reg 5 [RIP+] LEA
116 ! 0 JMP f rc-relative rel-word-pic-tail
117 ] JIT-WORD-JUMP jit-define
120 ! no-op on x86-64. in factor contexts vm-reg always contains the
124 : jit-load-context ( -- ) ;
125 ! ctx-reg vm-reg vm-context-offset [+] MOV ;
127 : jit-save-context ( -- ) ;
129 ! The reason for -8 I think is because we are anticipating a CALL
130 ! instruction. After the call instruction, the contexts frame_top
131 ! will point to the origin jump address.
133 ! ctx-reg context-callstack-top-offset [+] R11 MOV
134 ! ctx-reg context-datastack-offset [+] ds-reg MOV
135 ! ctx-reg context-retainstack-offset [+] rs-reg MOV ;
137 ! ctx-reg must already have been loaded
138 : jit-restore-context ( -- ) ;
139 ! ds-reg ctx-reg context-datastack-offset [+] MOV
140 ! rs-reg ctx-reg context-retainstack-offset [+] MOV ;
144 ! ! ctx-reg is preserved across the call because it is non-volatile
147 ! ! call the primitive
149 ! RAX 0 MOV f f rc-absolute-cell rel-dlsym
151 ! jit-restore-context
152 ] JIT-PRIMITIVE jit-define
155 : jit-jump-quot ( -- )
156 quot-entry-point-offset arg1 ADR
158 ! arg1 quot-entry-point-offset [+] JMP ;
160 : jit-call-quot ( -- )
161 quot-entry-point-offset arg1 ADR
163 ! arg1 quot-entry-point-offset [+] CALL ;
165 : signal-handler-save-regs ( -- regs ) { } ;
166 ! { RAX RCX RDX RBX RBP RSI RDI R8 R9 R10 R11 R12 R13 R14 R15 } ;
170 ! temp2 0 MOV f rc-absolute-cell rel-literal
172 ] PIC-CHECK-TUPLE jit-define
177 1 bootstrap-cells rs-reg rs-reg ADDi64
178 -1 bootstrap-cells ds-reg rs-reg LDR-post ;
181 1 bootstrap-cells ds-reg ds-reg ADDi64
182 -1 bootstrap-cells rs-reg ds-reg LDR-post ;
185 1 bootstrap-cells rs-reg rs-reg ADDi64
186 -1 bootstrap-cells ds-reg rs-reg LDR-post
187 1 bootstrap-cells rs-reg rs-reg ADDi64
188 -1 bootstrap-cells ds-reg rs-reg LDR-post ;
191 1 bootstrap-cells ds-reg ds-reg ADDi64
192 -1 bootstrap-cells rs-reg ds-reg LDR-post
193 1 bootstrap-cells ds-reg ds-reg ADDi64
194 -1 bootstrap-cells rs-reg ds-reg LDR-post ;
197 1 bootstrap-cells rs-reg rs-reg ADDi64
198 -1 bootstrap-cells ds-reg rs-reg LDR-post
199 1 bootstrap-cells rs-reg rs-reg ADDi64
200 -1 bootstrap-cells ds-reg rs-reg LDR-post
201 1 bootstrap-cells rs-reg rs-reg ADDi64
202 -1 bootstrap-cells ds-reg rs-reg LDR-post ;
205 1 bootstrap-cells ds-reg ds-reg ADDi64
206 -1 bootstrap-cells rs-reg ds-reg LDR-post
207 1 bootstrap-cells ds-reg ds-reg ADDi64
208 -1 bootstrap-cells rs-reg ds-reg LDR-post
209 1 bootstrap-cells ds-reg ds-reg ADDi64
210 -1 bootstrap-cells rs-reg ds-reg LDR-post ;
213 : jit-switch-context ( reg -- ) drop ;
214 ! ! Push a bogus return address so the GC can track this frame back
218 ! ! Make the new context the current one
220 ! vm-reg vm-context-offset [+] ctx-reg MOV
222 ! ! Load new stack pointer
223 ! RSP ctx-reg context-callstack-top-offset [+] MOV
225 ! ! Load new ds, rs registers
226 ! jit-restore-context
228 ! ctx-reg jit-update-tib ;
230 : jit-pop-context-and-param ( -- ) ;
232 ! arg1 arg1 alien-offset [+] MOV
233 ! arg2 ds-reg -8 [+] MOV
236 : jit-push-param ( -- ) ;
238 ! ds-reg [] arg2 MOV ;
240 : jit-set-context ( -- ) ;
241 ! jit-pop-context-and-param
243 ! arg1 jit-switch-context
247 : jit-pop-quot-and-param ( -- ) ;
249 ! arg2 ds-reg -8 [+] MOV
252 : jit-start-context ( -- ) ;
253 ! Create the new context in return-reg. Have to save context
254 ! twice, first before calling new_context() which may GC,
255 ! and again after popping the two parameters from the stack.
257 ! vm-reg "new_context" jit-call-1arg
259 ! jit-pop-quot-and-param
261 ! return-reg jit-switch-context
265 : jit-delete-current-context ( -- ) ;
266 ! vm-reg "delete_context" jit-call-1arg ;
270 ! 0 CALL f rc-relative rel-word
278 ! 0 [RIP+] EAX MOV rc-relative rel-safepoint
279 ] JIT-SAFEPOINT jit-define
281 ! # All arm.64 subprimitives
297 ! Rn Rd MOVr64 ! comment
299 vm-reg "begin_callback" jit-call-1arg
301 return-reg arg1 MOVr64 ! arg1 is return
304 vm-reg "end_callback" jit-call-1arg
306 } define-sub-primitives
311 ! { (set-context) [ jit-set-context ] }
312 ! { (set-context-and-delete) [
313 ! jit-delete-current-context
316 ! { (start-context) [ jit-start-context ] }
317 ! { (start-context-and-delete) [ jit-start-context-and-delete ] }
323 ! ! vm-reg "begin_callback" jit-call-1arg
325 ! ! ! call the quotation
326 ! ! arg1 return-reg MOV
329 ! ! vm-reg "end_callback" jit-call-1arg
348 ! ! vm-reg "begin_callback" jit-call-1arg
350 ! ! return-reg arg1 MOVr64 ! arg1 is return
353 ! ! vm-reg "end_callback" jit-call-1arg
358 ! { unwind-native-frames [ ] }
361 ! { fixnum+ [ [ ADD ] "overflow_fixnum_add" jit-overflow ] }
362 ! { fixnum- [ [ SUB ] "overflow_fixnum_subtract" jit-overflow ] }
367 ! RBX ds-reg 8 [+] MOV
368 ! RBX tag-bits get SAR
375 ! arg1 tag-bits get SAR
378 ! "overflow_fixnum_multiply" jit-call
393 ! RSP [] arg1 16-bit-version-of MOV
398 ! ! Load callstack object
400 ! ds-reg bootstrap-cell SUB
401 ! ! Get ctx->callstack_bottom
403 ! arg1 ctx-reg context-callstack-bottom-offset [+] MOV
404 ! ! Get top of callstack object -- 'src' for memcpy
405 ! arg2 arg4 callstack-top-offset [+] LEA
406 ! ! Get callstack length, in bytes --- 'len' for memcpy
407 ! arg3 arg4 callstack-length-offset [+] MOV
408 ! arg3 tag-bits get SHR
409 ! ! Compute new stack pointer -- 'dst' for memcpy
411 ! ! Install new stack pointer
413 ! ! Call memcpy; arguments are now in the correct registers
414 ! ! Create register shadow area for Win64
416 ! "factor_memcpy" jit-call
417 ! ! Tear down register shadow area
419 ! ! Return with new callstack
422 ! } define-sub-primitives
426 ! C to Factor entry point
428 ! ! Optimizing compiler's side of callback accesses
429 ! ! arguments that are on the stack via the frame pointer.
430 ! ! On x86-32 fastcall, and x86-64, some arguments are passed
431 ! ! in registers, and so the only registers that are safe for
432 ! ! use here are frame-reg, nv-reg and vm-reg.
434 ! frame-reg stack-reg MOV
436 ! ! Save all non-volatile registers
437 ! nv-regs [ PUSH ] each
441 ! ! Load VM into vm-reg
442 ! vm-reg 0 MOV 0 rc-absolute-cell rel-vm
445 ! nv-reg vm-reg vm-context-offset [+] MOV
448 ! ! Switch over to the spare context
449 ! nv-reg vm-reg vm-spare-context-offset [+] MOV
450 ! vm-reg vm-context-offset [+] nv-reg MOV
452 ! ! Save C callstack pointer
453 ! nv-reg context-callstack-save-offset [+] stack-reg MOV
455 ! ! Load Factor stack pointers
456 ! stack-reg nv-reg context-callstack-bottom-offset [+] MOV
457 ! nv-reg jit-update-tib
460 ! rs-reg nv-reg context-retainstack-offset [+] MOV
461 ! ds-reg nv-reg context-datastack-offset [+] MOV
463 ! ! Call into Factor code
464 ! link-reg 0 MOV f rc-absolute-cell rel-word
467 ! ! Load VM into vm-reg; only needed on x86-32, but doesn't
469 ! vm-reg 0 MOV 0 rc-absolute-cell rel-vm
471 ! ! Load C callstack pointer
472 ! nv-reg vm-reg vm-context-offset [+] MOV
473 ! stack-reg nv-reg context-callstack-save-offset [+] MOV
477 ! vm-reg vm-context-offset [+] nv-reg MOV
479 ! ! Restore non-volatile registers
482 ! nv-regs <reversed> [ POP ] each
486 ! ! Callbacks which return structs, or use stdcall/fastcall/thiscall,
487 ! ! need a parameter here.
489 ! ! See the comment for M\ x86.32 stack-cleanup in cpu.x86.32
490 ! 0xffff RET f rc-absolute-2 rel-untagged
491 ] CALLBACK-STUB jit-define
495 ! temp0 0 MOV f rc-absolute-cell rel-literal
496 ! ! increment datastack pointer
497 ! ds-reg bootstrap-cell ADD
498 ! ! store literal on datastack
499 ! ds-reg [] temp0 MOV
500 ] JIT-PUSH-LITERAL jit-define
503 ! 0 CALL f rc-relative rel-word-pic
504 ] JIT-WORD-CALL jit-define
506 ! The *-signal-handler subprimitives are special-cased in vm/quotations.cpp
507 ! not to trigger generation of a stack frame, so they can
508 ! peform their own prolog/epilog preserving registers.
510 ! It is important that the total is 192/64 and that it matches the
511 ! constants in vm/cpu-x86.*.hpp
512 : jit-signal-handler-prolog ( -- ) ;
513 ! ! Return address already on stack -> 8/4 bytes.
515 ! ! Push all registers. 15 regs/120 bytes on 64bit, 7 regs/28 bytes
516 ! ! on 32bit -> 128/32 bytes.
517 ! signal-handler-save-regs [ PUSH ] each
519 ! ! Push flags -> 136/36 bytes
522 ! ! Register parameter area 32 bytes, unused on platforms other than
523 ! ! windows 64 bit, but including it doesn't hurt. Plus
524 ! ! alignment. LEA used so we don't dirty flags -> 192/64 bytes.
525 ! stack-reg stack-reg 7 bootstrap-cells neg [+] LEA
529 : jit-signal-handler-epilog ( -- ) ;
530 ! stack-reg stack-reg 7 bootstrap-cells [+] LEA
532 ! signal-handler-save-regs reverse [ POP ] each ;
536 ! temp0 ds-reg [] MOV
538 ! ds-reg bootstrap-cell SUB
539 ! ! compare boolean with f
540 ! temp0 \ f type-number CMP
541 ! ! jump to true branch if not equal
542 ! 0 JNE f rc-relative rel-word
543 ! ! jump to false branch if equal
544 ! 0 JMP f rc-relative rel-word
550 ! 0 CALL f rc-relative rel-word
556 ! 0 CALL f rc-relative rel-word
558 ] JIT-2DIP jit-define
562 ! 0 CALL f rc-relative rel-word
564 ] JIT-3DIP jit-define
568 ! temp0 ds-reg [] MOV
570 ! ds-reg bootstrap-cell SUB
572 ! [ temp0 word-entry-point-offset [+] CALL ]
573 ! [ temp0 word-entry-point-offset [+] JMP ]
574 ! \ (execute) define-combinator-primitive
577 ! temp0 ds-reg [] MOV
578 ! ds-reg bootstrap-cell SUB
579 ! temp0 word-entry-point-offset [+] JMP
580 ] JIT-EXECUTE jit-define
583 ! stack-reg stack-framrcee-size bootstrap-cell - SUB
584 stack-frame-size bootstrap-cell - stack-reg stack-reg SUBi64
585 ] JIT-PROLOG jit-define
588 ! stack-reg stack-frame-size bootstrap-cell - ADD
589 ] JIT-EPILOG jit-define
593 ] JIT-RETURN jit-define
595 ! ! ! Polymorphic inline caches
597 ! The PIC stubs are not permitted to touch pic-tail-reg.
599 ! Load a value from a stack position
601 ! temp1 ds-reg 0x7f [+] MOV f rc-absolute-1 rel-untagged
602 ] PIC-LOAD jit-define
605 ! temp1/32 tag-mask get AND
610 ! temp1/32 tag-mask get AND
611 ! temp1/32 tuple type-number CMP
613 ! [ temp1 temp0 tuple-class-offset [+] MOV ]
615 ] PIC-TUPLE jit-define
618 ! temp1/32 0x7f CMP f rc-absolute-1 rel-untagged
619 ] PIC-CHECK-TAG jit-define
622 ! 0 JE f rc-relative rel-word
625 ! ! ! Megamorphic caches
630 ! temp1/32 tag-mask get AND
631 ! temp1/32 tag-bits get SHL
632 ! temp1/32 tuple type-number tag-fixnum CMP
634 ! [ temp1 temp0 tuple-class-offset [+] MOV ]
637 ! temp0 0 MOV f rc-absolute-cell rel-literal
638 ! ! key = hashcode(class)
640 ! bootstrap-cell 4 = [ temp2 1 SHR ] when
641 ! ! key &= cache.length - 1
642 ! temp2 mega-cache-size get 1 - bootstrap-cell * AND
643 ! ! cache += array-start-offset
644 ! temp0 array-start-offset ADD
647 ! ! if(get(cache) == class)
651 ! ! megamorphic_cache_hits++
652 ! temp1 0 MOV rc-absolute-cell rel-megamorphic-cache-hits
654 ! ! goto get(cache + bootstrap-cell)
655 ! temp0 temp0 bootstrap-cell [+] MOV
656 ! temp0 word-entry-point-offset [+] JMP
657 ! ! fall-through on miss
659 ] MEGA-LOOKUP jit-define
662 : jit-compare ( insn -- ) drop ;
664 ! temp3 0 MOV t rc-absolute-cell rel-literal
666 ! temp1 \ f type-number MOV
668 ! temp0 ds-reg [] MOV
669 ! ! adjust stack pointer
670 ! ds-reg bootstrap-cell SUB
671 ! ! compare with second value
672 ! ds-reg [] temp0 CMP
674 ! [ temp1 temp3 ] dip execute( dst src -- )
676 ! ds-reg [] temp1 MOV ;
679 : jit-math ( insn -- ) drop ;
680 ! ! load second input
681 ! temp0 ds-reg [] MOV
683 ! ds-reg bootstrap-cell SUB
685 ! [ ds-reg [] temp0 ] dip execute( dst src -- ) ;
687 : jit-fixnum-/mod ( -- ) ;
688 ! ! load second parameter
689 ! temp1 ds-reg [] MOV
690 ! ! load first parameter
691 ! div-arg ds-reg bootstrap-cell neg [+] MOV
693 ! mod-arg div-arg MOV
695 ! mod-arg bootstrap-cell-bits 1 - SAR
699 ! # Rest of arm64 subprimitives
704 ! { fixnum+fast [ \ ADD jit-math ] }
707 ! { fixnum-bitand [ \ AND jit-math ] }
712 ! ds-reg [] tag-mask get XOR
714 ! { fixnum-bitor [ \ OR jit-math ] }
715 ! { fixnum-bitxor [ \ XOR jit-math ] }
716 ! { fixnum-shift-fast [
718 ! shift-arg ds-reg [] MOV
719 ! ! untag shift count
720 ! shift-arg tag-bits get SAR
721 ! ! adjust stack pointer
722 ! ds-reg bootstrap-cell SUB
724 ! temp3 ds-reg [] MOV
727 ! ! compute positive shift value in temp2
730 ! ! compute negative shift value in temp3
732 ! temp3 tag-mask get bitnot AND
734 ! ! if shift count was negative, move temp0 to temp2
737 ! ds-reg [] temp2 MOV
742 ! temp0 ds-reg [] MOV
743 ! ds-reg bootstrap-cell SUB
745 ! temp0 tag-mask get TEST
746 ! temp0 \ f type-number MOV
747 ! temp1 1 tag-fixnum MOV
749 ! ds-reg [] temp0 MOV
751 ! { eq? [ \ CMOVE jit-compare ] }
752 ! { fixnum> [ \ CMOVG jit-compare ] }
753 ! { fixnum>= [ \ CMOVGE jit-compare ] }
754 ! { fixnum< [ \ CMOVL jit-compare ] }
755 ! { fixnum<= [ \ CMOVLE jit-compare ] }
760 ! ! adjust stack pointer
761 ! ds-reg bootstrap-cell SUB
763 ! ds-reg [] mod-arg MOV
767 ! ! adjust stack pointer
768 ! ds-reg bootstrap-cell SUB
770 ! div-arg tag-bits get SHL
772 ! ds-reg [] div-arg MOV
774 ! { fixnum/mod-fast [
777 ! div-arg tag-bits get SHL
779 ! ds-reg [] mod-arg MOV
780 ! ds-reg bootstrap-cell neg [+] div-arg MOV
785 ! ! load second input
786 ! temp0 ds-reg [] MOV
788 ! ds-reg bootstrap-cell SUB
790 ! temp1 ds-reg [] MOV
791 ! ! untag second input
792 ! temp0 tag-bits get SAR
796 ! ds-reg [] temp0 MOV
800 ! { fixnum-fast [ \ SUB jit-math ] }
805 ! temp0 ds-reg [] MOV
806 ! ! adjust stack pointer
807 ! ds-reg bootstrap-cell SUB
808 ! ! turn local number into offset
810 ! ! decrement retain stack pointer
814 ! ! load local number
815 ! temp0 ds-reg [] MOV
816 ! ! turn local number into offset
819 ! temp0 rs-reg temp0 [+] MOV
821 ! ds-reg [] temp0 MOV
823 ! { load-local [ jit->r ] }
828 ! temp0 ds-reg [] MOV
829 ! ! adjust stack pointer
830 ! ds-reg bootstrap-cell SUB
832 ! temp1 ds-reg [] MOV
833 ! ! turn slot number into offset
836 ! temp1 tag-bits get SHR
837 ! temp1 tag-bits get SHL
839 ! temp0 temp1 temp0 [+] MOV
841 ! ds-reg [] temp0 MOV
843 ! { string-nth-fast [
844 ! ! load string index from stack
845 ! temp0 ds-reg bootstrap-cell neg [+] MOV
846 ! temp0 tag-bits get SHR
847 ! ! load string from stack
848 ! temp1 ds-reg [] MOV
850 ! temp0 8-bit-version-of temp0 temp1 string-offset [++] MOV
851 ! temp0 temp0 8-bit-version-of MOVZX
852 ! temp0 tag-bits get SHL
853 ! ! store character to stack
854 ! ds-reg bootstrap-cell SUB
855 ! ds-reg [] temp0 MOV
859 ! temp0 ds-reg [] MOV
861 ! temp0/32 tag-mask get AND
863 ! temp0/32 tag-bits get SHL
865 ! ds-reg [] temp0 MOV
871 ! { drop [ ds-reg bootstrap-cell SUB ] }
872 ! { 2drop [ ds-reg 2 bootstrap-cells SUB ] }
873 ! { 3drop [ ds-reg 3 bootstrap-cells SUB ] }
874 ! { 4drop [ ds-reg 4 bootstrap-cells SUB ] }
878 ! temp0 ds-reg [] MOV
879 ! ds-reg bootstrap-cell ADD
880 ! ds-reg [] temp0 MOV
883 ! temp0 ds-reg [] MOV
884 ! temp1 ds-reg bootstrap-cell neg [+] MOV
885 ! ds-reg 2 bootstrap-cells ADD
886 ! ds-reg [] temp0 MOV
887 ! ds-reg bootstrap-cell neg [+] temp1 MOV
890 ! temp0 ds-reg [] MOV
891 ! temp1 ds-reg -1 bootstrap-cells [+] MOV
892 ! temp3 ds-reg -2 bootstrap-cells [+] MOV
893 ! ds-reg 3 bootstrap-cells ADD
894 ! ds-reg [] temp0 MOV
895 ! ds-reg -1 bootstrap-cells [+] temp1 MOV
896 ! ds-reg -2 bootstrap-cells [+] temp3 MOV
899 ! temp0 ds-reg [] MOV
900 ! temp1 ds-reg -1 bootstrap-cells [+] MOV
901 ! temp2 ds-reg -2 bootstrap-cells [+] MOV
902 ! temp3 ds-reg -3 bootstrap-cells [+] MOV
903 ! ds-reg 4 bootstrap-cells ADD
904 ! ds-reg [] temp0 MOV
905 ! ds-reg -1 bootstrap-cells [+] temp1 MOV
906 ! ds-reg -2 bootstrap-cells [+] temp2 MOV
907 ! ds-reg -3 bootstrap-cells [+] temp3 MOV
910 ! temp0 ds-reg [] MOV
911 ! temp1 ds-reg -1 bootstrap-cells [+] MOV
912 ! ds-reg [] temp1 MOV
913 ! ds-reg bootstrap-cell ADD
914 ! ds-reg [] temp0 MOV
917 ! ! ### Misc shufflers
919 ! temp0 ds-reg -1 bootstrap-cells [+] MOV
920 ! ds-reg bootstrap-cell ADD
921 ! ds-reg [] temp0 MOV
924 ! temp0 ds-reg -2 bootstrap-cells [+] MOV
925 ! ds-reg bootstrap-cell ADD
926 ! ds-reg [] temp0 MOV
931 ! temp0 ds-reg [] MOV
932 ! ds-reg bootstrap-cell SUB
933 ! ds-reg [] temp0 MOV
936 ! temp0 ds-reg [] MOV
937 ! ds-reg 2 bootstrap-cells SUB
938 ! ds-reg [] temp0 MOV
943 ! temp0 ds-reg [] MOV
944 ! temp1 ds-reg -1 bootstrap-cells [+] MOV
945 ! temp3 ds-reg -2 bootstrap-cells [+] MOV
946 ! ds-reg -2 bootstrap-cells [+] temp0 MOV
947 ! ds-reg -1 bootstrap-cells [+] temp3 MOV
948 ! ds-reg [] temp1 MOV
951 ! temp0 ds-reg [] MOV
952 ! temp1 ds-reg -1 bootstrap-cells [+] MOV
953 ! temp3 ds-reg -2 bootstrap-cells [+] MOV
954 ! ds-reg -2 bootstrap-cells [+] temp1 MOV
955 ! ds-reg -1 bootstrap-cells [+] temp0 MOV
956 ! ds-reg [] temp3 MOV
959 ! temp0 ds-reg [] MOV
960 ! temp1 ds-reg bootstrap-cell neg [+] MOV
961 ! ds-reg bootstrap-cell neg [+] temp0 MOV
962 ! ds-reg [] temp1 MOV
965 ! temp0 ds-reg -1 bootstrap-cells [+] MOV
966 ! temp1 ds-reg -2 bootstrap-cells [+] MOV
967 ! ds-reg -2 bootstrap-cells [+] temp0 MOV
968 ! ds-reg -1 bootstrap-cells [+] temp1 MOV
971 ! ! ## Signal handling
972 ! { leaf-signal-handler [
973 ! jit-signal-handler-prolog
975 ! temp0 vm-reg vm-signal-handler-addr-offset [+] MOV
977 ! jit-signal-handler-epilog
978 ! ! Pop the fake leaf frame along with our return address
979 ! leaf-stack-frame-size bootstrap-cell - RET
982 ! jit-signal-handler-prolog
984 ! temp0 vm-reg vm-signal-handler-addr-offset [+] MOV
986 ! jit-signal-handler-epilog
989 } define-sub-primitives
991 [ "bootstrap.arm.64" forget-vocab ] with-compilation-unit