1 /*
2  * This software is licensed under the terms of the MIT License.
3  * See COPYING for further information.
4  * ---
5  * Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
6  * Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
7  */
8 
9 #ifndef IGUARD_util_compat_h
10 #define IGUARD_util_compat_h
11 
12 #include "taisei.h"
13 
14 // Common standard library headers
15 #include <complex.h>
16 #include <ctype.h>
17 #include <float.h>
18 #include <inttypes.h>
19 #include <limits.h>
20 #include <math.h>
21 #include <stdalign.h>
22 #include <stdbool.h>
23 #include <stddef.h>
24 #include <stdint.h>
25 #include <stdlib.h>
26 #include <stdnoreturn.h>
27 #include <string.h>
28 
29 #include "util/assert.h"
30 
31 #ifdef __FAST_MATH__
32 	#error -ffast-math is prohibited
33 #endif
34 
35 #ifdef _WIN32
36 	// Include the god-awful windows.h header here so that we can fight the obnoxious namespace pollution it introduces.
37 	// We obviously don't need it in every source file, but it's easier to do it globally and early than to try to infer
38 	// just where down the maze of includes some of our dependencies happens to smuggle it in.
39 	//
40 	// *sigh*
41 	//
42 	// Goddamn it.
43 
44 	// Make sure we get the "unicode" (actually UTF-16) versions of win32 APIs; it defaults to legacy crippled ones.
45 	#ifndef UNICODE
46 		#define UNICODE
47 	#endif
48 	#ifndef _UNICODE
49 		#define _UNICODE
50 	#endif
51 
52 	// Ask windows.h to include a little bit less of the stupid crap we'll never use.
53 	// Some of it actually clashes with our names.
54 	#define WIN32_LEAN_AND_MEAN
55 	#define NOGDI
56 	#define NOMINMAX
57 
58 	#include <windows.h>
59 
60 	// far/near pointers are obviously very relevant for modern CPUs and totally deserve their very own, unprefixed keywords!
61 	#undef near
62 	#undef far
63 #endif
64 
65 // This macro should be provided by stddef.h, but in practice it sometimes is not.
66 #ifndef offsetof
67 	#ifdef __GNUC__
68 		#define offsetof(type, field) __builtin_offsetof(type, field)
69 	#else
70 		#define offsetof(type, field) ((size_t)&(((type *)0)->field))
71 	#endif
72 #endif
73 
74 #define PRAGMA(p) _Pragma(#p)
75 
76 #ifndef __GNUC__ // clang defines this too
77 	#define __attribute__(...)
78 	#define __extension__
79 	#define UNREACHABLE
80 	#define DIAGNOSTIC(x)
81 	#define DIAGNOSTIC_GCC(x)
82 	#define DIAGNOSTIC_CLANG(x)
83 	#define LIKELY(x) (bool)(x)
84 	#define UNLIKELY(x) (bool)(x)
85 #else
86 	#ifdef TAISEI_BUILDCONF_USE_GNU_EXTENSIONS
87 		#define USE_GNU_EXTENSIONS
88 	#endif
89 	#define UNREACHABLE __builtin_unreachable()
90 
91 	#define DIAGNOSTIC(x) PRAGMA(GCC diagnostic x)
92 
93 	#if defined(__clang__)
94 		#define DIAGNOSTIC_GCC(x)
95 		#define DIAGNOSTIC_CLANG(x) PRAGMA(clang diagnostic x)
96 	#else
97 		#define DIAGNOSTIC_GCC(x) PRAGMA(GCC diagnostic x)
98 		#define DIAGNOSTIC_CLANG(x)
99 	#endif
100 
101 	#define LIKELY(x) __builtin_expect((bool)(x), 1)
102 	#define UNLIKELY(x) __builtin_expect((bool)(x), 0)
103 #endif
104 
105 #ifndef __has_attribute
106 	#ifdef __GNUC__
107 		#define __has_attribute(attr) 1
108 	#else
109 		#define __has_attribute(attr) 0
110 	#endif
111 #endif
112 
113 #undef ASSUME
114 
115 #ifdef __has_builtin
116 	#if __has_builtin(__builtin_assume)
117 		#define ASSUME(x) __builtin_assume(x)
118 	#endif
119 #endif
120 
121 #if !defined(ASSUME) && defined(__GNUC__)
122 	#define ASSUME(x) do { if(!(x)) { UNREACHABLE; } } while(0)
123 #endif
124 
125 #ifndef ASSUME
126 	#define ASSUME(x)
127 #endif
128 
129 // On windows, use the MinGW implementations of printf and friends instead of the crippled mscrt ones.
130 #ifdef __USE_MINGW_ANSI_STDIO
131 	#define FORMAT_ATTR __MINGW_PRINTF_FORMAT
132 #else
133 	#define FORMAT_ATTR printf
134 #endif
135 
136 #undef uint
137 typedef unsigned int uint;
138 
139 #undef ushort
140 typedef unsigned short ushort;
141 
142 #undef ulong
143 typedef unsigned long ulong;
144 
145 #undef uchar
146 typedef unsigned char uchar;
147 
148 #undef schar
149 typedef signed char schar;
150 
151 #undef float32
152 typedef float float32;
153 
154 #undef float64
155 typedef double float64;
156 
157 #undef float64x
158 typedef long double float64x;
159 
160 #undef real
161 typedef float64 real;
162 
163 #undef cmplx32
164 typedef _Complex float cmplx32;
165 
166 #undef cmplx64
167 typedef _Complex double cmplx64;
168 
169 #undef cmplx
170 typedef cmplx64 cmplx;
171 
172 // These definitions are common but non-standard, so we provide our own
173 #undef M_PI
174 #undef M_PI_2
175 #undef M_PI_4
176 #undef M_E
177 #define M_PI 3.14159265358979323846
178 #define M_PI_2 1.57079632679489661923
179 #define M_PI_4 0.78539816339744830962
180 #define M_E 2.7182818284590452354
181 
182 #ifndef TAISEI_BUILDCONF_HAVE_MAX_ALIGN_T
183 	#if TAISEI_BUILDCONF_MALLOC_ALIGNMENT <= 0
184 		#warning malloc alignment is unknown, assuming 8
185 		#undef TAISEI_BUILDCONF_MALLOC_ALIGNMENT
186 		#define TAISEI_BUILDCONF_MALLOC_ALIGNMENT 8
187 	#endif
188 
189 	#undef max_align_t
190 	#define max_align_t _fake_max_align_t
191 	typedef struct { alignas(TAISEI_BUILDCONF_MALLOC_ALIGNMENT) char a; } max_align_t;
192 #endif
193 
194 // In case the C11 CMPLX macro is not present, try our best to provide a substitute
195 #if !defined CMPLX
196   #undef HAS_BUILTIN_COMPLEX
197 
198   #if defined __has_builtin
199     #if __has_builtin(__builtin_complex)
200       #define HAS_BUILTIN_COMPLEX
201     #endif
202   #else
203     #if defined __GNUC__ && defined __GNUC_MINOR__
204       #if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))
205         #define HAS_BUILTIN_COMPLEX
206       #endif
207     #endif
208   #endif
209 
210   #if defined HAS_BUILTIN_COMPLEX
211     #define CMPLX(re,im) __builtin_complex((double)(re), (double)(im))
212   #elif defined __clang__
213     #define CMPLX(re,im) (__extension__ (_Complex double){(double)(re), (double)(im)})
214   #elif defined _Imaginary_I
215     #define CMPLX(re,im) (_Complex double)((double)(re) + _Imaginary_I * (double)(im))
216   #else
217     #define CMPLX(re,im) (_Complex double)((double)(re) + _Complex_I * (double)(im))
218   #endif
219 #elif defined __EMSCRIPTEN__ && defined __clang__
220   // CMPLX from emscripten headers uses the clang-specific syntax without __extension__
221   #pragma clang diagnostic ignored "-Wcomplex-component-init"
222 #endif
223 
224 /*
225  * Abstract away the nasty GNU attribute syntax.
226  */
227 
228 // Function is a hot spot.
229 #define attr_hot \
230 	__attribute__ ((hot))
231 
232 // Function has no side-effects.
233 #define attr_pure \
234 	__attribute__ ((pure))
235 
236 // Function has no side-effects, return value depends on arguments only.
237 // Must not take pointer parameters, must not return void.
238 #define attr_const \
239 	__attribute__ ((const))
240 
241 // Function never returns NULL.
242 #define attr_returns_nonnull \
243 	__attribute__ ((returns_nonnull))
244 
245 // Function must be called with NULL as the last argument (for varargs functions).
246 #define attr_sentinel \
247 	__attribute__ ((sentinel))
248 
249 // Symbol is meant to be possibly unused.
250 #define attr_unused \
251 	__attribute__ ((unused))
252 
253 // Symbol should be emitted even if it appears to be unused.
254 #define attr_used \
255 	__attribute__ ((used))
256 
257 // Function or type is deprecated and should not be used.
258 #define attr_deprecated(msg) \
259 	__attribute__ ((deprecated(msg)))
260 
261 // Function parameters at specified positions must not be NULL.
262 #define attr_nonnull(...) \
263 	__attribute__ ((nonnull(__VA_ARGS__)))
264 
265 // All pointer parameters must not be NULL.
266 #define attr_nonnull_all \
267 	__attribute__ ((nonnull))
268 
269 // The return value of this function must not be ignored.
270 #define attr_nodiscard \
271 	__attribute__ ((warn_unused_result))
272 
273 // Function takes a printf-style format string and variadic arguments.
274 #define attr_printf(fmt_index, firstarg_index) \
275 	__attribute__ ((format(FORMAT_ATTR, fmt_index, firstarg_index)))
276 
277 // Function must be inlined regardless of optimization settings.
278 #define attr_must_inline \
279 	__attribute__ ((always_inline))
280 
281 // Function returns a pointer aligned to x bytes
282 #define attr_returns_aligned(x) \
283 	__attribute__ ((assume_aligned(x)))
284 
285 // Function returns a pointer aligned the same as max_align_t
286 #define attr_returns_max_aligned \
287 	attr_returns_aligned(alignof(max_align_t))
288 
289 // Shorthand: always returns non-null pointer aligned to max_align_t; no discard.
290 #define attr_returns_allocated \
291 	attr_returns_nonnull attr_returns_max_aligned attr_nodiscard
292 
293 // Structure must not be initialized with an implicit (non-designated) initializer.
294 #if __has_attribute(designated_init) && defined(TAISEI_BUILDCONF_USE_DESIGNATED_INIT)
295 	#define attr_designated_init \
296 		__attribute__ ((designated_init))
297 #else
298 	#define attr_designated_init
299 #endif
300 
301 #define INLINE static inline attr_must_inline __attribute__((gnu_inline))
302 
303 #ifdef USE_GNU_EXTENSIONS
304 	#define ASSUME_ALIGNED(expr, alignment) (__extension__ ({ \
305 		static_assert(__builtin_constant_p(alignment), ""); \
306 		__auto_type _assume_aligned_ptr = (expr); \
307 		assert(((uintptr_t)_assume_aligned_ptr & ((alignment) - 1)) == 0); \
308 		__builtin_assume_aligned(_assume_aligned_ptr, (alignment)); \
309 	}))
310 #else
311 	#define ASSUME_ALIGNED(expr, alignment) (expr)
312 #endif
313 
314 #define CASTPTR_ASSUME_ALIGNED(expr, type) ((type*)ASSUME_ALIGNED((expr), alignof(type)))
315 
316 #ifdef USE_GNU_EXTENSIONS
317 	#define NOT_NULL(expr) (__extension__ ({ \
318 		__auto_type _assume_not_null_ptr = (expr); \
319 		assume(_assume_not_null_ptr != NULL); \
320 		_assume_not_null_ptr; \
321 	}))
322 #else
323 	#define NOT_NULL(expr) (expr)
324 #endif
325 
326 #ifdef __SWITCH__
327 	#include "../arch_switch.h"
328 	#define atexit nxAtExit
329 	#define exit nxExit
330 	#define abort nxAbort
331 #endif
332 
333 #endif // IGUARD_util_compat_h
334