]> gitweb.factorcode.org Git - factor.git/commitdiff
ARM64: Finish implementation
authorGiftpflanze <gifti@tools.wmflabs.org>
Sun, 29 Jan 2023 06:40:04 +0000 (06:40 +0000)
committerGiftpflanze <gifti@tools.wmflabs.org>
Sun, 29 Jan 2023 06:46:07 +0000 (06:46 +0000)
basis/bootstrap/assembler/arm.64.factor
basis/cpu/arm/assembler/64/64.factor
basis/cpu/arm/assembler/opcodes/opcodes.factor

index 32f6347d74634117e8bfb97b2abc74fb8c446178..7a49a7531c23dcbf2924e5031e3322fa30ade538 100644 (file)
 ! See https://factorcode.org/license.txt for BSD license.
 USING: bootstrap.image.private compiler.codegen.relocation
 compiler.constants compiler.units cpu.arm.assembler
-cpu.arm.assembler.64 cpu.arm.assembler.opcodes kernel
-kernel.private layouts math namespaces vocabs ;
+cpu.arm.assembler.64 cpu.arm.assembler.opcodes
+generic.single.private kernel kernel.private layouts
+locals.backend math math.private namespaces slots.private
+strings.private threads.private vocabs ;
 IN: bootstrap.assembler.arm
 
 8 \ cell set
 
 big-endian off
 
-! Stack frame
-! https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling?view=vs-2019
+! X0-X17  volatile     scratch registers
+! X0-X8                parameter registers
+! X0                   result register
+! X16-X17              intra-procedure-call registers
+! X18-X29 non-volatile scratch registers
+! X18                  platform register (TEB pointer under Windows)
+! X29/FP               frame pointer
+! X30/LR  non-volatile link register
 
-! x0   Volatile        Parameter/scratch register 1, result register
-! x1-x7        Volatile        Parameter/scratch register 2-8
-! x8-x15       Volatile        Scratch registers
-! x16-x17      Volatile        Intra-procedure-call scratch registers
-! x18  Non-volatile    Platform register: in kernel mode, points to KPCR for the current processor;
-!   in user mode, points to TEB
-! x19-x28      Non-volatile    Scratch registers
-! x29/fp       Non-volatile    Frame pointer
-! x30/lr       Non-volatile    Link register
-
-! varargs https://developer.arm.com/documentation/ihi0055/d/?lang=en
+: words ( n -- n ) 4 * ;
 : stack-frame-size ( -- n ) 8 bootstrap-cells ;
-: volatile-regs ( -- seq ) { X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 } ;
-! windows arm - X18 is non-volatile https://docs.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions?view=msvc-160
-: nv-regs ( -- seq ) { X18 X19 X20 X21 X22 X23 X24 X25 X26 X27 X28 X29 X30 } ;
-
-! callee-save = non-volatile aka call-preserved
-
-! x30 is the link register (used to return from subroutines)
-! x29 is the frame register
-! x19 to x29 are callee-saved
-! x18 is the 'platform register', used for some operating-system-specific special purpose,
-!   or an additional caller-saved register
-! x16 and x17 are the Intra-Procedure-call scratch register
-! x9 to x15: used to hold local variables (caller saved)
-! x8: used to hold indirect return value address
-! x0 to x7: used to hold argument values passed to a subroutine, and also hold
-!   results returned from a subroutine
-
-! https://en.wikichip.org/wiki/arm/aarch64
-! Generally, X0 through X18 (volatile, can corrupt) while X19-X29 must be preserved (non-volatile)
-! Volatile registers' content may change over a subroutine call
-! non-volatile register is a type of register with contents that must be preserved over subroutine calls
-! Register   Role    Requirement
-! X0 -  X7   Parameter/result registers   Can Corrupt (volatile)
-! X8         Indirect result location register (volatile)
-! X9 -  X15  Temporary registers (volatile)
-! X16 - X17  Intra-procedure call temporary (volatile)
-! X16 - syscall reg with SVC instruction
-! X18        Platform register, otherwise temporary, DONT USE (volatile)
-
-! X19 - X29    Callee-saved register    Must preserve (non-volatile)
-! X29 - frame pointer register, must always be valid
-! X30    Link Register LR   Can Corrupt
-! X31  Stack Pointer SP
-! 16-byte stack alignment
-
-! stack walking - {fp, lr} pairs if compiled with frame pointers enabled
 
+: return-reg ( -- reg ) X0 ;
 : arg1 ( -- reg ) X0 ;
 : arg2 ( -- reg ) X1 ;
 : arg3 ( -- reg ) X2 ;
 : arg4 ( -- reg ) X3 ;
-
-! Red zone
-! windows arm64: 16 bytes https://devblogs.microsoft.com/oldnewthing/20190111-00/?p=100685
-! windows arm32: 8 bytes
-! x86/x64: 0 bytes
-! Apple arm64: 128 bytes https://developer.apple.com/documentation/xcode/writing_arm64_code_for_apple_platforms?language=objc
-: red-zone-size ( -- n ) 16 ; ! 16 bytes on windows, or 128 bytes on linux? or 0?
-! 0 or 16 likely
-! no red zone on x86/x64 windows
-
-! https://github.com/MicrosoftDocs/cpp-docs/blob/master/docs/build/arm64-windows-abi-conventions.md
-
-: shift-arg ( -- reg ) X1 ;
-: div-arg ( -- reg ) X0 ;
-: mod-arg ( -- reg ) X2 ;
-
-! caller-saved registers X9-X15
-! callee-saved registers X19-X29
 : temp0 ( -- reg ) X9 ;
 : temp1 ( -- reg ) X10 ;
 : temp2 ( -- reg ) X11 ;
 : temp3 ( -- reg ) X12 ;
-
-: return-reg ( -- reg ) X0 ;
 : stack-reg ( -- reg ) SP ;
-! https://developer.arm.com/documentation/dui0801/a/Overview-of-AArch64-state/Link-registers
 : link-reg ( -- reg ) X30 ; ! LR
 : stack-frame-reg ( -- reg ) X29 ; ! FP
 : vm-reg ( -- reg ) X28 ;
 : ds-reg ( -- reg ) X27 ;
 : rs-reg ( -- reg ) X26 ;
 : ctx-reg ( -- reg ) X25 ;
-: pic-tail-reg ( -- reg ) X24 ;
-! : fixnum>slot@ ( -- ) temp0 1 SAR ;
-! : rex-length ( -- n ) 1 ;
+
+: push-link-reg ( -- ) -16 stack-reg link-reg STRpre ;
+: pop-link-reg ( -- ) 16 stack-reg link-reg LDRpost ;
+
+: load0 ( -- ) 0 ds-reg temp0 LDRuoff ;
+: load1/0 ( -- ) -8 ds-reg temp0 temp1 LDPsoff ;
+: load2/1 ( -- ) -16 ds-reg temp1 temp2 LDPsoff ;
+: load2/1* ( -- ) -8 ds-reg temp1 temp2 LDPsoff ;
+: load3/2 ( -- ) -24 ds-reg temp2 temp3 LDPsoff ;
+: load-arg1/2 ( -- ) -8 ds-reg arg2 arg1 LDPsoff ;
+
+: ndrop ( n -- ) bootstrap-cells ds-reg dup SUBi ;
+
+: pop0 ( -- ) -8 ds-reg temp0 LDRpost ;
+: popr ( -- ) -8 rs-reg temp0 LDRpost ;
+: pop-arg1 ( -- ) -8 ds-reg arg1 LDRpost ;
+: pop-arg2 ( -- ) -8 ds-reg arg2 LDRpost ;
+
+: push0 ( -- ) 8 ds-reg temp0 STRpre ;
+: push1 ( -- ) 8 ds-reg temp1 STRpre ;
+: push2 ( -- ) 8 ds-reg temp2 STRpre ;
+: push3 ( -- ) 8 ds-reg temp3 STRpre ;
+: pushr ( -- ) 8 rs-reg temp0 STRpre ;
+: push-arg2 ( -- ) 8 ds-reg arg2 STRpre ;
+
+: push-down0 ( n -- ) neg bootstrap-cells ds-reg temp0 STRpre ;
+: push-down-arg3 ( -- ) -8 ds-reg arg3 STRpre ;
+
+: store0 ( -- ) 0 ds-reg temp0 STRuoff ;
+: store1 ( -- ) 0 ds-reg temp1 STRuoff ;
+: store0/1 ( -- ) -8 ds-reg temp1 temp0 STPsoff ;
+: store0/2 ( -- ) -8 ds-reg temp2 temp0 STPsoff ;
+: store1/0 ( -- ) -8 ds-reg temp0 temp1 STPsoff ;
+: store1/2 ( -- ) -16 ds-reg temp2 temp1 STPsoff ;
+
+:: tag ( reg -- ) tag-bits get reg reg LSLi ;
+:: untag ( reg -- ) tag-bits get reg reg ASRi ;
+: tagged>offset ( -- ) 1 temp0 temp0 ASRi ;
+
+: >r ( -- ) pop0 pushr ;
+: r> ( -- ) popr push0 ;
 
 : jit-call ( name -- )
     ! RAX 0 MOV f rc-absolute-cell rel-dlsym
     ! RAX CALL ;
-    12 temp0 LDRl
+    push-link-reg
+    3 words temp0 LDRl
     temp0 BLR
-    12 Br
-    NOP NOP f rc-absolute-cell rel-dlsym ;
+    3 words Br
+    NOP NOP f rc-absolute-cell rel-dlsym
+    pop-link-reg ;
 
 :: jit-call-1arg ( arg1s name -- )
     ! arg1 arg1s MOVr
@@ -128,7 +110,11 @@ big-endian off
 [
     ! pic-tail-reg 5 [RIP+] LEA
     ! 0 JMP f rc-relative rel-word-pic-tail
-    f RET
+    4 words temp0 LDRl32
+    4 words temp1 ADR
+    temp1 temp0 temp0 ADDr
+    temp0 BR
+    NOP f rc-relative rel-word-pic-tail
 ] JIT-WORD-JUMP jit-define
 
 : jit-load-vm ( -- ) ;
@@ -145,7 +131,7 @@ big-endian off
     ! R11 RSP -8 [+] LEA
     ! ctx-reg context-callstack-top-offset [+] R11 MOV
     stack-reg temp0 MOVsp
-    -8 temp0 temp0 SUBi
+    16 temp0 temp0 SUBi
     context-callstack-top-offset ctx-reg temp0 STRuoff
     ! ctx-reg context-datastack-offset [+] ds-reg MOV
     ! ctx-reg context-retainstack-offset [+] rs-reg MOV ;
@@ -160,6 +146,7 @@ big-endian off
     context-retainstack-offset ctx-reg rs-reg LDRuoff ;
 
 [
+    push-link-reg
     ! ! ctx-reg is preserved across the call because it is non-volatile
     ! ! in the C ABI
     jit-save-context
@@ -168,73 +155,109 @@ big-endian off
     ! RAX 0 MOV f f rc-absolute-cell rel-dlsym
     ! RAX CALL
     vm-reg arg1 MOVr
-    12 temp0 LDRl
+    3 words temp0 LDRl
     temp0 BLR
-    12 Br
+    3 words Br
     NOP NOP f f rc-absolute-cell rel-dlsym
     jit-restore-context
+    pop-link-reg
 ] JIT-PRIMITIVE jit-define
 
 : jit-jump-quot ( -- )
+    ! arg1 quot-entry-point-offset [+] JMP ;
     quot-entry-point-offset arg1 temp0 LDRpre
     temp0 BR ;
