1 /* Test floating-point environment includes SSE state (bug 16064).
2    Copyright (C) 2014-2021 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 <cpuid.h>
20 #include <fenv.h>
21 #include <float.h>
22 #include <stdbool.h>
23 #include <stdio.h>
24 
25 static bool
have_sse2(void)26 have_sse2 (void)
27 {
28   unsigned int eax, ebx, ecx, edx;
29 
30   if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx))
31     return false;
32 
33   return (edx & bit_SSE2) != 0;
34 }
35 
36 static __attribute__ ((noinline)) int
sse_tests(void)37 sse_tests (void)
38 {
39   int ret = 0;
40   fenv_t base_env;
41   if (fegetenv (&base_env) != 0)
42     {
43       puts ("fegetenv (&base_env) failed");
44       return 1;
45     }
46   if (fesetround (FE_UPWARD) != 0)
47     {
48       puts ("fesetround (FE_UPWARD) failed");
49       return 1;
50     }
51   if (fesetenv (&base_env) != 0)
52     {
53       puts ("fesetenv (&base_env) failed");
54       return 1;
55     }
56   volatile float a = 1.0f, b = FLT_MIN, c;
57   c = a + b;
58   if (c != 1.0f)
59     {
60       puts ("fesetenv did not restore rounding mode");
61       ret = 1;
62     }
63   if (fesetround (FE_DOWNWARD) != 0)
64     {
65       puts ("fesetround (FE_DOWNWARD) failed");
66       return 1;
67     }
68   if (feupdateenv (&base_env) != 0)
69     {
70       puts ("feupdateenv (&base_env) failed");
71       return 1;
72     }
73   volatile float d = -FLT_MIN, e;
74   e = a + d;
75   if (e != 1.0f)
76     {
77       puts ("feupdateenv did not restore rounding mode");
78       ret = 1;
79     }
80   if (fesetround (FE_UPWARD) != 0)
81     {
82       puts ("fesetround (FE_UPWARD) failed");
83       return 1;
84     }
85   fenv_t upward_env;
86   if (feholdexcept (&upward_env) != 0)
87     {
88       puts ("feholdexcept (&upward_env) failed");
89       return 1;
90     }
91   if (fesetround (FE_DOWNWARD) != 0)
92     {
93       puts ("fesetround (FE_DOWNWARD) failed");
94       return 1;
95     }
96   if (fesetenv (&upward_env) != 0)
97     {
98       puts ("fesetenv (&upward_env) failed");
99       return 1;
100     }
101   e = a + d;
102   if (e != 1.0f)
103     {
104       puts ("fesetenv did not restore rounding mode from feholdexcept");
105       ret = 1;
106     }
107   if (fesetround (FE_UPWARD) != 0)
108     {
109       puts ("fesetround (FE_UPWARD) failed");
110       return 1;
111     }
112   if (fesetenv (FE_DFL_ENV) != 0)
113     {
114       puts ("fesetenv (FE_DFL_ENV) failed");
115       return 1;
116     }
117   c = a + b;
118   if (c != 1.0f)
119     {
120       puts ("fesetenv (FE_DFL_ENV) did not restore rounding mode");
121       ret = 1;
122     }
123   return ret;
124 }
125 
126 static int
do_test(void)127 do_test (void)
128 {
129   if (!have_sse2 ())
130     {
131       puts ("CPU does not support SSE2, cannot test");
132       return 0;
133     }
134   return sse_tests ();
135 }
136 
137 #define TEST_FUNCTION do_test ()
138 #include <test-skeleton.c>
139