diff options
Diffstat (limited to 'mesalib/src/util')
-rw-r--r-- | mesalib/src/util/Makefile.am | 4 | ||||
-rw-r--r-- | mesalib/src/util/Makefile.sources | 1 | ||||
-rw-r--r-- | mesalib/src/util/macros.h | 14 | ||||
-rw-r--r-- | mesalib/src/util/roundeven_test.c | 140 | ||||
-rw-r--r-- | mesalib/src/util/rounding.h | 78 | ||||
-rw-r--r-- | mesalib/src/util/u_atomic.h | 2 |
6 files changed, 233 insertions, 6 deletions
diff --git a/mesalib/src/util/Makefile.am b/mesalib/src/util/Makefile.am index ec49dc6cf..2e7542e42 100644 --- a/mesalib/src/util/Makefile.am +++ b/mesalib/src/util/Makefile.am @@ -50,7 +50,9 @@ endif libmesautil_la_LIBADD = $(SHA1_LIBS) -check_PROGRAMS = u_atomic_test +roundeven_test_LDADD = -lm + +check_PROGRAMS = u_atomic_test roundeven_test TESTS = $(check_PROGRAMS) BUILT_SOURCES = $(MESA_UTIL_GENERATED_FILES) diff --git a/mesalib/src/util/Makefile.sources b/mesalib/src/util/Makefile.sources index 560ea836a..3e0d02bad 100644 --- a/mesalib/src/util/Makefile.sources +++ b/mesalib/src/util/Makefile.sources @@ -14,6 +14,7 @@ MESA_UTIL_FILES := \ register_allocate.h \ rgtc.c \ rgtc.h \ + rounding.h \ set.c \ set.h \ simple_list.h \ diff --git a/mesalib/src/util/macros.h b/mesalib/src/util/macros.h index b862bfd5f..6c7bda7ae 100644 --- a/mesalib/src/util/macros.h +++ b/mesalib/src/util/macros.h @@ -73,15 +73,13 @@ do { \ assert(!str); \ __builtin_unreachable(); \ } while (0) -#elif _MSC_VER >= 1200 +#elif defined (_MSC_VER) #define unreachable(str) \ do { \ assert(!str); \ __assume(0); \ } while (0) -#endif - -#ifndef unreachable +#else #define unreachable(str) assert(!str) #endif @@ -99,7 +97,7 @@ do { \ #define assume(expr) ((expr) ? ((void) 0) \ : (assert(!"assumption failed"), \ __builtin_unreachable())) -#elif _MSC_VER >= 1200 +#elif defined (_MSC_VER) #define assume(expr) __assume(expr) #else #define assume(expr) assert(expr) @@ -178,5 +176,11 @@ do { \ # endif #endif +#ifdef HAVE_FUNC_ATTRIBUTE_UNUSED +#define UNUSED __attribute__((unused)) +#else +#define UNUSED +#endif + #endif /* UTIL_MACROS_H */ diff --git a/mesalib/src/util/roundeven_test.c b/mesalib/src/util/roundeven_test.c new file mode 100644 index 000000000..7526db1f3 --- /dev/null +++ b/mesalib/src/util/roundeven_test.c @@ -0,0 +1,140 @@ +/* + * Copyright © 2015 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include <stdio.h> +#include <stdbool.h> +#include <string.h> +#include <math.h> + +#include "macros.h" +#include "rounding.h" + +int main(int argc, char *argv[]) +{ + const struct { + float input, expected; + } float_data[] = { + { 0.0, 0.0 }, + { nextafterf(0.5, 0.0), 0.0 }, + { 0.5, 0.0 }, + { nextafterf(0.5, 1.0), 1.0 }, + { 1.0, 1.0 }, + { nextafterf(1.5, 1.0), 1.0 }, + { 1.5, 2.0 }, + { nextafterf(1.5, 2.0), 2.0 }, + { 2.0, 2.0 }, + { nextafterf(2.5, 2.0), 2.0 }, + { 2.5, 2.0 }, + { nextafterf(2.5, 3.0), 3.0 }, + }; + + const struct { + double input, expected; + } double_data[] = { + { 0.0, 0.0 }, + { nextafter(0.5, 0.0), 0.0 }, + { 0.5, 0.0 }, + { nextafter(0.5, 1.0), 1.0 }, + { 1.0, 1.0 }, + { nextafter(1.5, 1.0), 1.0 }, + { 1.5, 2.0 }, + { nextafter(1.5, 2.0), 2.0 }, + { 2.0, 2.0 }, + { nextafter(2.5, 2.0), 2.0 }, + { 2.5, 2.0 }, + { nextafter(2.5, 3.0), 3.0 }, + }; + + bool failed = false; + int i; + + for (i = 0; i < ARRAY_SIZE(float_data); i++) { + float output = _mesa_roundevenf(float_data[i].input); + if (memcmp(&float_data[i].expected, &output, sizeof(float))) { + fprintf(stderr, "%d float: expected %f (%a) from " + "_mesa_roundevenf(%f (%a)) but got %f (%a)\n", + i, + float_data[i].expected, + float_data[i].expected, + float_data[i].input, + float_data[i].input, + output, + output); + failed = true; + } + } + + /* Test negated values */ + for (i = 0; i < ARRAY_SIZE(float_data); i++) { + float output = _mesa_roundevenf(-float_data[i].input); + float negated_expected = -float_data[i].expected; + if (memcmp(&negated_expected, &output, sizeof(float))) { + fprintf(stderr, "%d float: expected %f (%a) from " + "_mesa_roundevenf(%f (%a)) but got %f (%a)\n", + i, + negated_expected, + negated_expected, + -float_data[i].input, + -float_data[i].input, + output, + output); + failed = true; + } + } + + for (i = 0; i < ARRAY_SIZE(double_data); i++) { + double output = _mesa_roundeven(double_data[i].input); + if (memcmp(&double_data[i].expected, &output, sizeof(double))) { + fprintf(stderr, "%d double: expected %f (%a) from " + "_mesa_roundeven(%f (%a)) but got %f (%a)\n", + i, + double_data[i].expected, + double_data[i].expected, + double_data[i].input, + double_data[i].input, + output, + output); + failed = true; + } + } + + /* Test negated values */ + for (i = 0; i < ARRAY_SIZE(double_data); i++) { + double output = _mesa_roundeven(-double_data[i].input); + double negated_expected = -double_data[i].expected; + if (memcmp(&negated_expected, &output, sizeof(double))) { + fprintf(stderr, "%d double: expected %f (%a) from " + "_mesa_roundeven(%f (%a)) but got %f (%a)\n", + i, + negated_expected, + negated_expected, + -double_data[i].input, + -double_data[i].input, + output, + output); + failed = true; + } + } + + return failed; +} diff --git a/mesalib/src/util/rounding.h b/mesalib/src/util/rounding.h new file mode 100644 index 000000000..0cbe9269f --- /dev/null +++ b/mesalib/src/util/rounding.h @@ -0,0 +1,78 @@ +/* + * Copyright © 2015 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include <math.h> + +#ifdef __SSE4_1__ +#include <smmintrin.h> +#endif + +/* The C standard library has functions round()/rint()/nearbyint() that round + * their arguments according to the rounding mode set in the floating-point + * control register. While there are trunc()/ceil()/floor() functions that do + * a specific operation without modifying the rounding mode, there is no + * roundeven() in any version of C. + * + * Technical Specification 18661 (ISO/IEC TS 18661-1:2014) adds roundeven(), + * but it's unfortunately not implemented by glibc. + * + * This implementation differs in that it does not raise the inexact exception. + * + * We use rint() to implement these functions, with the assumption that the + * floating-point rounding mode has not been changed from the default Round + * to Nearest. + */ + +/** + * \brief Rounds \c x to the nearest integer, with ties to the even integer. + */ +static inline float +_mesa_roundevenf(float x) +{ +#ifdef __SSE4_1__ + float ret; + __m128 m = _mm_load_ss(&x); + m = _mm_round_ss(m, m, _MM_FROUND_CUR_DIRECTION | _MM_FROUND_NO_EXC); + _mm_store_ss(&ret, m); + return ret; +#else + return rintf(x); +#endif +} + +/** + * \brief Rounds \c x to the nearest integer, with ties to the even integer. + */ +static inline double +_mesa_roundeven(double x) +{ +#ifdef __SSE4_1__ + double ret; + __m128d m = _mm_load_sd(&x); + m = _mm_round_sd(m, m, _MM_FROUND_CUR_DIRECTION | _MM_FROUND_NO_EXC); + _mm_store_sd(&ret, m); + return ret; +#else + return rint(x); +#endif +} diff --git a/mesalib/src/util/u_atomic.h b/mesalib/src/util/u_atomic.h index d15398e1e..e38395ac6 100644 --- a/mesalib/src/util/u_atomic.h +++ b/mesalib/src/util/u_atomic.h @@ -6,6 +6,8 @@ * */ +#include "no_extern_c.h" + #ifndef U_ATOMIC_H #define U_ATOMIC_H |