-    ! arg1 quot-entry-point-offset [+] JMP ;
 
 : jit-call-quot ( -- )
-    quot-entry-point-offset arg1 temp0 LDRpre
-    temp0 BLR ;
     ! arg1 quot-entry-point-offset [+] CALL ;
-
-: signal-handler-save-regs ( -- regs ) { } ;
-    ! { RAX RCX RDX RBX RBP RSI RDI R8 R9 R10 R11 R12 R13 R14 R15 } ;
+    push-link-reg
+    quot-entry-point-offset arg1 temp0 LDRpre
+    temp0 BLR
+    pop-link-reg ;
 
 [
     ! temp2 0 MOV f rc-absolute-cell rel-literal
     ! temp1 temp2 CMP
+    3 words temp2 LDRl
+    temp2 temp1 CMPr
+    3 words Br
+    NOP NOP f rc-absolute-cell rel-literal
 ] PIC-CHECK-TUPLE jit-define
 
-: jit->r ( -- )
-    -8 ds-reg temp0 LDRpost
-    8 rs-reg temp0 STRpre ;
-
-: jit-r> ( -- )
-    -8 rs-reg temp0 LDRpost
-    8 ds-reg temp0 STRpre ;
-
-: jit-2>r ( -- )
-    -8 ds-reg temp0 LDRpost
-    -8 ds-reg temp1 LDRpost
-    8 rs-reg temp1 STRpre
-    8 rs-reg temp0 STRpre ;
-
-: jit-2r> ( -- )
-    -8 rs-reg temp0 LDRpost
-    -8 rs-reg temp1 LDRpost
-    8 ds-reg temp1 STRpre
-    8 ds-reg temp0 STRpre ;
-
-: jit-3>r ( -- )
-    -8 ds-reg temp0 LDRpost
-    -8 ds-reg temp1 LDRpost
-    -8 ds-reg temp2 LDRpost
-    8 rs-reg temp2 STRpre
-    8 rs-reg temp1 STRpre
-    8 rs-reg temp0 STRpre ;
-
-: jit-3r> ( -- )
-    -8 rs-reg temp0 LDRpost
-    -8 rs-reg temp1 LDRpost
-    -8 rs-reg temp2 LDRpost
-    8 ds-reg temp2 STRpre
-    8 ds-reg temp1 STRpre
-    8 ds-reg temp0 STRpre ;
+! Inline cache miss entry points
+: jit-load-return-address ( -- )
+    ! RBX RSP stack-frame-size bootstrap-cell - [+] MOV ;
+    stack-frame-size bootstrap-cell - stack-reg arg1 LDRuoff ;
+
+! 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
+    ! arg1 RBX MOV
+    ! arg2 vm-reg MOV
+    vm-reg arg2 MOVr
+    ! RAX 0 MOV rc-absolute-cell rel-inline-cache-miss
+    ! RAX CALL
+    5 words temp0 LDRl
+    push-link-reg
+    temp0 BLR
+    pop-link-reg
+    3 words Br
+    NOP NOP rc-absolute-cell rel-inline-cache-miss
+    jit-load-context
+    jit-restore-context ;
+
+[ jit-load-return-address jit-inline-cache-miss ]
+[
+    ! RAX CALL
+    push-link-reg
+    temp0 BLR
+    pop-link-reg
+]
+[
+    ! RAX JMP
+    temp0 BR
+]
+\ inline-cache-miss define-combinator-primitive
+
+[ jit-inline-cache-miss ]
+[
+    ! RAX CALL
+    push-link-reg
+    temp0 BLR
+    pop-link-reg
+]
+[
+    ! RAX JMP
+    temp0 BR
+]
+\ inline-cache-miss-tail define-combinator-primitive
+
+! Overflowing fixnum arithmetic
+: jit-overflow ( insn func -- )
+    ! ds-reg 8 SUB
+    jit-save-context
+    ! arg1 ds-reg [] MOV
+    ! arg2 ds-reg 8 [+] MOV
+    load-arg1/2
+    ! arg3 arg1 MOV
+    ! [ [ arg3 arg2 ] dip call ] dip
+    [ [ arg2 arg1 arg3 ] dip call ] dip
+    ! ds-reg [] arg3 MOV
+    push-down-arg3
+    ! [ JNO ]
+    [ VC B.cond ] [
+        ! arg3 vm-reg MOV
+        vm-reg arg3 MOVr
+        jit-call
+    ] jit-conditional ; inline
 
 ! Contexts
 : jit-switch-context ( reg -- )
     ! ! Push a bogus return address so the GC can track this frame back
     ! ! to the owner
     ! 0 CALL
-    0 BL
+    0 BL ! ?!
 
     ! ! Make the new context the current one
     ! ctx-reg swap MOV
@@ -257,30 +280,29 @@ big-endian off
     ! arg1 arg1 alien-offset [+] MOV
     ! arg2 ds-reg -8 [+] MOV
     ! ds-reg 16 SUB ;
-    -8 ds-reg arg1 LDRpost
+    pop-arg1
     alien-offset arg1 arg1 ADDi
     0 arg1 arg1 LDRuoff
-    -8 ds-reg arg2 LDRpost ;
+    pop-arg2 ;
 
 : jit-push-param ( -- )
     ! ds-reg 8 ADD
     ! ds-reg [] arg2 MOV ;
-    8 ds-reg arg2 STRpre ;
+    push-arg2 ;
 
 : jit-set-context ( -- )
     jit-pop-context-and-param
     jit-save-context
     arg1 jit-switch-context
     ! RSP 8 ADD
-    8 stack-reg stack-reg ADDi
+    16 stack-reg stack-reg ADDi
     jit-push-param ;
 
 : jit-pop-quot-and-param ( -- )
     ! arg1 ds-reg [] MOV
     ! arg2 ds-reg -8 [+] MOV
     ! ds-reg 16 SUB ;
-    -8 ds-reg arg1 LDRpost
-    -8 ds-reg arg2 LDRpost ;
+    pop-arg1 pop-arg2 ;
 
 : jit-start-context ( -- )
     ! Create the new context in return-reg. Have to save context
@@ -314,24 +336,30 @@ big-endian off
     ! Pops the quotation from the stack and puts it in arg1.
     ! arg1 ds-reg [] MOV
     ! ds-reg 8 SUB
+    pop-arg1
 
     ! Jump to quotation arg1
     jit-jump-quot ;
 
 [
     ! 0 [RIP+] EAX MOV rc-relative rel-safepoint
+    4 words temp0 LDRl32
+    4 words temp1 ADR
+    temp1 temp0 W0 STRr32
+    2 words Br
+    NOP rc-relative rel-safepoint
 ] JIT-SAFEPOINT jit-define
 
 ! # All arm.64 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 ] }
+    { (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 [
@@ -342,70 +370,112 @@ big-endian off
 
             vm-reg "end_callback" jit-call-1arg
     ] }
-    ! { unwind-native-frames [ ] }
+    { unwind-native-frames [
+        ! ! unwind-native-frames is marked as "special" in
+        ! ! vm/quotations.cpp so it does not have a standard prolog
+        ! ! Unwind stack frames
+        ! RSP arg2 MOV
+        arg2 stack-reg MOVsp
+        ! ! Load VM pointer into vm-reg, since we're entering from
+        ! ! C code
+        ! vm-reg 0 MOV 0 rc-absolute-cell rel-vm
+        2 words vm-reg LDRl
+        3 words Br
+        NOP NOP 0 rc-absolute-cell rel-vm
+        ! ! Load ds and rs registers
+        jit-load-context
+        jit-restore-context
+        ! ! Clear the fault flag
+        ! vm-reg vm-fault-flag-offset [+] 0 MOV
+        vm-fault-flag-offset vm-reg XZR STRuoff
+        ! ! Call quotation
+        jit-jump-quot
+    ] }
 
     ! ## Math
-    ! { fixnum+ [ [ ADD ] "overflow_fixnum_add" jit-overflow ] }
-    ! { fixnum- [ [ SUB ] "overflow_fixnum_subtract" jit-overflow ] }
-    ! { fixnum* [
-    !     ds-reg 8 SUB
-    !     jit-save-context
-    !     RCX ds-reg [] MOV
-    !     RBX ds-reg 8 [+] MOV
-    !     RBX tag-bits get SAR
-    !     RAX RCX MOV
-    !     RBX IMUL
-    !     ds-reg [] RAX MOV
-    !     [ JNO ]
-    !     [
-    !         arg1 RCX MOV
-    !         arg1 tag-bits get SAR
-    !         arg2 RBX MOV
-    !         arg3 vm-reg MOV
-    !         "overflow_fixnum_multiply" jit-call
-    !     ]
-    !     jit-conditional
-    ! ] }
+    { fixnum+ [ [ ADDr ] "overflow_fixnum_add" jit-overflow ] }
+    { fixnum- [ [ SUBr ] "overflow_fixnum_subtract" jit-overflow ] }
+    { fixnum* [
+        ! ds-reg 8 SUB
+        jit-save-context
+        ! RCX ds-reg [] MOV
+        ! RBX ds-reg 8 [+] MOV
+        load1/0
+        ! RBX tag-bits get SAR
+        temp0 untag
+        ! RAX RCX MOV
+        ! RBX IMUL
+        ! RAX * RBX = RDX:RAX
+        temp1 temp0 temp0 MUL
+        ! ds-reg [] RAX MOV
+        1 push-down0
+        ! [ JNO ]
+        [ VC B.cond ] [
+            ! arg1 RCX MOV
+            temp1 arg1 MOVr
+            ! arg1 tag-bits get SAR
+            temp1 untag
+            ! arg2 RBX MOV
+            temp0 arg2 MOVr
+            ! arg3 vm-reg MOV
+            vm-reg arg3 MOVr
+            "overflow_fixnum_multiply" jit-call
+        ] jit-conditional
+    ] }
 
     ! ## Misc
-    ! { fpu-state [
-    !     RSP 2 SUB
-    !     RSP [] FNSTCW
-    !     FNINIT
-    !     AX RSP [] MOV
-    !     RSP 2 ADD
-    ! ] }
-    ! { set-fpu-state [
-    !     RSP 2 SUB
-    !     RSP [] arg1 16-bit-version-of MOV
-    !     RSP [] FLDCW
-    !     RSP 2 ADD
-    ! ] }
-    ! { set-callstack [
-    !     ! Load callstack object
-    !     arg4 ds-reg [] MOV
-    !     ds-reg bootstrap-cell SUB
-    !     ! Get ctx->callstack_bottom
-    !     jit-load-context
-    !     arg1 ctx-reg context-callstack-bottom-offset [+] MOV
-    !     ! Get top of callstack object -- 'src' for memcpy
-    !     arg2 arg4 callstack-top-offset [+] LEA
-    !     ! Get callstack length, in bytes --- 'len' for memcpy
-    !     arg3 arg4 callstack-length-offset [+] MOV
-    !     arg3 tag-bits get SHR
-    !     ! Compute new stack pointer -- 'dst' for memcpy
-    !     arg1 arg3 SUB
-    !     ! Install new stack pointer
-    !     RSP arg1 MOV
-    !     ! Call memcpy; arguments are now in the correct registers
-    !     ! Create register shadow area for Win64
-    !     RSP 32 SUB
-    !     "factor_memcpy" jit-call
-    !     ! Tear down register shadow area
-    !     RSP 32 ADD
-    !     ! Return with new callstack
-    !     0 RET
-    ! ] }
+    { fpu-state [
+        ! RSP 2 SUB
+        ! RSP [] FNSTCW
+        ! FNINIT
+        ! AX RSP [] MOV
+        ! RSP 2 ADD
+        FPSR XZR MSRr
+        FPCR arg1 MRS
+    ] }
+    { set-fpu-state [
+        ! RSP 2 SUB
+        ! RSP [] arg1 16-bit-version-of MOV
+        ! RSP [] FLDCW
+        ! RSP 2 ADD
+        FPCR arg1 MSRr
+    ] }
+    { set-callstack [
+        ! ! Load callstack object
+        ! arg4 ds-reg [] MOV
+        ! ds-reg bootstrap-cell SUB
+        pop0
+        ! ! Get ctx->callstack_bottom
+        jit-load-context
+        ! arg1 ctx-reg context-callstack-bottom-offset [+] MOV
+        context-callstack-bottom-offset ctx-reg arg1 LDRuoff
+        ! ! Get top of callstack object -- 'src' for memcpy
+        ! arg2 arg4 callstack-top-offset [+] LEA
+        callstack-top-offset temp0 arg2 ADDr
+        ! ! Get callstack length, in bytes --- 'len' for memcpy
+        ! arg3 arg4 callstack-length-offset [+] MOV
+        2 temp0 temp0 SUBi ! callstack-length-offset
+        0 temp0 arg3 LDRuoff
+        ! arg3 tag-bits get SHR
+        tag-bits get arg3 arg3 LSRi
+        ! ! Compute new stack pointer -- 'dst' for memcpy
+        ! arg1 arg3 SUB
+        arg3 arg1 arg1 SUBr
+        ! ! Install new stack pointer
+        ! RSP arg1 MOV
+        arg1 stack-reg MOVsp
+        ! ! Call memcpy; arguments are now in the correct registers
+        ! ! Create register shadow area for Win64
+        ! RSP 32 SUB
+        32 stack-reg stack-reg SUBi
+        "factor_memcpy" jit-call
+        ! ! Tear down register shadow area
+        ! RSP 32 ADD
+        32 stack-reg stack-reg ADDi
+        ! ! Return with new callstack
+        ! 0 RET
+        f RET
+    ] }
 } define-sub-primitives
 
 ! C to Factor entry point
