1 /* Measure math inline functions.
2 Copyright (C) 2015-2023 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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.
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.
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/>. */
21 #define TEST_NAME "math-inlines"
22 #define TEST_FUNCTION test_main ()
23 #include "bench-timing.h"
25 #include "bench-util.h"
31 #define BOOLTEST(func) \
32 static int __attribute__((noinline)) \
33 func ## _f (double d, int i) \
41 func ## _t (volatile double *p, size_t n, size_t iters) \
45 for (j = 0; j < iters; j++) \
46 for (i = 0; i < n; i++) \
47 if (func ## _f (p[i] * 2.0, i) != 0) \
52 #define VALUETEST(func) \
53 static int __attribute__((noinline)) \
54 func ## _f (double d) \
59 func ## _t (volatile double *p, size_t n, size_t iters) \
63 for (j = 0; j < iters; j++) \
64 for (i = 0; i < n; i++) \
65 res += func ## _f (p[i] * 2.0); \
73 } ieee_double_shape_type
;
75 #define EXTRACT_WORDS64(i,d) \
77 ieee_double_shape_type gh_u; \
82 /* Inlines similar to existing math_private.h versions. */
84 static __always_inline
int
85 __isnan_inl (double d
)
88 EXTRACT_WORDS64 (di
, d
);
89 return (di
& 0x7fffffffffffffffull
) > 0x7ff0000000000000ull
;
92 static __always_inline
int
93 __isinf_ns2 (double d
)
96 EXTRACT_WORDS64 (di
, d
);
97 return (di
& 0x7fffffffffffffffull
) == 0x7ff0000000000000ull
;
100 static __always_inline
int
101 __finite_inl (double d
)
104 EXTRACT_WORDS64 (di
, d
);
105 return (di
& 0x7fffffffffffffffull
) < 0x7ff0000000000000ull
;
108 #define __isnormal_inl(X) (__fpclassify (X) == FP_NORMAL)
110 /* Inlines for the builtin functions. */
112 #define __isnan_builtin(X) __builtin_isnan (X)
113 #define __isinf_ns_builtin(X) __builtin_isinf (X)
114 #define __isinf_builtin(X) __builtin_isinf_sign (X)
115 #define __isfinite_builtin(X) __builtin_isfinite (X)
116 #define __isnormal_builtin(X) __builtin_isnormal (X)
117 #define __fpclassify_builtin(X) __builtin_fpclassify (FP_NAN, FP_INFINITE, \
118 FP_NORMAL, FP_SUBNORMAL, FP_ZERO, (X))
120 static double __attribute ((noinline
))
121 kernel_standard (double x
, double y
, int z
)
126 volatile double rem1
= 2.5;
128 static __always_inline
double
129 remainder_test1 (double x
)
132 if (((__builtin_expect (y
== 0.0, 0) && !__isnan_inl (x
))
133 || (__builtin_expect (__isinf_ns2 (x
), 0) && !__isnan_inl (y
))))
134 return kernel_standard (x
, y
, 10);
136 return remainder (x
, y
);
139 static __always_inline
double
140 remainder_test2 (double x
)
143 if (((__builtin_expect (y
== 0.0, 0) && !__builtin_isnan (x
))
144 || (__builtin_expect (__builtin_isinf (x
), 0) && !__builtin_isnan (y
))))
145 return kernel_standard (x
, y
, 10);
147 return remainder (x
, y
);
150 /* Create test functions for each possibility. */
153 BOOLTEST (__isnan_inl
)
154 BOOLTEST (__isnan_builtin
)
158 BOOLTEST (__isinf_builtin
)
159 BOOLTEST (__isinf_ns2
)
160 BOOLTEST (__isinf_ns_builtin
)
164 BOOLTEST (__finite_inl
)
165 BOOLTEST (__isfinite_builtin
)
168 BOOLTEST (__isnormal_inl
)
169 BOOLTEST (__isnormal_builtin
)
172 VALUETEST (__fpclassify
)
173 VALUETEST (__fpclassify_builtin
)
174 VALUETEST (fpclassify
)
176 VALUETEST (remainder_test1
)
177 VALUETEST (remainder_test2
)
179 typedef int (*proto_t
) (volatile double *p
, size_t n
, size_t iters
);
187 #define IMPL(name) { #name, name ## _t }
189 static impl_t test_list
[] =
193 IMPL (__isnan_builtin
),
198 IMPL (__isinf_ns_builtin
),
199 IMPL (__isinf_builtin
),
204 IMPL (__isfinite_builtin
),
207 IMPL (__isnormal_inl
),
208 IMPL (__isnormal_builtin
),
212 IMPL (__fpclassify_builtin
),
215 IMPL (remainder_test1
),
216 IMPL (remainder_test2
)
220 do_one_test (json_ctx_t
*json_ctx
, proto_t test_fn
, volatile double *arr
,
221 size_t len
, const char *testname
)
224 timing_t start
, stop
, cur
;
226 json_attr_object_begin (json_ctx
, testname
);
229 test_fn (arr
, len
, iters
);
231 TIMING_DIFF (cur
, start
, stop
);
233 json_attr_double (json_ctx
, "duration", cur
);
234 json_attr_double (json_ctx
, "iterations", iters
);
235 json_attr_double (json_ctx
, "mean", cur
/ iters
);
236 json_attr_object_end (json_ctx
);
239 static volatile double arr1
[SIZE
];
240 static volatile double arr2
[SIZE
];
250 json_init (&json_ctx
, 2, stdout
);
251 json_attr_object_begin (&json_ctx
, TEST_NAME
);
253 /* Create 2 test arrays, one with 10% zeroes, 10% negative values,
254 79% positive values and 1% infinity/NaN. The other contains
255 50% inf, 50% NaN. This relies on rand behaving correctly. */
257 for (i
= 0; i
< SIZE
; i
++)
259 int x
= rand () & 255;
260 arr1
[i
] = (x
< 25) ? 0.0 : ((x
< 50) ? -1 : 100);
261 if (x
== 255) arr1
[i
] = __builtin_inf ();
262 if (x
== 254) arr1
[i
] = __builtin_nan ("0");
263 arr2
[i
] = (x
< 128) ? __builtin_inf () : __builtin_nan ("0");
266 for (i
= 0; i
< sizeof (test_list
) / sizeof (test_list
[0]); i
++)
268 json_attr_object_begin (&json_ctx
, test_list
[i
].name
);
269 do_one_test (&json_ctx
, test_list
[i
].fn
, arr2
, SIZE
, "inf/nan");
270 json_attr_object_end (&json_ctx
);
273 for (i
= 0; i
< sizeof (test_list
) / sizeof (test_list
[0]); i
++)
275 json_attr_object_begin (&json_ctx
, test_list
[i
].name
);
276 do_one_test (&json_ctx
, test_list
[i
].fn
, arr1
, SIZE
, "normal");
277 json_attr_object_end (&json_ctx
);
280 json_attr_object_end (&json_ctx
);
284 #include "bench-util.c"
285 #include "../test-skeleton.c"