; Copyright (C) 2026 Kiyotsugu Arai
; SPDX-License-Identifier: LGPL-3.0-or-later
;
; mpn_x64_add.asm — add_n/sub_n 小サイズ特化 (n=1..4)
;
; 関数:
;   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)
;
; 目的: n <= 4 での呼び出しオーバーヘッドを最小化
;   - push/pop なし (volatile レジスタのみ使用)
;   - ループなし (フルアンロール)
;   - ジャンプテーブルでディスパッチ (CMP チェーンは CF を破壊するため不可)
;
; Windows x64 calling convention:
;   rcx = rp, rdx = ap, r8 = bp, r9 = n (1..4)
;   戻り値: rax (carry/borrow, 0 or 1)
;   非破壊: rbx, rbp, rdi, rsi, r12-r15
;   破壊可: 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]
; 戻り値: キャリー (0 or 1)
; 前提: 1 <= n <= 4
;
; ジャンプテーブルでディスパッチ後、フルアンロール ADC チェーン。
; CF を破壊する命令 (CMP, TEST, SUB) は ADC チェーン内に存在しない。
; =====================================================================
mpn_add_n_small_asm PROC
    ; r9 = n (1..4), ジャンプテーブルのインデックスに変換
    lea     r10, [addn_s_jt]
    jmp     qword ptr [r10 + r9*8 - 8]

; --- ジャンプテーブル (コードセグメント内に配置) ---
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]
; 戻り値: ボロー (0 or 1)
; 前提: 1 <= n <= 4
;
; mpn_add_n_small_asm と同一構造。ADD/ADC → 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