@@ -434,7 +504,9 @@ big-endian off
 
     ! ! Load VM into vm-reg
     ! vm-reg 0 MOV 0 rc-absolute-cell rel-vm
-    104 vm-reg LDRl
+    2 words vm-reg LDRl
+    3 words Br
+    NOP NOP 0 rc-absolute-cell rel-vm
 
     ! ! Save old context
     ! nv-reg vm-reg vm-context-offset [+] MOV
@@ -472,8 +544,10 @@ big-endian off
     ! ! Call into Factor code
     ! link-reg 0 MOV f rc-absolute-cell rel-word
     ! link-reg CALL
-    68 temp0 LDRl
+    3 words temp0 LDRl
     temp0 BLR
+    3 words Br
+    NOP NOP f rc-absolute-cell rel-word
 
     ! ! Load C callstack pointer
     ! nv-reg vm-reg vm-context-offset [+] MOV
@@ -509,23 +583,39 @@ big-endian off
 
     ! ! See the comment for M\ x86.32 stack-cleanup in cpu.x86.32
     ! 0xffff RET f rc-absolute-2 rel-untagged
+    4 words temp0 ADR
+    2 temp0 temp0 LDRHuoff
+    temp0 stack-reg stack-reg ADDr
     f RET
-
-    NOP NOP 0 rc-absolute-cell rel-vm
-    NOP NOP f rc-absolute-cell rel-word
+    NOP f rc-absolute-2 rel-untagged
 ] CALLBACK-STUB jit-define
 
 [
     ! ! load literal
     ! temp0 0 MOV f rc-absolute-cell rel-literal
+    2 words temp0 LDRl
+    3 words Br
+    NOP NOP f rc-absolute-cell rel-literal
     ! ! increment datastack pointer
     ! ds-reg bootstrap-cell ADD
     ! ! store literal on datastack
     ! ds-reg [] temp0 MOV
+    push0
 ] JIT-PUSH-LITERAL jit-define
 
+: call-relative ( -- word class )
+    push-link-reg
+    5 words temp0 LDRl32
+    5 words temp1 ADR
+    temp1 temp0 temp0 ADDr
+    temp0 BLR
+    2 words Br
+    NOP f rc-relative
+    pop-link-reg ;
+
 [
     ! 0 CALL f rc-relative rel-word-pic
+    call-relative rel-word-pic
 ] JIT-WORD-CALL jit-define
 
 ! The *-signal-handler subprimitives are special-cased in vm/quotations.cpp
@@ -534,7 +624,7 @@ big-endian off
 !
 ! It is important that the total is 192/64 and that it matches the
 ! constants in vm/cpu-x86.*.hpp
-: jit-signal-handler-prolog ( -- ) ;
+: jit-signal-handler-prolog ( -- )
     ! ! Return address already on stack -> 8/4 bytes.
 
     ! ! Push all registers. 15 regs/120 bytes on 64bit, 7 regs/28 bytes
@@ -543,64 +633,126 @@ big-endian off
 
     ! ! Push flags -> 136/36 bytes
     ! PUSHF
+    -16 SP X1 X0 STPpre
+    -16 SP X3 X2 STPpre
+    -16 SP X5 X4 STPpre
+    -16 SP X7 X6 STPpre
+    -16 SP X9 X8 STPpre
+    -16 SP X11 X10 STPpre
+    -16 SP X13 X12 STPpre
+    -16 SP X15 X14 STPpre
+    -16 SP X17 X16 STPpre
+    -16 SP X19 X18 STPpre
+    -16 SP X21 X20 STPpre
+    -16 SP X23 X22 STPpre
+    -16 SP X25 X24 STPpre
+    -16 SP X27 X26 STPpre
+    -16 SP X29 X28 STPpre
+    NZCV X0 MRS
+    -16 SP X0 X30 STPpre
 
     ! ! Register parameter area 32 bytes, unused on platforms other than
     ! ! windows 64 bit, but including it doesn't hurt. Plus
     ! ! alignment. LEA used so we don't dirty flags -> 192/64 bytes.
     ! stack-reg stack-reg 7 bootstrap-cells neg [+] LEA
 
-    jit-load-vm ;
+    jit-load-vm ;
 
-: jit-signal-handler-epilog ( -- ) ;
+: jit-signal-handler-epilog ( -- )
     ! stack-reg stack-reg 7 bootstrap-cells [+] LEA
     ! POPF
     ! signal-handler-save-regs reverse [ POP ] each ;
+    16 SP X0 X30 LDPpost
+    NZCV X0 MSRr
+    16 SP X29 X28 LDPpost
+    16 SP X27 X26 LDPpost
+    16 SP X25 X24 LDPpost
+    16 SP X23 X22 LDPpost
+    16 SP X21 X20 LDPpost
+    16 SP X19 X18 LDPpost
+    16 SP X17 X16 LDPpost
+    16 SP X15 X14 LDPpost
+    16 SP X13 X12 LDPpost
+    16 SP X11 X10 LDPpost
+    16 SP X9 X8 LDPpost
+    16 SP X7 X6 LDPpost
+    16 SP X5 X4 LDPpost
+    16 SP X3 X2 LDPpost
+    16 SP X1 X0 LDPpost ;
 
 [
     ! ! load boolean
     ! temp0 ds-reg [] MOV
     ! ! pop boolean
     ! ds-reg bootstrap-cell SUB
+    pop0
     ! ! compare boolean with f
     ! temp0 \ f type-number CMP
+    \ f type-number temp0 CMPi
     ! ! jump to true branch if not equal
     ! 0 JNE f rc-relative rel-word
+    6 words EQ B.cond
+    4 words temp0 LDRl32
+    4 words temp1 ADR
+    temp1 temp0 temp0 ADDr
+    temp0 BR
+    NOP f rc-relative rel-word
     ! ! jump to false branch if equal
     ! 0 JMP f rc-relative rel-word
+    4 words temp0 LDRl32
+    4 words temp1 ADR
+    temp1 temp0 temp0 ADDr
+    temp0 BR
+    NOP f rc-relative rel-word
 ] JIT-IF jit-define
 
 [
-    ! jit->r
+    >r
     ! 0 CALL f rc-relative rel-word
-    ! jit-r>
+    call-relative rel-word
+    r>
 ] JIT-DIP jit-define
 
 [
-    ! jit-2>r
+    >r >r
     ! 0 CALL f rc-relative rel-word
-    ! jit-2r>
+    call-relative rel-word
+    r> r>
 ] JIT-2DIP jit-define
 
 [
-    ! jit-3>r
+    >r >r >r
     ! 0 CALL f rc-relative rel-word
-    ! jit-3r>
+    call-relative rel-word
+    r> r> r>
 ] JIT-3DIP jit-define
 
-! [
-!     ! load from stack
-!     temp0 ds-reg [] MOV
-!     ! pop stack
-!     ds-reg bootstrap-cell SUB
-! ]
-! [ temp0 word-entry-point-offset [+] CALL ]
-! [ temp0 word-entry-point-offset [+] JMP ]
-! \ (execute) define-combinator-primitive
+[
+    ! ! load from stack
+    ! temp0 ds-reg [] MOV
+    ! ! pop stack
+    ! ds-reg bootstrap-cell SUB
+    pop0
+]
+[
+    ! temp0 word-entry-point-offset [+] CALL
+    push-link-reg
+    temp0 BLR
+    pop-link-reg
+]
+[
+    ! temp0 word-entry-point-offset [+] JMP
+    temp0 BR
+]
+\ (execute) define-combinator-primitive
 
 [
     ! temp0 ds-reg [] MOV
     ! ds-reg bootstrap-cell SUB
+    pop0
     ! temp0 word-entry-point-offset [+] JMP
+    word-entry-point-offset temp0 temp0 ADDi
+    temp0 BR
 ] JIT-EXECUTE jit-define
 
 ! https://elixir.bootlin.com/linux/latest/source/arch/arm64/kernel/stacktrace.c#L22
@@ -627,27 +779,51 @@ big-endian off
 ! Load a value from a stack position
 [
     ! temp1 ds-reg 0x7f [+] MOV f rc-absolute-1 rel-untagged
+    4 words temp2 ADR
+    3 temp2 temp2 LDRBuoff
+    temp2 ds-reg temp1 LDRr
+    2 words Br
+    NOP f rc-absolute-1 rel-untagged
 ] PIC-LOAD jit-define
 
 [
     ! temp1/32 tag-mask get AND
+    tag-mask get temp1 temp1 ANDi32
 ] PIC-TAG jit-define
 
 [
     ! temp0 temp1 MOV
+    temp1 temp0 MOVr
     ! temp1/32 tag-mask get AND
+    tag-mask get temp1 temp1 ANDi32
     ! temp1/32 tuple type-number CMP
+    tuple type-number temp1 CMPi
     ! [ JNE ]
     ! [ temp1 temp0 tuple-class-offset [+] MOV ]
-    ! jit-conditional
+    [ NE B.cond ] [
+        ! tuple-class-offset temp0 temp1 LDRuoff
+        1 temp0 temp0 ADDi
+        0 temp0 temp1 LDRuoff
+    ] jit-conditional
 ] PIC-TUPLE jit-define
 
 [
     ! temp1/32 0x7f CMP f rc-absolute-1 rel-untagged
+    4 words temp2 ADR
+    3 temp2 temp2 LDRBuoff
+    temp2 temp1 CMPr
+    2 words Br
+    NOP f rc-absolute-1 rel-untagged
 ] PIC-CHECK-TAG jit-define
 
 [
     ! 0 JE f rc-relative rel-word
+    6 words NE B.cond
+    4 words temp3 LDRl32
+    4 words temp2 ADR
+    temp3 temp2 temp2 ADDr
+    temp2 BR
+    NOP f rc-relative rel-word
 ] PIC-HIT jit-define
 
 ! ! ! Megamorphic caches
