Showing the changes to lib (3 of 16 files). Show all
Unified · Split
| @@ -28,6 +28,11 @@ ifndef TARGET # native library · 27 unmodified lines | |||
| 28 | ifeq ($(ARCH),arm) | 28 | ifeq ($(ARCH),arm) |
| 29 | TARGET = arm | 29 | TARGET = arm |
| 30 | XCC = $(CC) | 30 | XCC = $(CC) |
| 31 | else | ||
| 32 | ifeq ($(ARCH),arm64) | ||
| 33 | TARGET = arm64 | ||
| 34 | else | ||
| 35 | endif | ||
| 31 | endif | 36 | endif |
| 32 | endif | 37 | endif |
| 33 | endif | 38 | endif |
| @@ -49,6 +54,7 @@ X86_64_O = libtcc1.o alloca86_64.o · 15 unmodified lines | |||
| 49 | ARM_O = libtcc1.o armeabi.o alloca-arm.o | 54 | ARM_O = libtcc1.o armeabi.o alloca-arm.o |
| 50 | WIN32_O = $(I386_O) crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o | 55 | WIN32_O = $(I386_O) crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o |
| 51 | WIN64_O = $(X86_64_O) crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o | 56 | WIN64_O = $(X86_64_O) crt1.o wincrt1.o dllcrt1.o dllmain.o chkstk.o |
| 57 | ARM64_O = lib-arm64.o | ||
| 52 | 58 | ||
| 53 | # build TCC runtime library to contain PIC code, so it can be linked | 59 | # build TCC runtime library to contain PIC code, so it can be linked |
| 54 | # into shared libraries | 60 | # into shared libraries |
| @@ -86,6 +92,11 @@ ifeq "$(TARGET)" "arm" · 31 unmodified lines | |||
| 86 | OBJ = $(addprefix $(DIR)/,$(ARM_O)) | 92 | OBJ = $(addprefix $(DIR)/,$(ARM_O)) |
| 87 | TGT = -DTCC_TARGET_ARM | 93 | TGT = -DTCC_TARGET_ARM |
| 88 | XCC ?= $(TCC) -B$(TOP) | 94 | XCC ?= $(TCC) -B$(TOP) |
| 95 | else | ||
| 96 | ifeq "$(TARGET)" "arm64" | ||
| 97 | OBJ = $(addprefix $(DIR)/,$(ARM64_O)) | ||
| 98 | TGT = -DTCC_TARGET_ARM64 | ||
| 99 | XCC ?= $(TCC) -B$(TOP) | ||
| 89 | else | 100 | else |
| 90 | $(error libtcc1.a not supported on target '$(TARGET)') | 101 | $(error libtcc1.a not supported on target '$(TARGET)') |
| 91 | endif | 102 | endif |
| @@ -93,6 +104,7 @@ endif · 1 unmodified line | |||
| 93 | endif | 104 | endif |
| 94 | endif | 105 | endif |
| 95 | endif | 106 | endif |
| 107 | endif | ||
| 96 | 108 | ||
| 97 | XFLAGS = $(CPPFLAGS) $(CFLAGS) $(PICFLAGS) $(TGT) | 109 | XFLAGS = $(CPPFLAGS) $(CFLAGS) $(PICFLAGS) $(TGT) |
| 98 | 110 | ||
| @@ -0,0 +1,652 @@ | |||
| 1 | /* | ||
| 2 | * TCC runtime library for arm64. | ||
| 3 | * | ||
| 4 | * Copyright (c) 2015 Edmund Grimley Evans | ||
| 5 | * | ||
| 6 | * Copying and distribution of this file, with or without modification, | ||
| 7 | * are permitted in any medium without royalty provided the copyright | ||
| 8 | * notice and this notice are preserved. This file is offered as-is, | ||
| 9 | * without any warranty. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <stdint.h> | ||
| 13 | #include <string.h> | ||
| 14 | |||
| 15 | void __clear_cache(char *beg, char *end) | ||
| 16 | { | ||
| 17 | #warning __clear_cache not yet implemented | ||
| 18 | } | ||
| 19 | |||
| 20 | typedef struct { | ||
| 21 | uint64_t x0, x1; | ||
| 22 | } u128_t; | ||
| 23 | |||
| 24 | static long double f3_zero(int sgn) | ||
| 25 | { | ||
| 26 | long double f; | ||
| 27 | u128_t x = { 0, (uint64_t)sgn << 63 }; | ||
| 28 | memcpy(&f, &x, 16); | ||
| 29 | return f; | ||
| 30 | } | ||
| 31 | |||
| 32 | static long double f3_infinity(int sgn) | ||
| 33 | { | ||
| 34 | long double f; | ||
| 35 | u128_t x = { 0, (uint64_t)sgn << 63 | 0x7fff000000000000 }; | ||
| 36 | memcpy(&f, &x, 16); | ||
| 37 | return f; | ||
| 38 | } | ||
| 39 | |||
| 40 | static long double f3_NaN(void) | ||
| 41 | { | ||
| 42 | long double f; | ||
| 43 | #if 0 | ||
| 44 | // ARM's default NaN usually has just the top fraction bit set: | ||
| 45 | u128_t x = { 0, 0x7fff800000000000 }; | ||
| 46 | #else | ||
| 47 | // GCC's library sets all fraction bits: | ||
| 48 | u128_t x = { -1, 0x7fffffffffffffff }; | ||
| 49 | #endif | ||
| 50 | memcpy(&f, &x, 16); | ||
| 51 | return f; | ||
| 52 | } | ||
| 53 | |||
| 54 | static int fp3_convert_NaN(long double *f, int sgn, u128_t mnt) | ||
| 55 | { | ||
| 56 | u128_t x = { mnt.x0, | ||
| 57 | mnt.x1 | 0x7fff800000000000 | (uint64_t)sgn << 63 }; | ||
| 58 | memcpy(f, &x, 16); | ||
| 59 | return 1; | ||
| 60 | } | ||
| 61 | |||
| 62 | static int fp3_detect_NaNs(long double *f, | ||
| 63 | int a_sgn, int a_exp, u128_t a, | ||
| 64 | int b_sgn, int b_exp, u128_t b) | ||
| 65 | { | ||
| 66 | // Detect signalling NaNs: | ||
| 67 | if (a_exp == 32767 && (a.x0 | a.x1 << 16) && !(a.x1 >> 47 & 1)) | ||
| 68 | return fp3_convert_NaN(f, a_sgn, a); | ||
| 69 | if (b_exp == 32767 && (b.x0 | b.x1 << 16) && !(b.x1 >> 47 & 1)) | ||
| 70 | return fp3_convert_NaN(f, b_sgn, b); | ||
| 71 | |||
| 72 | // Detect quiet NaNs: | ||
| 73 | if (a_exp == 32767 && (a.x0 | a.x1 << 16)) | ||
| 74 | return fp3_convert_NaN(f, a_sgn, a); | ||
| 75 | if (b_exp == 32767 && (b.x0 | b.x1 << 16)) | ||
| 76 | return fp3_convert_NaN(f, b_sgn, b); | ||
| 77 | |||
| 78 | return 0; | ||
| 79 | } | ||
| 80 | |||
| 81 | static void f3_unpack(int *sgn, int32_t *exp, u128_t *mnt, long double f) | ||
| 82 | { | ||
| 83 | u128_t x; | ||
| 84 | memcpy(&x, &f, 16); | ||
| 85 | *sgn = x.x1 >> 63; | ||
| 86 | *exp = x.x1 >> 48 & 32767; | ||
| 87 | x.x1 = x.x1 << 16 >> 16; | ||
| 88 | if (*exp) | ||
| 89 | x.x1 |= (uint64_t)1 << 48; | ||
| 90 | else | ||
| 91 | *exp = 1; | ||
| 92 | *mnt = x; | ||
| 93 | } | ||
| 94 | |||
| 95 | static u128_t f3_normalise(int32_t *exp, u128_t mnt) | ||
| 96 | { | ||
| 97 | int sh; | ||
| 98 | if (!(mnt.x0 | mnt.x1)) | ||
| 99 | return mnt; | ||
| 100 | if (!mnt.x1) { | ||
| 101 | mnt.x1 = mnt.x0; | ||
| 102 | mnt.x0 = 0; | ||
| 103 | *exp -= 64; | ||
| 104 | } | ||
| 105 | for (sh = 32; sh; sh >>= 1) { | ||
| 106 | if (!(mnt.x1 >> (64 - sh))) { | ||
| 107 | mnt.x1 = mnt.x1 << sh | mnt.x0 >> (64 - sh); | ||
| 108 | mnt.x0 = mnt.x0 << sh; | ||
| 109 | *exp -= sh; | ||
| 110 | } | ||
| 111 | } | ||
| 112 | return mnt; | ||
| 113 | } | ||
| 114 | |||
| 115 | static u128_t f3_sticky_shift(int32_t sh, u128_t x) | ||
| 116 | { | ||
| 117 | if (sh >= 128) { | ||
| 118 | x.x0 = !!(x.x0 | x.x1); | ||
| 119 | x.x1 = 0; | ||
| 120 | return x; | ||
| 121 | } | ||
| 122 | if (sh >= 64) { | ||
| 123 | x.x0 = x.x1 | !!x.x0; | ||
| 124 | x.x1 = 0; | ||
| 125 | sh -= 64; | ||
| 126 | } | ||
| 127 | if (sh > 0) { | ||
| 128 | x.x0 = x.x0 >> sh | x.x1 << (64 - sh) | !!(x.x0 << (64 - sh)); | ||
| 129 | x.x1 = x.x1 >> sh; | ||
| 130 | } | ||
| 131 | return x; | ||
| 132 | } | ||
| 133 | |||
| 134 | static long double f3_round(int sgn, int32_t exp, u128_t x) | ||
| 135 | { | ||
| 136 | long double f; | ||
| 137 | int error; | ||
| 138 | |||
| 139 | if (exp > 0) { | ||
| 140 | x = f3_sticky_shift(13, x); | ||
| 141 | } | ||
| 142 | else { | ||
| 143 | x = f3_sticky_shift(14 - exp, x); | ||
| 144 | exp = 0; | ||
| 145 | } | ||
| 146 | |||
| 147 | error = x.x0 & 3; | ||
| 148 | x.x0 = x.x0 >> 2 | x.x1 << 62; | ||
| 149 | x.x1 = x.x1 >> 2; | ||
| 150 | |||
| 151 | if (error == 3 || ((error == 2) & (x.x0 & 1))) { | ||
| 152 | if (!++x.x0) { | ||
| 153 | ++x.x1; | ||
| 154 | if (x.x1 == (uint64_t)1 << 48) | ||
| 155 | exp = 1; | ||
| 156 | else if (x.x1 == (uint64_t)1 << 49) { | ||
| 157 | ++exp; | ||
| 158 | x.x0 = x.x0 >> 1 | x.x1 << 63; | ||
| 159 | x.x1 = x.x1 >> 1; | ||
| 160 | } | ||
| 161 | } | ||
| 162 | } | ||
| 163 | |||
| 164 | if (exp >= 32767) | ||
| 165 | return f3_infinity(sgn); | ||
| 166 | |||
| 167 | x.x1 = x.x1 << 16 >> 16 | (uint64_t)exp << 48 | (uint64_t)sgn << 63; | ||
| 168 | memcpy(&f, &x, 16); | ||
| 169 | return f; | ||
| 170 | } | ||
| 171 | |||
| 172 | static long double f3_add(long double fa, long double fb, int neg) | ||
| 173 | { | ||
| 174 | u128_t a, b, x; | ||
| 175 | int32_t a_exp, b_exp, x_exp; | ||
| 176 | int a_sgn, b_sgn, x_sgn; | ||
| 177 | long double fx; | ||
| 178 | |||
| 179 | f3_unpack(&a_sgn, &a_exp, &a, fa); | ||
| 180 | f3_unpack(&b_sgn, &b_exp, &b, fb); | ||
| 181 | |||
| 182 | if (fp3_detect_NaNs(&fx, a_sgn, a_exp, a, b_sgn, b_exp, b)) | ||
| 183 | return fx; | ||
| 184 | |||
| 185 | b_sgn ^= neg; | ||
| 186 | |||
| 187 | // Handle infinities and zeroes: | ||
| 188 | if (a_exp == 32767 && b_exp == 32767 && a_sgn != b_sgn) | ||
| 189 | return f3_NaN(); | ||
| 190 | if (a_exp == 32767) | ||
| 191 | return f3_infinity(a_sgn); | ||
| 192 | if (b_exp == 32767) | ||
| 193 | return f3_infinity(b_sgn); | ||
| 194 | if (!(a.x0 | a.x1 | b.x0 | b.x1)) | ||
| 195 | return f3_zero(a_sgn & b_sgn); | ||
| 196 | |||
| 197 | a.x1 = a.x1 << 3 | a.x0 >> 61; | ||
| 198 | a.x0 = a.x0 << 3; | ||
| 199 | b.x1 = b.x1 << 3 | b.x0 >> 61; | ||
| 200 | b.x0 = b.x0 << 3; | ||
| 201 | |||
| 202 | if (a_exp <= b_exp) { | ||
| 203 | a = f3_sticky_shift(b_exp - a_exp, a); | ||
| 204 | a_exp = b_exp; | ||
| 205 | } | ||
| 206 | else { | ||
| 207 | b = f3_sticky_shift(a_exp - b_exp, b); | ||
| 208 | b_exp = a_exp; | ||
| 209 | } | ||
| 210 | |||
| 211 | x_sgn = a_sgn; | ||
| 212 | x_exp = a_exp; | ||
| 213 | if (a_sgn == b_sgn) { | ||
| 214 | x.x0 = a.x0 + b.x0; | ||
| 215 | x.x1 = a.x1 + b.x1 + (x.x0 < a.x0); | ||
| 216 | } | ||
| 217 | else { | ||
| 218 | x.x0 = a.x0 - b.x0; | ||
| 219 | x.x1 = a.x1 - b.x1 - (x.x0 > a.x0); | ||
| 220 | if (x.x1 >> 63) { | ||
| 221 | x_sgn ^= 1; | ||
| 222 | x.x0 = -x.x0; | ||
| 223 | x.x1 = -x.x1 - !!x.x0; | ||
| 224 | } | ||
| 225 | } | ||
| 226 | |||
| 227 | if (!(x.x0 | x.x1)) | ||
| 228 | return f3_zero(0); | ||
| 229 | |||
| 230 | x = f3_normalise(&x_exp, x); | ||
| 231 | |||
| 232 | return f3_round(x_sgn, x_exp + 12, x); | ||
| 233 | } | ||
| 234 | |||
| 235 | long double __addtf3(long double a, long double b) | ||
| 236 | { | ||
| 237 | return f3_add(a, b, 0); | ||
| 238 | } | ||
| 239 | |||
| 240 | long double __subtf3(long double a, long double b) | ||
| 241 | { | ||
| 242 | return f3_add(a, b, 1); | ||
| 243 | } | ||
| 244 | |||
| 245 | long double __multf3(long double fa, long double fb) | ||
| 246 | { | ||
| 247 | u128_t a, b, x; | ||
| 248 | int32_t a_exp, b_exp, x_exp; | ||
| 249 | int a_sgn, b_sgn, x_sgn; | ||
| 250 | long double fx; | ||
| 251 | |||
| 252 | f3_unpack(&a_sgn, &a_exp, &a, fa); | ||
| 253 | f3_unpack(&b_sgn, &b_exp, &b, fb); | ||
| 254 | |||
| 255 | if (fp3_detect_NaNs(&fx, a_sgn, a_exp, a, b_sgn, b_exp, b)) | ||
| 256 | return fx; | ||
| 257 | |||
| 258 | // Handle infinities and zeroes: | ||
| 259 | if ((a_exp == 32767 && !(b.x0 | b.x1)) || | ||
| 260 | (b_exp == 32767 && !(a.x0 | a.x1))) | ||
| 261 | return f3_NaN(); | ||
| 262 | if (a_exp == 32767 || b_exp == 32767) | ||
| 263 | return f3_infinity(a_sgn ^ b_sgn); | ||
| 264 | if (!(a.x0 | a.x1) || !(b.x0 | b.x1)) | ||
| 265 | return f3_zero(a_sgn ^ b_sgn); | ||
| 266 | |||
| 267 | a = f3_normalise(&a_exp, a); | ||
| 268 | b = f3_normalise(&b_exp, b); | ||
| 269 | |||
| 270 | x_sgn = a_sgn ^ b_sgn; | ||
| 271 | x_exp = a_exp + b_exp - 16352; | ||
| 272 | |||
| 273 | { | ||
| 274 | // Convert to base (1 << 30), discarding bottom 6 bits, which are zero, | ||
| 275 | // so there are (32, 30, 30, 30) bits in (a3, a2, a1, a0): | ||
| 276 | uint64_t a0 = a.x0 << 28 >> 34; | ||
| 277 | uint64_t b0 = b.x0 << 28 >> 34; | ||
| 278 | uint64_t a1 = a.x0 >> 36 | a.x1 << 62 >> 34; | ||
| 279 | uint64_t b1 = b.x0 >> 36 | b.x1 << 62 >> 34; | ||
| 280 | uint64_t a2 = a.x1 << 32 >> 34; | ||
| 281 | uint64_t b2 = b.x1 << 32 >> 34; | ||
| 282 | uint64_t a3 = a.x1 >> 32; | ||
| 283 | uint64_t b3 = b.x1 >> 32; | ||
| 284 | // Use 16 small multiplications and additions that do not overflow: | ||
| 285 | uint64_t x0 = a0 * b0; | ||
| 286 | uint64_t x1 = (x0 >> 30) + a0 * b1 + a1 * b0; | ||
| 287 | uint64_t x2 = (x1 >> 30) + a0 * b2 + a1 * b1 + a2 * b0; | ||
| 288 | uint64_t x3 = (x2 >> 30) + a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0; | ||
| 289 | uint64_t x4 = (x3 >> 30) + a1 * b3 + a2 * b2 + a3 * b1; | ||
| 290 | uint64_t x5 = (x4 >> 30) + a2 * b3 + a3 * b2; | ||
| 291 | uint64_t x6 = (x5 >> 30) + a3 * b3; | ||
| 292 | // We now have (64, 30, 30, ...) bits in (x6, x5, x4, ...). | ||
| 293 | // Take the top 128 bits, setting bottom bit if any lower bits were set: | ||
| 294 | uint64_t y0 = (x5 << 34 | x4 << 34 >> 30 | x3 << 34 >> 60 | | ||
| 295 | !!(x3 << 38 | (x2 | x1 | x0) << 34)); | ||
| 296 | uint64_t y1 = x6; | ||
| 297 | // Top bit may be zero. Renormalise: | ||
| 298 | if (!(y1 >> 63)) { | ||
| 299 | y1 = y1 << 1 | y0 >> 63; | ||
| 300 | y0 = y0 << 1; | ||
| 301 | --x_exp; | ||
| 302 | } | ||
| 303 | x.x0 = y0; | ||
| 304 | x.x1 = y1; | ||
| 305 | } | ||
| 306 | |||
| 307 | return f3_round(x_sgn, x_exp, x); | ||
| 308 | } | ||
| 309 | |||
| 310 | long double __divtf3(long double fa, long double fb) | ||
| 311 | { | ||
| 312 | u128_t a, b, x; | ||
| 313 | int32_t a_exp, b_exp, x_exp; | ||
| 314 | int a_sgn, b_sgn, x_sgn, i; | ||
| 315 | long double fx; | ||
| 316 | |||
| 317 | f3_unpack(&a_sgn, &a_exp, &a, fa); | ||
| 318 | f3_unpack(&b_sgn, &b_exp, &b, fb); | ||
| 319 | |||
| 320 | if (fp3_detect_NaNs(&fx, a_sgn, a_exp, a, b_sgn, b_exp, b)) | ||
| 321 | return fx; | ||
| 322 | |||
| 323 | // Handle infinities and zeroes: | ||
| 324 | if ((a_exp == 32767 && b_exp == 32767) || | ||
| 325 | (!(a.x0 | a.x1) && !(b.x0 | b.x1))) | ||
| 326 | return f3_NaN(); | ||
| 327 | if (a_exp == 32767 || !(b.x0 | b.x1)) | ||
| 328 | return f3_infinity(a_sgn ^ b_sgn); | ||
| 329 | if (!(a.x0 | a.x1) || b_exp == 32767) | ||
| 330 | return f3_zero(a_sgn ^ b_sgn); | ||
| 331 | |||
| 332 | a = f3_normalise(&a_exp, a); | ||
| 333 | b = f3_normalise(&b_exp, b); | ||
| 334 | |||
| 335 | x_sgn = a_sgn ^ b_sgn; | ||
| 336 | x_exp = a_exp - b_exp + 16395; | ||
| 337 | |||
| 338 | a.x0 = a.x0 >> 1 | a.x1 << 63; | ||
| 339 | a.x1 = a.x1 >> 1; | ||
| 340 | b.x0 = b.x0 >> 1 | b.x1 << 63; | ||
| 341 | b.x1 = b.x1 >> 1; | ||
| 342 | x.x0 = 0; | ||
| 343 | x.x1 = 0; | ||
| 344 | for (i = 0; i < 116; i++) { | ||
| 345 | x.x1 = x.x1 << 1 | x.x0 >> 63; | ||
| 346 | x.x0 = x.x0 << 1; | ||
| 347 | if (a.x1 > b.x1 || (a.x1 == b.x1 && a.x0 >= b.x0)) { | ||
| 348 | a.x1 = a.x1 - b.x1 - (a.x0 < b.x0); | ||
| 349 | a.x0 = a.x0 - b.x0; | ||
| 350 | x.x0 |= 1; | ||
| 351 | } | ||
| 352 | a.x1 = a.x1 << 1 | a.x0 >> 63; | ||
| 353 | a.x0 = a.x0 << 1; | ||
| 354 | } | ||
| 355 | x.x0 |= !!(a.x0 | a.x1); | ||
| 356 | |||
| 357 | x = f3_normalise(&x_exp, x); | ||
| 358 | |||
| 359 | return f3_round(x_sgn, x_exp, x); | ||
| 360 | } | ||
| 361 | |||
| 362 | long double __extendsftf2(float f) | ||
| 363 | { | ||
| 364 | long double fx; | ||
| 365 | u128_t x; | ||
| 366 | uint32_t a; | ||
| 367 | uint64_t aa; | ||
| 368 | memcpy(&a, &f, 4); | ||
| 369 | aa = a; | ||
| 370 | x.x0 = 0; | ||
| 371 | if (!(a << 1)) | ||
| 372 | x.x1 = aa << 32; | ||
| 373 | else if (a << 1 >> 24 == 255) | ||
| 374 | x.x1 = (0x7fff000000000000 | aa >> 31 << 63 | aa << 41 >> 16 | | ||
| 375 | (uint64_t)!!(a << 9) << 47); | ||
| 376 | else | ||
| 377 | x.x1 = (aa >> 31 << 63 | ((aa >> 23 & 255) + 16256) << 48 | | ||
| 378 | aa << 41 >> 16); | ||
| 379 | memcpy(&fx, &x, 16); | ||
| 380 | return fx; | ||
| 381 | } | ||
| 382 | |||
| 383 | long double __extenddftf2(double f) | ||
| 384 | { | ||
| 385 | long double fx; | ||
| 386 | u128_t x; | ||
| 387 | uint64_t a; | ||
| 388 | memcpy(&a, &f, 8); | ||
| 389 | x.x0 = a << 60; | ||
| 390 | if (!(a << 1)) | ||
| 391 | x.x1 = a; | ||
| 392 | else if (a << 1 >> 53 == 2047) | ||
| 393 | x.x1 = (0x7fff000000000000 | a >> 63 << 63 | a << 12 >> 16 | | ||
| 394 | (uint64_t)!!(a << 12) << 47); | ||
| 395 | else | ||
| 396 | x.x1 = a >> 63 << 63 | ((a >> 52 & 2047) + 15360) << 48 | a << 12 >> 16; | ||
| 397 | memcpy(&fx, &x, 16); | ||
| 398 | return fx; | ||
| 399 | } | ||
| 400 | |||
| 401 | float __trunctfsf2(long double f) | ||
| 402 | { | ||
| 403 | u128_t mnt; | ||
| 404 | int32_t exp; | ||
| 405 | int sgn; | ||
| 406 | uint32_t x; | ||
| 407 | float fx; | ||
| 408 | |||
| 409 | f3_unpack(&sgn, &exp, &mnt, f); | ||
| 410 | |||
| 411 | if (exp == 32767 && (mnt.x0 | mnt.x1 << 16)) | ||
| 412 | x = 0x7fc00000 | (uint32_t)sgn << 31 | (mnt.x1 >> 25 & 0x007fffff); | ||
| 413 | else if (exp > 16510) | ||
| 414 | x = 0x7f800000 | (uint32_t)sgn << 31; | ||
| 415 | else if (exp < 16233) | ||
| 416 | x = (uint32_t)sgn << 31; | ||
| 417 | else { | ||
| 418 | exp -= 16257; | ||
| 419 | x = mnt.x1 >> 23 | !!(mnt.x0 | mnt.x1 << 41); | ||
| 420 | if (exp < 0) { | ||
| 421 | x = x >> -exp | !!(x << (32 + exp)); | ||
| 422 | exp = 0; | ||
| 423 | } | ||
| 424 | if ((x & 3) == 3 || (x & 7) == 6) | ||
| 425 | x += 4; | ||
| 426 | x = ((x >> 2) + (exp << 23)) | (uint32_t)sgn << 31; | ||
| 427 | } | ||
| 428 | memcpy(&fx, &x, 4); | ||
| 429 | return fx; | ||
| 430 | } | ||
| 431 | |||
| 432 | double __trunctfdf2(long double f) | ||
| 433 | { | ||
| 434 | u128_t mnt; | ||
| 435 | int32_t exp; | ||
| 436 | int sgn; | ||
| 437 | uint64_t x; | ||
| 438 | double fx; | ||
| 439 | |||
| 440 | f3_unpack(&sgn, &exp, &mnt, f); | ||
| 441 | |||
| 442 | if (exp == 32767 && (mnt.x0 | mnt.x1 << 16)) | ||
| 443 | x = (0x7ff8000000000000 | (uint64_t)sgn << 63 | | ||
| 444 | mnt.x1 << 16 >> 12 | mnt.x0 >> 60); | ||
| 445 | else if (exp > 17406) | ||
| 446 | x = 0x7ff0000000000000 | (uint64_t)sgn << 63; | ||
| 447 | else if (exp < 15308) | ||
| 448 | x = (uint64_t)sgn << 63; | ||
| 449 | else { | ||
| 450 | exp -= 15361; | ||
| 451 | x = mnt.x1 << 6 | mnt.x0 >> 58 | !!(mnt.x0 << 6); | ||
| 452 | if (exp < 0) { | ||
| 453 | x = x >> -exp | !!(x << (64 + exp)); | ||
| 454 | exp = 0; | ||
| 455 | } | ||
| 456 | if ((x & 3) == 3 || (x & 7) == 6) | ||
| 457 | x += 4; | ||
| 458 | x = ((x >> 2) + ((uint64_t)exp << 52)) | (uint64_t)sgn << 63; | ||
| 459 | } | ||
| 460 | memcpy(&fx, &x, 8); | ||
| 461 | return fx; | ||
| 462 | } | ||
| 463 | |||
| 464 | int32_t __fixtfsi(long double fa) | ||
| 465 | { | ||
| 466 | u128_t a; | ||
| 467 | int32_t a_exp; | ||
| 468 | int a_sgn; | ||
| 469 | int32_t x; | ||
| 470 | f3_unpack(&a_sgn, &a_exp, &a, fa); | ||
| 471 | if (a_exp < 16369) | ||
| 472 | return 0; | ||
| 473 | if (a_exp > 16413) | ||
| 474 | return a_sgn ? -0x80000000 : 0x7fffffff; | ||
| 475 | x = a.x1 >> (16431 - a_exp); | ||
| 476 | return a_sgn ? -x : x; | ||
| 477 | } | ||
| 478 | |||
| 479 | int64_t __fixtfdi(long double fa) | ||
| 480 | { | ||
| 481 | u128_t a; | ||
| 482 | int32_t a_exp; | ||
| 483 | int a_sgn; | ||
| 484 | int64_t x; | ||
| 485 | f3_unpack(&a_sgn, &a_exp, &a, fa); | ||
| 486 | if (a_exp < 16383) | ||
| 487 | return 0; | ||
| 488 | if (a_exp > 16445) | ||
| 489 | return a_sgn ? -0x8000000000000000 : 0x7fffffffffffffff; | ||
| 490 | x = (a.x1 << 15 | a.x0 >> 49) >> (16446 - a_exp); | ||
| 491 | return a_sgn ? -x : x; | ||
| 492 | } | ||
| 493 | |||
| 494 | uint32_t __fixunstfsi(long double fa) | ||
| 495 | { | ||
| 496 | u128_t a; | ||
| 497 | int32_t a_exp; | ||
| 498 | int a_sgn; | ||
| 499 | f3_unpack(&a_sgn, &a_exp, &a, fa); | ||
| 500 | if (a_sgn || a_exp < 16369) | ||
| 501 | return 0; | ||
| 502 | if (a_exp > 16414) | ||
| 503 | return -1; | ||
| 504 | return a.x1 >> (16431 - a_exp); | ||
| 505 | } | ||
| 506 | |||
| 507 | uint64_t __fixunstfdi(long double fa) | ||
| 508 | { | ||
| 509 | u128_t a; | ||
| 510 | int32_t a_exp; | ||
| 511 | int a_sgn; | ||
| 512 | f3_unpack(&a_sgn, &a_exp, &a, fa); | ||
| 513 | if (a_sgn || a_exp < 16383) | ||
| 514 | return 0; | ||
| 515 | if (a_exp > 16446) | ||
| 516 | return -1; | ||
| 517 | return (a.x1 << 15 | a.x0 >> 49) >> (16446 - a_exp); | ||
| 518 | } | ||
| 519 | |||
| 520 | long double __floatsitf(int32_t a) | ||
| 521 | { | ||
| 522 | int sgn = 0; | ||
| 523 | int exp = 16414; | ||
| 524 | uint32_t mnt = a; | ||
| 525 | u128_t x = { 0, 0 }; | ||
| 526 | long double f; | ||
| 527 | int i; | ||
| 528 | if (a) { | ||
| 529 | if (a < 0) { | ||
| 530 | sgn = 1; | ||
| 531 | mnt = -mnt; | ||
| 532 | } | ||
| 533 | for (i = 16; i; i >>= 1) | ||
| 534 | if (!(mnt >> (32 - i))) { | ||
| 535 | mnt <<= i; | ||
| 536 | exp -= i; | ||
| 537 | } | ||
| 538 | x.x1 = ((uint64_t)sgn << 63 | (uint64_t)exp << 48 | | ||
| 539 | (uint64_t)(mnt << 1) << 16); | ||
| 540 | } | ||
| 541 | memcpy(&f, &x, 16); | ||
| 542 | return f; | ||
| 543 | } | ||
| 544 | |||
| 545 | long double __floatditf(int64_t a) | ||
| 546 | { | ||
| 547 | int sgn = 0; | ||
| 548 | int exp = 16446; | ||
| 549 | uint64_t mnt = a; | ||
| 550 | u128_t x = { 0, 0 }; | ||
| 551 | long double f; | ||
| 552 | int i; | ||
| 553 | if (a) { | ||
| 554 | if (a < 0) { | ||
| 555 | sgn = 1; | ||
| 556 | mnt = -mnt; | ||
| 557 | } | ||
| 558 | for (i = 32; i; i >>= 1) | ||
| 559 | if (!(mnt >> (64 - i))) { | ||
| 560 | mnt <<= i; | ||
| 561 | exp -= i; | ||
| 562 | } | ||
| 563 | x.x0 = mnt << 49; | ||
| 564 | x.x1 = (uint64_t)sgn << 63 | (uint64_t)exp << 48 | mnt << 1 >> 16; | ||
| 565 | } | ||
| 566 | memcpy(&f, &x, 16); | ||
| 567 | return f; | ||
| 568 | } | ||
| 569 | |||
| 570 | long double __floatunsitf(uint32_t a) | ||
| 571 | { | ||
| 572 | int exp = 16414; | ||
| 573 | uint32_t mnt = a; | ||
| 574 | u128_t x = { 0, 0 }; | ||
| 575 | long double f; | ||
| 576 | int i; | ||
| 577 | if (a) { | ||
| 578 | for (i = 16; i; i >>= 1) | ||
| 579 | if (!(mnt >> (32 - i))) { | ||
| 580 | mnt <<= i; | ||
| 581 | exp -= i; | ||
| 582 | } | ||
| 583 | x.x1 = (uint64_t)exp << 48 | (uint64_t)(mnt << 1) << 16; | ||
| 584 | } | ||
| 585 | memcpy(&f, &x, 16); | ||
| 586 | return f; | ||
| 587 | } | ||
| 588 | |||
| 589 | long double __floatunditf(uint64_t a) | ||
| 590 | { | ||
| 591 | int exp = 16446; | ||
| 592 | uint64_t mnt = a; | ||
| 593 | u128_t x = { 0, 0 }; | ||
| 594 | long double f; | ||
| 595 | int i; | ||
| 596 | if (a) { | ||
| 597 | for (i = 32; i; i >>= 1) | ||
| 598 | if (!(mnt >> (64 - i))) { | ||
| 599 | mnt <<= i; | ||
| 600 | exp -= i; | ||
| 601 | } | ||
| 602 | x.x0 = mnt << 49; | ||
| 603 | x.x1 = (uint64_t)exp << 48 | mnt << 1 >> 16; | ||
| 604 | } | ||
| 605 | memcpy(&f, &x, 16); | ||
| 606 | return f; | ||
| 607 | } | ||
| 608 | |||
| 609 | static int f3_cmp(long double fa, long double fb) | ||
| 610 | { | ||
| 611 | u128_t a, b; | ||
| 612 | memcpy(&a, &fa, 16); | ||
| 613 | memcpy(&b, &fb, 16); | ||
| 614 | return (!(a.x0 | a.x1 << 1 | b.x0 | b.x1 << 1) ? 0 : | ||
| 615 | ((a.x1 << 1 >> 49 == 0x7fff && (a.x0 | a.x1 << 16)) || | ||
| 616 | (b.x1 << 1 >> 49 == 0x7fff && (b.x0 | b.x1 << 16))) ? 2 : | ||
| 617 | a.x1 >> 63 != b.x1 >> 63 ? (int)(b.x1 >> 63) - (int)(a.x1 >> 63) : | ||
| 618 | a.x1 < b.x1 ? (int)(a.x1 >> 63 << 1) - 1 : | ||
| 619 | a.x1 > b.x1 ? 1 - (int)(a.x1 >> 63 << 1) : | ||
| 620 | a.x0 < b.x0 ? (int)(a.x1 >> 63 << 1) - 1 : | ||
| 621 | b.x0 < a.x0 ? 1 - (int)(a.x1 >> 63 << 1) : 0); | ||
| 622 | } | ||
| 623 | |||
| 624 | int __eqtf2(long double a, long double b) | ||
| 625 | { | ||
| 626 | return !!f3_cmp(a, b); | ||
| 627 | } | ||
| 628 | |||
| 629 | int __netf2(long double a, long double b) | ||
| 630 | { | ||
| 631 | return !!f3_cmp(a, b); | ||
| 632 | } | ||
| 633 | |||
| 634 | int __lttf2(long double a, long double b) | ||
| 635 | { | ||
| 636 | return f3_cmp(a, b); | ||
| 637 | } | ||
| 638 | |||
| 639 | int __letf2(long double a, long double b) | ||
| 640 | { | ||
| 641 | return f3_cmp(a, b); | ||
| 642 | } | ||
| 643 | |||
| 644 | int __gttf2(long double a, long double b) | ||
| 645 | { | ||
| 646 | return -f3_cmp(b, a); | ||
| 647 | } | ||
| 648 | |||
| 649 | int __getf2(long double a, long double b) | ||
| 650 | { | ||
| 651 | return -f3_cmp(b, a); | ||
| 652 | } | ||
| @@ -0,0 +1,510 @@ | |||
| 1 | /* | ||
| 2 | * Test 128-bit floating-point arithmetic on arm64: | ||
| 3 | * build with two different compilers and compare the output. | ||
| 4 | * | ||
| 5 | * Copyright (c) 2015 Edmund Grimley Evans | ||
| 6 | * | ||
| 7 | * Copying and distribution of this file, with or without modification, | ||
| 8 | * are permitted in any medium without royalty provided the copyright | ||
| 9 | * notice and this notice are preserved. This file is offered as-is, | ||
| 10 | * without any warranty. | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <stdint.h> | ||
| 14 | #include <stdio.h> | ||
| 15 | #include <stdlib.h> | ||
| 16 | #include <string.h> | ||
| 17 | |||
| 18 | #define check(x) ((x) ? (void)0 : check_fail(#x, __FILE__, __LINE__)) | ||
| 19 | |||
| 20 | void check_fail(const char *assertion, const char *file, unsigned int line) | ||
| 21 | { | ||
| 22 | printf("%s:%d: Check (%s) failed.", file, line, assertion); | ||
| 23 | exit(1); | ||
| 24 | } | ||
| 25 | |||
| 26 | typedef struct { | ||
| 27 | unsigned long long x0, x1; | ||
| 28 | } u128_t; | ||
| 29 | |||
| 30 | float copy_fi(uint32_t x) | ||
| 31 | { | ||
| 32 | float f; | ||
| 33 | memcpy(&f, &x, 4); | ||
| 34 | return f; | ||
| 35 | } | ||
| 36 | |||
| 37 | double copy_di(uint64_t x) | ||
| 38 | { | ||
| 39 | double f; | ||
| 40 | memcpy(&f, &x, 8); | ||
| 41 | return f; | ||
| 42 | } | ||
| 43 | |||
| 44 | long double copy_ldi(u128_t x) | ||
| 45 | { | ||
| 46 | long double f; | ||
| 47 | memcpy(&f, &x, 16); | ||
| 48 | return f; | ||
| 49 | } | ||
| 50 | |||
| 51 | uint32_t copy_if(float f) | ||
| 52 | { | ||
| 53 | uint32_t x; | ||
| 54 | memcpy(&x, &f, 4); | ||
| 55 | return x; | ||
| 56 | } | ||
| 57 | |||
| 58 | uint64_t copy_id(double f) | ||
| 59 | { | ||
| 60 | uint64_t x; | ||
| 61 | memcpy(&x, &f, 8); | ||
| 62 | return x; | ||
| 63 | } | ||
| 64 | |||
| 65 | u128_t copy_ild(long double f) | ||
| 66 | { | ||
| 67 | u128_t x; | ||
| 68 | memcpy(&x, &f, 16); | ||
| 69 | return x; | ||
| 70 | } | ||
| 71 | |||
| 72 | long double make(int sgn, int exp, uint64_t high, uint64_t low) | ||
| 73 | { | ||
| 74 | u128_t x = { low, | ||
| 75 | (0x0000ffffffffffff & high) | | ||
| 76 | (0x7fff000000000000 & (uint64_t)exp << 48) | | ||
| 77 | (0x8000000000000000 & (uint64_t)sgn << 63) }; | ||
| 78 | return copy_ldi(x); | ||
| 79 | } | ||
| 80 | |||
| 81 | void cmp(long double a, long double b) | ||
| 82 | { | ||
| 83 | u128_t ax = copy_ild(a); | ||
| 84 | u128_t bx = copy_ild(b); | ||
| 85 | int eq = (a == b); | ||
| 86 | int ne = (a != b); | ||
| 87 | int lt = (a < b); | ||
| 88 | int le = (a <= b); | ||
| 89 | int gt = (a > b); | ||
| 90 | int ge = (a >= b); | ||
| 91 | |||
| 92 | check(eq == 0 || eq == 1); | ||
| 93 | check(lt == 0 || lt == 1); | ||
| 94 | check(gt == 0 || gt == 1); | ||
| 95 | check(ne == !eq && le == (lt | eq) && ge == (gt | eq)); | ||
| 96 | check(eq + lt + gt < 2); | ||
| 97 | |||
| 98 | printf("cmp %016llx%016llx %016llx%016llx %d %d %d\n", | ||
| 99 | ax.x1, ax.x0, bx.x1, bx.x0, lt, eq, gt); | ||
| 100 | } | ||
| 101 | |||
| 102 | void cmps(void) | ||
| 103 | { | ||
| 104 | int i, j; | ||
| 105 | |||
| 106 | for (i = 0; i < 2; i++) | ||
| 107 | for (j = 0; j < 2; j++) | ||
| 108 | cmp(make(i, 0, 0, 0), make(j, 0, 0, 0)); | ||
| 109 | |||
| 110 | for (i = 0; i < 2; i++) { | ||
| 111 | for (j = 0; j < 64; j++) { | ||
| 112 | long double f1 = make(i, 32767, (uint64_t)1 << j, 0); | ||
| 113 | long double f2 = make(i, 32767, 0, (uint64_t)1 << j); | ||
| 114 | cmp(f1, 0); | ||
| 115 | cmp(f2, 0); | ||
| 116 | cmp(0, f1); | ||
| 117 | cmp(0, f2); | ||
| 118 | } | ||
| 119 | } | ||
| 120 | |||
| 121 | for (i = 0; i < 6; i++) | ||
| 122 | for (j = 0; j < 6; j++) | ||
| 123 | cmp(make(i & 1, i >> 1, 0, 0), | ||
| 124 | make(j & 1, j >> 1, 0, 0)); | ||
| 125 | |||
| 126 | for (i = 0; i < 2; i++) { | ||
| 127 | for (j = 0; j < 2; j++) { | ||
| 128 | int a, b; | ||
| 129 | for (a = 0; a < 2; a++) { | ||
| 130 | for (b = 0; b < 2; b++) { | ||
| 131 | cmp(make(i, j, a, b), make(i, j, 0, 0)); | ||
| 132 | cmp(make(i, j, 0, 0), make(i, j, a, b)); | ||
| 133 | } | ||
| 134 | } | ||
| 135 | } | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | void xop(const char *name, long double a, long double b, long double c) | ||
| 140 | { | ||
| 141 | u128_t ax = copy_ild(a); | ||
| 142 | u128_t bx = copy_ild(b); | ||
| 143 | u128_t cx = copy_ild(c); | ||
| 144 | printf("%s %016llx%016llx %016llx%016llx %016llx%016llx\n", | ||
| 145 | name, ax.x1, ax.x0, bx.x1, bx.x0, cx.x1, cx.x0); | ||
| 146 | } | ||
| 147 | |||
| 148 | void fadd(long double a, long double b) | ||
| 149 | { | ||
| 150 | xop("add", a, b, a + b); | ||
| 151 | } | ||
| 152 | |||
| 153 | void fsub(long double a, long double b) | ||
| 154 | { | ||
| 155 | xop("sub", a, b, a - b); | ||
| 156 | } | ||
| 157 | |||
| 158 | void fmul(long double a, long double b) | ||
| 159 | { | ||
| 160 | xop("mul", a, b, a * b); | ||
| 161 | } | ||
| 162 | |||
| 163 | void fdiv(long double a, long double b) | ||
| 164 | { | ||
| 165 | xop("div", a, b, a / b); | ||
| 166 | } | ||
| 167 | |||
| 168 | void nanz(void) | ||
| 169 | { | ||
| 170 | // Check NaNs: | ||
| 171 | { | ||
| 172 | long double x[7]; | ||
| 173 | int i, j, n = 0; | ||
| 174 | x[n++] = make(0, 32000, 0x95132b76effc, 0xd79035214b4f8d53); | ||
| 175 | x[n++] = make(1, 32001, 0xbe71d7a51587, 0x30601c6815d6c3ac); | ||
| 176 | x[n++] = make(0, 32767, 0, 1); | ||
| 177 | x[n++] = make(0, 32767, (uint64_t)1 << 46, 0); | ||
| 178 | x[n++] = make(1, 32767, (uint64_t)1 << 47, 0); | ||
| 179 | x[n++] = make(1, 32767, 0x7596c7099ad5, 0xe25fed2c58f73fc9); | ||
| 180 | x[n++] = make(0, 32767, 0x835d143360f9, 0x5e315efb35630666); | ||
| 181 | check(n == sizeof(x) / sizeof(*x)); | ||
| 182 | for (i = 0; i < n; i++) { | ||
| 183 | for (j = 0; j < n; j++) { | ||
| 184 | fadd(x[i], x[j]); | ||
| 185 | fsub(x[i], x[j]); | ||
| 186 | fmul(x[i], x[j]); | ||
| 187 | fdiv(x[i], x[j]); | ||
| 188 | } | ||
| 189 | } | ||
| 190 | } | ||
| 191 | |||
| 192 | // Check infinities and zeroes: | ||
| 193 | { | ||
| 194 | long double x[6]; | ||
| 195 | int i, j, n = 0; | ||
| 196 | x[n++] = make(1, 32000, 0x62acda85f700, 0x47b6c9f35edc4044); | ||
| 197 | x[n++] = make(0, 32001, 0x94b7abf55af7, 0x9f425fe354428e19); | ||
| 198 | x[n++] = make(0, 32767, 0, 0); | ||
| 199 | x[n++] = make(1, 32767, 0, 0); | ||
| 200 | x[n++] = make(0, 0, 0, 0); | ||
| 201 | x[n++] = make(1, 0, 0, 0); | ||
| 202 | check(n == sizeof(x) / sizeof(*x)); | ||
| 203 | for (i = 0; i < n; i++) { | ||
| 204 | for (j = 0; j < n; j++) { | ||
| 205 | fadd(x[i], x[j]); | ||
| 206 | fsub(x[i], x[j]); | ||
| 207 | fmul(x[i], x[j]); | ||
| 208 | fdiv(x[i], x[j]); | ||
| 209 | } | ||
| 210 | } | ||
| 211 | } | ||
| 212 | } | ||
| 213 | |||
| 214 | void adds(void) | ||
| 215 | { | ||
| 216 | // Check shifting and add/sub: | ||
| 217 | { | ||
| 218 | int i; | ||
| 219 | for (i = -130; i <= 130; i++) { | ||
| 220 | int s1 = (uint32_t)i % 3 < 1; | ||
| 221 | int s2 = (uint32_t)i % 5 < 2; | ||
| 222 | fadd(make(s1, 16384 , 0x502c065e4f71a65d, 0xd2f9bdb031f4f031), | ||
| 223 | make(s2, 16384 + i, 0xae267395a9bc1033, 0xb56b5800da1ba448)); | ||
| 224 | } | ||
| 225 | } | ||
| 226 | |||
| 227 | // Check normalisation: | ||
| 228 | { | ||
| 229 | uint64_t a0 = 0xc6bab0a6afbef5ed; | ||
| 230 | uint64_t a1 = 0x4f84136c4a2e9b52; | ||
| 231 | int ee[] = { 0, 1, 10000 }; | ||
| 232 | int e, i; | ||
| 233 | for (e = 0; e < sizeof(ee) / sizeof(*ee); e++) { | ||
| 234 | int exp = ee[e]; | ||
| 235 | fsub(make(0, exp, a1, a0), make(0, 0, 0, 0)); | ||
| 236 | for (i = 63; i >= 0; i--) | ||
| 237 | fsub(make(0, exp, a1 | (uint64_t)1 << i >> 1, a0), | ||
| 238 | make(0, exp, a1 >> i << i, 0)); | ||
| 239 | for (i = 63; i >=0; i--) | ||
| 240 | fsub(make(0, exp, a1, a0 | (uint64_t)1 << i >> 1), | ||
| 241 | make(0, exp, a1, a0 >> i << i)); | ||
| 242 | } | ||
| 243 | } | ||
| 244 | |||
| 245 | // Carry/overflow from rounding: | ||
| 246 | { | ||
| 247 | fadd(make(0, 114, -1, -1), make(0, 1, 0, 0)); | ||
| 248 | fadd(make(0, 32766, -1, -1), make(0, 32653, 0, 0)); | ||
| 249 | fsub(make(1, 32766, -1, -1), make(0, 32653, 0, 0)); | ||
| 250 | } | ||
| 251 | } | ||
| 252 | |||
| 253 | void muls(void) | ||
| 254 | { | ||
| 255 | int i, j; | ||
| 256 | |||
| 257 | { | ||
| 258 | long double max = make(0, 32766, -1, -1); | ||
| 259 | long double min = make(0, 0, 0, 1); | ||
| 260 | fmul(max, max); | ||
| 261 | fmul(max, min); | ||
| 262 | fmul(min, min); | ||
| 263 | } | ||
| 264 | |||
| 265 | for (i = 117; i > 0; i--) | ||
| 266 | fmul(make(0, 16268, 0x643dcea76edc, 0xe0877a598403627a), | ||
| 267 | make(i & 1, i, 0, 0)); | ||
| 268 | |||
| 269 | fmul(make(0, 16383, -1, -3), make(0, 16383, 0, 1)); | ||
| 270 | // Round to next exponent: | ||
| 271 | fmul(make(0, 16383, -1, -2), make(0, 16383, 0, 1)); | ||
| 272 | // Round from subnormal to normal: | ||
| 273 | fmul(make(0, 1, -1, -1), make(0, 16382, 0, 0)); | ||
| 274 | |||
| 275 | for (i = 0; i < 2; i++) | ||
| 276 | for (j = 0; j < 112; j++) | ||
| 277 | fmul(make(0, 16383, (uint64_t)1 << i, 0), | ||
| 278 | make(0, 16383, | ||
| 279 | j < 64 ? 0 : (uint64_t)1 << (j - 64), | ||
| 280 | j < 64 ? (uint64_t)1 << j : 0)); | ||
| 281 | } | ||
| 282 | |||
| 283 | void divs(void) | ||
| 284 | { | ||
| 285 | int i; | ||
| 286 | |||
| 287 | { | ||
| 288 | long double max = make(0, 32766, -1, -1); | ||
| 289 | long double min = make(0, 0, 0, 1); | ||
| 290 | fdiv(max, max); | ||
| 291 | fdiv(max, min); | ||
| 292 | fdiv(min, max); | ||
| 293 | fdiv(min, min); | ||
| 294 | } | ||
| 295 | |||
| 296 | for (i = 0; i < 64; i++) | ||
| 297 | fdiv(make(0, 16383, -1, -1), make(0, 16383, -1, -(uint64_t)1 << i)); | ||
| 298 | for (i = 0; i < 48; i++) | ||
| 299 | fdiv(make(0, 16383, -1, -1), make(0, 16383, -(uint64_t)1 << i, 0)); | ||
| 300 | } | ||
| 301 | |||
| 302 | void cvtlsw(int32_t a) | ||
| 303 | { | ||
| 304 | long double f = a; | ||
| 305 | u128_t x = copy_ild(f); | ||
| 306 | printf("cvtlsw %08lx %016llx%016llx\n", (long)(uint32_t)a, x.x1, x.x0); | ||
| 307 | } | ||
| 308 | |||
| 309 | void cvtlsx(int64_t a) | ||
| 310 | { | ||
| 311 | long double f = a; | ||
| 312 | u128_t x = copy_ild(f); | ||
| 313 | printf("cvtlsx %016llx %016llx%016llx\n", | ||
| 314 | (long long)(uint64_t)a, x.x1, x.x0); | ||
| 315 | } | ||
| 316 | |||
| 317 | void cvtluw(uint32_t a) | ||
| 318 | { | ||
| 319 | long double f = a; | ||
| 320 | u128_t x = copy_ild(f); | ||
| 321 | printf("cvtluw %08lx %016llx%016llx\n", (long)a, x.x1, x.x0); | ||
| 322 | } | ||
| 323 | |||
| 324 | void cvtlux(uint64_t a) | ||
| 325 | { | ||
| 326 | long double f = a; | ||
| 327 | u128_t x = copy_ild(f); | ||
| 328 | printf("cvtlux %016llx %016llx%016llx\n", (long long)a, x.x1, x.x0); | ||
| 329 | } | ||
| 330 | |||
| 331 | void cvtil(long double a) | ||
| 332 | { | ||
| 333 | u128_t x = copy_ild(a); | ||
| 334 | int32_t b1 = a; | ||
| 335 | int64_t b2 = a; | ||
| 336 | uint32_t b3 = a; | ||
| 337 | uint64_t b4 = a; | ||
| 338 | printf("cvtswl %016llx%016llx %08lx\n", | ||
| 339 | x.x1, x.x0, (long)(uint32_t)b1); | ||
| 340 | printf("cvtsxl %016llx%016llx %016llx\n", | ||
| 341 | x.x1, x.x0, (long long)(uint64_t)b2); | ||
| 342 | printf("cvtuwl %016llx%016llx %08lx\n", | ||
| 343 | x.x1, x.x0, (long)b3); | ||
| 344 | printf("cvtuxl %016llx%016llx %016llx\n", | ||
| 345 | x.x1, x.x0, (long long)b4); | ||
| 346 | } | ||
| 347 | |||
| 348 | void cvtlf(float a) | ||
| 349 | { | ||
| 350 | uint32_t ax = copy_if(a); | ||
| 351 | long double b = a; | ||
| 352 | u128_t bx = copy_ild(b); | ||
| 353 | printf("cvtlf %08lx %016llx%016llx\n", (long)ax, bx.x1, bx.x0); | ||
| 354 | } | ||
| 355 | |||
| 356 | void cvtld(double a) | ||
| 357 | { | ||
| 358 | uint64_t ax = copy_id(a); | ||
| 359 | long double b = a; | ||
| 360 | u128_t bx = copy_ild(b); | ||
| 361 | printf("cvtld %016llx %016llx%016llx\n", (long long)ax, bx.x1, bx.x0); | ||
| 362 | } | ||
| 363 | |||
| 364 | void cvtfl(long double a) | ||
| 365 | { | ||
| 366 | u128_t ax = copy_ild(a); | ||
| 367 | float b = a; | ||
| 368 | uint32_t bx = copy_if(b); | ||
| 369 | printf("cvtfl %016llx%016llx %08lx\n", ax.x1, ax.x0, (long)bx); | ||
| 370 | } | ||
| 371 | |||
| 372 | void cvtdl(long double a) | ||
| 373 | { | ||
| 374 | u128_t ax = copy_ild(a); | ||
| 375 | double b = a; | ||
| 376 | uint64_t bx = copy_id(b); | ||
| 377 | printf("cvtdl %016llx%016llx %016llx\n", ax.x1, ax.x0, (long long)bx); | ||
| 378 | } | ||
| 379 | |||
| 380 | void cvts(void) | ||
| 381 | { | ||
| 382 | int i, j; | ||
| 383 | |||
| 384 | { | ||
| 385 | uint32_t x = 0xad040c5b; | ||
| 386 | cvtlsw(0); | ||
| 387 | for (i = 0; i < 31; i++) | ||
| 388 | cvtlsw(x >> (31 - i)); | ||
| 389 | for (i = 0; i < 31; i++) | ||
| 390 | cvtlsw(-(x >> (31 - i))); | ||
| 391 | cvtlsw(0x80000000); | ||
| 392 | } | ||
| 393 | { | ||
| 394 | uint64_t x = 0xb630a248cad9afd2; | ||
| 395 | cvtlsx(0); | ||
| 396 | for (i = 0; i < 63; i++) | ||
| 397 | cvtlsx(x >> (63 - i)); | ||
| 398 | for (i = 0; i < 63; i++) | ||
| 399 | cvtlsx(-(x >> (63 - i))); | ||
| 400 | cvtlsx(0x8000000000000000); | ||
| 401 | } | ||
| 402 | { | ||
| 403 | uint32_t x = 0xad040c5b; | ||
| 404 | cvtluw(0); | ||
| 405 | for (i = 0; i < 32; i++) | ||
| 406 | cvtluw(x >> (31 - i)); | ||
| 407 | } | ||
| 408 | { | ||
| 409 | uint64_t x = 0xb630a248cad9afd2; | ||
| 410 | cvtlux(0); | ||
| 411 | for (i = 0; i < 64; i++) | ||
| 412 | cvtlux(x >> (63 - i)); | ||
| 413 | } | ||
| 414 | |||
| 415 | for (i = 0; i < 2; i++) { | ||
| 416 | cvtil(make(i, 32767, 0, 1)); | ||
| 417 | cvtil(make(i, 32767, (uint64_t)1 << 47, 0)); | ||
| 418 | cvtil(make(i, 32767, 123, 456)); | ||
| 419 | cvtil(make(i, 32767, 0, 0)); | ||
| 420 | cvtil(make(i, 16382, -1, -1)); | ||
| 421 | cvtil(make(i, 16383, -1, -1)); | ||
| 422 | cvtil(make(i, 16384, 0x7fffffffffff, -1)); | ||
| 423 | cvtil(make(i, 16384, 0x800000000000, 0)); | ||
| 424 | for (j = 0; j < 68; j++) | ||
| 425 | cvtil(make(i, 16381 + j, 0xd4822c0a10ec, 0x1fe2f8b2669f5c9d)); | ||
| 426 | } | ||
| 427 | |||
| 428 | cvtlf(copy_fi(0x00000000)); | ||
| 429 | cvtlf(copy_fi(0x456789ab)); | ||
| 430 | cvtlf(copy_fi(0x7f800000)); | ||
| 431 | cvtlf(copy_fi(0x7f923456)); | ||
| 432 | cvtlf(copy_fi(0x7fdbcdef)); | ||
| 433 | cvtlf(copy_fi(0x80000000)); | ||
| 434 | cvtlf(copy_fi(0xabcdef12)); | ||
| 435 | cvtlf(copy_fi(0xff800000)); | ||
| 436 | cvtlf(copy_fi(0xff923456)); | ||
| 437 | cvtlf(copy_fi(0xffdbcdef)); | ||
| 438 | |||
| 439 | cvtld(copy_di(0x0000000000000000)); | ||
| 440 | cvtld(copy_di(0x456789abcdef0123)); | ||
| 441 | cvtld(copy_di(0x7ff0000000000000)); | ||
| 442 | cvtld(copy_di(0x7ff123456789abcd)); | ||
| 443 | cvtld(copy_di(0x7ffabcdef1234567)); | ||
| 444 | cvtld(copy_di(0x8000000000000000)); | ||
| 445 | cvtld(copy_di(0xcdef123456789abc)); | ||
| 446 | cvtld(copy_di(0xfff0000000000000)); | ||
| 447 | cvtld(copy_di(0xfff123456789abcd)); | ||
| 448 | cvtld(copy_di(0xfffabcdef1234567)); | ||
| 449 | |||
| 450 | for (i = 0; i < 2; i++) { \ | ||
| 451 | cvtfl(make(i, 0, 0, 0)); | ||
| 452 | cvtfl(make(i, 16232, -1, -1)); | ||
| 453 | cvtfl(make(i, 16233, 0, 0)); | ||
| 454 | cvtfl(make(i, 16233, 0, 1)); | ||
| 455 | cvtfl(make(i, 16383, 0xab0ffd000000, 0)); | ||
| 456 | cvtfl(make(i, 16383, 0xab0ffd000001, 0)); | ||
| 457 | cvtfl(make(i, 16383, 0xab0ffeffffff, 0)); | ||
| 458 | cvtfl(make(i, 16383, 0xab0fff000000, 0)); | ||
| 459 | cvtfl(make(i, 16383, 0xab0fff000001, 0)); | ||
| 460 | cvtfl(make(i, 16510, 0xfffffeffffff, -1)); | ||
| 461 | cvtfl(make(i, 16510, 0xffffff000000, 0)); | ||
| 462 | cvtfl(make(i, 16511, 0, 0)); | ||
| 463 | cvtfl(make(i, 32767, 0, 0)); | ||
| 464 | cvtfl(make(i, 32767, 0, 1)); | ||
| 465 | cvtfl(make(i, 32767, 0x4cbe01ac5f40, 0x75cee3c6afbb00b5)); | ||
| 466 | cvtfl(make(i, 32767, 0x800000000000, 1)); | ||
| 467 | cvtfl(make(i, 32767, 0xa11caaaf6a52, 0x696033e871eab099)); | ||
| 468 | } | ||
| 469 | |||
| 470 | for (i = 0; i < 2; i++) { | ||
| 471 | cvtdl(make(i, 0, 0, 0)); | ||
| 472 | cvtdl(make(i, 15307, -1, -1)); | ||
| 473 | cvtdl(make(i, 15308, 0, 0)); | ||
| 474 | cvtdl(make(i, 15308, 0, 1)); | ||
| 475 | cvtdl(make(i, 16383, 0xabc123abc0ff, 0xe800000000000000)); | ||
| 476 | cvtdl(make(i, 16383, 0xabc123abc0ff, 0xe800000000000001)); | ||
| 477 | cvtdl(make(i, 16383, 0xabc123abc0ff, 0xf7ffffffffffffff)); | ||
| 478 | cvtdl(make(i, 16383, 0xabc123abc0ff, 0xf800000000000000)); | ||
| 479 | cvtdl(make(i, 16383, 0xabc123abc0ff, 0xf800000000000001)); | ||
| 480 | cvtdl(make(i, 17406, 0xffffffffffff, 0xf7ffffffffffffff)); | ||
| 481 | cvtdl(make(i, 17406, 0xffffffffffff, 0xf800000000000000)); | ||
| 482 | cvtdl(make(i, 17407, 0, 0)); | ||
| 483 | cvtdl(make(i, 32767, 0, 0)); | ||
| 484 | cvtdl(make(i, 32767, 0, 1)); | ||
| 485 | cvtdl(make(i, 32767, 0x4cbe01ac5f40, 0x75cee3c6afbb00b5)); | ||
| 486 | cvtdl(make(i, 32767, 0x800000000000, 1)); | ||
| 487 | cvtdl(make(i, 32767, 0xa11caaaf6a52, 0x696033e871eab099)); | ||
| 488 | } | ||
| 489 | } | ||
| 490 | |||
| 491 | void tests(void) | ||
| 492 | { | ||
| 493 | cmps(); | ||
| 494 | nanz(); | ||
| 495 | adds(); | ||
| 496 | muls(); | ||
| 497 | divs(); | ||
| 498 | cvts(); | ||
| 499 | } | ||
| 500 | |||
| 501 | int main() | ||
| 502 | { | ||
| 503 | #ifdef __aarch64__ | ||
| 504 | tests(); | ||
| 505 | #else | ||
| 506 | printf("This test program is intended for a little-endian architecture\n" | ||
| 507 | "with an IEEE-standard 128-bit long double.\n"); | ||
| 508 | #endif | ||
| 509 | return 0; | ||
| 510 | } | ||