1 /* Test x86-specific floating-point environment (bug 16068): x87 part.
2    Copyright (C) 2015-2022 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 #include <fenv.h>
20 #include <float.h>
21 #include <fpu_control.h>
22 #include <stdint.h>
23 #include <stdio.h>
24 
25 static uint16_t
get_x87_cw(void)26 get_x87_cw (void)
27 {
28   fpu_control_t cw;
29   _FPU_GETCW (cw);
30   return cw;
31 }
32 
33 static void
set_x87_cw(uint16_t val)34 set_x87_cw (uint16_t val)
35 {
36   fpu_control_t cw = val;
37   _FPU_SETCW (cw);
38 }
39 
40 static void
set_x87_cw_bits(uint16_t mask,uint16_t bits)41 set_x87_cw_bits (uint16_t mask, uint16_t bits)
42 {
43   uint16_t cw = get_x87_cw ();
44   cw = (cw & ~mask) | bits;
45   set_x87_cw (cw);
46 }
47 
48 static int
test_x87_cw_bits(const char * test,uint16_t mask,uint16_t bits)49 test_x87_cw_bits (const char *test, uint16_t mask, uint16_t bits)
50 {
51   uint16_t cw = get_x87_cw ();
52   printf ("Testing %s: cw = %x\n", test, cw);
53   if ((cw & mask) == bits)
54     {
55       printf ("PASS: %s\n", test);
56       return 0;
57     }
58   else
59     {
60       printf ("FAIL: %s\n", test);
61       return 1;
62     }
63 }
64 
65 static uint16_t
get_x87_sw(void)66 get_x87_sw (void)
67 {
68   uint16_t temp;
69   __asm__ __volatile__ ("fnstsw %0" : "=a" (temp));
70   return temp;
71 }
72 
73 static void
set_x87_sw_bits(uint16_t mask,uint16_t bits)74 set_x87_sw_bits (uint16_t mask, uint16_t bits)
75 {
76   fenv_t temp;
77   __asm__ __volatile__ ("fnstenv %0" : "=m" (temp));
78   temp.__status_word = (temp.__status_word & ~mask) | bits;
79   __asm__ __volatile__ ("fldenv %0" : : "m" (temp));
80 }
81 
82 static int
test_x87_sw_bits(const char * test,uint16_t mask,uint16_t bits)83 test_x87_sw_bits (const char *test, uint16_t mask, uint16_t bits)
84 {
85   uint16_t sw = get_x87_sw ();
86   printf ("Testing %s: sw = %x\n", test, sw);
87   if ((sw & mask) == bits)
88     {
89       printf ("PASS: %s\n", test);
90       return 0;
91     }
92   else
93     {
94       printf ("FAIL: %s\n", test);
95       return 1;
96     }
97 }
98 
99 #define X87_CW_PREC_MASK _FPU_EXTENDED
100 
101 static int
do_test(void)102 do_test (void)
103 {
104   int result = 0;
105   fenv_t env1, env2;
106   /* Test precision mask.  */
107   fegetenv (&env1);
108   set_x87_cw_bits (X87_CW_PREC_MASK, _FPU_SINGLE);
109   fegetenv (&env2);
110   fesetenv (&env1);
111   result |= test_x87_cw_bits ("fesetenv precision restoration",
112 			      X87_CW_PREC_MASK, _FPU_EXTENDED);
113   set_x87_cw_bits (X87_CW_PREC_MASK, _FPU_EXTENDED);
114   fesetenv (&env2);
115   result |= test_x87_cw_bits ("fesetenv precision restoration 2",
116 			      X87_CW_PREC_MASK, _FPU_SINGLE);
117   set_x87_cw_bits (X87_CW_PREC_MASK, _FPU_DOUBLE);
118   fesetenv (FE_NOMASK_ENV);
119   result |= test_x87_cw_bits ("fesetenv (FE_NOMASK_ENV) precision restoration",
120 			      X87_CW_PREC_MASK, _FPU_EXTENDED);
121   set_x87_cw_bits (X87_CW_PREC_MASK, _FPU_SINGLE);
122   fesetenv (FE_DFL_ENV);
123   result |= test_x87_cw_bits ("fesetenv (FE_DFL_ENV) precision restoration",
124 			      X87_CW_PREC_MASK, _FPU_EXTENDED);
125   /* Test x87 denormal operand masking.  */
126   set_x87_cw_bits (_FPU_MASK_DM, 0);
127   fegetenv (&env2);
128   fesetenv (&env1);
129   result |= test_x87_cw_bits ("fesetenv denormal mask restoration",
130 			      _FPU_MASK_DM, _FPU_MASK_DM);
131   set_x87_cw_bits (_FPU_MASK_DM, _FPU_MASK_DM);
132   fesetenv (&env2);
133   result |= test_x87_cw_bits ("fesetenv denormal mask restoration 2",
134 			      _FPU_MASK_DM, 0);
135   set_x87_cw_bits (_FPU_MASK_DM, 0);
136   /* Presume FE_NOMASK_ENV should leave the "denormal operand"
137      exception masked, as not a standard exception.  */
138   fesetenv (FE_NOMASK_ENV);
139   result |= test_x87_cw_bits ("fesetenv (FE_NOMASK_ENV) denormal mask "
140 			      "restoration",
141 			      _FPU_MASK_DM, _FPU_MASK_DM);
142   set_x87_cw_bits (_FPU_MASK_DM, 0);
143   fesetenv (FE_DFL_ENV);
144   result |= test_x87_cw_bits ("fesetenv (FE_DFL_ENV) denormal mask "
145 			      "restoration",
146 			      _FPU_MASK_DM, _FPU_MASK_DM);
147   /* Test x87 denormal operand exception.  */
148   set_x87_sw_bits (__FE_DENORM, __FE_DENORM);
149   fegetenv (&env2);
150   fesetenv (&env1);
151   result |= test_x87_sw_bits ("fesetenv denormal exception restoration",
152 			      __FE_DENORM, 0);
153   set_x87_sw_bits (__FE_DENORM, 0);
154   fesetenv (&env2);
155   result |= test_x87_sw_bits ("fesetenv denormal exception restoration 2",
156 			      __FE_DENORM, __FE_DENORM);
157   set_x87_sw_bits (__FE_DENORM, __FE_DENORM);
158   fesetenv (FE_NOMASK_ENV);
159   result |= test_x87_sw_bits ("fesetenv (FE_NOMASK_ENV) exception restoration",
160 			      __FE_DENORM, 0);
161   set_x87_sw_bits (__FE_DENORM, __FE_DENORM);
162   fesetenv (FE_DFL_ENV);
163   result |= test_x87_sw_bits ("fesetenv (FE_DFL_ENV) exception restoration",
164 			      __FE_DENORM, 0);
165   return result;
166 }
167 
168 #define TEST_FUNCTION do_test ()
169 #include <test-skeleton.c>
170