@@ -655,365 +831,379 @@ big-endian off
 [
     ! ! class = ...
     ! temp0 temp1 MOV
+    temp1 temp0 MOVr
     ! temp1/32 tag-mask get AND
+    tag-mask get temp1 temp1 ANDi32
     ! temp1/32 tag-bits get SHL
+    temp1 tag
     ! temp1/32 tuple type-number tag-fixnum CMP
+    tuple type-number tag-fixnum temp1 CMPi
     ! [ JNE ]
     ! [ temp1 temp0 tuple-class-offset [+] MOV ]
-    ! jit-conditional
+    [ NE B.cond ] [
+        ! tuple-class-offset temp0 temp1 LDRuoff
+        1 temp0 temp0 ADDi
+        0 temp0 temp1 LDRuoff
+    ] jit-conditional
     ! ! cache = ...
     ! temp0 0 MOV f rc-absolute-cell rel-literal
+    2 words temp0 LDRl
+    3 words Br
+    NOP NOP f rc-absolute-cell rel-literal
     ! ! key = hashcode(class)
     ! temp2 temp1 MOV
-    ! bootstrap-cell 4 = [ temp2 1 SHR ] when
+    temp1 temp2 MOVr
     ! ! key &= cache.length - 1
     ! temp2 mega-cache-size get 1 - bootstrap-cell * AND
+    mega-cache-size get 1 - bootstrap-cells temp2 temp2 ANDi
     ! ! cache += array-start-offset
     ! temp0 array-start-offset ADD
+    array-start-offset temp0 temp0 ADDi
     ! ! cache += key
     ! temp0 temp2 ADD
+    temp2 temp0 temp0 ADDr
     ! ! if(get(cache) == class)
     ! temp0 [] temp1 CMP
+    0 temp0 temp2 LDRuoff
+    temp1 temp2 CMPr
     ! [ JNE ]
-    ! [
-    !     ! megamorphic_cache_hits++
-    !     temp1 0 MOV rc-absolute-cell rel-megamorphic-cache-hits
-    !     temp1 [] 1 ADD
-    !     ! goto get(cache + bootstrap-cell)
-    !     temp0 temp0 bootstrap-cell [+] MOV
-    !     temp0 word-entry-point-offset [+] JMP
-    !     ! fall-through on miss
-    ! ] jit-conditional
+    [ NE B.cond ] [
+        ! ! megamorphic_cache_hits++
+        ! temp1 0 MOV rc-absolute-cell rel-megamorphic-cache-hits
+        2 words temp1 LDRl
+        3 words Br
+        NOP NOP rc-absolute-cell rel-megamorphic-cache-hits
+        ! temp1 [] 1 ADD
+        0 temp1 temp2 LDRuoff
+        1 temp2 temp2 ADDi
+        0 temp1 temp2 STRuoff
+        ! ! goto get(cache + bootstrap-cell)
+        ! temp0 temp0 bootstrap-cell [+] MOV
+        bootstrap-cell temp0 temp0 LDRuoff
+        ! temp0 word-entry-point-offset [+] JMP
+        word-entry-point-offset temp0 temp0 ADDi
+        temp0 BR
+        ! ! fall-through on miss
+    ] jit-conditional
 ] MEGA-LOOKUP jit-define
 
 ! Comparisons
-: jit-compare ( insn -- ) drop ;
+: jit-compare ( cond -- )
     ! ! load t
     ! temp3 0 MOV t rc-absolute-cell rel-literal
+    2 words temp3 LDRl
+    3 words Br
+    NOP NOP t rc-absolute-cell rel-literal
     ! ! load f
     ! temp1 \ f type-number MOV
+    \ f type-number temp2 MOVwi
     ! ! load first value
     ! temp0 ds-reg [] MOV
     ! ! adjust stack pointer
     ! ds-reg bootstrap-cell SUB
+    load1/0
     ! ! compare with second value
     ! ds-reg [] temp0 CMP
+    temp1 temp0 CMPr
     ! ! move t if true
     ! [ temp1 temp3 ] dip execute( dst src -- )
+    [ temp2 temp3 temp0 ] dip CSEL
     ! ! store
-    ! ds-reg [] temp1 MOV ;
+    ! ds-reg [] temp1 MOV
+    1 push-down0 ;
 
 ! Math
-: jit-math ( insn -- ) drop ;
+: jit-math ( insn -- )
     ! ! load second input
     ! temp0 ds-reg [] MOV
     ! ! pop stack
     ! ds-reg bootstrap-cell SUB
+    load1/0
     ! ! compute result
-    ! [ ds-reg [] temp0 ] dip execute( dst src -- ) ;
+    ! [ ds-reg [] temp0 ] dip execute( dst src -- )
+    [ temp0 temp1 temp0 ] dip execute( arg2 arg1 dst -- )
+    1 push-down0 ;
 
-: jit-fixnum-/mod ( -- ) ;
+: jit-fixnum-/mod ( -- )
     ! ! load second parameter
     ! temp1 ds-reg [] MOV
     ! ! load first parameter
     ! div-arg ds-reg bootstrap-cell neg [+] MOV
-    ! ! make a copy
-    ! mod-arg div-arg MOV
-    ! ! sign-extend
-    ! mod-arg bootstrap-cell-bits 1 - SAR
+    load1/0
     ! ! divide
