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 |
26 | get_x87_cw (void) |
27 | { |
28 | fpu_control_t cw; |
29 | _FPU_GETCW (cw); |
30 | return cw; |
31 | } |
32 | |
33 | static void |
34 | set_x87_cw (uint16_t val) |
35 | { |
36 | fpu_control_t cw = val; |
37 | _FPU_SETCW (cw); |
38 | } |
39 | |
40 | static void |
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 |
49 | test_x87_cw_bits (const char *test, uint16_t mask, uint16_t bits) |
50 | { |
51 | uint16_t cw = get_x87_cw (); |
52 | printf (format: "Testing %s: cw = %x\n" , test, cw); |
53 | if ((cw & mask) == bits) |
54 | { |
55 | printf (format: "PASS: %s\n" , test); |
56 | return 0; |
57 | } |
58 | else |
59 | { |
60 | printf (format: "FAIL: %s\n" , test); |
61 | return 1; |
62 | } |
63 | } |
64 | |
65 | static uint16_t |
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 |
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 |
83 | test_x87_sw_bits (const char *test, uint16_t mask, uint16_t bits) |
84 | { |
85 | uint16_t sw = get_x87_sw (); |
86 | printf (format: "Testing %s: sw = %x\n" , test, sw); |
87 | if ((sw & mask) == bits) |
88 | { |
89 | printf (format: "PASS: %s\n" , test); |
90 | return 0; |
91 | } |
92 | else |
93 | { |
94 | printf (format: "FAIL: %s\n" , test); |
95 | return 1; |
96 | } |
97 | } |
98 | |
99 | #define X87_CW_PREC_MASK _FPU_EXTENDED |
100 | |
101 | static int |
102 | do_test (void) |
103 | { |
104 | int result = 0; |
105 | fenv_t env1, env2; |
106 | /* Test precision mask. */ |
107 | fegetenv (envp: &env1); |
108 | set_x87_cw_bits (X87_CW_PREC_MASK, _FPU_SINGLE); |
109 | fegetenv (envp: &env2); |
110 | fesetenv (envp: &env1); |
111 | result |= test_x87_cw_bits (test: "fesetenv precision restoration" , |
112 | X87_CW_PREC_MASK, _FPU_EXTENDED); |
113 | set_x87_cw_bits (X87_CW_PREC_MASK, _FPU_EXTENDED); |
114 | fesetenv (envp: &env2); |
115 | result |= test_x87_cw_bits (test: "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 (test: "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 (test: "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, bits: 0); |
127 | fegetenv (envp: &env2); |
128 | fesetenv (envp: &env1); |
129 | result |= test_x87_cw_bits (test: "fesetenv denormal mask restoration" , |
130 | _FPU_MASK_DM, _FPU_MASK_DM); |
131 | set_x87_cw_bits (_FPU_MASK_DM, _FPU_MASK_DM); |
132 | fesetenv (envp: &env2); |
133 | result |= test_x87_cw_bits (test: "fesetenv denormal mask restoration 2" , |
134 | _FPU_MASK_DM, bits: 0); |
135 | set_x87_cw_bits (_FPU_MASK_DM, bits: 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 (test: "fesetenv (FE_NOMASK_ENV) denormal mask " |
140 | "restoration" , |
141 | _FPU_MASK_DM, _FPU_MASK_DM); |
142 | set_x87_cw_bits (_FPU_MASK_DM, bits: 0); |
143 | fesetenv (FE_DFL_ENV); |
144 | result |= test_x87_cw_bits (test: "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 (mask: __FE_DENORM, bits: __FE_DENORM); |
149 | fegetenv (envp: &env2); |
150 | fesetenv (envp: &env1); |
151 | result |= test_x87_sw_bits (test: "fesetenv denormal exception restoration" , |
152 | mask: __FE_DENORM, bits: 0); |
153 | set_x87_sw_bits (mask: __FE_DENORM, bits: 0); |
154 | fesetenv (envp: &env2); |
155 | result |= test_x87_sw_bits (test: "fesetenv denormal exception restoration 2" , |
156 | mask: __FE_DENORM, bits: __FE_DENORM); |
157 | set_x87_sw_bits (mask: __FE_DENORM, bits: __FE_DENORM); |
158 | fesetenv (FE_NOMASK_ENV); |
159 | result |= test_x87_sw_bits (test: "fesetenv (FE_NOMASK_ENV) exception restoration" , |
160 | mask: __FE_DENORM, bits: 0); |
161 | set_x87_sw_bits (mask: __FE_DENORM, bits: __FE_DENORM); |
162 | fesetenv (FE_DFL_ENV); |
163 | result |= test_x87_sw_bits (test: "fesetenv (FE_DFL_ENV) exception restoration" , |
164 | mask: __FE_DENORM, bits: 0); |
165 | return result; |
166 | } |
167 | |
168 | #define TEST_FUNCTION do_test () |
169 | #include <test-skeleton.c> |
170 | |