1//===-- int_lib.h - configuration header for compiler-rt  -----------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file is not part of the interface of this library.
10//
11// This file defines various standard types, most importantly a number of unions
12// used to access parts of larger types.
13//
14//===----------------------------------------------------------------------===//
15
16#ifndef INT_TYPES_H
17#define INT_TYPES_H
18
19#include "int_endianness.h"
20
21// si_int is defined in Linux sysroot's asm-generic/siginfo.h
22#ifdef si_int
23#undef si_int
24#endif
25typedef int32_t si_int;
26typedef uint32_t su_int;
27#if UINT_MAX == 0xFFFFFFFF
28#define clzsi __builtin_clz
29#define ctzsi __builtin_ctz
30#elif ULONG_MAX == 0xFFFFFFFF
31#define clzsi __builtin_clzl
32#define ctzsi __builtin_ctzl
33#else
34#error could not determine appropriate clzsi macro for this system
35#endif
36
37typedef int64_t di_int;
38typedef uint64_t du_int;
39
40typedef union {
41  di_int all;
42  struct {
43#if _YUGA_LITTLE_ENDIAN
44    su_int low;
45    si_int high;
46#else
47    si_int high;
48    su_int low;
49#endif // _YUGA_LITTLE_ENDIAN
50  } s;
51} dwords;
52
53typedef union {
54  du_int all;
55  struct {
56#if _YUGA_LITTLE_ENDIAN
57    su_int low;
58    su_int high;
59#else
60    su_int high;
61    su_int low;
62#endif // _YUGA_LITTLE_ENDIAN
63  } s;
64} udwords;
65
66#if defined(__LP64__) || defined(__wasm__) || defined(__mips64) ||             \
67    defined(__SIZEOF_INT128__) || defined(_WIN64)
68#define CRT_HAS_128BIT
69#endif
70
71// MSVC doesn't have a working 128bit integer type. Users should really compile
72// compiler-rt with clang, but if they happen to be doing a standalone build for
73// asan or something else, disable the 128 bit parts so things sort of work.
74#if defined(_MSC_VER) && !defined(__clang__)
75#undef CRT_HAS_128BIT
76#endif
77
78#ifdef CRT_HAS_128BIT
79typedef int ti_int __attribute__((mode(TI)));
80typedef unsigned tu_int __attribute__((mode(TI)));
81
82typedef union {
83  ti_int all;
84  struct {
85#if _YUGA_LITTLE_ENDIAN
86    du_int low;
87    di_int high;
88#else
89    di_int high;
90    du_int low;
91#endif // _YUGA_LITTLE_ENDIAN
92  } s;
93} twords;
94
95typedef union {
96  tu_int all;
97  struct {
98#if _YUGA_LITTLE_ENDIAN
99    du_int low;
100    du_int high;
101#else
102    du_int high;
103    du_int low;
104#endif // _YUGA_LITTLE_ENDIAN
105  } s;
106} utwords;
107
108static __inline ti_int make_ti(di_int h, di_int l) {
109  twords r;
110  r.s.high = h;
111  r.s.low = l;
112  return r.all;
113}
114
115static __inline tu_int make_tu(du_int h, du_int l) {
116  utwords r;
117  r.s.high = h;
118  r.s.low = l;
119  return r.all;
120}
121
122#endif // CRT_HAS_128BIT
123
124// FreeBSD's boot environment does not support using floating-point and poisons
125// the float and double keywords.
126#if defined(__FreeBSD__) && defined(_STANDALONE)
127#define CRT_HAS_FLOATING_POINT 0
128#else
129#define CRT_HAS_FLOATING_POINT 1
130#endif
131
132#if CRT_HAS_FLOATING_POINT
133typedef union {
134  su_int u;
135  float f;
136} float_bits;
137
138typedef union {
139  udwords u;
140  double f;
141} double_bits;
142
143typedef struct {
144#if _YUGA_LITTLE_ENDIAN
145  udwords low;
146  udwords high;
147#else
148  udwords high;
149  udwords low;
150#endif // _YUGA_LITTLE_ENDIAN
151} uqwords;
152
153// Check if the target supports 80 bit extended precision long doubles.
154// Notably, on x86 Windows, MSVC only provides a 64-bit long double, but GCC
155// still makes it 80 bits. Clang will match whatever compiler it is trying to
156// be compatible with. On 32-bit x86 Android, long double is 64 bits, while on
157// x86_64 Android, long double is 128 bits.
158#if (defined(__i386__) || defined(__x86_64__)) &&                              \
159    !(defined(_MSC_VER) || defined(__ANDROID__))
160#define HAS_80_BIT_LONG_DOUBLE 1
161#elif defined(__m68k__) || defined(__ia64__)
162#define HAS_80_BIT_LONG_DOUBLE 1
163#else
164#define HAS_80_BIT_LONG_DOUBLE 0
165#endif
166
167#if HAS_80_BIT_LONG_DOUBLE
168typedef long double xf_float;
169typedef union {
170  uqwords u;
171  xf_float f;
172} xf_bits;
173#endif
174
175#ifdef __powerpc64__
176// From https://gcc.gnu.org/wiki/Ieee128PowerPC:
177// PowerPC64 uses the following suffixes:
178// IFmode: IBM extended double
179// KFmode: IEEE 128-bit floating point
180// TFmode: Matches the default for long double. With -mabi=ieeelongdouble,
181//         it is IEEE 128-bit, with -mabi=ibmlongdouble IBM extended double
182// Since compiler-rt only implements the tf set of libcalls, we use long double
183// for the tf_float typedef.
184typedef long double tf_float;
185#define CRT_LDBL_128BIT
186#define CRT_HAS_F128
187#if __LDBL_MANT_DIG__ == 113 && !defined(__LONG_DOUBLE_IBM128__)
188#define CRT_HAS_IEEE_TF
189#define CRT_LDBL_IEEE_F128
190#endif
191#define TF_C(x) x##L
192#elif __LDBL_MANT_DIG__ == 113 ||                                              \
193    (__FLT_RADIX__ == 16 && __LDBL_MANT_DIG__ == 28)
194// Use long double instead of __float128 if it matches the IEEE 128-bit format
195// or the IBM hexadecimal format.
196#define CRT_LDBL_128BIT
197#define CRT_HAS_F128
198#if __LDBL_MANT_DIG__ == 113
199#define CRT_HAS_IEEE_TF
200#define CRT_LDBL_IEEE_F128
201#endif
202typedef long double tf_float;
203#define TF_C(x) x##L
204#elif defined(__FLOAT128__) || defined(__SIZEOF_FLOAT128__)
205#define CRT_HAS___FLOAT128_KEYWORD
206#define CRT_HAS_F128
207// NB: we assume the __float128 type uses IEEE representation.
208#define CRT_HAS_IEEE_TF
209typedef __float128 tf_float;
210#define TF_C(x) x##Q
211#endif
212
213#ifdef CRT_HAS_F128
214typedef union {
215  uqwords u;
216  tf_float f;
217} tf_bits;
218#endif
219
220// __(u)int128_t is currently needed to compile the *tf builtins as we would
221// otherwise need to manually expand the bit manipulation on two 64-bit value.
222#if defined(CRT_HAS_128BIT) && defined(CRT_HAS_F128)
223#define CRT_HAS_TF_MODE
224#endif
225
226#if __STDC_VERSION__ >= 199901L
227typedef float _Complex Fcomplex;
228typedef double _Complex Dcomplex;
229typedef long double _Complex Lcomplex;
230#if defined(CRT_LDBL_128BIT)
231typedef Lcomplex Qcomplex;
232#define CRT_HAS_NATIVE_COMPLEX_F128
233#elif defined(CRT_HAS___FLOAT128_KEYWORD)
234#if defined(__clang_major__) && __clang_major__ > 10
235// Clang prior to 11 did not support __float128 _Complex.
236typedef __float128 _Complex Qcomplex;
237#define CRT_HAS_NATIVE_COMPLEX_F128
238#elif defined(__GNUC__) && __GNUC__ >= 7
239// GCC does not allow __float128 _Complex, but accepts _Float128 _Complex.
240typedef _Float128 _Complex Qcomplex;
241#define CRT_HAS_NATIVE_COMPLEX_F128
242#endif
243#endif
244
245#define COMPLEX_REAL(x) __real__(x)
246#define COMPLEX_IMAGINARY(x) __imag__(x)
247#else
248typedef struct {
249  float real, imaginary;
250} Fcomplex;
251
252typedef struct {
253  double real, imaginary;
254} Dcomplex;
255
256typedef struct {
257  long double real, imaginary;
258} Lcomplex;
259
260#define COMPLEX_REAL(x) (x).real
261#define COMPLEX_IMAGINARY(x) (x).imaginary
262#endif
263
264#ifdef CRT_HAS_NATIVE_COMPLEX_F128
265#define COMPLEXTF_REAL(x) __real__(x)
266#define COMPLEXTF_IMAGINARY(x) __imag__(x)
267#elif defined(CRT_HAS_F128)
268typedef struct {
269  tf_float real, imaginary;
270} Qcomplex;
271#define COMPLEXTF_REAL(x) (x).real
272#define COMPLEXTF_IMAGINARY(x) (x).imaginary
273#endif
274
275#endif // CRT_HAS_FLOATING_POINT
276#endif // INT_TYPES_H
277