-    ! temp1 IDIV ;
+    temp0 temp1 temp2 SDIV
+    temp1 temp0 temp2 temp0 MSUB ;
 
 ! # Rest of arm64 subprimitives
 {
-    ! ! ## Fixnums
-
-    ! ! ### Add
-    ! { fixnum+fast [ \ ADD jit-math ] }
-
-    ! ! ### Bit stuff
-    ! { fixnum-bitand [ \ AND jit-math ] }
-    ! { fixnum-bitnot [
-    !     ! complement
-    !     ds-reg [] NOT
-    !     ! clear tag bits
-    !     ds-reg [] tag-mask get XOR
-    ! ] }
-    ! { fixnum-bitor [ \ OR jit-math ] }
-    ! { fixnum-bitxor [ \ XOR jit-math ] }
-    ! { fixnum-shift-fast [
-    !     ! load shift count
-    !     shift-arg ds-reg [] MOV
-    !     ! untag shift count
-    !     shift-arg tag-bits get SAR
-    !     ! adjust stack pointer
-    !     ds-reg bootstrap-cell SUB
-    !     ! load value
-    !     temp3 ds-reg [] MOV
-    !     ! make a copy
-    !     temp2 temp3 MOV
-    !     ! compute positive shift value in temp2
-    !     temp2 CL SHL
-    !     shift-arg NEG
-    !     ! compute negative shift value in temp3
-    !     temp3 CL SAR
-    !     temp3 tag-mask get bitnot AND
-    !     shift-arg 0 CMP
-    !     ! if shift count was negative, move temp0 to temp2
-    !     temp2 temp3 CMOVGE
-    !     ! push to stack
-    !     ds-reg [] temp2 MOV
-    ! ] }
-
-    ! ! ### Comparisons
-    ! { both-fixnums? [
-    !     temp0 ds-reg [] MOV
-    !     ds-reg bootstrap-cell SUB
-    !     temp0 ds-reg [] OR
-    !     temp0 tag-mask get TEST
-    !     temp0 \ f type-number MOV
-    !     temp1 1 tag-fixnum MOV
-    !     temp0 temp1 CMOVE
-    !     ds-reg [] temp0 MOV
-    ! ] }
-    ! { eq? [ \ CMOVE jit-compare ] }
-    ! { fixnum> [ \ CMOVG jit-compare ] }
-    ! { fixnum>= [ \ CMOVGE jit-compare ] }
-    ! { fixnum< [ \ CMOVL jit-compare ] }
-    ! { fixnum<= [ \ CMOVLE jit-compare ] }
-
-    ! ! ### Div/mod
-    ! { fixnum-mod [
-    !     jit-fixnum-/mod
-    !     ! adjust stack pointer
-    !     ds-reg bootstrap-cell SUB
-    !     ! push to stack
-    !     ds-reg [] mod-arg MOV
-    ! ] }
-    ! { fixnum/i-fast [
-    !     jit-fixnum-/mod
-    !     ! adjust stack pointer
-    !     ds-reg bootstrap-cell SUB
-    !     ! tag it
-    !     div-arg tag-bits get SHL
-    !     ! push to stack
-    !     ds-reg [] div-arg MOV
-    ! ] }
-    ! { fixnum/mod-fast [
-    !     jit-fixnum-/mod
-    !     ! tag it
-    !     div-arg tag-bits get SHL
-    !     ! push to stack
-    !     ds-reg [] mod-arg MOV
-    !     ds-reg bootstrap-cell neg [+] div-arg MOV
-    ! ] }
-
-    ! ! ### Mul
-    ! { fixnum*fast [
-    !     ! load second input
-    !     temp0 ds-reg [] MOV
-    !     ! pop stack
-    !     ds-reg bootstrap-cell SUB
-    !     ! load first input
-    !     temp1 ds-reg [] MOV
-    !     ! untag second input
-    !     temp0 tag-bits get SAR
-    !     ! multiply
-    !     temp0 temp1 IMUL2
-    !     ! push result
-    !     ds-reg [] temp0 MOV
-    ! ] }
-
-    ! ! ### Sub
-    ! { fixnum-fast [ \ SUB jit-math ] }
-
-    ! ! ## Locals
-    ! { drop-locals [
-    !     ! load local count
-    !     temp0 ds-reg [] MOV
-    !     ! adjust stack pointer
-    !     ds-reg bootstrap-cell SUB
-    !     ! turn local number into offset
-    !     fixnum>slot@
-    !     ! decrement retain stack pointer
-    !     rs-reg temp0 SUB
-    ! ] }
-    ! { get-local [
-    !     ! load local number
-    !     temp0 ds-reg [] MOV
-    !     ! turn local number into offset
-    !     fixnum>slot@
-    !     ! load local value
-    !     temp0 rs-reg temp0 [+] MOV
-    !     ! push to stack
-    !     ds-reg [] temp0 MOV
-    ! ] }
-    ! { load-local [ jit->r ] }
-
-    ! ! ## Objects
-    ! { slot [
-    !     ! load slot number
-    !     temp0 ds-reg [] MOV
-    !     ! adjust stack pointer
-    !     ds-reg bootstrap-cell SUB
-    !     ! load object
-    !     temp1 ds-reg [] MOV
-    !     ! turn slot number into offset
-    !     fixnum>slot@
-    !     ! mask off tag
-    !     temp1 tag-bits get SHR
-    !     temp1 tag-bits get SHL
-    !     ! load slot value
-    !     temp0 temp1 temp0 [+] MOV
-    !     ! push to stack
-    !     ds-reg [] temp0 MOV
-    ! ] }
-    ! { string-nth-fast [
-    !     ! load string index from stack
-    !     temp0 ds-reg bootstrap-cell neg [+] MOV
-    !     temp0 tag-bits get SHR
-    !     ! load string from stack
-    !     temp1 ds-reg [] MOV
-    !     ! load character
-    !     temp0 8-bit-version-of temp0 temp1 string-offset [++] MOV
-    !     temp0 temp0 8-bit-version-of MOVZX
-    !     temp0 tag-bits get SHL
-    !     ! store character to stack
-    !     ds-reg bootstrap-cell SUB
-    !     ds-reg [] temp0 MOV
-    ! ] }
-    ! { tag [
-    !     ! load from stack
-    !     temp0 ds-reg [] MOV
-    !     ! compute tag
-    !     temp0/32 tag-mask get AND
-    !     ! tag the tag
-    !     temp0/32 tag-bits get SHL
-    !     ! push to stack
-    !     ds-reg [] temp0 MOV
-    ! ] }
+    ! ## Fixnums
+
+    ! ### Add
+    { fixnum+fast [ \ ADDr jit-math ] }
+
+    ! ### Bit stuff
+    { fixnum-bitand [ \ ANDr jit-math ] }
+    { fixnum-bitnot [
+        ! ! complement
+        ! ds-reg [] NOT
+        load0
+        temp0 temp0 MVN
+        ! ! clear tag bits
+        ! ds-reg [] tag-mask get XOR
+        tag-mask get temp0 temp0 EORi
+        store0
+    ] }
+    { fixnum-bitor [ \ ORRr jit-math ] }
+    { fixnum-bitxor [ \ EORr jit-math ] }
+    { fixnum-shift-fast [
+        ! ! load shift count
+        ! shift-arg ds-reg [] MOV
+        ! ! adjust stack pointer
+        ! ds-reg bootstrap-cell SUB
+        ! ! load value
+        ! temp3 ds-reg [] MOV
+        load1/0
+        ! ! untag shift count
+        ! shift-arg tag-bits get SAR
+        temp0 untag
+        ! ! make a copy
+        ! temp2 temp3 MOV
+        temp1 temp2 MOVr
+        ! ! compute positive shift value in temp2
+        ! temp2 CL SHL
+        temp0 temp1 temp1 LSLr
+        ! ! compute negative shift value in temp3
+        ! shift-arg NEG
+        temp0 temp0 NEG
+        ! temp3 CL SAR
+        temp0 temp2 temp2 ASRr
+        ! temp3 tag-mask get bitnot AND
+        tag-mask get temp3 MOVwi
+        temp3 temp2 temp3 BIC
+        ! ! if shift count was negative, move temp3 to temp2
+        ! shift-arg 0 CMP
+        ! temp2 temp3 CMOVGE
+        temp2 temp1 temp0 PL CSEL
+        ! ! push to stack
+        ! ds-reg [] temp2 MOV
+        1 push-down0
+    ] }
+
+    ! ### Comparisons
+    { both-fixnums? [
+        ! temp0 ds-reg [] MOV
+        ! ds-reg bootstrap-cell SUB
+        load1/0
+        ! temp0 ds-reg [] OR
+        temp1 temp0 temp0 ORRr
+        ! temp0 tag-mask get TEST
+        tag-mask get temp0 TSTi
+        ! temp0 \ f type-number MOV
+        \ f type-number temp0 MOVwi
+        ! temp1 1 tag-fixnum MOV
+        1 tag-fixnum temp1 MOVwi
+        ! temp0 temp1 CMOVE
+        temp0 temp1 temp0 EQ CSEL
+        ! ds-reg [] temp0 MOV
+        1 push-down0
+    ] }
+    { eq? [ EQ jit-compare ] }
+    { fixnum> [ GT jit-compare ] }
+    { fixnum>= [ GE jit-compare ] }
+    { fixnum< [ LT jit-compare ] }
+    { fixnum<= [ LE jit-compare ] }
+
+    ! ### Div/mod
+    { fixnum-mod [
+        jit-fixnum-/mod
+        ! ! adjust stack pointer
+        ! ds-reg bootstrap-cell SUB
+        ! ! push to stack
+        ! ds-reg [] mod-arg MOV
+        1 push-down0
+    ] }
+    { fixnum/i-fast [
+        jit-fixnum-/mod
+        ! ! adjust stack pointer
+        ! ds-reg bootstrap-cell SUB
+        ! ! tag it
+        ! div-arg tag-bits get SHL
+        tag-bits get temp2 temp0 LSLi
+        ! ! push to stack
+        ! ds-reg [] div-arg MOV
+        1 push-down0
+    ] }
+    { fixnum/mod-fast [
+        jit-fixnum-/mod
+        ! ! tag it
+        ! div-arg tag-bits get SHL
+        temp2 tag
+        ! ! push to stack
+        ! ds-reg [] mod-arg MOV
+        ! ds-reg bootstrap-cell neg [+] div-arg MOV
+        store0/2
+    ] }
+
+    ! ### Mul
+    { fixnum*fast [
+        ! ! load second input
+        ! temp0 ds-reg [] MOV
+        ! ! pop stack
+        ! ds-reg bootstrap-cell SUB
+        ! ! load first input
+        ! temp1 ds-reg [] MOV
+        load1/0
+        ! ! untag second input
+        ! temp0 tag-bits get SAR
+        temp0 untag
+        ! ! multiply
+        ! temp0 temp1 IMUL2
+        temp1 temp0 temp0 MUL
+        ! ! push result
+        ! ds-reg [] temp0 MOV
+        1 push-down0
+    ] }
+
+    ! ### Sub
+    { fixnum-fast [ \ SUBr jit-math ] }
+
+    ! ## Locals
+    { drop-locals [
+        ! ! load local count
+        ! temp0 ds-reg [] MOV
+        ! ! adjust stack pointer
+        ! ds-reg bootstrap-cell SUB
+        pop0
+        ! ! turn local number into offset
+        tagged>offset
+        ! ! decrement retain stack pointer
+        ! rs-reg temp0 SUB
+        temp0 rs-reg rs-reg SUBr
+    ] }
+    { get-local [
+        ! ! load local number
+        ! temp0 ds-reg [] MOV
+        load0
+        ! ! turn local number into offset
+        tagged>offset
+        ! ! load local value
+        ! temp0 rs-reg temp0 [+] MOV
+        temp0 rs-reg temp0 LDRr
+        ! ! push to stack
+        ! ds-reg [] temp0 MOV
+        store0
+    ] }
+    { load-local [ >r ] }
+
+    ! ## Objects
+    { slot [
+        ! ! load slot number
+        ! temp0 ds-reg [] MOV
+        ! ! adjust stack pointer
+        ! ds-reg bootstrap-cell SUB
+        ! ! load object
+        ! temp1 ds-reg [] MOV
+        load1/0
+        ! ! turn slot number into offset
+        tagged>offset
+        ! ! mask off tag
+        ! temp1 tag-bits get SHR
+        temp1 untag
+        ! temp1 tag-bits get SHL
+        temp1 tag
+        ! ! load slot value
+        ! temp0 temp1 temp0 [+] MOV
+        temp1 temp0 temp0 LDRr
+        ! ! push to stack
+        ! ds-reg [] temp0 MOV
+        1 push-down0
+    ] }
+    { string-nth-fast [
+        ! ! load string index from stack
+        ! temp0 ds-reg bootstrap-cell neg [+] MOV
+        ! temp0 tag-bits get SHR
+        ! ! load string from stack
+        ! temp1 ds-reg [] MOV
+        load1/0
+        ! ! load character
+        ! temp0 8-bit-version-of temp0 temp1 string-offset [++] MOV
+        ! temp0 temp0 8-bit-version-of MOVZX
+        ! temp0 tag-bits get SHL
+        temp1 temp0 temp0 LDRBr
+        temp0 tag
+        ! ! store character to stack
+        ! ds-reg bootstrap-cell SUB
+        ! ds-reg [] temp0 MOV
+        1 push-down0
+    ] }
+    { tag [
+        ! ! load from stack
+        ! temp0 ds-reg [] MOV
+        load0
+        ! ! compute tag
+        ! temp0/32 tag-mask get AND
+        tag-mask get temp0 temp0 ANDi32
+        ! ! tag the tag
+        ! temp0/32 tag-bits get SHL
+        temp0 tag
+        ! ! push to stack
+        ! ds-reg [] temp0 MOV
+        store0
+    ] }
 
     ! ! ## Shufflers
 
     ! ! ### Drops
-    ! { drop [ ds-reg bootstrap-cell SUB ] }
-    ! { 2drop [ ds-reg 2 bootstrap-cells SUB ] }
-    ! { 3drop [ ds-reg 3 bootstrap-cells SUB ] }
-    ! { 4drop [ ds-reg 4 bootstrap-cells SUB ] }
+    { drop [ 1 ndrop ] }
+    { 2drop [ 2 ndrop ] }
+    { 3drop [ 3 ndrop ] }
+    { 4drop [ 4 ndrop ] }
 
     ! ! ### Dups
-    ! { dup [
-    !     temp0 ds-reg [] MOV
-    !     ds-reg bootstrap-cell ADD
-    !     ds-reg [] temp0 MOV
-    ! ] }
-    ! { 2dup [
-    !     temp0 ds-reg [] MOV
-    !     temp1 ds-reg bootstrap-cell neg [+] MOV
-    !     ds-reg 2 bootstrap-cells ADD
-    !     ds-reg [] temp0 MOV
-    !     ds-reg bootstrap-cell neg [+] temp1 MOV
-    ! ] }
-    ! { 3dup [
-    !     temp0 ds-reg [] MOV
-    !     temp1 ds-reg -1 bootstrap-cells [+] MOV
-    !     temp3 ds-reg -2 bootstrap-cells [+] MOV
-    !     ds-reg 3 bootstrap-cells ADD
-    !     ds-reg [] temp0 MOV
-    !     ds-reg -1 bootstrap-cells [+] temp1 MOV
-    !     ds-reg -2 bootstrap-cells [+] temp3 MOV
-    ! ] }
-    ! { 4dup [
-    !     temp0 ds-reg [] MOV
-    !     temp1 ds-reg -1 bootstrap-cells [+] MOV
-    !     temp2 ds-reg -2 bootstrap-cells [+] MOV
-    !     temp3 ds-reg -3 bootstrap-cells [+] MOV
-    !     ds-reg 4 bootstrap-cells ADD
-    !     ds-reg [] temp0 MOV
-    !     ds-reg -1 bootstrap-cells [+] temp1 MOV
-    !     ds-reg -2 bootstrap-cells [+] temp2 MOV
-    !     ds-reg -3 bootstrap-cells [+] temp3 MOV
-    ! ] }
-    ! { dupd [
-    !     temp0 ds-reg [] MOV
-    !     temp1 ds-reg -1 bootstrap-cells [+] MOV
-    !     ds-reg [] temp1 MOV
-    !     ds-reg bootstrap-cell ADD
-    !     ds-reg [] temp0 MOV
-    ! ] }
+    { dup [ load0 push0 ] }
+    { 2dup [ load1/0 push1 push0 ] }
+    { 3dup [ load3/2 load1/0 push2 push1 push0 ] }
+    { 4dup [ load3/2 load1/0 push3 push2 push1 push0 ] }
+    { dupd [ load1/0 store1 push0 ] }
 
     ! ! ### Misc shufflers
-    ! { over [
-    !     temp0 ds-reg -1 bootstrap-cells [+] MOV
-    !     ds-reg bootstrap-cell ADD
-    !     ds-reg [] temp0 MOV
-    ! ] }
-    ! { pick [
-    !     temp0 ds-reg -2 bootstrap-cells [+] MOV
-    !     ds-reg bootstrap-cell ADD
-    !     ds-reg [] temp0 MOV
-    ! ] }
+    { over [ load1/0 push1 ] }
+    { pick [ load3/2 push2 ] }
 
     ! ! ### Nips
-    ! { nip [
-    !     temp0 ds-reg [] MOV
-    !     ds-reg bootstrap-cell SUB
-    !     ds-reg [] temp0 MOV
-    ! ] }
-    ! { 2nip [
-    !     temp0 ds-reg [] MOV
-    !     ds-reg 2 bootstrap-cells SUB
-    !     ds-reg [] temp0 MOV
-    ! ] }
+    { nip [ load0 1 push-down0 ] }
+    { 2nip [ load0 2 push-down0 ] }
 
     ! ! ### Swaps
-    ! { -rot [
-    !     temp0 ds-reg [] MOV
-    !     temp1 ds-reg -1 bootstrap-cells [+] MOV
-    !     temp3 ds-reg -2 bootstrap-cells [+] MOV
-    !     ds-reg -2 bootstrap-cells [+] temp0 MOV
-    !     ds-reg -1 bootstrap-cells [+] temp3 MOV
-    !     ds-reg [] temp1 MOV
-    ! ] }
-    ! { rot [
-    !     temp0 ds-reg [] MOV
-    !     temp1 ds-reg -1 bootstrap-cells [+] MOV
-    !     temp3 ds-reg -2 bootstrap-cells [+] MOV
-    !     ds-reg -2 bootstrap-cells [+] temp1 MOV
-    !     ds-reg -1 bootstrap-cells [+] temp0 MOV
-    !     ds-reg [] temp3 MOV
-    ! ] }
-    ! { swap [
-    !     temp0 ds-reg [] MOV
-    !     temp1 ds-reg bootstrap-cell neg [+] MOV
-    !     ds-reg bootstrap-cell neg [+] temp0 MOV
-    !     ds-reg [] temp1 MOV
-    ! ] }
-    ! { swapd [
-    !     temp0 ds-reg -1 bootstrap-cells [+] MOV
-    !     temp1 ds-reg -2 bootstrap-cells [+] MOV
-    !     ds-reg -2 bootstrap-cells [+] temp0 MOV
-    !     ds-reg -1 bootstrap-cells [+] temp1 MOV
-    ! ] }
-
-    ! ! ## Signal handling
-    ! { leaf-signal-handler [
-    !     jit-signal-handler-prolog
-    !     jit-save-context
-    !     temp0 vm-reg vm-signal-handler-addr-offset [+] MOV
-    !     temp0 CALL
-    !     jit-signal-handler-epilog
-    !     ! Pop the fake leaf frame along with our return address
-    !     leaf-stack-frame-size bootstrap-cell - RET
-    ! ] }
-    ! { signal-handler [
-    !     jit-signal-handler-prolog
-    !     jit-save-context
-    !     temp0 vm-reg vm-signal-handler-addr-offset [+] MOV
-    !     temp0 CALL
-    !     jit-signal-handler-epilog
-    !     0 RET
-    ! ] }
+    { -rot [ pop0 load2/1* store0/2 push1 ] }
+    { rot [ pop0 load2/1* store1/0 push2 ] }
+    { swap [ load1/0 store0/1 ] }
+    { swapd [ load2/1 store1/2 ] }
+
+    ! ## Signal handling
+    { leaf-signal-handler [
+        jit-signal-handler-prolog
+        jit-save-context
+        ! temp0 vm-reg vm-signal-handler-addr-offset [+] MOV
+        ! temp0 CALL
+        vm-signal-handler-addr-offset vm-reg temp0 LDRuoff
+        temp0 BLR
+        jit-signal-handler-epilog
+        ! Pop the fake leaf frame along with our return address
+        ! leaf-stack-frame-size bootstrap-cell - RET
+        leaf-stack-frame-size bootstrap-cell - SP SP ADDr
+    ] }
+    { signal-handler [
+        jit-signal-handler-prolog
+        jit-save-context
+        ! temp0 vm-reg vm-signal-handler-addr-offset [+] MOV
+        ! temp0 CALL
+        vm-signal-handler-addr-offset vm-reg temp0 LDRuoff
+        temp0 BLR
+        jit-signal-handler-epilog
+        ! 0 RET
+        f RET
+    ] }
 } define-sub-primitives
 
 [ "bootstrap.arm.64" forget-vocab ] with-compilation-unit
