diff --git a/src/algorithms.hpp b/src/algorithms.hpp index 43893b3198bcc00591bc4301efbbdcb0159330d6..9a3ecdf7f2197e233fd2c848aa86cf124aef3a41 100644 --- a/src/algorithms.hpp +++ b/src/algorithms.hpp @@ -29,7 +29,7 @@ typename util::sequence_traits<C>::value_type sum(C const& c) { using value_type = typename util::sequence_traits<C>::value_type; - return std::accumulate(std::begin(c), std::end(c), value_type{0}); + return std::accumulate(util::cbegin(c), util::cend(c), value_type{0}); } template <typename C> diff --git a/src/util/compat.hpp b/src/util/compat.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c288effefd8c50593ed82750714691b2dc409ba4 --- /dev/null +++ b/src/util/compat.hpp @@ -0,0 +1,37 @@ +#pragma once + +/* Collection of compatibility workarounds to deal with compiler defects */ + +#include <cstddef> +#include <cmath> + +namespace compat { + +// std::end() broken with (at least) xlC 13.1.4. + +template <typename T> +auto end(T& x) -> decltype(x.end()) { return x.end(); } + +template <typename T, std::size_t N> +T* end(T (&x)[N]) { return &x[0]+N; } + +template <typename T, std::size_t N> +const T* end(const T (&x)[N]) { return &x[0]+N; } + +// workaround bad optimization reordering in xlC 13.1.4 + +inline void compiler_barrier_if_xlc_leq(unsigned ver) { +#if defined(__xlC__) + if (__xlC__<=ver) { + asm volatile ("" ::: "memory"); + } +#endif +} + +// Work around bad ordering of std::isinf() (sometimes) within switch, xlC 13.1.4; +// wrapping the call within another function appears to be sufficient. + +template <typename X> +inline constexpr bool isinf(X x) { return std::isinf(x); } + +} diff --git a/src/util/iterutil.hpp b/src/util/iterutil.hpp index 8c327d4140c24790ca7576fafb190932508524e6..00e52d628475dde475c4d9e11e849c2df6c38b73 100644 --- a/src/util/iterutil.hpp +++ b/src/util/iterutil.hpp @@ -10,6 +10,7 @@ #include <type_traits> #include <utility> +#include <util/compat.hpp> #include <util/meta.hpp> namespace nest { @@ -78,7 +79,8 @@ auto front(Seq& seq) -> decltype(*std::begin(seq)) { template <typename Seq> auto back(Seq& seq) -> decltype(*std::begin(seq)) { - return *upto(std::begin(seq), std::end(seq)); + // COMPAT: use own `end` implementation to work around xlC 13.1 bug. + return *upto(std::begin(seq), compat::end(seq)); } /* diff --git a/src/util/meta.hpp b/src/util/meta.hpp index 3bc8d9416875af778d77db9d597859a077814b95..34b809bbfe3de94546a743f313f2cee8576e305b 100644 --- a/src/util/meta.hpp +++ b/src/util/meta.hpp @@ -6,6 +6,8 @@ #include <iterator> #include <type_traits> +#include <util/compat.hpp> + namespace nest { namespace mc { namespace util { @@ -36,8 +38,9 @@ constexpr auto cbegin(const T& c) -> decltype(std::begin(c)) { } template <typename T> -constexpr auto cend(const T& c) -> decltype(std::end(c)) { - return std::end(c); +constexpr auto cend(const T& c) -> decltype(compat::end(c)) { + // COMPAT: use own `end` implementation to work around xlC 13.1 bug. + return compat::end(c); } template <typename T> diff --git a/src/util/uninitialized.hpp b/src/util/uninitialized.hpp index a13842acb3fa796a86a7c76e924c779fb6e0383a..f9c1bf3685a98c5f405a3f0c0fe929adf8a182b9 100644 --- a/src/util/uninitialized.hpp +++ b/src/util/uninitialized.hpp @@ -12,6 +12,7 @@ #include <type_traits> #include <utility> +#include "util/compat.hpp" #include "util/meta.hpp" namespace nest { @@ -33,8 +34,18 @@ public: using reference = X&; using const_reference= const X&; - pointer ptr() { return static_cast<X*>(static_cast<void*>(&data)); } - const_pointer cptr() const { return static_cast<const X*>(static_cast<const void*>(&data)); } + pointer ptr() { + // COMPAT: xlC 13.1.4 workaround: + // should be equivalent to `return reinterpret_cast<X*>(&data)`. + compat::compiler_barrier_if_xlc_leq(0x0d01); + return static_cast<X*>(static_cast<void*>(&data)); + } + const_pointer cptr() const { + // COMPAT: xlC 13.1.4 workaround: + // should be equivalent to `return reinterpret_cast<const X*>(&data)` + compat::compiler_barrier_if_xlc_leq(0x0d01); + return static_cast<const X*>(static_cast<const void*>(&data)); + } reference ref() { return *ptr(); } const_reference cref() const { return *cptr(); } diff --git a/tests/unit/test_math.cpp b/tests/unit/test_math.cpp index 2bae462d10e2b2a797e6cd3eb0e7ffd52f5e0dac..1a5f442f2bba5a1b04db8fd64d1c39897ac6f8f0 100644 --- a/tests/unit/test_math.cpp +++ b/tests/unit/test_math.cpp @@ -2,7 +2,9 @@ #include <limits> #include "../gtest.h" + #include <math.hpp> +#include <util/compat.hpp> using namespace nest::mc::math; @@ -82,17 +84,20 @@ TEST(math, infinity) { // check values for float, double, long double auto finf = infinity<float>(); EXPECT_TRUE((std::is_same<float, decltype(finf)>::value)); - EXPECT_TRUE(std::isinf(finf)); + // COMPAT: use compatibility wrapper for isinf() thanks to xlC 13.1 bug. + EXPECT_TRUE(compat::isinf(finf)); EXPECT_GT(finf, 0.f); auto dinf = infinity<double>(); EXPECT_TRUE((std::is_same<double, decltype(dinf)>::value)); - EXPECT_TRUE(std::isinf(dinf)); + // COMPAT: use compatibility wrapper for isinf() thanks to xlC 13.1 bug. + EXPECT_TRUE(compat::isinf(dinf)); EXPECT_GT(dinf, 0.0); auto ldinf = infinity<long double>(); EXPECT_TRUE((std::is_same<long double, decltype(ldinf)>::value)); - EXPECT_TRUE(std::isinf(ldinf)); + // COMPAT: use compatibility wrapper for isinf() thanks to xlC 13.1 bug. + EXPECT_TRUE(compat::isinf(ldinf)); EXPECT_GT(ldinf, 0.0l); // check default value promotes correctly (i.e., acts like INFINITY)