Elliott Hughes | a0664b9 | 2017-04-18 17:46:52 -0700 | [diff] [blame^] | 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 | } |