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 } 109