| 1 | /* Test fscale instruction. */ |
| 2 | |
| 3 | #include <stdint.h> |
| 4 | #include <stdio.h> |
| 5 | |
| 6 | union u { |
| 7 | struct { uint64_t sig; uint16_t sign_exp; } s; |
| 8 | long double ld; |
| 9 | }; |
| 10 | |
| 11 | volatile long double ld_third = 1.0L / 3.0L; |
| 12 | volatile long double ld_four_thirds = 4.0L / 3.0L; |
| 13 | volatile union u ld_invalid_1 = { .s = { 1, 1234 } }; |
| 14 | volatile union u ld_invalid_2 = { .s = { 0, 1234 } }; |
| 15 | volatile union u ld_invalid_3 = { .s = { 0, 0x7fff } }; |
| 16 | volatile union u ld_invalid_4 = { .s = { (UINT64_C(1) << 63) - 1, 0x7fff } }; |
| 17 | |
| 18 | volatile long double ld_res; |
| 19 | |
| 20 | int isnan_ld(long double x) |
| 21 | { |
| 22 | union u tmp = { .ld = x }; |
| 23 | return ((tmp.s.sign_exp & 0x7fff) == 0x7fff && |
| 24 | (tmp.s.sig >> 63) != 0 && |
| 25 | (tmp.s.sig << 1) != 0); |
| 26 | } |
| 27 | |
| 28 | int issignaling_ld(long double x) |
| 29 | { |
| 30 | union u tmp = { .ld = x }; |
| 31 | return isnan_ld(x) && (tmp.s.sig & UINT64_C(0x4000000000000000)) == 0; |
| 32 | } |
| 33 | |
| 34 | int main(void) |
| 35 | { |
| 36 | short cw; |
| 37 | int ret = 0; |
| 38 | __asm__ volatile ("fscale" : "=t" (ld_res) : |
| 39 | "0" (2.5L), "u" (__builtin_nansl(""))); |
| 40 | if (!isnan_ld(ld_res) || issignaling_ld(ld_res)) { |
| 41 | printf("FAIL: fscale snan\n"); |
| 42 | ret = 1; |
| 43 | } |
| 44 | __asm__ volatile ("fscale" : "=t" (ld_res) : |
| 45 | "0" (2.5L), "u" (ld_invalid_1.ld)); |
| 46 | if (!isnan_ld(ld_res) || issignaling_ld(ld_res)) { |
| 47 | printf("FAIL: fscale invalid 1\n"); |
| 48 | ret = 1; |
| 49 | } |
| 50 | __asm__ volatile ("fscale" : "=t" (ld_res) : |
| 51 | "0" (2.5L), "u" (ld_invalid_2.ld)); |
| 52 | if (!isnan_ld(ld_res) || issignaling_ld(ld_res)) { |
| 53 | printf("FAIL: fscale invalid 2\n"); |
| 54 | ret = 1; |
| 55 | } |
| 56 | __asm__ volatile ("fscale" : "=t" (ld_res) : |
| 57 | "0" (2.5L), "u" (ld_invalid_3.ld)); |
| 58 | if (!isnan_ld(ld_res) || issignaling_ld(ld_res)) { |
| 59 | printf("FAIL: fscale invalid 3\n"); |
| 60 | ret = 1; |
| 61 | } |
| 62 | __asm__ volatile ("fscale" : "=t" (ld_res) : |
| 63 | "0" (2.5L), "u" (ld_invalid_4.ld)); |
| 64 | if (!isnan_ld(ld_res) || issignaling_ld(ld_res)) { |
| 65 | printf("FAIL: fscale invalid 4\n"); |
| 66 | ret = 1; |
| 67 | } |
| 68 | __asm__ volatile ("fscale" : "=t" (ld_res) : |
| 69 | "0" (0.0L), "u" (__builtin_infl())); |
| 70 | if (!isnan_ld(ld_res) || issignaling_ld(ld_res)) { |
| 71 | printf("FAIL: fscale 0 up inf\n"); |
| 72 | ret = 1; |
| 73 | } |
| 74 | __asm__ volatile ("fscale" : "=t" (ld_res) : |
| 75 | "0" (__builtin_infl()), "u" (-__builtin_infl())); |
| 76 | if (!isnan_ld(ld_res) || issignaling_ld(ld_res)) { |
| 77 | printf("FAIL: fscale inf down inf\n"); |
| 78 | ret = 1; |
| 79 | } |
| 80 | /* Set round-downward. */ |
| 81 | __asm__ volatile ("fnstcw %0" : "=m" (cw)); |
| 82 | cw = (cw & ~0xc00) | 0x400; |
| 83 | __asm__ volatile ("fldcw %0" : : "m" (cw)); |
| 84 | __asm__ volatile ("fscale" : "=t" (ld_res) : |
| 85 | "0" (1.0L), "u" (__builtin_infl())); |
| 86 | if (ld_res != __builtin_infl()) { |
| 87 | printf("FAIL: fscale finite up inf\n"); |
| 88 | ret = 1; |
| 89 | } |
| 90 | __asm__ volatile ("fscale" : "=t" (ld_res) : |
| 91 | "0" (-1.0L), "u" (-__builtin_infl())); |
| 92 | if (ld_res != -0.0L || __builtin_copysignl(1.0L, ld_res) != -1.0L) { |
| 93 | printf("FAIL: fscale finite down inf\n"); |
| 94 | ret = 1; |
| 95 | } |
| 96 | /* Set round-to-nearest with single-precision rounding. */ |
| 97 | cw = cw & ~0xf00; |
| 98 | __asm__ volatile ("fldcw %0" : : "m" (cw)); |
| 99 | __asm__ volatile ("fscale" : "=t" (ld_res) : |
| 100 | "0" (ld_third), "u" (2.0L)); |
| 101 | cw = cw | 0x300; |
| 102 | __asm__ volatile ("fldcw %0" : : "m" (cw)); |
| 103 | if (ld_res != ld_four_thirds) { |
| 104 | printf("FAIL: fscale single-precision\n"); |
| 105 | ret = 1; |
| 106 | } |
| 107 | return ret; |
| 108 | } |