[PATCH 3/13] Add runtime support for loongarch64

[email protected]
Newsgroups gmane.lisp.steel-bank.devel
Message-ID <[email protected]>
This patch adds the src/runtime support for LoongArch 64-bit in SBCL,includes a series of support files: Config.loongarch64-linux, loongarch64-arch.c, loongarch64-arch.h, loongarch64-assem.S, loongarch64-linux-os.c, loongarch64-linux-os.h, and loongarch64-lispregs.h.

_______________________________________________
Sbcl-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/sbcl-devel
0003-Add-runtime-support-for-loongarch64.patch (application/octet-stream, 20.9 KB)
From 8dd242246bc172de0496fc119334e5087b801599 Mon Sep 17 00:00:00 2001
From: ZiLong Wang <[email protected]>
Date: Sat, 17 Jan 2026 10:07:06 +0800
Subject: [PATCH 03/13] Add runtime support for LoongArch

---
 src/runtime/Config.loongarch64-linux |  35 +++
 src/runtime/loongarch64-arch.c       | 321 +++++++++++++++++++++++++++
 src/runtime/loongarch64-arch.h       |   5 +
 src/runtime/loongarch64-assem.S      |  61 +++++
 src/runtime/loongarch64-linux-os.c   | 134 +++++++++++
 src/runtime/loongarch64-linux-os.h   |   9 +
 src/runtime/loongarch64-lispregs.h   |  56 +++++
 7 files changed, 621 insertions(+)
 create mode 100644 src/runtime/Config.loongarch64-linux
 create mode 100644 src/runtime/loongarch64-arch.c
 create mode 100644 src/runtime/loongarch64-arch.h
 create mode 100644 src/runtime/loongarch64-assem.S
 create mode 100644 src/runtime/loongarch64-linux-os.c
 create mode 100644 src/runtime/loongarch64-linux-os.h
 create mode 100644 src/runtime/loongarch64-lispregs.h

