1 /* Test x86-specific floating-point environment (bug 16068): SSE part.
2    Copyright (C) 2015-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 <stdint.h>
24 #include <stdio.h>
25 
26 static bool
have_sse2(void)27 have_sse2 (void)
28 {
29   unsigned int eax, ebx, ecx, edx;
30 
31   if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx))
32     return false;
33 
34   return (edx & bit_SSE2) != 0;
35 }
36 
37 static uint32_t
get_sse_mxcsr(void)38 get_sse_mxcsr (void)
39 {
40   uint32_t temp;
41   __asm__ __volatile__ ("stmxcsr %0" : "=m" (temp));
42   return temp;
43 }
44 
45 static void
set_sse_mxcsr(uint32_t val)46 set_sse_mxcsr (uint32_t val)
47 {
48   __asm__ __volatile__ ("ldmxcsr %0" : : "m" (val));
49 }
50 
51 static void
set_sse_mxcsr_bits(uint32_t mask,uint32_t bits)52 set_sse_mxcsr_bits (uint32_t mask, uint32_t bits)
53 {
54   uint32_t mxcsr = get_sse_mxcsr ();
55   mxcsr = (mxcsr & ~mask) | bits;
56   set_sse_mxcsr (mxcsr);
57 }
58 
59 static int
test_sse_mxcsr_bits(const char * test,uint32_t mask,uint32_t bits)60 test_sse_mxcsr_bits (const char *test, uint32_t mask, uint32_t bits)
61 {
62   uint32_t mxcsr = get_sse_mxcsr ();
63   printf ("Testing %s: mxcsr = %x\n", test, mxcsr);
64   if ((mxcsr & mask) == bits)
65     {
66       printf ("PASS: %s\n", test);
67       return 0;
68     }
69   else
70     {
71       printf ("FAIL: %s\n", test);
72       return 1;
73     }
74 }
75 
76 #define MXCSR_FZ 0x8000
77 #define MXCSR_DAZ 0x40
78 #define MXCSR_DE 0x2
79 #define MXCSR_DM 0x100
80 
81 static __attribute__ ((noinline)) int
sse_tests(void)82 sse_tests (void)
83 {
84   int result = 0;
85   fenv_t env1, env2;
86   /* Test FZ bit.  */
87   fegetenv (&env1);
88   set_sse_mxcsr_bits (MXCSR_FZ, MXCSR_FZ);
89   fegetenv (&env2);
90   fesetenv (&env1);
91   result |= test_sse_mxcsr_bits ("fesetenv FZ restoration",
92 				 MXCSR_FZ, 0);
93   set_sse_mxcsr_bits (MXCSR_FZ, 0);
94   fesetenv (&env2);
95   result |= test_sse_mxcsr_bits ("fesetenv FZ restoration 2",
96 				 MXCSR_FZ, MXCSR_FZ);
97   set_sse_mxcsr_bits (MXCSR_FZ, MXCSR_FZ);
98   fesetenv (FE_NOMASK_ENV);
99   result |= test_sse_mxcsr_bits ("fesetenv (FE_NOMASK_ENV) FZ restoration",
100 				 MXCSR_FZ, 0);
101   set_sse_mxcsr_bits (MXCSR_FZ, MXCSR_FZ);
102   fesetenv (FE_DFL_ENV);
103   result |= test_sse_mxcsr_bits ("fesetenv (FE_DFL_ENV) FZ restoration",
104 				 MXCSR_FZ, 0);
105   /* Test DAZ bit.  */
106   set_sse_mxcsr_bits (MXCSR_DAZ, MXCSR_DAZ);
107   fegetenv (&env2);
108   fesetenv (&env1);
109   result |= test_sse_mxcsr_bits ("fesetenv DAZ restoration",
110 				 MXCSR_DAZ, 0);
111   set_sse_mxcsr_bits (MXCSR_DAZ, 0);
112   fesetenv (&env2);
113   result |= test_sse_mxcsr_bits ("fesetenv DAZ restoration 2",
114 				 MXCSR_DAZ, MXCSR_DAZ);
115   set_sse_mxcsr_bits (MXCSR_DAZ, MXCSR_DAZ);
116   fesetenv (FE_NOMASK_ENV);
117   result |= test_sse_mxcsr_bits ("fesetenv (FE_NOMASK_ENV) DAZ restoration",
118 				 MXCSR_DAZ, 0);
119   set_sse_mxcsr_bits (MXCSR_DAZ, MXCSR_DAZ);
120   fesetenv (FE_DFL_ENV);
121   result |= test_sse_mxcsr_bits ("fesetenv (FE_DFL_ENV) DAZ restoration",
122 				 MXCSR_DAZ, 0);
123   /* Test DM bit.  */
124   set_sse_mxcsr_bits (MXCSR_DM, 0);
125   fegetenv (&env2);
126   fesetenv (&env1);
127   result |= test_sse_mxcsr_bits ("fesetenv DM restoration",
128 				 MXCSR_DM, MXCSR_DM);
129   set_sse_mxcsr_bits (MXCSR_DM, MXCSR_DM);
130   fesetenv (&env2);
131   result |= test_sse_mxcsr_bits ("fesetenv DM restoration 2",
132 				 MXCSR_DM, 0);
133   set_sse_mxcsr_bits (MXCSR_DM, 0);
134   /* Presume FE_NOMASK_ENV should leave the "denormal operand"
135      exception masked, as not a standard exception.  */
136   fesetenv (FE_NOMASK_ENV);
137   result |= test_sse_mxcsr_bits ("fesetenv (FE_NOMASK_ENV) DM restoration",
138 				 MXCSR_DM, MXCSR_DM);
139   set_sse_mxcsr_bits (MXCSR_DM, 0);
140   fesetenv (FE_DFL_ENV);
141   result |= test_sse_mxcsr_bits ("fesetenv (FE_DFL_ENV) DM restoration",
142 				 MXCSR_DM, MXCSR_DM);
143   /* Test DE bit.  */
144   set_sse_mxcsr_bits (MXCSR_DE, MXCSR_DE);
145   fegetenv (&env2);
146   fesetenv (&env1);
147   result |= test_sse_mxcsr_bits ("fesetenv DE restoration",
148 				 MXCSR_DE, 0);
149   set_sse_mxcsr_bits (MXCSR_DE, 0);
150   fesetenv (&env2);
151   result |= test_sse_mxcsr_bits ("fesetenv DE restoration 2",
152 				 MXCSR_DE, MXCSR_DE);
153   set_sse_mxcsr_bits (MXCSR_DE, MXCSR_DE);
154   fesetenv (FE_NOMASK_ENV);
155   result |= test_sse_mxcsr_bits ("fesetenv (FE_NOMASK_ENV) DE restoration",
156 				 MXCSR_DE, 0);
157   set_sse_mxcsr_bits (MXCSR_DE, MXCSR_DE);
158   fesetenv (FE_DFL_ENV);
159   result |= test_sse_mxcsr_bits ("fesetenv (FE_DFL_ENV) DE restoration",
160 				 MXCSR_DE, 0);
161   return result;
162 }
163 
164 static int
do_test(void)165 do_test (void)
166 {
167   if (!have_sse2 ())
168     {
169       puts ("CPU does not support SSE2, cannot test");
170       return 0;
171     }
172   return sse_tests ();
173 }
174 
175 #define TEST_FUNCTION do_test ()
176 #include <test-skeleton.c>
177