index 63db4ad663a1101ac48dcb9fbfa6c7dfa2696776..69e071fda43bebafa2edd443fcaaa7264714f8ae 100644 (file)
@@ -7,13 +7,20 @@ IN: cpu.arm.assembler.64
 : ADC ( Rm Rn Rd -- ) ADC64-encode ;
 : ADCS ( Rm Rn Rd -- ) ADCS64-encode ;
 
-: ADDr ( Rm Rn Rd -- ) [ 0 0 ] 2dip ADDer64-encode ;
-
 : ADDi ( imm12 Rn Rd -- )
     [ 12 prepare-split-imm 1 0 ? swap ] 2dip
     ADDi64-encode ;
 
+: ADDr ( Rm Rn Rd -- ) [ 0 0 ] 2dip ADDer64-encode ;
+
+: ANDi ( imm13 Rn Rd -- ) [ 13 bits ] 2dip ANDi64-encode ;
+: ANDi32 ( imm12 Rn Rd -- ) [ 12 bits ] 2dip ANDi32-encode ;
+: ANDr ( Rm Rn Rd -- ) [ [ 0 ] dip 0 ] 2dip ANDsr64-encode ;
+
 : ASRi ( imm6 Rn Rd -- ) [ 6 ?bits ] 2dip ASRi64-encode ;
+: ASRr ( Rm Rn Rd -- ) ASRr64-encode ;
+
+: BIC ( Rm Rn Rd -- ) [ [ 0 ] dip 0 ] 2dip BIC64-encode ;
 
 : CBNZ ( imm19 Rt -- ) [ 19 ?bits ] dip CBNZ64-encode ;
 
@@ -21,52 +28,93 @@ IN: cpu.arm.assembler.64
     [ 12 prepare-split-imm 1 0 ? swap ] dip
     CMPi64-encode ;
 
+: CMPr ( Rm Rn -- ) [ 3 0 ] dip CMPer64-encode ;
+
 ! cond4 is EQ NE CS HS CC LO MI PL VS VC HI LS GE LT GT LE AL NV
 : CSEL ( Rm Rn Rd cond4 -- ) -rot CSEL64-encode ;
 : CSET ( Rd cond4 -- ) swap CSET64-encode ;
 : CSETM ( Rd cond4 -- ) swap CSETM64-encode ;
 
-: LDRpre ( imm9 Rn Rt -- ) [ 9 bits ] 2dip LDRpre64-encode ;
-: LDRpost ( imm9 Rn Rt -- ) [ 9 bits ] 2dip LDRpost64-encode ;
-: LDRuoff ( imm12 Rn Rt -- ) [ 8 / ] 2dip LDRuoff64-encode ;
-: LDRl ( imm19 Rt -- ) [ 4 / 19 bits ] dip LDRl64-encode ;
-: LDRl32 ( imm19 Rt -- ) [ 4 / 19 bits ] dip LDRl32-encode ;
+: EORi ( imm13 Rn Rd -- ) [ 13 bits ] 2dip EORi64-encode ;
+: EORr ( Rm Rn Rd -- ) [ [ 0 ] dip 0 ] 2dip EORsr64-encode ;
 
-: LDPpre ( imm7 Rn Rt2 Rt -- )
+: FPCR ( -- op0 op1 CRn CRm op2 ) 3 3 4 4 0 ;
+: FPSR ( -- op0 op1 CRn CRm op2 ) 3 3 4 4 1 ;
+
+: LDPpre ( imm10 Rn Rt2 Rt -- )
     [ 8 / 7 bits ] 3dip swapd LDPpre64-encode ;
 
-: LDPpost ( imm7 Rn Rt2 Rt -- )
+: LDPpost ( imm10 Rn Rt2 Rt -- )
     [ 8 / 7 bits ] 3dip swapd LDPpost64-encode ;
 
-: LDPsoff ( imm7 Rn Rt2 Rt -- )
+: LDPsoff ( imm10 Rn Rt2 Rt -- )
     [ 8 / 7 bits ] 3dip swapd LDPsoff64-encode ;
 
+: LDRpre ( imm9 Rn Rt -- ) [ 9 bits ] 2dip LDRpre64-encode ;
+: LDRpost ( imm9 Rn Rt -- ) [ 9 bits ] 2dip LDRpost64-encode ;
+: LDRuoff ( imm15 Rn Rt -- ) [ 8 / 12 ?bits ] 2dip LDRuoff64-encode ;
+: LDRl ( imm21 Rt -- ) [ 4 / 19 bits ] dip LDRl64-encode ;
+: LDRl32 ( imm21 Rt -- ) [ 4 / 19 bits ] dip LDRl32-encode ;
+: LDRr ( Rm Rn Rt -- ) [ 3 0 ] 2dip LDRr64-encode ;
+
+: LDRBr ( Rm Rn Rt -- ) [ 0 ] 2dip LDRBsr-encode ;
+
+: LDRBuoff ( imm12 Rn Rt -- )
+    [ 12 ?bits ] 2dip LDRBuoff-encode ;
+
+: LDRHuoff ( imm14 Rn Rt -- )
+    [ 2 / 12 ?bits ] 2dip LDRHuoff-encode ;
+
 : LSLi ( imm6 Rn Rd -- ) [ 6 ?bits ] 2dip LSLi64-encode ;
+: LSLr ( Rm Rn Rd -- ) LSLr64-encode ;
+
 : LSRi ( imm6 Rn Rd -- ) [ 6 ?bits ] 2dip LSRi64-encode ;
 
 : MOVwi ( imm Rt -- ) [ 0 ] 2dip MOVwi64-encode ;
 : MOVr ( Rn Rd -- ) MOVr64-encode ;
 : MOVsp ( Rn Rd -- ) [ 0 ] 2dip MOVsp64-encode ;
 
-: STPpre ( imm7 Rn Rt2 Rt -- )
+: MRS ( op0 op1 CRn CRm op2 Rt -- ) MRS-encode ;
+
+: MSRr ( op0 op1 CRn CRm op2 Rt -- ) MSRr-encode ;
+
+: MSUB ( Ra Rm Rn Rd -- ) [ swap ] 2dip MSUB64-encode ;
+
+: MUL ( Rm Rn Rd -- ) MUL64-encode ;
+
+: MVN ( Rm Rd -- ) [ [ 0 ] dip 0 ] dip MVN64-encode ;
+
+: NEG ( Rm Rd -- ) [ [ 0 ] dip 0 ] dip NEG64-encode ;
+
+: NZCV ( -- op0 op1 CRn CRm op2 ) 3 3 4 2 0 ;
+
+: ORRr ( Rm Rn Rd -- ) [ [ 0 ] dip 0 ] 2dip ORRsr64-encode ;
+
+: SDIV ( Rm Rn Rd -- ) SDIV64-encode ;
+
+: STPpre ( imm10 Rn Rt2 Rt -- )
     [ 8 / 7 bits ] 3dip swapd STPpre64-encode ;
 
-: STPpost ( imm7 Rn Rt2 Rt -- )
+: STPpost ( imm10 Rn Rt2 Rt -- )
     [ 8 / 7 bits ] 3dip swapd STPpost64-encode ;
 
-: STPsoff ( imm7 Rn Rt2 Rt -- )
+: STPsoff ( imm10 Rn Rt2 Rt -- )
     [ 8 / 7 bits ] 3dip swapd STPsoff64-encode ;
 
 : STRpre ( imm9 Rn Rt -- ) [ 9 bits ] 2dip STRpre64-encode ;
 
 : STRpost ( imm9 Rn Rt -- ) [ 9 bits ] 2dip STRpost64-encode ;
 
