qemu/tests/tcg/i386/test-i386-fscale.c
<<
>>
Prefs
   1/* Test fscale instruction.  */
   2
   3#include <stdint.h>
   4#include <stdio.h>
   5
   6union u {
   7    struct { uint64_t sig; uint16_t sign_exp; } s;
   8    long double ld;
   9};
  10
  11volatile long double ld_third = 1.0L / 3.0L;
  12volatile long double ld_four_thirds = 4.0L / 3.0L;
  13volatile union u ld_invalid_1 = { .s = { 1, 1234 } };
  14volatile union u ld_invalid_2 = { .s = { 0, 1234 } };
  15volatile union u ld_invalid_3 = { .s = { 0, 0x7fff } };
  16volatile union u ld_invalid_4 = { .s = { (UINT64_C(1) << 63) - 1, 0x7fff } };
  17
  18volatile long double ld_res;
  19
  20int 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
  28int 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
  34int 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