xref: /aosp_15_r20/bionic/tests/fenv_test.cpp (revision 8d67ca893c1523eb926b9080dbe4e2ffd2a27ba1)
1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <gtest/gtest.h>
18 
19 #include "DoNotOptimize.h"
20 #include "utils.h"
21 
22 #include <fenv.h>
23 #include <stdint.h>
24 #include <sys/cdefs.h>
25 
TestRounding(float expectation1,float expectation2)26 static void TestRounding(float expectation1, float expectation2) {
27   // Volatile to prevent compile-time evaluation.
28   volatile float f = 1.968750f;
29   volatile float m = 0x1.0p23f;
30   float x;
31   DoNotOptimize(x = f + m);
32   ASSERT_FLOAT_EQ(expectation1, x);
33   DoNotOptimize(x = x - m);
34   ASSERT_EQ(expectation2, x);
35 }
36 
DivideByZero()37 static void DivideByZero() {
38   // Volatile to prevent compile-time evaluation.
39   volatile float zero = 0.0f;
40   DoNotOptimize(123.0f / zero);
41 }
42 
TEST(fenv,fesetround_fegetround_FE_TONEAREST)43 TEST(fenv, fesetround_fegetround_FE_TONEAREST) {
44   fesetround(FE_TONEAREST);
45   ASSERT_EQ(FE_TONEAREST, fegetround());
46   TestRounding(8388610.0f, 2.0f);
47 }
48 
TEST(fenv,fesetround_fegetround_FE_TOWARDZERO)49 TEST(fenv, fesetround_fegetround_FE_TOWARDZERO) {
50   fesetround(FE_TOWARDZERO);
51   ASSERT_EQ(FE_TOWARDZERO, fegetround());
52   TestRounding(8388609.0f, 1.0f);
53 }
54 
TEST(fenv,fesetround_fegetround_FE_UPWARD)55 TEST(fenv, fesetround_fegetround_FE_UPWARD) {
56   fesetround(FE_UPWARD);
57   ASSERT_EQ(FE_UPWARD, fegetround());
58   TestRounding(8388610.0f, 2.0f);
59 }
60 
TEST(fenv,fesetround_fegetround_FE_DOWNWARD)61 TEST(fenv, fesetround_fegetround_FE_DOWNWARD) {
62   fesetround(FE_DOWNWARD);
63   ASSERT_EQ(FE_DOWNWARD, fegetround());
64   TestRounding(8388609.0f, 1.0f);
65 }
66 
TEST(fenv,feclearexcept_fetestexcept)67 TEST(fenv, feclearexcept_fetestexcept) {
68   // Clearing clears.
69   feclearexcept(FE_ALL_EXCEPT);
70   ASSERT_EQ(0, fetestexcept(FE_ALL_EXCEPT));
71 
72   // Dividing by zero sets FE_DIVBYZERO.
73   DivideByZero();
74   int raised = fetestexcept(FE_DIVBYZERO | FE_OVERFLOW);
75   ASSERT_TRUE((raised & FE_OVERFLOW) == 0);
76   ASSERT_TRUE((raised & FE_DIVBYZERO) != 0);
77 
78   // Clearing an unset bit is a no-op.
79   feclearexcept(FE_OVERFLOW);
80   ASSERT_TRUE((raised & FE_OVERFLOW) == 0);
81   ASSERT_TRUE((raised & FE_DIVBYZERO) != 0);
82 
83   // Clearing a set bit works.
84   feclearexcept(FE_DIVBYZERO);
85   ASSERT_EQ(0, fetestexcept(FE_ALL_EXCEPT));
86 }
87 
TEST(fenv,FE_DFL_ENV_macro)88 TEST(fenv, FE_DFL_ENV_macro) {
89   ASSERT_EQ(0, fesetenv(FE_DFL_ENV));
90 }
91 
TEST(fenv,feraiseexcept)92 TEST(fenv, feraiseexcept) {
93   feclearexcept(FE_ALL_EXCEPT);
94   ASSERT_EQ(0, fetestexcept(FE_ALL_EXCEPT));
95 
96   ASSERT_EQ(0, feraiseexcept(FE_DIVBYZERO | FE_OVERFLOW));
97   ASSERT_EQ(FE_DIVBYZERO | FE_OVERFLOW, fetestexcept(FE_ALL_EXCEPT));
98 }
99 
TEST(fenv,fegetenv_fesetenv)100 TEST(fenv, fegetenv_fesetenv) {
101   // Set FE_OVERFLOW only.
102   feclearexcept(FE_ALL_EXCEPT);
103   ASSERT_EQ(0, fetestexcept(FE_ALL_EXCEPT));
104   ASSERT_EQ(0, feraiseexcept(FE_OVERFLOW));
105 
106   // fegetenv (unlike feholdexcept) leaves the current state untouched...
107   fenv_t state;
108   ASSERT_EQ(0, fegetenv(&state));
109   ASSERT_EQ(FE_OVERFLOW, fetestexcept(FE_ALL_EXCEPT));
110 
111   // Dividing by zero sets the appropriate flag...
112   DivideByZero();
113   ASSERT_EQ(FE_DIVBYZERO | FE_OVERFLOW, fetestexcept(FE_ALL_EXCEPT));
114 
115   // And fesetenv (unlike feupdateenv) clobbers that to return to where
116   // we started.
117   ASSERT_EQ(0, fesetenv(&state));
118   ASSERT_EQ(FE_OVERFLOW, fetestexcept(FE_ALL_EXCEPT));
119 }
120 
TEST(fenv,fegetenv_fesetenv_rounding_mode)121 TEST(fenv, fegetenv_fesetenv_rounding_mode) {
122   // Test that fegetenv()/fesetenv() includes the rounding mode.
123   fesetround(FE_DOWNWARD);
124   ASSERT_EQ(FE_DOWNWARD, fegetround());
125 
126   fenv_t env;
127   fegetenv(&env);
128 
129   fesetround(FE_UPWARD);
130   ASSERT_EQ(FE_UPWARD, fegetround());
131 
132   fesetenv(&env);
133   ASSERT_EQ(FE_DOWNWARD, fegetround());
134 }
135 
TEST(fenv,feholdexcept_feupdateenv)136 TEST(fenv, feholdexcept_feupdateenv) {
137   // Set FE_OVERFLOW only.
138   feclearexcept(FE_ALL_EXCEPT);
139   ASSERT_EQ(0, fetestexcept(FE_ALL_EXCEPT));
140   ASSERT_EQ(0, feraiseexcept(FE_OVERFLOW));
141 
142   // feholdexcept (unlike fegetenv) clears everything...
143   fenv_t state;
144   ASSERT_EQ(0, feholdexcept(&state));
145   ASSERT_EQ(0, fetestexcept(FE_ALL_EXCEPT));
146 
147   // Dividing by zero sets the appropriate flag...
148   DivideByZero();
149   ASSERT_EQ(FE_DIVBYZERO, fetestexcept(FE_ALL_EXCEPT));
150 
151   // And feupdateenv (unlike fesetenv) merges what we started with
152   // (FE_OVERFLOW) with what we now have (FE_DIVBYZERO).
153   ASSERT_EQ(0, feupdateenv(&state));
154   ASSERT_EQ(FE_DIVBYZERO | FE_OVERFLOW, fetestexcept(FE_ALL_EXCEPT));
155 }
156 
TEST(fenv,fegetexceptflag_fesetexceptflag)157 TEST(fenv, fegetexceptflag_fesetexceptflag) {
158   // Set three flags.
159   feclearexcept(FE_ALL_EXCEPT);
160   ASSERT_EQ(0, feraiseexcept(FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW));
161   ASSERT_EQ(FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW, fetestexcept(FE_ALL_EXCEPT));
162 
163   fexcept_t all; // FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW
164   fexcept_t two; // FE_OVERFLOW | FE_UNDERFLOW
165   ASSERT_EQ(0, fegetexceptflag(&all, FE_ALL_EXCEPT));
166   ASSERT_EQ(0, fegetexceptflag(&two, FE_OVERFLOW | FE_UNDERFLOW));
167 
168   // Check we can restore all.
169   feclearexcept(FE_ALL_EXCEPT);
170   ASSERT_EQ(0, fesetexceptflag(&all, FE_ALL_EXCEPT));
171   ASSERT_EQ(FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW, fetestexcept(FE_ALL_EXCEPT));
172 
173   // Check that `two` only stored a subset.
174   feclearexcept(FE_ALL_EXCEPT);
175   ASSERT_EQ(0, fesetexceptflag(&two, FE_ALL_EXCEPT));
176   ASSERT_EQ(FE_OVERFLOW | FE_UNDERFLOW, fetestexcept(FE_ALL_EXCEPT));
177 
178   // Check that we can restore a single flag.
179   feclearexcept(FE_ALL_EXCEPT);
180   ASSERT_EQ(0, fesetexceptflag(&all, FE_DIVBYZERO));
181   ASSERT_EQ(FE_DIVBYZERO, fetestexcept(FE_ALL_EXCEPT));
182 
183   // Check that we can restore a subset of flags.
184   feclearexcept(FE_ALL_EXCEPT);
185   ASSERT_EQ(0, fesetexceptflag(&all, FE_OVERFLOW | FE_UNDERFLOW));
186   ASSERT_EQ(FE_OVERFLOW | FE_UNDERFLOW, fetestexcept(FE_ALL_EXCEPT));
187 }
188 
TEST(fenv,fedisableexcept_fegetexcept)189 TEST(fenv, fedisableexcept_fegetexcept) {
190 #if !defined(ANDROID_HOST_MUSL)
191   feclearexcept(FE_ALL_EXCEPT);
192   ASSERT_EQ(0, fetestexcept(FE_ALL_EXCEPT));
193 
194   // No SIGFPE please...
195   ASSERT_EQ(0, fedisableexcept(FE_ALL_EXCEPT));
196   ASSERT_EQ(0, fegetexcept());
197   ASSERT_EQ(0, feraiseexcept(FE_INVALID));
198   ASSERT_EQ(FE_INVALID, fetestexcept(FE_ALL_EXCEPT));
199 #else
200   GTEST_SKIP() << "musl doesn't have fegetexcept";
201 #endif
202 }
203 
TEST(fenv,feenableexcept_fegetexcept)204 TEST(fenv, feenableexcept_fegetexcept) {
205 #if !defined(ANDROID_HOST_MUSL)
206 #if defined(__aarch64__) || defined(__arm__) || defined(__riscv)
207   // ARM and RISC-V don't support hardware trapping of floating point
208   // exceptions. ARM used to if you go back far enough, but it was
209   // removed in the Cortex-A8 between r3p1 and r3p2. RISC-V never has.
210   ASSERT_EQ(-1, feenableexcept(FE_INVALID));
211   ASSERT_EQ(0, fegetexcept());
212   ASSERT_EQ(-1, feenableexcept(FE_DIVBYZERO));
213   ASSERT_EQ(0, fegetexcept());
214   ASSERT_EQ(-1, feenableexcept(FE_OVERFLOW));
215   ASSERT_EQ(0, fegetexcept());
216   ASSERT_EQ(-1, feenableexcept(FE_UNDERFLOW));
217   ASSERT_EQ(0, fegetexcept());
218   ASSERT_EQ(-1, feenableexcept(FE_INEXACT));
219   ASSERT_EQ(0, fegetexcept());
220 #if defined(_FE_DENORMAL)  // riscv64 doesn't support this.
221   ASSERT_EQ(-1, feenableexcept(FE_DENORMAL));
222   ASSERT_EQ(0, fegetexcept());
223 #endif
224 #else
225   // We can't recover from SIGFPE, so sacrifice a child...
226   pid_t pid = fork();
227   ASSERT_NE(-1, pid) << strerror(errno);
228 
229   if (pid == 0) {
230     signal(SIGFPE, SIG_DFL);  // Disable debuggerd.
231     feclearexcept(FE_ALL_EXCEPT);
232     ASSERT_EQ(0, fetestexcept(FE_ALL_EXCEPT));
233     ASSERT_EQ(0, feenableexcept(FE_INVALID));
234     ASSERT_EQ(FE_INVALID, fegetexcept());
235     ASSERT_EQ(0, feraiseexcept(FE_INVALID));
236     _exit(123);
237   }
238 
239   AssertChildExited(pid, -SIGFPE);
240 #endif
241 #else
242   GTEST_SKIP() << "musl doesn't have fegetexcept";
243 #endif
244 }
245