Skip to content
Snippets Groups Projects
Commit d73f2240 authored by Sam Yates's avatar Sam Yates Committed by Ben Cumming
Browse files

Work around xlC 13.1.4 compiler bugs. (#115)

Addresses in part issue #113.

* Make compatibility wrappers/functions that dance around xlC
  bugs. Wrappers are provied in `util/compat.hpp` and live in
  the `compat` namespace.
      - `compat::end` reimplements `std::end` but in a way that
	apparently does not trigger the xlC bug.
      - `compat::compiler_barrier_if_xlc_leq()` inserts a compiler
	reordering barrier if the compiler is xlC and the version
	less than or equal to that specified. Name is deliberately
	verbose.
      - `compat::isinf()` is an inline wrapper around `std::isinf()`,
	which apparently is sufficient to defuse an evaluation
	order bug with `std::isinf()` in switch statements.
* Use `compat::compiler_barrier_if_xlc_leq()` in `util::unitialized`
  reference access methods to avoid improper reordering with -O2.
* Use `compat::isinf()` in `test_math.cpp` to defuse improper
  reordering within `EXPECT_EQ` gtest macro of `std::isinf()`.
* Use `compat::end()` in `util::back()` and `util::cend()` to avoid
  incorrect `std::end()` behaviour with -O2.
* Use `util::cend()` in `algorithms::sum()`, again to avoid
  incorrect `std::end()` behaviour with -O2.
parent b9834880
No related branches found
No related tags found
No related merge requests found
......@@ -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>
......
#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); }
}
......@@ -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));
}
/*
......
......@@ -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>
......
......@@ -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(); }
......
......@@ -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)
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment