Home | History | Annotate | Download | only in x86
      1 
      2 /* Tests out of range handling for FSIN, FCOS, FSINCOS and FPTAN.  Be
      3    careful with the inline assembly -- this program is compiled as
      4    both a 32-bit and 64-bit test. */
      5 
      6 #include <stdio.h>
      7 #include <string.h>
      8 #include <assert.h>
      9 
     10 typedef  unsigned short int      UShort;
     11 typedef  unsigned int            UInt;
     12 typedef  double                  Double;
     13 typedef  unsigned long long int  ULong;
     14 
     15 typedef  struct { Double arg; Double st0; Double st1; UShort fpusw; }  Res;
     16 
     17 #define SHIFT_C3   14
     18 #define SHIFT_C2   10
     19 #define SHIFT_C1   9
     20 #define SHIFT_C0   8
     21 
     22 
     23 #define my_offsetof(type,memb) ((int)(unsigned long int)&((type*)0)->memb)
     24 
     25 void do_fsin ( /*OUT*/Res* r, double d )
     26 {
     27    assert(my_offsetof(Res,arg) == 0);
     28    assert(my_offsetof(Res,st0) == 8);
     29    assert(my_offsetof(Res,st1) == 16);
     30    assert(my_offsetof(Res,fpusw) == 24);
     31    memset(r, 0, sizeof(*r));
     32    r->arg = d;
     33    __asm__ __volatile__(
     34      "finit"              "\n\t"
     35      "fldpi"              "\n\t"
     36      "fldl 0(%0)"         "\n\t" // .arg
     37      "fsin"               "\n\t"
     38      "fstsw %%ax"         "\n\t"
     39      "fstpl 8(%0)"        "\n\t" // .st0
     40      "fstpl 16(%0)"       "\n\t" // .st1
     41      "movw %%ax, 24(%0)"  "\n\t" // .fpusw
     42      "finit"              "\n"
     43      : : "r"(r) : "eax","cc","memory"
     44    );
     45 }
     46 
     47 void do_fcos ( /*OUT*/Res* r, double d )
     48 {
     49    assert(my_offsetof(Res,arg) == 0);
     50    assert(my_offsetof(Res,st0) == 8);
     51    assert(my_offsetof(Res,st1) == 16);
     52    assert(my_offsetof(Res,fpusw) == 24);
     53    memset(r, 0, sizeof(*r));
     54    r->arg = d;
     55    __asm__ __volatile__(
     56      "finit"              "\n\t"
     57      "fldpi"              "\n\t"
     58      "fldl 0(%0)"         "\n\t" // .arg
     59      "fcos"               "\n\t"
     60      "fstsw %%ax"         "\n\t"
     61      "fstpl 8(%0)"        "\n\t" // .st0
     62      "fstpl 16(%0)"       "\n\t" // .st1
     63      "movw %%ax, 24(%0)"  "\n\t" // .fpusw
     64      "finit"              "\n"
     65      : : "r"(r) : "eax","cc","memory"
     66    );
     67 }
     68 
     69 void do_fsincos ( /*OUT*/Res* r, double d )
     70 {
     71    assert(my_offsetof(Res,arg) == 0);
     72    assert(my_offsetof(Res,st0) == 8);
     73    assert(my_offsetof(Res,st1) == 16);
     74    assert(my_offsetof(Res,fpusw) == 24);
     75    memset(r, 0, sizeof(*r));
     76    r->arg = d;
     77    __asm__ __volatile__(
     78      "finit"              "\n\t"
     79      "fldpi"              "\n\t"
     80      "fldl 0(%0)"         "\n\t" // .arg
     81      "fsincos"            "\n\t"
     82      "fstsw %%ax"         "\n\t"
     83      "fstpl 8(%0)"        "\n\t" // .st0
     84      "fstpl 16(%0)"       "\n\t" // .st1
     85      "movw %%ax, 24(%0)"  "\n\t" // .fpusw
     86      "finit"              "\n"
     87      : : "r"(r) : "eax","cc","memory"
     88    );
     89 }
     90 
     91 void do_fptan ( /*OUT*/Res* r, double d )
     92 {
     93    assert(my_offsetof(Res,arg) == 0);
     94    assert(my_offsetof(Res,st0) == 8);
     95    assert(my_offsetof(Res,st1) == 16);
     96    assert(my_offsetof(Res,fpusw) == 24);
     97    memset(r, 0, sizeof(*r));
     98    r->arg = d;
     99    __asm__ __volatile__(
    100      "finit"              "\n\t"
    101      "fldpi"              "\n\t"
    102      "fldl 0(%0)"         "\n\t" // .arg
    103      "fptan"              "\n\t"
    104      "fstsw %%ax"         "\n\t"
    105      "fstpl 8(%0)"        "\n\t" // .st0
    106      "fstpl 16(%0)"       "\n\t" // .st1
    107      "movw %%ax, 24(%0)"  "\n\t" // .fpusw
    108      "finit"              "\n"
    109      : : "r"(r) : "eax","cc","memory"
    110    );
    111 }
    112 
    113 
    114 void try ( char* name, void(*fn)(Res*,double), double d )
    115 {
    116    Res r;
    117    fn(&r, d);
    118    // Mask out all except C2 (range)
    119    r.fpusw &= (1 << SHIFT_C2);
    120    printf("%s  %16e --> %16e %16e %04x\n",
    121           name, r.arg, r.st0, r.st1, (UInt)r.fpusw);
    122 }
    123 
    124 int main ( void )
    125 {
    126    Double limit = 9223372036854775808.0; // 2^63
    127 
    128    char* names[4] = { "fsin   ", "fcos   ", "fsincos", "fptan  " };
    129    void(*fns[4])(Res*,double) = { do_fsin, do_fcos, do_fsincos, do_fptan };
    130 
    131    int i;
    132    for (i = 0; i < 4; i++) {
    133       char* name = names[i];
    134       void (*fn)(Res*,double) = fns[i];
    135 
    136       try( name, fn,   0.0   );
    137       try( name, fn,   0.123 );
    138       try( name, fn,  -0.456 );
    139       try( name, fn,  37.0   );
    140       try( name, fn, -53.0   );
    141       printf("\n");
    142 
    143       try( name, fn, limit * 0.900000 );
    144       try( name, fn, limit * 0.999999 );
    145       try( name, fn, limit * 1.000000 );
    146       try( name, fn, limit * 1.000001 );
    147       try( name, fn, limit * 1.100000 );
    148       printf("\n");
    149 
    150       try( name, fn, -limit * 0.900000 );
    151       try( name, fn, -limit * 0.999999 );
    152       try( name, fn, -limit * 1.000000 );
    153       try( name, fn, -limit * 1.000001 );
    154       try( name, fn, -limit * 1.100000 );
    155       printf("\n");
    156    }
    157 
    158    return 0;
    159 }
    160