diff --git a/src/runtime/Config.loongarch64-linux b/src/runtime/Config.loongarch64-linux
new file mode 100644
index 000000000..c46d54631
--- /dev/null
+++ b/src/runtime/Config.loongarch64-linux
@@ -0,0 +1,35 @@
+# -*- makefile -*- for the C-level run-time support for SBCL
+
+# This software is part of the SBCL system. See the README file for
+# more information.
+#
+# This software is derived from the CMU CL system, which was
+# written at Carnegie Mellon University and released into the
+# public domain. The software is in the public domain and is
+# provided with absolutely no warranty. See the COPYING and CREDITS
+# files for more information.
+
+ARCH_SRC = loongarch64-arch.c
+
+ASSEM_SRC = loongarch64-assem.S
+ARCH_SRC = loongarch64-arch.c
+
+OS_SRC = linux-os.c linux-mman.c loongarch64-linux-os.c
+OS_LIBS = -ldl -Wl,-no-as-needed
+
+ifdef LISP_FEATURE_SB_THREAD
+  OS_LIBS += -lpthread
+endif
+
+ifdef LISP_FEATURE_SB_CORE_COMPRESSION
+  OS_LIBS += -lzstd
+endif
+
+LINKFLAGS += -Wl,--export-dynamic
+DISABLE_PIE=no
+
+ifdef LISP_FEATURE_LARGEFILE
+  CFLAGS += -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
+endif
+
+GC_SRC = fullcgc.c gencgc.c traceroot.c
diff --git a/src/runtime/loongarch64-arch.c b/src/runtime/loongarch64-arch.c
new file mode 100644
index 000000000..aafa816bb
--- /dev/null
+++ b/src/runtime/loongarch64-arch.c
@@ -0,0 +1,321 @@
+/*
+ * This software is part of the SBCL system. See the README file for
+ * more information.
+ *
+ * This software is derived from the CMU CL system, which was
+ * written at Carnegie Mellon University and released into the
+ * public domain. The software is in the public domain and is
+ * provided with absolutely no warranty. See the COPYING and CREDITS
+ * files for more information.
+ */
+#include <stdio.h>
+
+#include "genesis/sbcl.h"
+#include "runtime.h"
+#include "arch.h"
+#include "globals.h"
+#include "validate.h"
+#include "os.h"
+#include "lispregs.h"
+#include <signal.h>
+#include "interrupt.h"
+#include "interr.h"
+#include "breakpoint.h"
+#include "pseudo-atomic.h"
+#include <unistd.h>
+
+#define BREAK_INST 0x002A0000 
+#define BREAK_MASK 0xFFFF8000 
+
+os_vm_address_t
+arch_get_bad_addr(int signam, siginfo_t *siginfo, os_context_t *context)
+{
+    return (os_vm_address_t)siginfo->si_addr;
+}
+
+void arch_skip_instruction(os_context_t *context)
+{
+    uint32_t trap_instruction = *(uint32_t *)OS_CONTEXT_PC(context);
+    unsigned code = trap_instruction & 0xFF;
+    if(code == trap_FunEndBreakpoint || code == trap_Breakpoint)
+        OS_CONTEXT_PC(context) += 4;
+    else
+        OS_CONTEXT_PC(context) += 8;
+}
+
+unsigned char *arch_internal_error_arguments(os_context_t *context)
+{
+    return (unsigned char*)(OS_CONTEXT_PC(context));
+}
+
+bool arch_pseudo_atomic_atomic(struct thread *thread) {
+    return get_pseudo_atomic_atomic(thread);
+}
+
+void arch_set_pseudo_atomic_interrupted(struct thread *thread) {
+    set_pseudo_atomic_interrupted(thread);
+}
+
+void arch_clear_pseudo_atomic_interrupted(struct thread *thread) {
+    clear_pseudo_atomic_interrupted(thread);
+}
+
+unsigned int arch_install_breakpoint(void *pc)
+{
+    unsigned int *ptr = (unsigned int *)pc;
+    unsigned int result = *ptr;
+
+    *ptr = BREAK_INST | trap_Breakpoint;
+
+    os_flush_icache((os_vm_address_t) ptr, sizeof(unsigned int));
+    return result;
+}
+
+void arch_remove_breakpoint(void *pc, unsigned int orig_inst)
+{ 
+    *(unsigned int *) pc = orig_inst;
+    os_flush_icache((os_vm_address_t) pc, sizeof(unsigned int));
+}
+
+static int sign_extend_u(int16_t value, int n_bits) {
+    int shift = 32 - n_bits;
+    return (value << shift) >> shift;
+}
+
+static bool is_load_store_pc_rel(unsigned int inst) {
+    unsigned int opcode = (inst >> 22) & 0x3FF; 
+    switch(opcode) {
+        case 0b0010100000: // LD.B
+        case 0b0010100001: // LD.H
+        case 0b0010100010: // LD.W
+        case 0b0010100011: // LD.D
+        case 0b0010101000: // LD.BU
+        case 0b0010101001: // LD.HU
+        case 0b0010101010: // LD.WU
+        case 0b0010100100: // ST.B
+        case 0b0010100101: // ST.H
+        case 0b0010100110: // ST.W
+        case 0b0010100111: // ST.D
+            return true;
+        default:
+            return false;
+    }
+}
+
+#define BREAKPOINT_TEMP_REG reg_T7
+
+void arch_do_displaced_inst(os_context_t *context, unsigned int orig_inst)
+{
+    unsigned int *pc = (unsigned int *)OS_CONTEXT_PC(context);
+    unsigned int *next_pc = pc;
+
+    if (((orig_inst >> 26) & 0x3F) >= 0b010110 && ((orig_inst >> 26) & 0x3F) <= 0b011011) {
+        int rj = (orig_inst >> 5) & 0x1F;
+        int rd = (orig_inst >> 0) & 0x1F;
+        int16_t imm16 = orig_inst & 0xFFFF;
+        int offset = sign_extend_u(imm16, 16);
+
+        uword_t val_j = *os_context_register_addr(context, rj);
+        uword_t val_d = *os_context_register_addr(context, rd);
+
+        int take_branch = 0;
+        switch ((orig_inst >> 26) & 0x3F) {
+            case 0b010110: take_branch = (val_j == val_d); break;          // BEQ
+            case 0b010111: take_branch = (val_j != val_d); break;          // BNE
+            case 0b011000: take_branch = ((sword_t)val_j < (sword_t)val_d); break; // BLT
+            case 0b011001: take_branch = ((sword_t)val_j >= (sword_t)val_d); break; // BGE
+            case 0b011010: take_branch = (val_j < val_d); break;           // BLTU
+            case 0b011011: take_branch = (val_j >= val_d); break;          // BGEU
+            default: lose("Unknown conditional branch");
+        }
+
+        if (take_branch)
+            next_pc += offset;
+        else
+            next_pc += 1;
+    }
+
+    // JIRL
+    else if (((orig_inst >> 26) & 0x3F) == 0b010011) {
+        int rj = (orig_inst >> 5) & 0x1F;
+        int rd = (orig_inst >> 0) & 0x1F; 
+        int16_t imm16 = orig_inst & 0xFFFF; 
+        int offset = sign_extend_u(imm16, 16);
+
+        uword_t target = *os_context_register_addr(context, rj) + offset;
+
+        if (rd != 0)
+            *os_context_register_addr(context, rd) = (uword_t)(pc + 2);
+        next_pc = (unsigned int *)target;
+    }
+
+    // Load/Store PC-relative
+    else if (is_load_store_pc_rel(orig_inst)) {
+        int rd = orig_inst & 0x1F;
+        int rj = (orig_inst >> 5) & 0x1F;
+        int16_t si12 = (orig_inst >> 10) & 0xFFF;
+        int offset = sign_extend_u(si12, 12);
+        uword_t addr = *os_context_register_addr(context, rj) + offset;
+
+        switch ((orig_inst >> 22) & 0x3FF) {
+            case 0b0010100000: *os_context_register_addr(context, rd) = (sword_t)*(int8_t *)addr; break;   // LD.B
+            case 0b0010100001: *os_context_register_addr(context, rd) = (sword_t)*(int16_t *)addr; break;  // LD.H
+            case 0b0010100010: *os_context_register_addr(context, rd) = (sword_t)*(int32_t *)addr; break;  // LD.W
+            case 0b0010100011: *os_context_register_addr(context, rd) = *(uword_t *)addr; break;          // LD.D
+            case 0b0010101000: *os_context_register_addr(context, rd) = *(uint8_t *)addr; break;          // LD.BU
+            case 0b0010101001: *os_context_register_addr(context, rd) = *(uint16_t *)addr; break;         // LD.HU
+            case 0b0010101010: *os_context_register_addr(context, rd) = *(uint32_t *)addr; break;         // LD.WU
+            case 0b0010100100: *(int8_t *)addr = (int8_t)*os_context_register_addr(context, rd); break;  // ST.B
+            case 0b0010100101: *(int16_t *)addr = (int16_t)*os_context_register_addr(context, rd); break; // ST.H
+            case 0b0010100110: *(int32_t *)addr = (int32_t)*os_context_register_addr(context, rd); break; // ST.W
+            case 0b0010100111: *(uword_t *)addr = *os_context_register_addr(context, rd); break;          // ST.D
+            default: lose("Unknown load/store instruction");
+        }
+
+        next_pc += 1; 
+    }
+
+    // Trampoline
+    else {
+        size_t size = getpagesize();
+        struct thread *th = get_sb_vm_thread();
+        unsigned int *trampoline = (unsigned int *)th->breakpoint_misc;
+
+        if (!trampoline) {
+            trampoline = mmap(NULL, size,
+                              PROT_READ | PROT_WRITE,
+                              MAP_PRIVATE | MAP_ANONYMOUS,
+                              -1, 0);
+            th->breakpoint_misc = trampoline;
+        } else {
+            os_protect((os_vm_address_t)trampoline, size, PROT_READ | PROT_WRITE);
+        }
+
+        unsigned int *inst_ptr = trampoline;
+
+        next_pc += 1;
+
+        *inst_ptr++ = orig_inst;
+
+        *inst_ptr++ = 0x1C000000 | BREAKPOINT_TEMP_REG;
+        *inst_ptr++ = 0x28C00000 | BREAKPOINT_TEMP_REG << 5 | BREAKPOINT_TEMP_REG | 12 << 10;
+        *inst_ptr++ = 0x4C000000  | BREAKPOINT_TEMP_REG << 5;
+
+        *(uword_t *)inst_ptr++ = (uword_t)next_pc;
+
+        OS_CONTEXT_PC(context) = (uword_t)trampoline;
+        os_flush_icache((os_vm_address_t)trampoline, (char*)inst_ptr - (char*)trampoline);
+        os_protect((os_vm_address_t)trampoline, size, PROT_READ | PROT_EXEC);
+        return;
+    }
+
+    OS_CONTEXT_PC(context) = (uword_t)next_pc;
+}
+
+
+void
+arch_handle_breakpoint(os_context_t *context)
+{
+    handle_breakpoint(context);
+}
+
+void
+arch_handle_fun_end_breakpoint(os_context_t *context)
+{
+    OS_CONTEXT_PC(context) = (uword_t)handle_fun_end_breakpoint(context);
+}
+
+void
+arch_handle_single_step_trap(os_context_t *context, int trap)
+{
+    handle_single_step_trap(context, trap, reg_LEXENV);
+    arch_skip_instruction(context);
+}
+
+
+static void
+sigtrap_handler(int signal, siginfo_t *info, os_context_t *context)
+{
+
+    uint32_t trap_instruction;
+    memcpy(&trap_instruction, (void *)OS_CONTEXT_PC(context), sizeof trap_instruction);
+    unsigned code;
+    unsigned code_1 = trap_instruction & 0xFF;
+
+    if ((trap_instruction & BREAK_MASK) != BREAK_INST) {
+        lose("Unrecognized trap instruction %08x in sigtrap_handler()",
+             trap_instruction);
+    }
+    if (code_1 == trap_Breakpoint || code_1 == trap_FunEndBreakpoint)
+        code = code_1;
+    else   
+        code = *((unsigned char *)(4 + OS_CONTEXT_PC(context)));
+
+    handle_trap(context, code);
+}
+
+void
+arch_install_interrupt_handlers(void)
+{
+    ll_install_handler(SIGTRAP, sigtrap_handler);
+}
+
+#define LINKAGE_TEMP_REG reg_LIP 
+
+
+void arch_write_linkage_table_entry(int index, void *target_addr, int datap)
+{
+    // allocate successive entries downward
+    char *reloc_addr =
+        (char*)ALIEN_LINKAGE_SPACE_END - (index + 1) * ALIEN_LINKAGE_TABLE_ENTRY_SIZE;
+
+    if (datap) {
+      *(unsigned long *)reloc_addr = (unsigned long)target_addr;
+      return;
+    }
+    int* inst_ptr;
+    unsigned inst;
+
+    inst_ptr = (int*) reloc_addr;
+
+#ifndef LISP_FEATURE_64_BIT
+    /*
+      lui   reg, %hi(address)
+      jr    reg, %lo(address)
+    */
+    unsigned int addr = (unsigned int)target_addr;
+    unsigned int hi = ((addr + 0x800) >> 12);
+    int lo = addr - (hi << 12);
+
+    inst = 0x16000000 | LINKAGE_TEMP_REG | hi << 5;
+    *inst_ptr++ = inst;
+
+    inst = 0x4C000000 | LINKAGE_TEMP_REG << 5 | lo << 10;
+    *inst_ptr++ = inst;
+#else
+    /*
+      pcaddu12i reg, 0
+      load reg, 12(reg)
+      jirl  reg
+      address
+    */
+
+    inst = 0x1C000000 | LINKAGE_TEMP_REG;
+    *inst_ptr++ = inst;
+
+    inst = 0x28C00000 | LINKAGE_TEMP_REG << 5 | LINKAGE_TEMP_REG | 12 << 10;
+    *inst_ptr++ = inst;
+
+    inst = 0x4C000000  | LINKAGE_TEMP_REG << 5;
+    *inst_ptr++ = inst;
+
+    *(unsigned long *)inst_ptr++ = (unsigned long)target_addr;
+#endif
+
+    os_flush_icache((os_vm_address_t) reloc_addr, (char*) inst_ptr - reloc_addr);
+}
+
+lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs) {
+    return ((lispobj(*)(lispobj, lispobj *, int, struct thread*))SYMBOL(CALL_INTO_LISP)->value)
+      (fun, args, nargs, get_sb_vm_thread());
+}
diff --git a/src/runtime/loongarch64-arch.h b/src/runtime/loongarch64-arch.h
new file mode 100644
index 000000000..619ae8fa9
--- /dev/null
+++ b/src/runtime/loongarch64-arch.h
@@ -0,0 +1,5 @@
+#ifndef _LOONGARCH64_ARCH_H
+#define _LOONGARCH64_ARCH_H
+
+#endif /* _LOONGARCH64_ARCH_H */
+
diff --git a/src/runtime/loongarch64-assem.S b/src/runtime/loongarch64-assem.S
new file mode 100644
index 000000000..1e0c5358c
--- /dev/null
+++ b/src/runtime/loongarch64-assem.S
@@ -0,0 +1,61 @@
+/*
+ * very-low-level utilities for runtime support
+ */
+
+/*
+ * This software is part of the SBCL system. See the README file for
+ * more information.
+ *
+ * This software is derived from the CMU CL system, which was
+ * written at Carnegie Mellon University and released into the
+ * public domain. The software is in the public domain and is
+ * provided with absolutely no warranty. See the COPYING and CREDITS
+ * files for more information.
+ */
+
+#ifdef __ELF__
+// Mark the object as not requiring an executable stack.
+.section .note.GNU-stack,"",%progbits
+#endif
+
+#include "globals.h"
+#include "lispregs.h"
+#include "validate.h"
+#include "genesis/closure.h"
+#include "genesis/static-symbols.h"
+
+        .text
+        .align 2
+
+        .global  fun_end_breakpoint_guts
+        .type fun_end_breakpoint_guts,%function
+fun_end_breakpoint_guts:
+        addi.d $r20, $r0, 2                        # li   $tmp 2
+        bge $r18, $r20, multiple_value_return      # bge  $nargs $tmp multiple_value_return
+        addi.d $r14, $r23, 0                       # move $ocfp $csp 
+        addi.d $r23, $r23, N_WORD_BYTES            # addi $cfp $cfp N_WORD_BYTES
+        addi.d $r18, $r0, (1 << N_FIXNUM_TAG_BITS) # li   $nargs (1 << N_FIXNUM_TAG_BITS)
+        addi.d $r5, $r16, 0                        # move $a1 $NULL
+        addi.d $r6, $r16, 0                        # move $a2 $NULL
+        addi.d $r7, $r16, 0                        # move $a3 $NULL
+
+multiple_value_return:
+        
+        .global fun_end_breakpoint_trap
+        .type fun_end_breakpoint_trap,%function
+
+fun_end_breakpoint_trap:
+        break   trap_FunEndBreakpoint        
+
+        .global  fun_end_breakpoint_end
+fun_end_breakpoint_end:
+
+        .align 2
+        .global do_pending_interrupt
+        .type do_pending_interrupt,%function
+do_pending_interrupt:
+        break   trap_PendingInterrupt      
+        .byte   trap_PendingInterrupt
+        .align 2 
+        ret           
+
diff --git a/src/runtime/loongarch64-linux-os.c b/src/runtime/loongarch64-linux-os.c
new file mode 100644
index 000000000..805a90d8e
--- /dev/null
+++ b/src/runtime/loongarch64-linux-os.c
@@ -0,0 +1,134 @@
+/*
+ * This is the LoongArch Linux incarnation of arch-dependent OS-dependent
+ * routines. See also "linux-os.c".
+ */
+
+/*
+ * This software is part of the SBCL system. See the README file for
+ * more information.
+ *
+ * This software is derived from the CMU CL system, which was
+ * written at Carnegie Mellon University and released into the
+ * public domain. The software is in the public domain and is
+ * provided with absolutely no warranty. See the COPYING and CREDITS
+ * files for more information.
+ */
+
+#include <stdio.h>
+
+#ifdef __linux__
+#else
+#include <sys/cachectl.h>
+#endif
+#include <sys/param.h>
+#include <sys/file.h>
+#include "genesis/sbcl.h"
+#include "os.h"
+#include "arch.h"
+#include "globals.h"
+#include "interrupt.h"
+#include "interr.h"
+#include "lispregs.h"
+
+#include <sys/types.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "validate.h"
+
+#include <stdint.h>
+#include <stddef.h>
+#include <sys/ucontext.h>   /* for ucontext_t / mcontext_t */
+#include <asm/sigcontext.h> /* for sctx_info, FPU_CTX_MAGIC, struct fpu_context */
+
+
+#define EXTCTX_SCAN_MAX_BYTES 16384
+
+int
+arch_os_thread_init(struct thread *thread)
+{
+    return 1;                  /* success */
+}
+
+int
+arch_os_thread_cleanup(struct thread *thread)
+{
+    return 1;                  /* success */
+}
+
+os_context_register_t *
+os_context_register_addr(os_context_t *context, int offset)
+{
+    return (os_context_register_t*)&(context->uc_mcontext.__gregs[offset]);
+}
+
+os_context_register_t *
+os_context_lr_addr(os_context_t *context)
+{
+    return os_context_register_addr(context, reg_LIP);
+}
+
+sigset_t *
+os_context_sigmask_addr(os_context_t *context)
+{
+    return &context->uc_sigmask;
+}
+
+void
+os_restore_fp_control(os_context_t *context)
+{
+    /* FIXME: Implement. */
+}
+
+os_context_register_t *
+os_context_float_register_addr(os_context_t *uc, int offset)
+{
+    if (offset < 0 || offset >= 32) return NULL; /* bounds check */
+
+    mcontext_t *mc = &uc->uc_mcontext;
+
+    uint8_t *p = (uint8_t *)&mc->__extcontext[0];
+    size_t remaining = EXTCTX_SCAN_MAX_BYTES;
+
+    while (remaining >= sizeof(struct sctx_info)) {
+        struct sctx_info *hdr = (struct sctx_info *)p;
+
+        if (hdr->size < sizeof(struct sctx_info)) break;
+
+        if (hdr->magic == FPU_CTX_MAGIC) {
+            if (hdr->size < (sizeof(struct sctx_info) + sizeof(struct fpu_context)))
+                return NULL;
+
+            uintptr_t base = ((uintptr_t)p + sizeof(struct sctx_info) + 15) & ~((uintptr_t)15);
+        struct fpu_context *fpu = (struct fpu_context *)base;
+            return (os_context_register_t *)&(fpu->regs[offset]);
+        }
+
+        size_t sz = hdr->size;
+        if (sz > remaining) break;
+        p += sz;
+        remaining -= sz;
+    }
+    return NULL;
+}
+
+
+void
+os_flush_icache(os_vm_address_t address, os_vm_size_t length)
+{
+    os_vm_address_t end_address
+        = (os_vm_address_t)(((uintptr_t) address) + length);
+#ifndef LISP_FEATURE_OS_PROVIDES_FLUSH_ICACHE
+        __builtin___clear_cache(address, end_address);
+#endif
+}
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+int _stat(const char *pathname, struct stat *sb) {return stat(pathname, sb); }
+int _lstat(const char *pathname, struct stat *sb) { return lstat(pathname, sb); }
+int _fstat(int fd, struct stat *sb) { return fstat(fd, sb); }
diff --git a/src/runtime/loongarch64-linux-os.h b/src/runtime/loongarch64-linux-os.h
new file mode 100644
index 000000000..b440ce4c4
--- /dev/null
+++ b/src/runtime/loongarch64-linux-os.h
@@ -0,0 +1,9 @@
+#ifndef _LOONGARCH64_LINUX_OS_H
+#define _LOONGARCH64_LINUX_OS_H
+
+typedef ucontext_t os_context_t;
+typedef long os_context_register_t;
+
+#define OS_CONTEXT_PC(context) ((context)->uc_mcontext.__pc)
+
+#endif /* _LOONGARCH64_LINUX_OS_H */
diff --git a/src/runtime/loongarch64-lispregs.h b/src/runtime/loongarch64-lispregs.h
new file mode 100644
index 000000000..5d0ca0657
--- /dev/null
+++ b/src/runtime/loongarch64-lispregs.h
@@ -0,0 +1,56 @@
+/*
+ * This software is part of the SBCL system. See the README file for
+ * more information.
+ *
+ * This software is derived from the CMU CL system, which was
+ * written at Carnegie Mellon University and released into the
+ * public domain. The software is in the public domain and is
+ * provided with absolutely no warranty. See the COPYING and CREDITS
+ * files for more information.
+ */
+
+#ifdef LANGUAGE_ASSEMBLY
+#define REG(num) $ ## num
+#else
+#define REG(num) num
+#endif
+
+#define NREGS (32)
+
+#define reg_ZERO      REG(0)
+#define REG_RA        REG(1)
+#define reg_RA        REG(1)
+#define reg_TP        REG(2)
+#define reg_NSP       REG(3)
+#define reg_A0        REG(4)
+#define reg_A1        REG(5)
+#define reg_NL0       REG(6)
+#define reg_NL1       REG(7)
+#define reg_A2        REG(8)
+#define reg_NL2       REG(9)
+#define reg_A3        REG(10)
+#define reg_NL3       REG(11)
+#define reg_LIP       REG(12)
+#define reg_CFP       REG(13)
+#define reg_OCFP      REG(14)
+#define reg_LEXENV    REG(15)
+#define reg_NULL      REG(16)
+#define reg_CODE      REG(17)
+#define reg_NARGS     REG(18)
+#define reg_T7        REG(19)
+#define reg_T8        REG(20)
+#define reg_RSV       REG(21)
+#define reg_NFP       REG(22)
+#define reg_CSP       REG(23)
+#define reg_A4        REG(24)
+#define reg_NL4       REG(25)
+#define reg_A5        REG(26)
+#define reg_NL5       REG(27)
+#define reg_L0        REG(28)
+#define reg_L1        REG(29)
+#ifdef LISP_FEATURE_SB_THREAD
+#define reg_THREAD    REG(30)
+#else
+#define reg_L2        REG(30)
+#endif
+#define reg_CFUNC     REG(31)
-- 
2.20.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.