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
25static uint16_t
26get_x87_cw (void)
27{
28 fpu_control_t cw;
29 _FPU_GETCW (cw);
30 return cw;
31}
32
33static void
34set_x87_cw (uint16_t val)
35{
36 fpu_control_t cw = val;
37 _FPU_SETCW (cw);
38}
39
40static void
41set_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
48static int
49test_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
65static uint16_t
66get_x87_sw (void)
67{
68 uint16_t temp;
69 __asm__ __volatile__ ("fnstsw %0" : "=a" (temp));
70 return temp;
71}
72
73static void
74set_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
82static int
83test_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
101static int
102do_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

source code of glibc/sysdeps/x86/fpu/test-fenv-x87.c