; Copyright (C) 2026 Kiyotsugu Arai
; SPDX-License-Identifier: LGPL-3.0-or-later
;
; mpn_x64_add.asm — add_n/sub_n small-size specialization (n=1..4)
;
; Functions:
;   mpn_add_n_small_asm(rp, ap, bp, n) -> carry  (n=1..4)
;   mpn_sub_n_small_asm(rp, ap, bp, n) -> borrow (n=1..4)
;
; Purpose: minimize call overhead for n <= 4
;   - no push/pop (volatile registers only)
;   - no loop (fully unrolled)
;   - dispatch via jump table (a CMP chain is unusable since it destroys CF)
;
; Windows x64 calling convention:
;   rcx = rp, rdx = ap, r8 = bp, r9 = n (1..4)
;   return value: rax (carry/borrow, 0 or 1)
;   non-volatile: rbx, rbp, rdi, rsi, r12-r15
;   volatile: rax, rcx, rdx, r8, r9, r10, r11

.code

; =====================================================================
; uint64_t mpn_add_n_small_asm(uint64_t* rp, const uint64_t* ap,
;                               const uint64_t* bp, size_t n)
;
; rp[0..n-1] = ap[0..n-1] + bp[0..n-1]
; return value: carry (0 or 1)
; precondition: 1 <= n <= 4
;
; After dispatching via the jump table, a fully unrolled ADC chain.
; No CF-destroying instruction (CMP, TEST, SUB) exists in the ADC chain.
; =====================================================================
mpn_add_n_small_asm PROC
    ; r9 = n (1..4), convert to jump-table index
    lea     r10, [addn_s_jt]
    jmp     qword ptr [r10 + r9*8 - 8]

; --- jump table (placed within the code segment) ---
addn_s_jt:
    dq      addn_s_1
    dq      addn_s_2
    dq      addn_s_3
    dq      addn_s_4

    ALIGN   16
addn_s_1:
    mov     rax, [rdx]
    add     rax, [r8]
    mov     [rcx], rax
    setc    al
    movzx   eax, al
    ret

    ALIGN   16
addn_s_2:
    mov     rax, [rdx]
    add     rax, [r8]
    mov     [rcx], rax
    mov     rax, [rdx + 8]
    adc     rax, [r8  + 8]
    mov     [rcx + 8], rax
    setc    al
    movzx   eax, al
    ret

    ALIGN   16
addn_s_3:
    mov     rax, [rdx]
    add     rax, [r8]
    mov     [rcx], rax
    mov     rax, [rdx + 8]
    adc     rax, [r8  + 8]
    mov     [rcx + 8], rax
    mov     rax, [rdx + 16]
    adc     rax, [r8  + 16]
    mov     [rcx + 16], rax
    setc    al
    movzx   eax, al
    ret

    ALIGN   16
addn_s_4:
    mov     rax, [rdx]
    add     rax, [r8]
    mov     [rcx], rax
    mov     rax, [rdx + 8]
    adc     rax, [r8  + 8]
    mov     [rcx + 8], rax
    mov     rax, [rdx + 16]
    adc     rax, [r8  + 16]
    mov     [rcx + 16], rax
    mov     rax, [rdx + 24]
    adc     rax, [r8  + 24]
    mov     [rcx + 24], rax
    setc    al
    movzx   eax, al
    ret
mpn_add_n_small_asm ENDP

; =====================================================================
; uint64_t mpn_sub_n_small_asm(uint64_t* rp, const uint64_t* ap,
;                               const uint64_t* bp, size_t n)
;
; rp[0..n-1] = ap[0..n-1] - bp[0..n-1]
; return value: borrow (0 or 1)
; precondition: 1 <= n <= 4
;
; Same structure as mpn_add_n_small_asm. ADD/ADC changed to SUB/SBB.
; =====================================================================
mpn_sub_n_small_asm PROC
    lea     r10, [subn_s_jt]
    jmp     qword ptr [r10 + r9*8 - 8]

subn_s_jt:
    dq      subn_s_1
    dq      subn_s_2
    dq      subn_s_3
    dq      subn_s_4

    ALIGN   16
subn_s_1:
    mov     rax, [rdx]
    sub     rax, [r8]
    mov     [rcx], rax
    setc    al
    movzx   eax, al
    ret

    ALIGN   16
subn_s_2:
    mov     rax, [rdx]
    sub     rax, [r8]
    mov     [rcx], rax
    mov     rax, [rdx + 8]
    sbb     rax, [r8  + 8]
    mov     [rcx + 8], rax
    setc    al
    movzx   eax, al
    ret

    ALIGN   16
subn_s_3:
    mov     rax, [rdx]
    sub     rax, [r8]
    mov     [rcx], rax
    mov     rax, [rdx + 8]
    sbb     rax, [r8  + 8]
    mov     [rcx + 8], rax
    mov     rax, [rdx + 16]
    sbb     rax, [r8  + 16]
    mov     [rcx + 16], rax
    setc    al
    movzx   eax, al
    ret

    ALIGN   16
subn_s_4:
    mov     rax, [rdx]
    sub     rax, [r8]
    mov     [rcx], rax
    mov     rax, [rdx + 8]
    sbb     rax, [r8  + 8]
    mov     [rcx + 8], rax
    mov     rax, [rdx + 16]
    sbb     rax, [r8  + 16]
    mov     [rcx + 16], rax
    mov     rax, [rdx + 24]
    sbb     rax, [r8  + 24]
    mov     [rcx + 24], rax
    setc    al
    movzx   eax, al
    ret
mpn_sub_n_small_asm ENDP

END