-: STRr ( Rm Rn Rt -- ) [ 0 0 ] 2dip STRr64-encode ;
+: STRr ( Rm Rn Rt -- ) [ 3 0 ] 2dip STRr64-encode ;
+: STRr32 ( Rm Rn Rt -- ) [ 3 0 ] 2dip STRr32-encode ;
 
-: STRuoff ( imm12 Rn Rt -- )
-    [ -3 shift ] 2dip STRuoff64-encode ;
+: STRuoff ( imm15 Rn Rt -- )
+    [ 8 / 12 ?bits ] 2dip STRuoff64-encode ;
 
 : SUBi ( imm12 Rn Rd -- )
     [ 12 prepare-split-imm 1 0 ? swap ] 2dip
     SUBi64-encode ;
 
+: SUBr ( Rm Rn Rd -- ) [ 3 0 ] 2dip SUBer64-encode ;
+
+: TSTi ( imm13 Rn -- ) [ 13 bits ] dip TSTi64-encode ;
index 31fdc2329b0c42afc50dd4d4d4d0903cbf50b2aa..4ee6dac405cca330bf01dde1da9b741375358222 100644 (file)
@@ -136,7 +136,6 @@ FIELD: CRm 4
 FIELD: CRn 4
 FIELD: nzcv4 4
 FIELD: nzcv 4
-FIELD: o0 1
 FIELD: hw2 2
 FIELD: mask4 4
 
@@ -243,28 +242,28 @@ SINGLETONS: SPSR_EL1 SPSR_EL2 SPSR_EL3 ;
 
 ! Instructions
 
-! https://www.element14.com/community/servlet/JiveServlet/previewBody/41836-102-1-229511/ARM.Reference_Manual.pdf
+! https://community.element14.com/products/devtools/technicallibrary/m/files/10863
 ! pg 16
-! cond code set in prev arm assembler
-: >CC ( x -- x ) ; inline
-: EQ ( -- n ) 0000 >CC ; inline ! Z set equal
-: NE ( -- n ) 0001 >CC ; inline ! Z clear not equal
-: CS ( -- n ) 0010 >CC ; inline ! C set unsigned higher or same
+! cond code set in previous arm assembly instruction
+: >CC ( x -- x ) >dec bin> ; inline
+: EQ ( -- n ) 0000 >CC ; inline ! Z set: equal
+: NE ( -- n ) 0001 >CC ; inline ! Z clear: not equal
+: CS ( -- n ) 0010 >CC ; inline ! C set: unsigned higher or same
 : HS ( -- n ) 0010 >CC ; inline !
-: CC ( -- n ) 0011 >CC ; inline ! C clear unsigned lower
+: CC ( -- n ) 0011 >CC ; inline ! C clear: unsigned lower
 : LO ( -- n ) 0011 >CC ; inline !
-: MI ( -- n ) 0100 >CC ; inline ! N set negative
-: PL ( -- n ) 0101 >CC ; inline ! N clear positive or zero
-: VS ( -- n ) 0110 >CC ; inline ! V set overflow
-: VC ( -- n ) 0111 >CC ; inline ! V clear no overflow
-: HI ( -- n ) 1000 >CC ; inline ! C set and Z clear unsigned higher
-: LS ( -- n ) 1001 >CC ; inline ! C clear or Z set unsigned lower or same
-: GE ( -- n ) 1010 >CC ; inline ! N equals V greater or equal
-: LT ( -- n ) 1011 >CC ; inline ! N not equal to V less than
-: GT ( -- n ) 1100 >CC ; inline ! Z clear AND (N equals V) greater than
-: LE ( -- n ) 1101 >CC ; inline ! Z set OR (N not equal to V) less than or equal
-: AL ( -- n ) 1110 >CC ; inline ! AL (ignored) always
-: NV ( -- n ) 1111 >CC ; inline ! no value
+: MI ( -- n ) 0100 >CC ; inline ! N set: negative
+: PL ( -- n ) 0101 >CC ; inline ! N clear: positive or zero
+: VS ( -- n ) 0110 >CC ; inline ! V set: overflow
+: VC ( -- n ) 0111 >CC ; inline ! V clear: no overflow
+: HI ( -- n ) 1000 >CC ; inline ! C set and Z clear: unsigned higher
+: LS ( -- n ) 1001 >CC ; inline ! C clear or Z set: unsigned lower or same
+: GE ( -- n ) 1010 >CC ; inline ! N equals V: greater or equal
+: LT ( -- n ) 1011 >CC ; inline ! N not equal to V: less than
+: GT ( -- n ) 1100 >CC ; inline ! Z clear AND (N equals V): greater than
+: LE ( -- n ) 1101 >CC ; inline ! Z set OR (N not equal to V): less than or equal
+: AL ( -- n ) 1110 >CC ; inline ! always
+: NV ( -- n ) 1111 >CC ; inline ! always
 
 : imm13>parts-64 ( imm13 -- imms immr N )
     [ -4 shift 4 bits ] [ 4 bits ] [ -8 shift ] tri ;
@@ -437,13 +436,11 @@ ARM-INSTRUCTION: BFXIL32-encode ( 0 01 100110 0 immrimms Rn Rd -- )
 ARM-INSTRUCTION: BFXIL64-encode ( 1 01 100110 Nimmrimms Rn Rd -- )
 
 ! BIC (shifted register): Bitwise Bit Clear (shifted register).
-ARM-INSTRUCTION: BIC-encode ( 0 Q 1 0111100000 a1 b1 c1 cmode4 0 1 d1 e1 f1 g1 h1 Rd -- )
-! BIC (shifted register): Bitwise Bit Clear (shifted register).
-ARM-INSTRUCTION: BICsr32-encode ( 0 00 01010 shift2 1 Rm imm6 Rn Rd -- )
-ARM-INSTRUCTION: BICsr64-encode ( 1 00 01010 shift2 1 Rm imm6 Rn Rd -- )
+ARM-INSTRUCTION: BIC32-encode ( 0 00 01010 shift2 1 Rm imm6 Rn Rd -- )
+ARM-INSTRUCTION: BIC64-encode ( 1 00 01010 shift2 1 Rm imm6 Rn Rd -- )
 ! BICS (shifted register): Bitwise Bit Clear (shifted register), setting flags.
-ARM-INSTRUCTION: BICSsr32-encode ( 0 11 01010 shift2 1 Rm imm6 Rn Rd -- )
-ARM-INSTRUCTION: BICSsr64-encode ( 1 11 01010 shift2 1 Rm imm6 Rn Rd -- )
+ARM-INSTRUCTION: BICS32-encode ( 0 11 01010 shift2 1 Rm imm6 Rn Rd -- )
+ARM-INSTRUCTION: BICS64-encode ( 1 11 01010 shift2 1 Rm imm6 Rn Rd -- )
 ! BL: Branch with Link.
 ARM-INSTRUCTION: BL-encode ( 1 00101 imm26 -- )
 ! BLR: Branch with Link to Register.
@@ -548,8 +545,8 @@ ARM-INSTRUCTION: CMNer64-encode ( 1 0 1 01011 00 1 Rm option3 imm3 Rn Rd -- )
 ARM-INSTRUCTION: CMNi32-encode ( 0 0 1 10001 shift2 imm12 Rn 11111 -- )
 ARM-INSTRUCTION: CMNi64-encode ( 1 0 1 10001 shift2 imm12 Rn 11111 -- )
 ! CMN (shifted register): Compare Negative (shifted register): an alias of ADDS (shifted register).
-ARM-INSTRUCTION: CMN-sr32-encode ( 0 0 1 01011 shift2 0 Rm imm6 Rn 11111 -- )
-ARM-INSTRUCTION: CMN-sr64-encode ( 1 0 1 01011 shift2 0 Rm imm6 Rn 11111 -- )
+ARM-INSTRUCTION: CMNsr32-encode ( 0 0 1 01011 shift2 0 Rm imm6 Rn 11111 -- )
+ARM-INSTRUCTION: CMNsr64-encode ( 1 0 1 01011 shift2 0 Rm imm6 Rn 11111 -- )
 
 ! CMP (extended register): Compare (extended register): an alias of SUBS (extended register).
 ARM-INSTRUCTION: CMPer32-encode ( 0 1 1 01011 00 1 Rm option3 imm3 Rn 11111 -- )
@@ -840,53 +837,53 @@ ARM-INSTRUCTION: LDRABoff-encode ( 11 111 0 00 1 S 1 imm9 0 1 Rn Rt  -- )
 ARM-INSTRUCTION: LDRABpre-encode ( 11 111 0 00 1 S 1 imm9 1 1 Rn Rt  -- )
 
 ! LDRB (immediate): Load Register Byte (immediate).
-ARM-INSTRUCTION: LDRBimmpost-encode ( 00 111 0 00 01 0 imm9 01 Rn Rt -- )
-ARM-INSTRUCTION: LDRBimmpre-encode ( 00 111 0 00 01 0 imm9 11 Rn Rt -- )
-ARM-INSTRUCTION: LDRBimmuoff-encode ( 00 111 0 01 01 imm12 Rn Rt -- )
+ARM-INSTRUCTION: LDRBpost-encode ( 00 111 0 00 01 0 imm9 01 Rn Rt -- )
+ARM-INSTRUCTION: LDRBpre-encode ( 00 111 0 00 01 0 imm9 11 Rn Rt -- )
+ARM-INSTRUCTION: LDRBuoff-encode ( 00 111 0 01 01 imm12 Rn Rt -- )
 
 ! LDRB (register): Load Register Byte (register).
 ! option: 010: UXTW, 110 SXTW, 111 SXTX, S shift 0/1
-ARM-INSTRUCTION: LDRBrext-encode ( 00 111 0 00 01 1 Rm option3 S 10 Rn Rt -- )
-ARM-INSTRUCTION: LDRBrshift-encode ( 00 111 0 00 01 1 Rm 011 S 10 Rn Rt -- )
+ARM-INSTRUCTION: LDRBer-encode ( 00 111 0 00 01 1 Rm option3 S 10 Rn Rt -- )
+ARM-INSTRUCTION: LDRBsr-encode ( 00 111 0 00 01 1 Rm 011 S 10 Rn Rt -- )
 
 ! LDRH (immediate): Load Register Halfword (immediate).
-ARM-INSTRUCTION: LDRHimmpost-encode ( 01 111 0 00 01 0 imm9 01 Rn Rt -- )
-ARM-INSTRUCTION: LDRHimmpre-encode ( 01 111 0 00 01 0 imm9 11 Rn Rt -- )
-ARM-INSTRUCTION: LDRHimmuoff-encode ( 01 111 0 01 01 imm12 Rn Rt -- )
+ARM-INSTRUCTION: LDRHpost-encode ( 01 111 0 00 01 0 imm9 01 Rn Rt -- )
+ARM-INSTRUCTION: LDRHpre-encode ( 01 111 0 00 01 0 imm9 11 Rn Rt -- )
+ARM-INSTRUCTION: LDRHuoff-encode ( 01 111 0 01 01 imm12 Rn Rt -- )
 
 ! LDRH (register): Load Register Halfword (register).
 ARM-INSTRUCTION: LDRHr-encode ( 01 111 0 00 01 1 Rm option3 S 10 Rn Rt  -- )
 
 ! LDRSB (immediate): Load Register Signed Byte (immediate).
