testfp.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  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. #include <stdint.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #define check(x) ((x) ? (void)0 : check_fail(#x, __FILE__, __LINE__))
  17. void check_fail(const char *assertion, const char *file, unsigned int line)
  18. {
  19. printf("%s:%d: Check (%s) failed.", file, line, assertion);
  20. exit(1);
  21. }
  22. typedef struct {
  23. unsigned long long x0, x1;
  24. } u128_t;
  25. float copy_fi(uint32_t x)
  26. {
  27. float f;
  28. memcpy(&f, &x, 4);
  29. return f;
  30. }
  31. double copy_di(uint64_t x)
  32. {
  33. double f;
  34. memcpy(&f, &x, 8);
  35. return f;
  36. }
  37. long double copy_ldi(u128_t x)
  38. {
  39. long double f;
  40. memcpy(&f, &x, 16);
  41. return f;
  42. }
  43. uint32_t copy_if(float f)
  44. {
  45. uint32_t x;
  46. memcpy(&x, &f, 4);
  47. return x;
  48. }
  49. uint64_t copy_id(double f)
  50. {
  51. uint64_t x;
  52. memcpy(&x, &f, 8);
  53. return x;
  54. }
  55. u128_t copy_ild(long double f)
  56. {
  57. u128_t x;
  58. memcpy(&x, &f, 16);
  59. return x;
  60. }
  61. long double make(int sgn, int exp, uint64_t high, uint64_t low)
  62. {
  63. u128_t x = { low,
  64. (0x0000ffffffffffff & high) |
  65. (0x7fff000000000000 & (uint64_t)exp << 48) |
  66. (0x8000000000000000 & (uint64_t)sgn << 63) };
  67. return copy_ldi(x);
  68. }
  69. void cmp(long double a, long double b)
  70. {
  71. u128_t ax = copy_ild(a);
  72. u128_t bx = copy_ild(b);
  73. int eq = (a == b);
  74. int ne = (a != b);
  75. int lt = (a < b);
  76. int le = (a <= b);
  77. int gt = (a > b);
  78. int ge = (a >= b);
  79. check(eq == 0 || eq == 1);
  80. check(lt == 0 || lt == 1);
  81. check(gt == 0 || gt == 1);
  82. check(ne == !eq && le == (lt | eq) && ge == (gt | eq));
  83. check(eq + lt + gt < 2);
  84. printf("cmp %016llx%016llx %016llx%016llx %d %d %d\n",
  85. ax.x1, ax.x0, bx.x1, bx.x0, lt, eq, gt);
  86. }
  87. void cmps(void)
  88. {
  89. int i, j;
  90. for (i = 0; i < 2; i++)
  91. for (j = 0; j < 2; j++)
  92. cmp(make(i, 0, 0, 0), make(j, 0, 0, 0));
  93. for (i = 0; i < 2; i++) {
  94. for (j = 0; j < 64; j++) {
  95. long double f1 = make(i, 32767, (uint64_t)1 << j, 0);
  96. long double f2 = make(i, 32767, 0, (uint64_t)1 << j);
  97. cmp(f1, 0);
  98. cmp(f2, 0);
  99. cmp(0, f1);
  100. cmp(0, f2);
  101. }
  102. }
  103. for (i = 0; i < 6; i++)
  104. for (j = 0; j < 6; j++)
  105. cmp(make(i & 1, i >> 1, 0, 0),
  106. make(j & 1, j >> 1, 0, 0));
  107. for (i = 0; i < 2; i++) {
  108. for (j = 0; j < 2; j++) {
  109. int a, b;
  110. for (a = 0; a < 2; a++) {
  111. for (b = 0; b < 2; b++) {
  112. cmp(make(i, j, a, b), make(i, j, 0, 0));
  113. cmp(make(i, j, 0, 0), make(i, j, a, b));
  114. }
  115. }
  116. }
  117. }
  118. }
  119. void xop(const char *name, long double a, long double b, long double c)
  120. {
  121. u128_t ax = copy_ild(a);
  122. u128_t bx = copy_ild(b);
  123. u128_t cx = copy_ild(c);
  124. printf("%s %016llx%016llx %016llx%016llx %016llx%016llx\n",
  125. name, ax.x1, ax.x0, bx.x1, bx.x0, cx.x1, cx.x0);
  126. }
  127. void fadd(long double a, long double b)
  128. {
  129. xop("add", a, b, a + b);
  130. }
  131. void fsub(long double a, long double b)
  132. {
  133. xop("sub", a, b, a - b);
  134. }
  135. void fmul(long double a, long double b)
  136. {
  137. xop("mul", a, b, a * b);
  138. }
  139. void fdiv(long double a, long double b)
  140. {
  141. xop("div", a, b, a / b);
  142. }
  143. void nanz(void)
  144. {
  145. // Check NaNs:
  146. {
  147. long double x[7];
  148. int i, j, n = 0;
  149. x[n++] = make(0, 32000, 0x95132b76effc, 0xd79035214b4f8d53);
  150. x[n++] = make(1, 32001, 0xbe71d7a51587, 0x30601c6815d6c3ac);
  151. x[n++] = make(0, 32767, 0, 1);
  152. x[n++] = make(0, 32767, (uint64_t)1 << 46, 0);
  153. x[n++] = make(1, 32767, (uint64_t)1 << 47, 0);
  154. x[n++] = make(1, 32767, 0x7596c7099ad5, 0xe25fed2c58f73fc9);
  155. x[n++] = make(0, 32767, 0x835d143360f9, 0x5e315efb35630666);
  156. check(n == sizeof(x) / sizeof(*x));
  157. for (i = 0; i < n; i++) {
  158. for (j = 0; j < n; j++) {
  159. fadd(x[i], x[j]);
  160. fsub(x[i], x[j]);
  161. fmul(x[i], x[j]);
  162. fdiv(x[i], x[j]);
  163. }
  164. }
  165. }
  166. // Check infinities and zeroes:
  167. {
  168. long double x[6];
  169. int i, j, n = 0;
  170. x[n++] = make(1, 32000, 0x62acda85f700, 0x47b6c9f35edc4044);
  171. x[n++] = make(0, 32001, 0x94b7abf55af7, 0x9f425fe354428e19);
  172. x[n++] = make(0, 32767, 0, 0);
  173. x[n++] = make(1, 32767, 0, 0);
  174. x[n++] = make(0, 0, 0, 0);
  175. x[n++] = make(1, 0, 0, 0);
  176. check(n == sizeof(x) / sizeof(*x));
  177. for (i = 0; i < n; i++) {
  178. for (j = 0; j < n; j++) {
  179. fadd(x[i], x[j]);
  180. fsub(x[i], x[j]);
  181. fmul(x[i], x[j]);
  182. fdiv(x[i], x[j]);
  183. }
  184. }
  185. }
  186. }
  187. void adds(void)
  188. {
  189. // Check shifting and add/sub:
  190. {
  191. int i;
  192. for (i = -130; i <= 130; i++) {
  193. int s1 = (uint32_t)i % 3 < 1;
  194. int s2 = (uint32_t)i % 5 < 2;
  195. fadd(make(s1, 16384 , 0x502c065e4f71a65d, 0xd2f9bdb031f4f031),
  196. make(s2, 16384 + i, 0xae267395a9bc1033, 0xb56b5800da1ba448));
  197. }
  198. }
  199. // Check normalisation:
  200. {
  201. uint64_t a0 = 0xc6bab0a6afbef5ed;
  202. uint64_t a1 = 0x4f84136c4a2e9b52;
  203. int ee[] = { 0, 1, 10000 };
  204. int e, i;
  205. for (e = 0; e < sizeof(ee) / sizeof(*ee); e++) {
  206. int exp = ee[e];
  207. fsub(make(0, exp, a1, a0), make(0, 0, 0, 0));
  208. for (i = 63; i >= 0; i--)
  209. fsub(make(0, exp, a1 | (uint64_t)1 << i >> 1, a0),
  210. make(0, exp, a1 >> i << i, 0));
  211. for (i = 63; i >=0; i--)
  212. fsub(make(0, exp, a1, a0 | (uint64_t)1 << i >> 1),
  213. make(0, exp, a1, a0 >> i << i));
  214. }
  215. }
  216. // Carry/overflow from rounding:
  217. {
  218. fadd(make(0, 114, -1, -1), make(0, 1, 0, 0));
  219. fadd(make(0, 32766, -1, -1), make(0, 32653, 0, 0));
  220. fsub(make(1, 32766, -1, -1), make(0, 32653, 0, 0));
  221. }
  222. }
  223. void muls(void)
  224. {
  225. int i, j;
  226. {
  227. long double max = make(0, 32766, -1, -1);
  228. long double min = make(0, 0, 0, 1);
  229. fmul(max, max);
  230. fmul(max, min);
  231. fmul(min, min);
  232. }
  233. for (i = 117; i > 0; i--)
  234. fmul(make(0, 16268, 0x643dcea76edc, 0xe0877a598403627a),
  235. make(i & 1, i, 0, 0));
  236. fmul(make(0, 16383, -1, -3), make(0, 16383, 0, 1));
  237. // Round to next exponent:
  238. fmul(make(0, 16383, -1, -2), make(0, 16383, 0, 1));
  239. // Round from subnormal to normal:
  240. fmul(make(0, 1, -1, -1), make(0, 16382, 0, 0));
  241. for (i = 0; i < 2; i++)
  242. for (j = 0; j < 112; j++)
  243. fmul(make(0, 16383, (uint64_t)1 << i, 0),
  244. make(0, 16383,
  245. j < 64 ? 0 : (uint64_t)1 << (j - 64),
  246. j < 64 ? (uint64_t)1 << j : 0));
  247. }
  248. void divs(void)
  249. {
  250. int i;
  251. {
  252. long double max = make(0, 32766, -1, -1);
  253. long double min = make(0, 0, 0, 1);
  254. fdiv(max, max);
  255. fdiv(max, min);
  256. fdiv(min, max);
  257. fdiv(min, min);
  258. }
  259. for (i = 0; i < 64; i++)
  260. fdiv(make(0, 16383, -1, -1), make(0, 16383, -1, -(uint64_t)1 << i));
  261. for (i = 0; i < 48; i++)
  262. fdiv(make(0, 16383, -1, -1), make(0, 16383, -(uint64_t)1 << i, 0));
  263. }
  264. void cvtlsw(int32_t a)
  265. {
  266. long double f = a;
  267. u128_t x = copy_ild(f);
  268. printf("cvtlsw %08lx %016llx%016llx\n", (long)(uint32_t)a, x.x1, x.x0);
  269. }
  270. void cvtlsx(int64_t a)
  271. {
  272. long double f = a;
  273. u128_t x = copy_ild(f);
  274. printf("cvtlsx %016llx %016llx%016llx\n",
  275. (long long)(uint64_t)a, x.x1, x.x0);
  276. }
  277. void cvtluw(uint32_t a)
  278. {
  279. long double f = a;
  280. u128_t x = copy_ild(f);
  281. printf("cvtluw %08lx %016llx%016llx\n", (long)a, x.x1, x.x0);
  282. }
  283. void cvtlux(uint64_t a)
  284. {
  285. long double f = a;
  286. u128_t x = copy_ild(f);
  287. printf("cvtlux %016llx %016llx%016llx\n", (long long)a, x.x1, x.x0);
  288. }
  289. void cvtil(long double a)
  290. {
  291. u128_t x = copy_ild(a);
  292. int32_t b1 = a;
  293. int64_t b2 = a;
  294. uint32_t b3 = a;
  295. uint64_t b4 = a;
  296. printf("cvtswl %016llx%016llx %08lx\n",
  297. x.x1, x.x0, (long)(uint32_t)b1);
  298. printf("cvtsxl %016llx%016llx %016llx\n",
  299. x.x1, x.x0, (long long)(uint64_t)b2);
  300. printf("cvtuwl %016llx%016llx %08lx\n",
  301. x.x1, x.x0, (long)b3);
  302. printf("cvtuxl %016llx%016llx %016llx\n",
  303. x.x1, x.x0, (long long)b4);
  304. }
  305. void cvtlf(float a)
  306. {
  307. uint32_t ax = copy_if(a);
  308. long double b = a;
  309. u128_t bx = copy_ild(b);
  310. printf("cvtlf %08lx %016llx%016llx\n", (long)ax, bx.x1, bx.x0);
  311. }
  312. void cvtld(double a)
  313. {
  314. uint64_t ax = copy_id(a);
  315. long double b = a;
  316. u128_t bx = copy_ild(b);
  317. printf("cvtld %016llx %016llx%016llx\n", (long long)ax, bx.x1, bx.x0);
  318. }
  319. void cvtfl(long double a)
  320. {
  321. u128_t ax = copy_ild(a);
  322. float b = a;
  323. uint32_t bx = copy_if(b);
  324. printf("cvtfl %016llx%016llx %08lx\n", ax.x1, ax.x0, (long)bx);
  325. }
  326. void cvtdl(long double a)
  327. {
  328. u128_t ax = copy_ild(a);
  329. double b = a;
  330. uint64_t bx = copy_id(b);
  331. printf("cvtdl %016llx%016llx %016llx\n", ax.x1, ax.x0, (long long)bx);
  332. }
  333. void cvts(void)
  334. {
  335. int i, j;
  336. {
  337. uint32_t x = 0xad040c5b;
  338. cvtlsw(0);
  339. for (i = 0; i < 31; i++)
  340. cvtlsw(x >> (31 - i));
  341. for (i = 0; i < 31; i++)
  342. cvtlsw(-(x >> (31 - i)));
  343. cvtlsw(0x80000000);
  344. }
  345. {
  346. uint64_t x = 0xb630a248cad9afd2;
  347. cvtlsx(0);
  348. for (i = 0; i < 63; i++)
  349. cvtlsx(x >> (63 - i));
  350. for (i = 0; i < 63; i++)
  351. cvtlsx(-(x >> (63 - i)));
  352. cvtlsx(0x8000000000000000);
  353. }
  354. {
  355. uint32_t x = 0xad040c5b;
  356. cvtluw(0);
  357. for (i = 0; i < 32; i++)
  358. cvtluw(x >> (31 - i));
  359. }
  360. {
  361. uint64_t x = 0xb630a248cad9afd2;
  362. cvtlux(0);
  363. for (i = 0; i < 64; i++)
  364. cvtlux(x >> (63 - i));
  365. }
  366. for (i = 0; i < 2; i++) {
  367. cvtil(make(i, 32767, 0, 1));
  368. cvtil(make(i, 32767, (uint64_t)1 << 47, 0));
  369. cvtil(make(i, 32767, 123, 456));
  370. cvtil(make(i, 32767, 0, 0));
  371. cvtil(make(i, 16382, -1, -1));
  372. cvtil(make(i, 16383, -1, -1));
  373. cvtil(make(i, 16384, 0x7fffffffffff, -1));
  374. cvtil(make(i, 16384, 0x800000000000, 0));
  375. for (j = 0; j < 68; j++)
  376. cvtil(make(i, 16381 + j, 0xd4822c0a10ec, 0x1fe2f8b2669f5c9d));
  377. }
  378. cvtlf(copy_fi(0x00000000));
  379. cvtlf(copy_fi(0x456789ab));
  380. cvtlf(copy_fi(0x7f800000));
  381. cvtlf(copy_fi(0x7f923456));
  382. cvtlf(copy_fi(0x7fdbcdef));
  383. cvtlf(copy_fi(0x80000000));
  384. cvtlf(copy_fi(0xabcdef12));
  385. cvtlf(copy_fi(0xff800000));
  386. cvtlf(copy_fi(0xff923456));
  387. cvtlf(copy_fi(0xffdbcdef));
  388. cvtld(copy_di(0x0000000000000000));
  389. cvtld(copy_di(0x456789abcdef0123));
  390. cvtld(copy_di(0x7ff0000000000000));
  391. cvtld(copy_di(0x7ff123456789abcd));
  392. cvtld(copy_di(0x7ffabcdef1234567));
  393. cvtld(copy_di(0x8000000000000000));
  394. cvtld(copy_di(0xcdef123456789abc));
  395. cvtld(copy_di(0xfff0000000000000));
  396. cvtld(copy_di(0xfff123456789abcd));
  397. cvtld(copy_di(0xfffabcdef1234567));
  398. for (i = 0; i < 2; i++) { \
  399. cvtfl(make(i, 0, 0, 0));
  400. cvtfl(make(i, 16232, -1, -1));
  401. cvtfl(make(i, 16233, 0, 0));
  402. cvtfl(make(i, 16233, 0, 1));
  403. cvtfl(make(i, 16383, 0xab0ffd000000, 0));
  404. cvtfl(make(i, 16383, 0xab0ffd000001, 0));
  405. cvtfl(make(i, 16383, 0xab0ffeffffff, 0));
  406. cvtfl(make(i, 16383, 0xab0fff000000, 0));
  407. cvtfl(make(i, 16383, 0xab0fff000001, 0));
  408. cvtfl(make(i, 16510, 0xfffffeffffff, -1));
  409. cvtfl(make(i, 16510, 0xffffff000000, 0));
  410. cvtfl(make(i, 16511, 0, 0));
  411. cvtfl(make(i, 32767, 0, 0));
  412. cvtfl(make(i, 32767, 0, 1));
  413. cvtfl(make(i, 32767, 0x4cbe01ac5f40, 0x75cee3c6afbb00b5));
  414. cvtfl(make(i, 32767, 0x800000000000, 1));
  415. cvtfl(make(i, 32767, 0xa11caaaf6a52, 0x696033e871eab099));
  416. }
  417. for (i = 0; i < 2; i++) {
  418. cvtdl(make(i, 0, 0, 0));
  419. cvtdl(make(i, 15307, -1, -1));
  420. cvtdl(make(i, 15308, 0, 0));
  421. cvtdl(make(i, 15308, 0, 1));
  422. cvtdl(make(i, 16383, 0xabc123abc0ff, 0xe800000000000000));
  423. cvtdl(make(i, 16383, 0xabc123abc0ff, 0xe800000000000001));
  424. cvtdl(make(i, 16383, 0xabc123abc0ff, 0xf7ffffffffffffff));
  425. cvtdl(make(i, 16383, 0xabc123abc0ff, 0xf800000000000000));
  426. cvtdl(make(i, 16383, 0xabc123abc0ff, 0xf800000000000001));
  427. cvtdl(make(i, 17406, 0xffffffffffff, 0xf7ffffffffffffff));
  428. cvtdl(make(i, 17406, 0xffffffffffff, 0xf800000000000000));
  429. cvtdl(make(i, 17407, 0, 0));
  430. cvtdl(make(i, 32767, 0, 0));
  431. cvtdl(make(i, 32767, 0, 1));
  432. cvtdl(make(i, 32767, 0x4cbe01ac5f40, 0x75cee3c6afbb00b5));
  433. cvtdl(make(i, 32767, 0x800000000000, 1));
  434. cvtdl(make(i, 32767, 0xa11caaaf6a52, 0x696033e871eab099));
  435. }
  436. }
  437. void tests(void)
  438. {
  439. cmps();
  440. nanz();
  441. adds();
  442. muls();
  443. divs();
  444. cvts();
  445. }
  446. int main()
  447. {
  448. #ifdef __aarch64__
  449. tests();
  450. #else
  451. printf("This test program is intended for a little-endian architecture\n"
  452. "with an IEEE-standard 128-bit long double.\n");
  453. #endif
  454. return 0;
  455. }