simdutf 9.3.3
Unicode at GB/s.
Loading...
Searching...
No Matches
portability.h
1#ifndef SIMDUTF_PORTABILITY_H
2#define SIMDUTF_PORTABILITY_H
3
4#include "simdutf/compiler_check.h"
5
6#include <cfloat>
7#include <cstddef>
8#include <cstdint>
9#include <cstdio>
10#include <cstdlib>
11#ifndef _WIN32
12 // strcasecmp, strncasecmp
13 #include <strings.h>
14#endif
15
16#if defined(__apple_build_version__)
17 #if __apple_build_version__ < 14000000
18 #define SIMDUTF_SPAN_DISABLED \
19 1 // apple-clang/13 doesn't support std::convertible_to
20 #endif
21#endif
22
23#if SIMDUTF_CPLUSPLUS20
24 #include <version>
25 #if __cpp_concepts >= 201907L && __cpp_lib_span >= 202002L && \
26 !defined(SIMDUTF_SPAN_DISABLED)
27 #define SIMDUTF_SPAN 1
28 #endif // __cpp_concepts >= 201907L && __cpp_lib_span >= 202002L
29 #if __cpp_lib_atomic_ref >= 201806L
30 #define SIMDUTF_ATOMIC_REF 1
31 #endif // __cpp_lib_atomic_ref
32 #if __has_cpp_attribute(maybe_unused) >= 201603L
33 #define SIMDUTF_MAYBE_UNUSED_AVAILABLE 1
34 #endif // __has_cpp_attribute(maybe_unused) >= 201603L
35#endif
36
37/**
38 * We want to check that it is actually a little endian system at
39 * compile-time.
40 */
41
42#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__)
43 #define SIMDUTF_IS_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
44#elif defined(_WIN32)
45 #define SIMDUTF_IS_BIG_ENDIAN 0
46#else
47 #if defined(__APPLE__) || \
48 defined(__FreeBSD__) // defined __BYTE_ORDER__ && defined
49 // __ORDER_BIG_ENDIAN__
50 #include <machine/endian.h>
51 #elif defined(sun) || \
52 defined(__sun) // defined(__APPLE__) || defined(__FreeBSD__)
53 #include <sys/byteorder.h>
54 #else // defined(__APPLE__) || defined(__FreeBSD__)
55
56 #ifdef __has_include
57 #if __has_include(<endian.h>)
58 #include <endian.h>
59 #endif //__has_include(<endian.h>)
60 #endif //__has_include
61
62 #endif // defined(__APPLE__) || defined(__FreeBSD__)
63
64 #ifndef !defined(__BYTE_ORDER__) || !defined(__ORDER_LITTLE_ENDIAN__)
65 #define SIMDUTF_IS_BIG_ENDIAN 0
66 #endif
67
68 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
69 #define SIMDUTF_IS_BIG_ENDIAN 0
70 #else // __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
71 #define SIMDUTF_IS_BIG_ENDIAN 1
72 #endif // __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
73
74#endif // defined __BYTE_ORDER__ && defined __ORDER_BIG_ENDIAN__
75
76/**
77 * At this point in time, SIMDUTF_IS_BIG_ENDIAN is defined.
78 */
79
80#ifdef _MSC_VER
81 #define SIMDUTF_VISUAL_STUDIO 1
82 /**
83 * We want to differentiate carefully between
84 * clang under visual studio and regular visual
85 * studio.
86 *
87 * Under clang for Windows, we enable:
88 * * target pragmas so that part and only part of the
89 * code gets compiled for advanced instructions.
90 *
91 */
92 #ifdef __clang__
93 // clang under visual studio
94 #define SIMDUTF_CLANG_VISUAL_STUDIO 1
95 #else
96 // just regular visual studio (best guess)
97 #define SIMDUTF_REGULAR_VISUAL_STUDIO 1
98 #endif // __clang__
99#endif // _MSC_VER
100
101#ifdef SIMDUTF_REGULAR_VISUAL_STUDIO
102 // https://en.wikipedia.org/wiki/C_alternative_tokens
103 // This header should have no effect, except maybe
104 // under Visual Studio.
105 #include <iso646.h>
106#endif
107
108#if (defined(__x86_64__) || defined(_M_AMD64)) && !defined(_M_ARM64EC)
109 #define SIMDUTF_IS_X86_64 1
110#elif defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC)
111 #define SIMDUTF_IS_ARM64 1
112#elif defined(__PPC64__) || defined(_M_PPC64)
113 #if defined(__VEC__) && defined(__ALTIVEC__) && defined(__POWER8_VECTOR__)
114 #define SIMDUTF_IS_PPC64 1
115 #endif
116#elif defined(__s390__)
117// s390 IBM system. Big endian.
118#elif (defined(__riscv) || defined(__riscv__)) && __riscv_xlen == 64
119 // RISC-V 64-bit
120 #define SIMDUTF_IS_RISCV64 1
121
122 // #if __riscv_v_intrinsic >= 1000000
123 // #define SIMDUTF_HAS_RVV_INTRINSICS 1
124 // #define SIMDUTF_HAS_RVV_TARGET_REGION 1
125 // #elif ...
126 // Check for special compiler versions that implement pre v1.0 intrinsics
127 #if __riscv_v_intrinsic >= 11000
128 #define SIMDUTF_HAS_RVV_INTRINSICS 1
129 #endif
130
131 #define SIMDUTF_HAS_ZVBB_INTRINSICS \
132 0 // there is currently no way to detect this
133
134 #if SIMDUTF_HAS_RVV_INTRINSICS && __riscv_vector && \
135 __riscv_v_min_vlen >= 128 && __riscv_v_elen >= 64
136 // RISC-V V extension
137 #define SIMDUTF_IS_RVV 1
138 #if SIMDUTF_HAS_ZVBB_INTRINSICS && __riscv_zvbb >= 1000000
139 // RISC-V Vector Basic Bit-manipulation
140 #define SIMDUTF_IS_ZVBB 1
141 #endif
142 #endif
143
144#elif defined(__loongarch_lp64)
145 #if defined(__loongarch_sx) && defined(__loongarch_asx)
146 #define SIMDUTF_IS_LSX 1
147 #define SIMDUTF_IS_LASX 1 // We can always run both
148 #elif defined(__loongarch_sx)
149 #define SIMDUTF_IS_LSX 1
150 // Adjust for runtime dispatching support.
151 #if defined(__GNUC__) && !defined(__clang__) && \
152 !defined(__INTEL_COMPILER) && !defined(__NVCOMPILER)
153 #if __GNUC__ > 15 || (__GNUC__ == 15 && __GNUC_MINOR__ >= 0)
154 // We are ok, we will support runtime dispatch for LASX.
155 #else
156 // We disable runtime dispatch for LASX, which means that we will not be
157 // able to use LASX even if it is supported by the hardware. Loongson
158 // users should update to GCC 15 or better.
159 #define SIMDUTF_IMPLEMENTATION_LASX 0
160 #endif
161 #elif defined(__clang__)
162 // LLVM supports runtime dispatch for LASX, see simdutf/lasx/intrinsics.h.
163 #else
164 // We are not using GCC or LLVM, so we do not support runtime dispatch
165 // for LASX. https://godbolt.org/z/jcMnrjYhs
166 #define SIMDUTF_IMPLEMENTATION_LASX 0
167 #endif
168 #endif
169#else
170 // The simdutf library is designed
171 // for 64-bit processors and it seems that you are not
172 // compiling for a known 64-bit platform. Please
173 // use a 64-bit target such as x64 or 64-bit ARM for best performance.
174 #define SIMDUTF_IS_32BITS 1
175
176 // We do not support 32-bit platforms, but it can be
177 // handy to identify them.
178 #if defined(_M_IX86) || defined(__i386__)
179 #define SIMDUTF_IS_X86_32BITS 1
180 #elif defined(__arm__) || defined(_M_ARM)
181 #define SIMDUTF_IS_ARM_32BITS 1
182 #elif defined(__PPC__) || defined(_M_PPC)
183 #define SIMDUTF_IS_PPC_32BITS 1
184 #endif
185
186#endif // defined(__x86_64__) || defined(_M_AMD64)
187
188#ifdef SIMDUTF_IS_32BITS
189 #ifndef SIMDUTF_NO_PORTABILITY_WARNING
190 // In the future, we may want to warn users of 32-bit systems that
191 // the simdutf does not support accelerated kernels for such systems.
192 #endif // SIMDUTF_NO_PORTABILITY_WARNING
193#endif // SIMDUTF_IS_32BITS
194
195// this is almost standard?
196#define SIMDUTF_STRINGIFY_IMPLEMENTATION_(a) #a
197#define SIMDUTF_STRINGIFY(a) SIMDUTF_STRINGIFY_IMPLEMENTATION_(a)
198
199// Our fast kernels require 64-bit systems.
200//
201// On 32-bit x86, we lack 64-bit popcnt, lzcnt, blsr instructions.
202// Furthermore, the number of SIMD registers is reduced.
203//
204// On 32-bit ARM, we would have smaller registers.
205//
206// The simdutf users should still have the fallback kernel. It is
207// slower, but it should run everywhere.
208
209//
210// Enable valid runtime implementations, and select
211// SIMDUTF_BUILTIN_IMPLEMENTATION
212//
213
214// We are going to use runtime dispatch.
215#if defined(SIMDUTF_IS_X86_64) || defined(SIMDUTF_IS_LSX)
216 #ifdef __clang__
217 // clang does not have GCC push pop
218 // warning: clang attribute push can't be used within a namespace in clang
219 // up til 8.0 so SIMDUTF_TARGET_REGION and SIMDUTF_UNTARGET_REGION must be
220 // *outside* of a namespace.
221 #define SIMDUTF_TARGET_REGION(T) \
222 _Pragma(SIMDUTF_STRINGIFY(clang attribute push( \
223 __attribute__((target(T))), apply_to = function)))
224 #define SIMDUTF_UNTARGET_REGION _Pragma("clang attribute pop")
225 #elif defined(__GNUC__)
226 // GCC is easier
227 #define SIMDUTF_TARGET_REGION(T) \
228 _Pragma("GCC push_options") _Pragma(SIMDUTF_STRINGIFY(GCC target(T)))
229 #define SIMDUTF_UNTARGET_REGION _Pragma("GCC pop_options")
230 #endif // clang then gcc
231
232#endif // defined(SIMDUTF_IS_X86_64) || defined(SIMDUTF_IS_LSX)
233
234// Default target region macros don't do anything.
235#ifndef SIMDUTF_TARGET_REGION
236 #define SIMDUTF_TARGET_REGION(T)
237 #define SIMDUTF_UNTARGET_REGION
238#endif
239
240// Is threading enabled?
241#if defined(_REENTRANT) || defined(_MT)
242 #ifndef SIMDUTF_THREADS_ENABLED
243 #define SIMDUTF_THREADS_ENABLED
244 #endif
245#endif
246
247// workaround for large stack sizes under -O0.
248// https://github.com/simdutf/simdutf/issues/691
249#ifdef __APPLE__
250 #ifndef __OPTIMIZE__
251 // Apple systems have small stack sizes in secondary threads.
252 // Lack of compiler optimization may generate high stack usage.
253 // Users may want to disable threads for safety, but only when
254 // in debug mode which we detect by the fact that the __OPTIMIZE__
255 // macro is not defined.
256 #undef SIMDUTF_THREADS_ENABLED
257 #endif
258#endif
259
260#ifdef SIMDUTF_VISUAL_STUDIO
261 // This is one case where we do not distinguish between
262 // regular visual studio and clang under visual studio.
263 // clang under Windows has _stricmp (like visual studio) but not strcasecmp
264 // (as clang normally has)
265 #define simdutf_strcasecmp _stricmp
266 #define simdutf_strncasecmp _strnicmp
267#else
268 // The strcasecmp, strncasecmp, and strcasestr functions do not work with
269 // multibyte strings (e.g. UTF-8). So they are only useful for ASCII in our
270 // context.
271 // https://www.gnu.org/software/libunistring/manual/libunistring.html#char-_002a-strings
272 #define simdutf_strcasecmp strcasecmp
273 #define simdutf_strncasecmp strncasecmp
274#endif
275
276#if defined(__GNUC__) && !defined(__clang__)
277 #if __GNUC__ >= 11
278 #define SIMDUTF_GCC11ORMORE 1
279 #endif // __GNUC__ >= 11
280 #if __GNUC__ == 10
281 #define SIMDUTF_GCC10 1
282 #endif // __GNUC__ == 10
283 #if __GNUC__ < 10
284 #define SIMDUTF_GCC9OROLDER 1
285 #endif // __GNUC__ == 10
286#endif // defined(__GNUC__) && !defined(__clang__)
287
288#endif // SIMDUTF_PORTABILITY_H