-ARM-INSTRUCTION: LDRSBimmpost32-encode ( 00 111 0 00 11 0 imm9 01 Rn Rt -- )
-ARM-INSTRUCTION: LDRSBimmpost64-encode ( 00 111 0 00 10 0 imm9 01 Rn Rt -- )
-ARM-INSTRUCTION: LDRSBimmpre32-encode  ( 00 111 0 00 11 0 imm9 11 Rn Rt -- )
-ARM-INSTRUCTION: LDRSBimmpre64-encode  ( 00 111 0 00 10 0 imm9 11 Rn Rt -- )
-ARM-INSTRUCTION: LDRSBimmuoff32-encode ( 00 111 0 01 11 imm12 Rn Rt -- )
-ARM-INSTRUCTION: LDRSBimmuoff64-encode ( 00 111 0 01 10 imm12 Rn Rt -- )
+ARM-INSTRUCTION: LDRSBpost32-encode ( 00 111 0 00 11 0 imm9 01 Rn Rt -- )
+ARM-INSTRUCTION: LDRSBpost64-encode ( 00 111 0 00 10 0 imm9 01 Rn Rt -- )
+ARM-INSTRUCTION: LDRSBpre32-encode  ( 00 111 0 00 11 0 imm9 11 Rn Rt -- )
+ARM-INSTRUCTION: LDRSBpre64-encode  ( 00 111 0 00 10 0 imm9 11 Rn Rt -- )
+ARM-INSTRUCTION: LDRSBuoff32-encode ( 00 111 0 01 11 imm12 Rn Rt -- )
+ARM-INSTRUCTION: LDRSBuoff64-encode ( 00 111 0 01 10 imm12 Rn Rt -- )
 
 ! LDRSB (register): Load Register Signed Byte (register).
-ARM-INSTRUCTION: LDRSBextreg32-encode   ( 00 111 0 00 11 1 Rm option3 S 10 Rn Rt -- )
-ARM-INSTRUCTION: LDRSBshiftreg32-encode ( 00 111 0 00 11 1 Rm 011 S 10 Rn Rt -- )
-ARM-INSTRUCTION: LDRSBextreg64-encode   ( 00 111 0 00 10 1 Rm option3 S 10 Rn Rt -- )
-ARM-INSTRUCTION: LDRSBshiftreg64-encode ( 00 111 0 00 10 1 Rm 011 S 10 Rn Rt -- )
+ARM-INSTRUCTION: LDRSBer32-encode   ( 00 111 0 00 11 1 Rm option3 S 10 Rn Rt -- )
+ARM-INSTRUCTION: LDRSBsr32-encode ( 00 111 0 00 11 1 Rm 011 S 10 Rn Rt -- )
+ARM-INSTRUCTION: LDRSBer64-encode   ( 00 111 0 00 10 1 Rm option3 S 10 Rn Rt -- )
+ARM-INSTRUCTION: LDRSBsr64-encode ( 00 111 0 00 10 1 Rm 011 S 10 Rn Rt -- )
 
 ! LDRSH (immediate): Load Register Signed Halfword (immediate).
-ARM-INSTRUCTION: LDRSHimmpost32-encode ( 01 111 0 00 11 0 imm9 01 Rn Rt -- )
-ARM-INSTRUCTION: LDRSHimmpost64-encode ( 01 111 0 00 10 0 imm9 01 Rn Rt -- )
-ARM-INSTRUCTION: LDRSHimmpre32-encode  ( 01 111 0 00 11 0 imm9 11 Rn Rt -- )
-ARM-INSTRUCTION: LDRSHimmpre64-encode  ( 01 111 0 00 10 0 imm9 11 Rn Rt -- )
-ARM-INSTRUCTION: LDRSHimmuoff32-encode ( 01 111 0 01 11 imm12 Rn Rt -- )
-ARM-INSTRUCTION: LDRSHimmuoff64-encode ( 01 111 0 01 10 imm12 Rn Rt -- )
+ARM-INSTRUCTION: LDRSHpost32-encode ( 01 111 0 00 11 0 imm9 01 Rn Rt -- )
+ARM-INSTRUCTION: LDRSHpost64-encode ( 01 111 0 00 10 0 imm9 01 Rn Rt -- )
+ARM-INSTRUCTION: LDRSHpre32-encode  ( 01 111 0 00 11 0 imm9 11 Rn Rt -- )
+ARM-INSTRUCTION: LDRSHpre64-encode  ( 01 111 0 00 10 0 imm9 11 Rn Rt -- )
+ARM-INSTRUCTION: LDRSHuoff32-encode ( 01 111 0 01 11 imm12 Rn Rt -- )
+ARM-INSTRUCTION: LDRSHuoff64-encode ( 01 111 0 01 10 imm12 Rn Rt -- )
 
 ! LDRSH (register): Load Register Signed Halfword (register).
-ARM-INSTRUCTION: LDRSH32-encode ( 01 111 0 00 11 1 Rm option3 S 10 Rn Rt -- )
-ARM-INSTRUCTION: LDRSH64-encode ( 01 111 0 00 10 1 Rm option3 S 10 Rn Rt -- )
+ARM-INSTRUCTION: LDRSHr32-encode ( 01 111 0 00 11 1 Rm option3 S 10 Rn Rt -- )
+ARM-INSTRUCTION: LDRSHr64-encode ( 01 111 0 00 10 1 Rm option3 S 10 Rn Rt -- )
 
 ! LDRSW (immediate): Load Register Signed Word (immediate).
-ARM-INSTRUCTION: LDRSWimmpost32-encode ( 10 111 0 00 10 0 imm9 01 Rn Rt -- )
-ARM-INSTRUCTION: LDRSWimmpre32-encode  ( 10 111 0 00 10 0 imm9 11 Rn Rt -- )
-ARM-INSTRUCTION: LDRSWimmuoff64-encode ( 10 111 0 01 10 imm12 Rn Rt -- )
+ARM-INSTRUCTION: LDRSWpost32-encode ( 10 111 0 00 10 0 imm9 01 Rn Rt -- )
+ARM-INSTRUCTION: LDRSWpre32-encode  ( 10 111 0 00 10 0 imm9 11 Rn Rt -- )
+ARM-INSTRUCTION: LDRSWuoff64-encode ( 10 111 0 01 10 imm12 Rn Rt -- )
 
 ! LDRSW (literal): Load Register Signed Word (literal).
 ARM-INSTRUCTION: LDRSWl-encode ( 10 011 0 00 imm19 Rt -- )
@@ -1134,13 +1131,13 @@ ARM-INSTRUCTION: MOVZ64-encode ( 1 10 100101 hw2 imm16 Rd -- )
 
 ! MRS: Move System Register.
 ! System register name, encoded in the "o0:op1:CRn:CRm:op2"
-ARM-INSTRUCTION: MRS-encode ( 1101010100 1 1 o0 op3 CRn CRm op3 Rt -- )
+ARM-INSTRUCTION: MRS-encode ( 1101010100 1 op2 op3 CRn CRm op3 Rt -- )
 
 ! MSR (immediate): Move immediate value to Special Register.
-ARM-INSTRUCTION: MRSi-encode ( 1101010100 0 00 op3 0100 CRm op3 11111 -- )
+ARM-INSTRUCTION: MSRi-encode ( 1101010100 0 00 op3 0100 CRm op3 11111 -- )
 
 ! MSR (register): Move general-purpose register to System Register.
-ARM-INSTRUCTION: MRSr-encode ( 1101010100 0 1 o0 op3 CRn CRm op3 Rt -- )
+ARM-INSTRUCTION: MSRr-encode ( 1101010100 0 op2 op3 CRn CRm op3 Rt -- )
 
 ! MSUB: Multiply-Subtract.
 ARM-INSTRUCTION: MSUB32-encode ( 0 00 11011 000 Rm 1 Ra Rn Rd -- )
@@ -1155,8 +1152,8 @@ ARM-INSTRUCTION: MVN32-encode ( 0 0 1 01010 shift2 1 Rm imm6 11111 Rd -- )
 ARM-INSTRUCTION: MVN64-encode ( 1 0 1 01010 shift2 1 Rm imm6 11111 Rd -- )
 
 ! NEG (shifted register): Negate (shifted register): an alias of SUB (shifted register).
-ARM-INSTRUCTION: NEGsr32-encode ( 0 1 0 01011 shift2 0 Rm imm6 11111 Rd -- )
-ARM-INSTRUCTION: NEGsr64-encode ( 1 1 0 01011 shift2 0 Rm imm6 11111 Rd -- )
+ARM-INSTRUCTION: NEG32-encode ( 0 1 0 01011 shift2 0 Rm imm6 11111 Rd -- )
+ARM-INSTRUCTION: NEG64-encode ( 1 1 0 01011 shift2 0 Rm imm6 11111 Rd -- )
 
 ! NEGS: Negate, setting flags: an alias of SUBS (shifted register).
 ARM-INSTRUCTION: NEGS32-encode ( 0 1 1 01011 shift2 0 Rm imm6 11111 Rd -- )
@@ -1178,8 +1175,8 @@ ARM-INSTRUCTION: ORNsr32-encode ( 0 01 01010 shift2 1 Rm imm6 Rn Rd -- )
 ARM-INSTRUCTION: ORNsr64-encode ( 1 01 01010 shift2 1 Rm imm6 Rn Rd -- )
 
 ! ORR (immediate): Bitwise OR (immediate).
-ARM-INSTRUCTION: ORR32-encode ( 0 01 100100 0 immrimms Rn Rd -- )
-ARM-INSTRUCTION: ORR64-encode ( 1 01 100100 Nimmrimms Rn Rd -- )
+ARM-INSTRUCTION: ORRi32-encode ( 0 01 100100 0 immrimms Rn Rd -- )
+ARM-INSTRUCTION: ORRi64-encode ( 1 01 100100 Nimmrimms Rn Rd -- )
 
 ! ORR (shifted register): Bitwise OR (shifted register).
 ARM-INSTRUCTION: ORRsr32-encode ( 0 01 01010 shift2 0 Rm imm6 Rn Rd -- )
@@ -1484,8 +1481,8 @@ ARM-INSTRUCTION: STRBpre-encode  ( 00 111 0 00 00 0 imm9 11 Rn Rt -- )
 ARM-INSTRUCTION: STRBuoff-encode ( 00 111 0 01 00 imm12 Rn Rt -- )
 
 ! STRB (register): Store Register Byte (register).
-ARM-INSTRUCTION: STRBext-encode   ( 00 111 0 00 00 1 Rm option3 S 10 Rn Rt -- )
-ARM-INSTRUCTION: STRBshift-encode ( 00 111 0 00 00 1 Rm 011 S 10 Rn Rt -- )
+ARM-INSTRUCTION: STRBer-encode   ( 00 111 0 00 00 1 Rm option3 S 10 Rn Rt -- )
+ARM-INSTRUCTION: STRBsr-encode ( 00 111 0 00 00 1 Rm 011 S 10 Rn Rt -- )
 
 ! STRH (immediate): Store Register Halfword (immediate).
 ARM-INSTRUCTION: STRHpost-encode ( 01 111 0 00 00 0 imm9 01 Rn Rt -- )
@@ -1493,7 +1490,7 @@ ARM-INSTRUCTION: STRHpre-encode  ( 01 111 0 00 00 0 imm9 11 Rn Rt -- )
 ARM-INSTRUCTION: STRHuoff-encode ( 01 111 0 01 00 imm12 Rn Rt -- )
 
 ! STRH (register): Store Register Halfword (register).
-ARM-INSTRUCTION: STRH-encode ( 01 111 0 00 00 1 Rm option3 S 10 Rn Rt -- )
+ARM-INSTRUCTION: STRHr-encode ( 01 111 0 00 00 1 Rm option3 S 10 Rn Rt -- )
 
 ! STSET, STSETL: Atomic bit set on word or doubleword in memory, without return: an alias of LDSET, LDSETA, LDSETAL, LDSETL.
 ! ARMv8.1