Files

512 lines
15 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
StarForth — Steady-State Virtual Machine Runtime
Copyright (c) 20232025 Robert A. James
All rights reserved.
This file is part of the StarForth project.
Licensed under the StarForth License, Version 1.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
https://github.com/star.4th@proton.me/StarForth/LICENSE.txt
This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND,
express or implied, including but not limited to the warranties of
merchantability, fitness for a particular purpose, and noninfringement.
See the License for the specific language governing permissions and
limitations under the License.
StarForth — Steady-State Virtual Machine Runtime
Copyright (c) 20232025 Robert A. James
All rights reserved.
This file is part of the StarForth project.
Licensed under the StarForth License, Version 1.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
https://github.com/star.4th@proton.me/StarForth/LICENSE.txt
This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND,
express or implied, including but not limited to the warranties of
merchantability, fitness for a particular purpose, and noninfringement.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file arch_detect.h
* @brief Architecture Detection and Unified API for StarForth
* @details Automatically selects x86_64 or ARM64 optimizations and provides
* a unified interface for architecture-specific optimizations.
*
* This work is released under license terms in LICENSE file.
* No warranty. Use at your own risk.
*/
#ifndef ARCH_DETECT_H
#define ARCH_DETECT_H
/**
* @defgroup arch_detect Architecture Detection
* @{
*
* @brief Automatic detection of target architecture and inclusion of optimization headers
*
* This module automatically detects the target architecture at compile time and includes
* the appropriate assembly optimization headers.
*
* Supported architectures:
* - x86_64 (AMD64, Intel 64)
* - ARM64 (AArch64, ARMv8-A)
*
* Unsupported architectures fall back to pure C implementations.
* @}
*/
/* Detect architecture at compile time */
#if defined(__x86_64__) || defined(_M_X64) || defined(__amd64__)
#define ARCH_X86_64 1
#define ARCH_ARM64 0
#define ARCH_RISCV64 0
#define ARCH_NAME "x86_64"
#elif defined(__aarch64__) || defined(_M_ARM64) || defined(__arm64__)
#define ARCH_X86_64 0
#define ARCH_ARM64 1
#define ARCH_RISCV64 0
#define ARCH_NAME "ARM64"
#elif defined(__riscv) && (__riscv_xlen == 64)
#define ARCH_X86_64 0
#define ARCH_ARM64 0
#define ARCH_RISCV64 1
#define ARCH_NAME "RISC-V 64"
#else
#define ARCH_X86_64 0
#define ARCH_ARM64 0
#define ARCH_RISCV64 0
#define ARCH_NAME "Unknown"
#warning "Unknown architecture, assembly optimizations disabled"
#endif
/* Include architecture-specific headers */
#if ARCH_X86_64 && USE_ASM_OPT
#include "vm_asm_opt.h"
#if USE_DIRECT_THREADING
#include "vm_inner_interp_asm.h"
#endif
#elif ARCH_ARM64 && USE_ASM_OPT
#include "vm_asm_opt_arm64.h"
#if USE_DIRECT_THREADING
#include "vm_inner_interp_arm64.h"
#endif
#elif ARCH_RISCV64 && USE_ASM_OPT
#include "vm_asm_opt_riscv64.h"
#if USE_DIRECT_THREADING
#include "vm_inner_interp_riscv64.h"
#endif
#endif
/**
* @defgroup unified_api Unified API Wrappers
* @{
*
* @brief Consistent API macros across all architectures
*
* These macros provide a consistent API across all architectures by automatically
* dispatching to the appropriate optimized or fallback implementation based on
* the target architecture and available optimizations.
* @}
*/
/* ========== Stack Operations ========== */
#if USE_ASM_OPT && (ARCH_X86_64 || ARCH_ARM64 || ARCH_RISCV64)
/* Use optimized assembly implementations */
#define vm_push_opt(vm, val) vm_push_asm(vm, val)
#define vm_pop_opt(vm) vm_pop_asm(vm)
#define vm_rpush_opt(vm, val) vm_rpush_asm(vm, val)
#define vm_rpop_opt(vm) vm_rpop_asm(vm)
#else
/* Fall back to standard C implementations */
#define vm_push_opt(vm, val) vm_push(vm, val)
#define vm_pop_opt(vm) vm_pop(vm)
#define vm_rpush_opt(vm, val) vm_rpush(vm, val)
#define vm_rpop_opt(vm) vm_rpop(vm)
#endif
/* ========== Arithmetic Operations ========== */
#if USE_ASM_OPT && (ARCH_X86_64 || ARCH_ARM64 || ARCH_RISCV64)
#define vm_add_overflow_opt(a, b, res) vm_add_check_overflow(a, b, res)
#define vm_sub_overflow_opt(a, b, res) vm_sub_check_overflow(a, b, res)
#define vm_mul_double_opt(a, b, hi, lo) vm_mul_double(a, b, hi, lo)
#define vm_divmod_opt(dividend, divisor, quot, rem) vm_divmod(dividend, divisor, quot, rem)
#else
/* Fallback implementations */
static inline int vm_add_overflow_opt(cell_t a, cell_t b, cell_t *res) {
*res = a + b;
/* Simple overflow check (not perfect) */
return ((a > 0 && b > 0 && *res < 0) || (a < 0 && b < 0 && *res > 0));
}
static inline int vm_sub_overflow_opt(cell_t a, cell_t b, cell_t *res) {
*res = a - b;
return ((a > 0 && b < 0 && *res < 0) || (a < 0 && b > 0 && *res > 0));
}
static inline void vm_mul_double_opt(cell_t a, cell_t b, cell_t *hi, cell_t *lo) {
/* Simplified - assumes 64-bit cell_t */
*lo = a * b;
*hi = 0; /* Would need 128-bit arithmetic for proper high word */
}
static inline void vm_divmod_opt(cell_t dividend, cell_t divisor, cell_t *quot, cell_t *rem) {
*quot = dividend / divisor;
*rem = dividend % divisor;
}
#endif
/* ========== String Operations ========== */
#if USE_ASM_OPT && (ARCH_X86_64 || ARCH_ARM64 || ARCH_RISCV64)
#define vm_strcmp_opt(s1, s2, len) vm_strcmp_asm(s1, s2, len)
#define vm_memcpy_opt(dst, src, len) vm_memcpy_asm(dst, src, len)
#define vm_memzero_opt(dst, len) vm_memzero_asm(dst, len)
#else
#include <string.h>
static inline int vm_strcmp_opt(const char *s1, const char *s2, size_t len) {
return memcmp(s1, s2, len) != 0;
}
static inline void vm_memcpy_opt(void *dst, const void *src, size_t len) {
memcpy(dst, src, len);
}
static inline void vm_memzero_opt(void *dst, size_t len) {
memset(dst, 0, len);
}
#endif
/* ========== Min/Max Operations ========== */
#if USE_ASM_OPT && (ARCH_X86_64 || ARCH_ARM64 || ARCH_RISCV64)
#define vm_min_opt(a, b) vm_min_asm(a, b)
#define vm_max_opt(a, b) vm_max_asm(a, b)
#else
static inline cell_t vm_min_opt(cell_t a, cell_t b) {
return (a < b) ? a : b;
}
static inline cell_t vm_max_opt(cell_t a, cell_t b) {
return (a > b) ? a : b;
}
#endif
/* ========== Absolute Value ========== */
#if USE_ASM_OPT && (ARCH_ARM64 || ARCH_RISCV64)
#define vm_abs_opt(a) vm_abs_asm(a)
#else
static inline cell_t vm_abs_opt(cell_t a) {
return (a < 0) ? -a : a;
}
#endif
/* ========== Bit Operations ========== */
#if USE_ASM_OPT && (ARCH_ARM64 || ARCH_RISCV64)
#define vm_clz_opt(x) vm_clz(x)
#define vm_ctz_opt(x) vm_ctz(x)
#define vm_popcnt_opt(x) vm_popcnt(x)
#elif USE_ASM_OPT && ARCH_X86_64
static inline int vm_clz_opt(cell_t x) {
return __builtin_clzll((unsigned long long) x);
}
static inline int vm_ctz_opt(cell_t x) {
return __builtin_ctzll((unsigned long long) x);
}
static inline int vm_popcnt_opt(cell_t x) {
return __builtin_popcountll((unsigned long long) x);
}
#else
/* Software fallback */
static inline int vm_clz_opt(cell_t x) {
if (x == 0) return 64;
int n = 0;
if ((x & 0xFFFFFFFF00000000ULL) == 0) {
n += 32;
x <<= 32;
}
if ((x & 0xFFFF000000000000ULL) == 0) {
n += 16;
x <<= 16;
}
if ((x & 0xFF00000000000000ULL) == 0) {
n += 8;
x <<= 8;
}
if ((x & 0xF000000000000000ULL) == 0) {
n += 4;
x <<= 4;
}
if ((x & 0xC000000000000000ULL) == 0) {
n += 2;
x <<= 2;
}
if ((x & 0x8000000000000000ULL) == 0) { n += 1; }
return n;
}
static inline int vm_ctz_opt(cell_t x) {
if (x == 0) return 64;
int n = 0;
if ((x & 0x00000000FFFFFFFFULL) == 0) {
n += 32;
x >>= 32;
}
if ((x & 0x000000000000FFFFULL) == 0) {
n += 16;
x >>= 16;
}
if ((x & 0x00000000000000FFULL) == 0) {
n += 8;
x >>= 8;
}
if ((x & 0x000000000000000FULL) == 0) {
n += 4;
x >>= 4;
}
if ((x & 0x0000000000000003ULL) == 0) {
n += 2;
x >>= 2;
}
if ((x & 0x0000000000000001ULL) == 0) { n += 1; }
return n;
}
static inline int vm_popcnt_opt(cell_t x) {
int count = 0;
while (x) {
count += x & 1;
x >>= 1;
}
return count;
}
#endif
/* ========== Cache Operations ========== */
#if USE_ASM_OPT && (ARCH_ARM64 || ARCH_RISCV64)
#define vm_prefetch_opt(addr) vm_prefetch(addr)
#define vm_prefetch_stream_opt(addr) vm_prefetch_stream(addr)
#elif USE_ASM_OPT && ARCH_X86_64
static inline void vm_prefetch_opt(const void *addr) {
__builtin_prefetch(addr, 0, 3); /* Read, high temporal locality */
}
static inline void vm_prefetch_stream_opt(const void *addr) {
__builtin_prefetch(addr, 0, 0); /* Read, no temporal locality */
}
#else
#define vm_prefetch_opt(addr) ((void)0)
#define vm_prefetch_stream_opt(addr) ((void)0)
#endif
/* ========== Inner Interpreter (Direct Threading) ========== */
#if USE_DIRECT_THREADING && ARCH_RISCV64
#define NEXT_OPT() NEXT_RV64()
#define vm_setup_registers_opt(vm) vm_setup_registers_rv64(vm)
#define vm_save_registers_opt(vm) vm_save_registers_rv64(vm)
#define PRIM_DUP_OPT() PRIM_DUP_RV64()
#define PRIM_DROP_OPT() PRIM_DROP_RV64()
#define PRIM_SWAP_OPT() PRIM_SWAP_RV64()
#define PRIM_OVER_OPT() PRIM_OVER_RV64()
#define PRIM_ROT_OPT() PRIM_ROT_RV64()
#define PRIM_PLUS_OPT() PRIM_PLUS_RV64()
#define PRIM_MINUS_OPT() PRIM_MINUS_RV64()
#define PRIM_STAR_OPT() PRIM_STAR_RV64()
#define PRIM_SLASH_OPT() PRIM_SLASH_RV64()
#define PRIM_MOD_OPT() PRIM_MOD_RV64()
#define PRIM_AND_OPT() PRIM_AND_RV64()
#define PRIM_OR_OPT() PRIM_OR_RV64()
#define PRIM_XOR_OPT() PRIM_XOR_RV64()
#define PRIM_INVERT_OPT() PRIM_INVERT_RV64()
#define PRIM_NEGATE_OPT() PRIM_NEGATE_RV64()
#define PRIM_FETCH_OPT() PRIM_FETCH_RV64()
#define PRIM_STORE_OPT() PRIM_STORE_RV64()
#define PRIM_C_FETCH_OPT() PRIM_C_FETCH_RV64()
#define PRIM_C_STORE_OPT() PRIM_C_STORE_RV64()
#define PRIM_TO_R_OPT() PRIM_TO_R_RV64()
#define PRIM_R_FROM_OPT() PRIM_R_FROM_RV64()
#define PRIM_R_FETCH_OPT() PRIM_R_FETCH_RV64()
#define PRIM_2DUP_OPT() PRIM_2DUP_RV64()
#define PRIM_2DROP_OPT() PRIM_2DROP_RV64()
#define PRIM_ZERO_EQUALS_OPT() PRIM_ZERO_EQUALS_RV64()
#define PRIM_ZERO_LESS_OPT() PRIM_ZERO_LESS_RV64()
#define PRIM_EQUALS_OPT() PRIM_EQUALS_RV64()
#define PRIM_LESS_OPT() PRIM_LESS_RV64()
#define PRIM_GREATER_OPT() PRIM_GREATER_RV64()
#define PRIM_BRANCH_OPT() PRIM_BRANCH_RV64()
#define PRIM_ZBRANCH_OPT() PRIM_ZBRANCH_RV64()
#define PRIM_EXECUTE_OPT() PRIM_EXECUTE_RV64()
#elif USE_DIRECT_THREADING && ARCH_X86_64
#define NEXT_OPT() NEXT_ASM()
#define vm_setup_registers_opt(vm) vm_setup_registers(vm)
#define vm_save_registers_opt(vm) vm_save_registers(vm)
/* Primitive word macros */
#define PRIM_DUP_OPT() PRIM_DUP()
#define PRIM_DROP_OPT() PRIM_DROP()
#define PRIM_SWAP_OPT() PRIM_SWAP()
#define PRIM_PLUS_OPT() PRIM_PLUS()
#define PRIM_MINUS_OPT() PRIM_MINUS()
#define PRIM_STAR_OPT() PRIM_STAR()
#define PRIM_FETCH_OPT() PRIM_FETCH()
#define PRIM_STORE_OPT() PRIM_STORE()
#define PRIM_TO_R_OPT() PRIM_TO_R()
#define PRIM_R_FROM_OPT() PRIM_R_FROM()
#define PRIM_R_FETCH_OPT() PRIM_R_FETCH()
#define PRIM_BRANCH_OPT() PRIM_BRANCH()
#define PRIM_ZBRANCH_OPT() PRIM_ZBRANCH()
#elif USE_DIRECT_THREADING && ARCH_ARM64
#define NEXT_OPT() NEXT_ARM64()
#define vm_setup_registers_opt(vm) vm_setup_registers_arm64(vm)
#define vm_save_registers_opt(vm) vm_save_registers_arm64(vm)
/* Primitive word macros */
#define PRIM_DUP_OPT() PRIM_DUP_ARM64()
#define PRIM_DROP_OPT() PRIM_DROP_ARM64()
#define PRIM_SWAP_OPT() PRIM_SWAP_ARM64()
#define PRIM_OVER_OPT() PRIM_OVER_ARM64()
#define PRIM_ROT_OPT() PRIM_ROT_ARM64()
#define PRIM_PLUS_OPT() PRIM_PLUS_ARM64()
#define PRIM_MINUS_OPT() PRIM_MINUS_ARM64()
#define PRIM_STAR_OPT() PRIM_STAR_ARM64()
#define PRIM_SLASH_OPT() PRIM_SLASH_ARM64()
#define PRIM_MOD_OPT() PRIM_MOD_ARM64()
#define PRIM_AND_OPT() PRIM_AND_ARM64()
#define PRIM_OR_OPT() PRIM_OR_ARM64()
#define PRIM_XOR_OPT() PRIM_XOR_ARM64()
#define PRIM_INVERT_OPT() PRIM_INVERT_ARM64()
#define PRIM_NEGATE_OPT() PRIM_NEGATE_ARM64()
#define PRIM_FETCH_OPT() PRIM_FETCH_ARM64()
#define PRIM_STORE_OPT() PRIM_STORE_ARM64()
#define PRIM_C_FETCH_OPT() PRIM_C_FETCH_ARM64()
#define PRIM_C_STORE_OPT() PRIM_C_STORE_ARM64()
#define PRIM_TO_R_OPT() PRIM_TO_R_ARM64()
#define PRIM_R_FROM_OPT() PRIM_R_FROM_ARM64()
#define PRIM_R_FETCH_OPT() PRIM_R_FETCH_ARM64()
#define PRIM_2DUP_OPT() PRIM_2DUP_ARM64()
#define PRIM_2DROP_OPT() PRIM_2DROP_ARM64()
#define PRIM_ZERO_EQUALS_OPT() PRIM_ZERO_EQUALS_ARM64()
#define PRIM_ZERO_LESS_OPT() PRIM_ZERO_LESS_ARM64()
#define PRIM_EQUALS_OPT() PRIM_EQUALS_ARM64()
#define PRIM_LESS_OPT() PRIM_LESS_ARM64()
#define PRIM_GREATER_OPT() PRIM_GREATER_ARM64()
#define PRIM_BRANCH_OPT() PRIM_BRANCH_ARM64()
#define PRIM_ZBRANCH_OPT() PRIM_ZBRANCH_ARM64()
#define PRIM_EXECUTE_OPT() PRIM_EXECUTE_ARM64()
#else
/* No direct threading - use standard C function calls */
#define NEXT_OPT() do {} while(0)
#define vm_setup_registers_opt(vm) do {} while(0)
#define vm_save_registers_opt(vm) do {} while(0)
/* Primitives fall back to function calls */
#define PRIM_DUP_OPT() do {} while(0)
#define PRIM_DROP_OPT() do {} while(0)
/* ... etc ... */
#endif
/**
* @defgroup runtime_detect Runtime Architecture Detection
* @{
*
* @brief Runtime detection of CPU features
*
* Functions for detecting available CPU features at runtime, such as SIMD
* support (SSE4.2, AVX, NEON) and other architecture-specific capabilities.
* @}
*/
#if ARCH_X86_64
/* Check for SSE4.2, AVX, etc. */
static inline int vm_has_sse42_opt(void) {
#if USE_ASM_OPT
return vm_has_sse42();
#else
return 0;
#endif
}
#elif ARCH_ARM64
/* Check for NEON, CRC32, etc. */
static inline int vm_has_neon_opt(void) {
#if USE_ASM_OPT
return vm_has_neon();
#else
return 0;
#endif
}
#else
static inline int vm_has_sse42_opt(void) { return 0; }
static inline int vm_has_neon_opt(void) { return 0; }
#endif
/**
* @defgroup build_info Build Information
* @{
*
* @brief Functions for querying build configuration
*
* Provides information about the build configuration, including target
* architecture, enabled optimizations, and threading model.
* @}
*/
static inline const char *vm_get_arch_name(void) {
return ARCH_NAME;
}
static inline int vm_has_asm_opt(void) {
#if USE_ASM_OPT
return 1;
#else
return 0;
#endif
}
static inline int vm_has_direct_threading(void) {
#if USE_DIRECT_THREADING
return 1;
#else
return 0;
#endif
}
static inline const char *vm_get_build_info(void) {
static char info[256];
snprintf(info, sizeof(info),
"Architecture: %s, ASM: %s, Direct Threading: %s",
vm_get_arch_name(),
vm_has_asm_opt() ? "enabled" : "disabled",
vm_has_direct_threading() ? "enabled" : "disabled"
);
return info;
}
#endif /* ARCH_DETECT_H */