// Copyright (C) 2026 Kiyotsugu Arai // SPDX-License-Identifier: LGPL-3.0-or-later // compiler_intrinsics.hpp // Compatibility layer for compiler intrinsics between MSVC and GCC #ifndef SANGI_COMPILER_INTRINSICS_HPP #define SANGI_COMPILER_INTRINSICS_HPP #include #ifdef _MSC_VER #include #else // --- _umul128: 64x64 -> 128-bit multiplication --- static inline uint64_t _umul128(uint64_t a, uint64_t b, uint64_t* hi) { __uint128_t r = (__uint128_t)a * b; *hi = (uint64_t)(r >> 64); return (uint64_t)r; } // --- _addcarry_u64: addition with carry --- static inline unsigned char _addcarry_u64(unsigned char carry_in, uint64_t a, uint64_t b, uint64_t* out) { __uint128_t sum = (__uint128_t)a + b + carry_in; *out = (uint64_t)sum; return (unsigned char)(sum >> 64); } // --- _subborrow_u64: subtraction with borrow --- static inline unsigned char _subborrow_u64(unsigned char borrow_in, uint64_t a, uint64_t b, uint64_t* out) { __uint128_t diff = (__uint128_t)a - b - borrow_in; *out = (uint64_t)diff; return (unsigned char)(diff >> 127); // borrow = sign bit } // --- _BitScanReverse64: position of the most significant bit --- static inline unsigned char _BitScanReverse64(unsigned long* index, uint64_t mask) { if (mask == 0) return 0; *index = 63 - __builtin_clzll(mask); return 1; } // --- _udiv128: 128/64 -> 64 division --- static inline uint64_t _udiv128(uint64_t hi, uint64_t lo, uint64_t divisor, uint64_t* remainder) { __uint128_t dividend = ((__uint128_t)hi << 64) | lo; *remainder = (uint64_t)(dividend % divisor); return (uint64_t)(dividend / divisor); } // --- __shiftleft128: 128-bit left shift --- static inline uint64_t __shiftleft128(uint64_t lo, uint64_t hi, unsigned char shift) { if (shift == 0) return hi; return (hi << shift) | (lo >> (64 - shift)); } // --- __shiftright128: 128-bit right shift --- static inline uint64_t __shiftright128(uint64_t lo, uint64_t hi, unsigned char shift) { if (shift == 0) return lo; return (lo >> shift) | (hi << (64 - shift)); } // --- __lzcnt64: leading-zero count --- static inline uint64_t __lzcnt64(uint64_t x) { return x ? __builtin_clzll(x) : 64; } // --- _mulx_u64: MULX (carry-less multiply) --- static inline uint64_t _mulx_u64(uint64_t a, uint64_t b, uint64_t* hi) { return _umul128(a, b, hi); } // --- _BitScanForward64: position of the least significant bit --- static inline unsigned char _BitScanForward64(unsigned long* index, uint64_t mask) { if (mask == 0) return 0; *index = __builtin_ctzll(mask); return 1; } // --- _tzcnt_u64: trailing-zero count --- static inline uint64_t _tzcnt_u64(uint64_t x) { return x ? __builtin_ctzll(x) : 64; } // --- _alloca → alloca --- #include #define _alloca alloca #endif // _MSC_VER #endif // SANGI_COMPILER_INTRINSICS_HPP