cemc 0.1.1

Cem language compiler - A concatenative language with green threads and linear types
Documentation
/**
 * Cem Runtime - ARM64 Context Switching (macOS)
 *
 * This file implements fast context switching for ARM64 (AArch64).
 * It saves and restores callee-saved registers according to the
 * ARM64 calling convention (AAPCS64).
 *
 * Calling convention reference:
 * - https://developer.arm.com/documentation/ihi0055/latest/
 *
 * Register usage:
 * - x0-x18: Caller-saved (not preserved across function calls)
 * - x19-x28: Callee-saved (must be preserved)
 * - x29: Frame pointer (FP) - callee-saved
 * - x30: Link register (LR) - holds return address
 * - sp: Stack pointer - callee-saved
 * - d0-d7: FP argument/result registers - caller-saved
 * - d8-d15: FP callee-saved registers
 * - d16-d31: FP caller-saved registers
 */

.text
.align 4

/**
 * void cem_swapcontext(cem_context_t* save_ctx, const cem_context_t* restore_ctx)
 *
 * Save current context to save_ctx and restore restore_ctx.
 *
 * Arguments:
 *   x0 = save_ctx (pointer to cem_context_t)
 *   x1 = restore_ctx (pointer to cem_context_t)
 *
 * Context layout (matches cem_context_t in context.h):
 *   Offset  Register
 *   0x00    x19
 *   0x08    x20
 *   0x10    x21
 *   0x18    x22
 *   0x20    x23
 *   0x28    x24
 *   0x30    x25
 *   0x38    x26
 *   0x40    x27
 *   0x48    x28
 *   0x50    x29 (FP)
 *   0x58    x30 (LR)
 *   0x60    sp
 *   0x68    d8
 *   0x70    d9
 *   0x78    d10
 *   0x80    d11
 *   0x88    d12
 *   0x90    d13
 *   0x98    d14
 *   0xA0    d15
 */
.globl _cem_swapcontext
_cem_swapcontext:
    // Save current context to save_ctx (x0)

    // Save general purpose registers x19-x28
    stp     x19, x20, [x0, #0x00]
    stp     x21, x22, [x0, #0x10]
    stp     x23, x24, [x0, #0x20]
    stp     x25, x26, [x0, #0x30]
    stp     x27, x28, [x0, #0x40]

    // Save frame pointer and link register
    stp     x29, x30, [x0, #0x50]

    // Save stack pointer
    // Note: We save the SP *after* this function was called
    // (i.e., the caller's SP)
    mov     x9, sp
    str     x9, [x0, #0x60]

    // Save floating point registers d8-d15
    stp     d8,  d9,  [x0, #0x68]
    stp     d10, d11, [x0, #0x78]
    stp     d12, d13, [x0, #0x88]
    stp     d14, d15, [x0, #0x98]

    // Restore context from restore_ctx (x1)

    // Restore general purpose registers x19-x28
    ldp     x19, x20, [x1, #0x00]
    ldp     x21, x22, [x1, #0x10]
    ldp     x23, x24, [x1, #0x20]
    ldp     x25, x26, [x1, #0x30]
    ldp     x27, x28, [x1, #0x40]

    // Restore frame pointer and link register
    ldp     x29, x30, [x1, #0x50]

    // Restore stack pointer
    ldr     x9, [x1, #0x60]
    mov     sp, x9

    // Restore floating point registers d8-d15
    ldp     d8,  d9,  [x1, #0x68]
    ldp     d10, d11, [x1, #0x78]
    ldp     d12, d13, [x1, #0x88]
    ldp     d14, d15, [x1, #0x98]

    // Return to the address in x30 (LR from restored context)
    ret

/**
 * Notes on stack alignment and calling convention:
 *
 * 1. Stack must be 16-byte aligned at function entry
 *    - The caller (C code) ensures this
 *    - Our SP save/restore maintains this
 *
 * 2. Link register (x30) holds return address
 *    - When we save x30, we save where to return to
 *    - When we restore x30, we restore the return address
 *    - The 'ret' instruction jumps to address in x30
 *
 * 3. For makecontext:
 *    - We set x30 to the function to execute
 *    - When swapcontext restores x30 and executes 'ret',
 *      it will jump to that function
 *    - The function will execute as if it was called normally
 *
 * 4. Callee-saved registers:
 *    - x19-x28: Must be preserved across calls
 *    - x29 (FP): Must be preserved
 *    - d8-d15: Must be preserved
 *    - Everything else is caller-saved (C compiler handles those)
 */