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