1/**
2 * Copyright 2021 Alibaba, Inc. and its affiliates. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15
16 * \author Hechong.xyf
17 * \date Dec 2017
18 * \brief Interface of Platform Definition
19 */
20
21#ifndef __AILEGO_INTERNAL_PLATFORM_H__
22#define __AILEGO_INTERNAL_PLATFORM_H__
23
24#if defined(_WIN32) || defined(_WIN64)
25#include <sdkddkver.h>
26#endif
27
28#include <sys/types.h>
29#include <limits.h>
30#include <stdbool.h>
31#include <stddef.h>
32#include <stdint.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <time.h>
37
38#if defined(_MSC_VER)
39#include <intrin.h>
40#else
41#include <strings.h>
42#include <unistd.h>
43#if defined(__x86_64__) || defined(__i386)
44#include <x86intrin.h>
45#endif
46#if defined(__ARM_NEON)
47#include <arm_neon.h>
48#endif
49#if defined(__ARM_FEATURE_CRC32)
50#include <arm_acle.h>
51#endif
52#endif
53
54#if defined(__cplusplus)
55extern "C" {
56#endif
57
58#ifndef NDEBUG
59#define AILEGO_DEBUG
60#endif
61
62//! Fixed Intel intrinsics macro in MSVC
63#if defined(_MSC_VER)
64#if (_M_IX86_FP == 2 || defined(_M_AMD64) || defined(_M_X64))
65#define __SSE__ 1
66#define __SSE2__ 1
67#if _MSC_VER >= 1500
68#define __SSE3__ 1
69#define __SSSE3__ 1
70#define __SSE4_1__ 1
71#define __SSE4_2__ 1
72#endif
73#elif _M_IX86_FP == 1
74#define __SSE__ 1
75#endif
76#endif // _MSC_VER
77
78#if defined(_WIN32) || defined(_WIN64)
79#if defined(_WIN64)
80#define AILEGO_M64
81#else
82#define AILEGO_M32
83#endif
84#endif
85
86#if defined(__GNUC__)
87#if defined(__x86_64__) || defined(__aarch64__) || defined(__ppc64__)
88#define AILEGO_M64
89#else
90#define AILEGO_M32
91#endif
92#endif
93
94#ifndef AILEGO_ALIGNED
95#if defined(_MSC_VER)
96#define AILEGO_ALIGNED(x) __declspec(align(x))
97#define AILEGO_DEPRECATED __declspec(deprecated)
98#elif defined(__GNUC__)
99#define AILEGO_ALIGNED(x) __attribute__((aligned(x)))
100#define AILEGO_DEPRECATED __attribute__((deprecated))
101#else
102#define AILEGO_ALIGNED(x)
103#define AILEGO_DEPRECATED
104#endif
105#endif
106
107//! Add 'inline' for MSVC
108#if defined(_MSC_VER) && !defined(__cplusplus)
109#if !defined(inline)
110#define inline __inline
111#endif
112#endif
113
114//! Add 'ssize_t' for MSVC
115#if defined(_MSC_VER)
116typedef intptr_t ssize_t;
117#endif
118
119#if defined(_MSC_VER)
120//! Returns the number of trailing 0-bits in x
121static inline int ailego_ctz32(uint32_t x) {
122 unsigned long r = 0;
123 _BitScanForward(&r, x);
124 return (int)r;
125}
126
127//! Returns the number of leading 0-bits in x
128static inline int ailego_clz32(uint32_t x) {
129 unsigned long r = 0;
130 _BitScanReverse(&r, x);
131 return (31 - (int)r);
132}
133
134#if defined(AILEGO_M64)
135//! Returns the number of trailing 0-bits in x
136static inline int ailego_ctz64(uint64_t x) {
137 unsigned long r = 0;
138 _BitScanForward64(&r, x);
139 return (int)r;
140}
141
142//! Returns the number of leading 0-bits in x
143static inline int ailego_clz64(uint64_t x) {
144 unsigned long r = 0;
145 _BitScanReverse64(&r, x);
146 return (63 - (int)r);
147}
148#else
149//! Returns the number of trailing 0-bits in x
150static inline int ailego_ctz64(uint64_t x) {
151 unsigned long r = 0;
152 unsigned long m = (unsigned long)x;
153 _BitScanForward(&r, m);
154 if (r == 0) {
155 m = (unsigned long)(x >> 32);
156 _BitScanForward(&r, m);
157 if (r != 0) {
158 r += 32;
159 }
160 }
161 return (int)r;
162}
163
164//! Returns the number of leading 0-bits in x
165static inline int ailego_clz64(uint64_t x) {
166 unsigned long r = 0;
167 unsigned long m = (unsigned long)(x >> 32);
168 _BitScanReverse(&r, m);
169 if (r != 0) {
170 return (31 - (int)r);
171 }
172 m = (unsigned long)x;
173 _BitScanReverse(&r, m);
174 return (63 - (int)r);
175}
176#endif // AILEGO_M64
177
178//! Counts the number of one bits
179#define ailego_popcount32(x) (__popcnt(x))
180#define ailego_popcount64(x) (__popcnt64(x))
181#define ailego_likely(x) (x)
182#define ailego_unlikely(x) (x)
183#ifdef __SSE__
184#define ailego_prefetch(p) _mm_prefetch((p), 0)
185#else
186#define ailego_prefetch(p) ((void)(p))
187#endif
188#else // !_MSC_VER
189#define ailego_ctz32(x) (__builtin_ctz(x))
190#define ailego_ctz64(x) (__builtin_ctzll(x))
191#define ailego_clz32(x) (__builtin_clz(x))
192#define ailego_clz64(x) (__builtin_clzll(x))
193#define ailego_popcount32(x) (__builtin_popcount(x))
194#define ailego_popcount64(x) (__builtin_popcountl(x))
195#define ailego_likely(x) (__builtin_expect(!!(x), 1))
196#define ailego_unlikely(x) (__builtin_expect(!!(x), 0))
197#define ailego_prefetch(p) (__builtin_prefetch((p)))
198#endif // _MSC_VER
199
200#if defined(AILEGO_M64)
201#define ailego_ctz ailego_ctz64
202#define ailego_clz ailego_clz64
203#define ailego_popcount ailego_popcount64
204#else
205#define ailego_ctz ailego_ctz32
206#define ailego_clz ailego_clz32
207#define ailego_popcount ailego_popcount32
208#endif // AILEGO_M64
209
210#if defined(__arm__) || defined(__aarch64__)
211// ARMv7 Architecture Reference Manual (for YIELD)
212// ARM Compiler toolchain Compiler Reference (for __yield() instrinsic)
213#if defined(__CC_ARM)
214#define ailego_yield() __yield()
215#else
216#define ailego_yield() __asm__ __volatile__("yield")
217#endif // __CC_ARM
218#elif defined(__SSE2__)
219#define ailego_yield() _mm_pause()
220#else
221#define ailego_yield() ((void)0)
222#endif // __arm__ || __aarch64__
223
224#if defined(_MSC_VER)
225#define ailego_aligned_malloc(SIZE, ALIGN) \
226 _aligned_malloc((size_t)(SIZE), (ALIGN))
227#define ailego_aligned_free _aligned_free
228#else // !_MSC_VER
229#if defined(_ISOC11_SOURCE)
230#define ailego_aligned_malloc(SIZE, ALIGN) \
231 aligned_alloc((ALIGN), (size_t)(SIZE))
232#else // !_ISOC11_SOURCE
233#define ailego_aligned_malloc(SIZE, ALIGN) \
234 ailego_posix_malloc((size_t)(SIZE), (ALIGN))
235#endif // _ISOC11_SOURCE
236#define ailego_aligned_free free
237#endif // _MSC_VER
238
239#if !defined(__SANITIZE_ADDRESS__)
240#if defined(__has_feature)
241#if __has_feature(address_sanitizer)
242#define __SANITIZE_ADDRESS__ 1
243#endif // address_sanitizer
244#endif // __has_feature
245#endif // !__SANITIZE_ADDRESS__
246
247#if !defined(__SANITIZE_ADDRESS__)
248#if !defined(ailego_malloc)
249#if defined(__AVX512F__)
250#define ailego_malloc(SIZE) ailego_aligned_malloc((SIZE), 64)
251#elif defined(__AVX__)
252#define ailego_malloc(SIZE) ailego_aligned_malloc((SIZE), 32)
253#elif defined(__SSE__)
254#define ailego_malloc(SIZE) ailego_aligned_malloc((SIZE), 16)
255#elif defined(__ARM_NEON)
256#define ailego_malloc(SIZE) ailego_aligned_malloc((SIZE), 16)
257#endif
258#endif // !ailego_malloc
259#if (defined(__SSE__) || defined(__ARM_NEON)) && !defined(ailego_free)
260#define ailego_free ailego_aligned_free
261#endif
262#endif // !__SANITIZE_ADDRESS__
263
264#ifndef ailego_malloc
265#define ailego_malloc(SIZE) malloc((size_t)(SIZE))
266#endif
267#ifndef ailego_free
268#define ailego_free free
269#endif
270
271#ifndef ailego_offsetof
272#define ailego_offsetof(TYPE, MEMBER) ((size_t) & ((TYPE *)0)->MEMBER)
273#endif
274
275#ifndef ailego_align
276#define ailego_align(SIZE, BOUND) (((SIZE) + ((BOUND)-1)) & ~((BOUND)-1))
277#endif
278
279#ifndef ailego_align8
280#define ailego_align8(SIZE) ailego_align(SIZE, 8)
281#endif
282
283#ifndef ailego_min
284#define ailego_min(A, B) (((A) < (B)) ? (A) : (B))
285#endif
286
287#ifndef ailego_max
288#define ailego_max(A, B) (((A) > (B)) ? (A) : (B))
289#endif
290
291#ifndef ailego_malloc_object
292#define ailego_malloc_object(TYPE) ((TYPE *)ailego_malloc(sizeof(TYPE)))
293#endif
294#ifndef ailego_malloc_array
295#define ailego_malloc_array(TYPE, SIZE) \
296 ((TYPE *)ailego_malloc(SIZE * sizeof(TYPE)))
297#endif
298
299#ifndef ailego_minus_if_ne_zero
300#define ailego_minus_if_ne_zero(COND) \
301 if (ailego_unlikely((COND) != 0)) return (-1)
302#endif
303
304#ifndef ailego_zero_if_ne_zero
305#define ailego_zero_if_ne_zero(COND) \
306 if (ailego_unlikely((COND) != 0)) return (0)
307#endif
308
309#ifndef ailego_null_if_ne_zero
310#define ailego_null_if_ne_zero(COND) \
311 if (ailego_unlikely((COND) != 0)) return (NULL)
312#endif
313
314#ifndef ailego_false_if_ne_zero
315#define ailego_false_if_ne_zero(COND) \
316 if (ailego_unlikely((COND) != 0)) return (false)
317#endif
318
319#ifndef ailego_return_if_ne_zero
320#define ailego_return_if_ne_zero(COND) \
321 if (ailego_unlikely((COND) != 0)) return
322#endif
323
324#ifndef ailego_break_if_ne_zero
325#define ailego_break_if_ne_zero(COND) \
326 if (ailego_unlikely((COND) != 0)) break
327#endif
328
329#ifndef ailego_continue_if_ne_zero
330#define ailego_continue_if_ne_zero(COND) \
331 if (ailego_unlikely((COND) != 0)) continue
332#endif
333
334#ifndef ailego_do_if_ne_zero
335#define ailego_do_if_ne_zero(COND) if (ailego_unlikely((COND) != 0))
336#endif
337
338#ifndef ailego_minus_if_lt_zero
339#define ailego_minus_if_lt_zero(COND) \
340 if (ailego_unlikely((COND) < 0)) return (-1)
341#endif
342
343#ifndef ailego_zero_if_lt_zero
344#define ailego_zero_if_lt_zero(COND) \
345 if (ailego_unlikely((COND) < 0)) return (0)
346#endif
347
348#ifndef ailego_null_if_lt_zero
349#define ailego_null_if_lt_zero(COND) \
350 if (ailego_unlikely((COND) < 0)) return (NULL)
351#endif
352
353#ifndef ailego_false_if_lt_zero
354#define ailego_false_if_lt_zero(COND) \
355 if (ailego_unlikely((COND) < 0)) return (false)
356#endif
357
358#ifndef ailego_return_if_lt_zero
359#define ailego_return_if_lt_zero(COND) \
360 if (ailego_unlikely((COND) < 0)) return
361#endif
362
363#ifndef ailego_break_if_lt_zero
364#define ailego_break_if_lt_zero(COND) \
365 if (ailego_unlikely((COND) < 0)) break
366#endif
367
368#ifndef ailego_continue_if_lt_zero
369#define ailego_continue_if_lt_zero(COND) \
370 if (ailego_unlikely((COND) < 0)) continue
371#endif
372
373#ifndef ailego_do_if_lt_zero
374#define ailego_do_if_lt_zero(COND) if (ailego_unlikely((COND) < 0))
375#endif
376
377#ifndef ailego_minus_if_false
378#define ailego_minus_if_false(COND) \
379 if (ailego_unlikely(!(COND))) return (-1)
380#endif
381
382#ifndef ailego_zero_if_false
383#define ailego_zero_if_false(COND) \
384 if (ailego_unlikely(!(COND))) return (0)
385#endif
386
387#ifndef ailego_null_if_false
388#define ailego_null_if_false(COND) \
389 if (ailego_unlikely(!(COND))) return (NULL)
390#endif
391
392#ifndef ailego_false_if_false
393#define ailego_false_if_false(COND) \
394 if (ailego_unlikely(!(COND))) return (false)
395#endif
396
397#ifndef ailego_return_if_false
398#define ailego_return_if_false(COND) \
399 if (ailego_unlikely(!(COND))) return
400#endif
401
402#ifndef ailego_break_if_false
403#define ailego_break_if_false(COND) \
404 if (ailego_unlikely(!(COND))) break
405#endif
406
407#ifndef ailego_continue_if_false
408#define ailego_continue_if_false(COND) \
409 if (ailego_unlikely(!(COND))) continue
410#endif
411
412#ifndef ailego_do_if_false
413#define ailego_do_if_false(COND) if (ailego_unlikely(!(COND)))
414#endif
415
416#ifndef ailego_compile_assert
417#define ailego_compile_assert(COND, MSG) \
418 typedef char Static_Assertion_##MSG[(!!(COND)) * 2 - 1]
419#endif
420
421#ifndef ailego_static_assert3
422#define ailego_static_assert3(COND, LINE) \
423 ailego_compile_assert(COND, At_Line_##LINE)
424#endif
425
426#ifndef ailego_static_assert2
427#define ailego_static_assert2(COND, LINE) ailego_static_assert3(COND, LINE)
428#endif
429
430#ifndef ailego_static_assert
431#define ailego_static_assert(COND) ailego_static_assert2(COND, __LINE__)
432#endif
433
434//! Abort and report if an assertion is failed
435#ifndef ailego_assert_abort
436#define ailego_assert_abort(COND, MSG) \
437 (void)(ailego_likely(COND) || (ailego_assert_report(__FILE__, __FUNCTION__, \
438 __LINE__, #COND, (MSG)), \
439 abort(), 0))
440#endif
441
442#ifdef AILEGO_DEBUG
443#ifndef ailego_assert
444#define ailego_assert(COND) ailego_assert_abort(COND, "")
445#endif
446#ifndef ailego_assert_with
447#define ailego_assert_with(COND, MSG) ailego_assert_abort(COND, MSG)
448#endif
449#else // !AILEGO_DEBUG
450#ifndef ailego_assert
451#define ailego_assert(COND) ((void)0)
452#endif
453#ifndef ailego_assert_with
454#define ailego_assert_with(COND, MSG) ((void)0)
455#endif
456#endif // AILEGO_DEBUG
457
458#ifndef ailego_check
459#define ailego_check(COND) ailego_assert_abort(COND, "")
460#endif
461#ifndef ailego_check_with
462#define ailego_check_with(COND, MSG) ailego_assert_abort(COND, MSG)
463#endif
464
465#ifndef _MSC_VER
466//! Allocates memory on a specified alignment boundary
467static inline void *ailego_posix_malloc(size_t size, size_t align) {
468 void *ptr;
469 ailego_null_if_ne_zero(posix_memalign(&ptr, align, size));
470 return ptr;
471}
472#endif
473
474//! Report an assertion is failed
475static inline void ailego_assert_report(const char *file, const char *func,
476 int line, const char *cond,
477 const char *msg) {
478 fprintf(stderr, "Assertion failed: (%s) in %s(), %s line %d. %s\n", cond,
479 func, file, line, msg);
480}
481
482#ifdef __cplusplus
483} /* extern "C" */
484#endif
485
486#endif // __AILEGO_INTERNAL_PLATFORM_H__
487