10d48b436SJoseph Myers /* Test fscale instruction. */ 20d48b436SJoseph Myers 30d48b436SJoseph Myers #include <stdint.h> 40d48b436SJoseph Myers #include <stdio.h> 50d48b436SJoseph Myers 60d48b436SJoseph Myers union u { 70d48b436SJoseph Myers struct { uint64_t sig; uint16_t sign_exp; } s; 80d48b436SJoseph Myers long double ld; 90d48b436SJoseph Myers }; 100d48b436SJoseph Myers 11*c535d687SJoseph Myers volatile long double ld_third = 1.0L / 3.0L; 12*c535d687SJoseph Myers volatile long double ld_four_thirds = 4.0L / 3.0L; 13b40eec96SJoseph Myers volatile union u ld_invalid_1 = { .s = { 1, 1234 } }; 14b40eec96SJoseph Myers volatile union u ld_invalid_2 = { .s = { 0, 1234 } }; 15b40eec96SJoseph Myers volatile union u ld_invalid_3 = { .s = { 0, 0x7fff } }; 16b40eec96SJoseph Myers volatile union u ld_invalid_4 = { .s = { (UINT64_C(1) << 63) - 1, 0x7fff } }; 17b40eec96SJoseph Myers 180d48b436SJoseph Myers volatile long double ld_res; 190d48b436SJoseph Myers 200d48b436SJoseph Myers int isnan_ld(long double x) 210d48b436SJoseph Myers { 220d48b436SJoseph Myers union u tmp = { .ld = x }; 230d48b436SJoseph Myers return ((tmp.s.sign_exp & 0x7fff) == 0x7fff && 240d48b436SJoseph Myers (tmp.s.sig >> 63) != 0 && 250d48b436SJoseph Myers (tmp.s.sig << 1) != 0); 260d48b436SJoseph Myers } 270d48b436SJoseph Myers 280d48b436SJoseph Myers int issignaling_ld(long double x) 290d48b436SJoseph Myers { 300d48b436SJoseph Myers union u tmp = { .ld = x }; 310d48b436SJoseph Myers return isnan_ld(x) && (tmp.s.sig & UINT64_C(0x4000000000000000)) == 0; 320d48b436SJoseph Myers } 330d48b436SJoseph Myers 340d48b436SJoseph Myers int main(void) 350d48b436SJoseph Myers { 36c1c5fb8fSJoseph Myers short cw; 370d48b436SJoseph Myers int ret = 0; 380d48b436SJoseph Myers __asm__ volatile ("fscale" : "=t" (ld_res) : 390d48b436SJoseph Myers "0" (2.5L), "u" (__builtin_nansl(""))); 400d48b436SJoseph Myers if (!isnan_ld(ld_res) || issignaling_ld(ld_res)) { 410d48b436SJoseph Myers printf("FAIL: fscale snan\n"); 420d48b436SJoseph Myers ret = 1; 430d48b436SJoseph Myers } 44b40eec96SJoseph Myers __asm__ volatile ("fscale" : "=t" (ld_res) : 45b40eec96SJoseph Myers "0" (2.5L), "u" (ld_invalid_1.ld)); 46b40eec96SJoseph Myers if (!isnan_ld(ld_res) || issignaling_ld(ld_res)) { 47b40eec96SJoseph Myers printf("FAIL: fscale invalid 1\n"); 48b40eec96SJoseph Myers ret = 1; 49b40eec96SJoseph Myers } 50b40eec96SJoseph Myers __asm__ volatile ("fscale" : "=t" (ld_res) : 51b40eec96SJoseph Myers "0" (2.5L), "u" (ld_invalid_2.ld)); 52b40eec96SJoseph Myers if (!isnan_ld(ld_res) || issignaling_ld(ld_res)) { 53b40eec96SJoseph Myers printf("FAIL: fscale invalid 2\n"); 54b40eec96SJoseph Myers ret = 1; 55b40eec96SJoseph Myers } 56b40eec96SJoseph Myers __asm__ volatile ("fscale" : "=t" (ld_res) : 57b40eec96SJoseph Myers "0" (2.5L), "u" (ld_invalid_3.ld)); 58b40eec96SJoseph Myers if (!isnan_ld(ld_res) || issignaling_ld(ld_res)) { 59b40eec96SJoseph Myers printf("FAIL: fscale invalid 3\n"); 60b40eec96SJoseph Myers ret = 1; 61b40eec96SJoseph Myers } 62b40eec96SJoseph Myers __asm__ volatile ("fscale" : "=t" (ld_res) : 63b40eec96SJoseph Myers "0" (2.5L), "u" (ld_invalid_4.ld)); 64b40eec96SJoseph Myers if (!isnan_ld(ld_res) || issignaling_ld(ld_res)) { 65b40eec96SJoseph Myers printf("FAIL: fscale invalid 4\n"); 66b40eec96SJoseph Myers ret = 1; 67b40eec96SJoseph Myers } 68c1c5fb8fSJoseph Myers __asm__ volatile ("fscale" : "=t" (ld_res) : 69c1c5fb8fSJoseph Myers "0" (0.0L), "u" (__builtin_infl())); 70c1c5fb8fSJoseph Myers if (!isnan_ld(ld_res) || issignaling_ld(ld_res)) { 71c1c5fb8fSJoseph Myers printf("FAIL: fscale 0 up inf\n"); 72c1c5fb8fSJoseph Myers ret = 1; 73c1c5fb8fSJoseph Myers } 74c1c5fb8fSJoseph Myers __asm__ volatile ("fscale" : "=t" (ld_res) : 75c1c5fb8fSJoseph Myers "0" (__builtin_infl()), "u" (-__builtin_infl())); 76c1c5fb8fSJoseph Myers if (!isnan_ld(ld_res) || issignaling_ld(ld_res)) { 77c1c5fb8fSJoseph Myers printf("FAIL: fscale inf down inf\n"); 78c1c5fb8fSJoseph Myers ret = 1; 79c1c5fb8fSJoseph Myers } 80c1c5fb8fSJoseph Myers /* Set round-downward. */ 81c1c5fb8fSJoseph Myers __asm__ volatile ("fnstcw %0" : "=m" (cw)); 82c1c5fb8fSJoseph Myers cw = (cw & ~0xc00) | 0x400; 83c1c5fb8fSJoseph Myers __asm__ volatile ("fldcw %0" : : "m" (cw)); 84c1c5fb8fSJoseph Myers __asm__ volatile ("fscale" : "=t" (ld_res) : 85c1c5fb8fSJoseph Myers "0" (1.0L), "u" (__builtin_infl())); 86c1c5fb8fSJoseph Myers if (ld_res != __builtin_infl()) { 87c1c5fb8fSJoseph Myers printf("FAIL: fscale finite up inf\n"); 88c1c5fb8fSJoseph Myers ret = 1; 89c1c5fb8fSJoseph Myers } 90c1c5fb8fSJoseph Myers __asm__ volatile ("fscale" : "=t" (ld_res) : 91c1c5fb8fSJoseph Myers "0" (-1.0L), "u" (-__builtin_infl())); 92c1c5fb8fSJoseph Myers if (ld_res != -0.0L || __builtin_copysignl(1.0L, ld_res) != -1.0L) { 93c1c5fb8fSJoseph Myers printf("FAIL: fscale finite down inf\n"); 94c1c5fb8fSJoseph Myers ret = 1; 95c1c5fb8fSJoseph Myers } 96*c535d687SJoseph Myers /* Set round-to-nearest with single-precision rounding. */ 97*c535d687SJoseph Myers cw = cw & ~0xf00; 98*c535d687SJoseph Myers __asm__ volatile ("fldcw %0" : : "m" (cw)); 99*c535d687SJoseph Myers __asm__ volatile ("fscale" : "=t" (ld_res) : 100*c535d687SJoseph Myers "0" (ld_third), "u" (2.0L)); 101*c535d687SJoseph Myers cw = cw | 0x300; 102*c535d687SJoseph Myers __asm__ volatile ("fldcw %0" : : "m" (cw)); 103*c535d687SJoseph Myers if (ld_res != ld_four_thirds) { 104*c535d687SJoseph Myers printf("FAIL: fscale single-precision\n"); 105*c535d687SJoseph Myers ret = 1; 106*c535d687SJoseph Myers } 1070d48b436SJoseph Myers return ret; 1080d48b436SJoseph Myers } 109