From 208ca28eba23da3a1ad49c9b78a2c4bd739c9da4 Mon Sep 17 00:00:00 2001
From: Sam Yates <yates@cscs.ch>
Date: Wed, 3 May 2017 14:15:56 +0200
Subject: [PATCH] Work-around for inlining bug in icc 16.0.3 (#248)

Fixes #247.

Forces evaluation of partition bounds call within the `div_component_sampler` constructor, which for subtle and obscure reasons is mis- or un-computed with icpc and the `-xMIC-AVX512` target option.

* Add `compat::sink()` function that forces evaluation of the argument.
* Add `compat::sink_if_icc_leq(version, const X&)` function that performs this only when run with the Intel compiler subject to version bound.
* Use the `compat::sink_if_icc_leq` function in the `div_component_sampler` constructor.
---
 src/compartment.hpp |  5 ++++-
 src/util/compat.hpp | 23 +++++++++++++++++++++++
 2 files changed, 27 insertions(+), 1 deletion(-)

diff --git a/src/compartment.hpp b/src/compartment.hpp
index db548fa3..10c26fd1 100644
--- a/src/compartment.hpp
+++ b/src/compartment.hpp
@@ -5,11 +5,12 @@
 
 #include <common_types.hpp>
 #include <math.hpp>
+#include <util/compat.hpp>
 #include <util/counter.hpp>
 #include <util/iterutil.hpp>
 #include <util/partition.hpp>
 #include <util/span.hpp>
-#include "util/rangeutil.hpp"
+#include <util/rangeutil.hpp>
 #include <util/transform.hpp>
 
 namespace nest {
@@ -184,6 +185,8 @@ public:
         using namespace util;
 
         segs_ = make_partition(offsets_, lengths);
+        compat::sink_if_icc_leq(20160415u, segs_.bounds());
+
         nseg_ = size(segs_);
         scale_ = segs_.bounds().second/n;
         assign(radii_, radii);
diff --git a/src/util/compat.hpp b/src/util/compat.hpp
index c288effe..a10e8cc1 100644
--- a/src/util/compat.hpp
+++ b/src/util/compat.hpp
@@ -34,4 +34,27 @@ inline void compiler_barrier_if_xlc_leq(unsigned ver) {
 template <typename X>
 inline constexpr bool isinf(X x) { return std::isinf(x); }
 
+// Work around a bad inlining-related optimization with icpc 16.0.3 and -xMIC-AVX512,
+// by forcing a computation.
+
+template <typename X>
+inline void sink(const X& x) {
+    char buf[sizeof x];
+    volatile char* bufptr = buf;
+    const char* xptr = reinterpret_cast<const char*>(&x);
+
+    for (std::size_t i = 0; i<sizeof buf; ++i) {
+        *bufptr++ = *xptr++;
+    }
+}
+
+template <typename X>
+inline void sink_if_icc_leq(unsigned ver, const X& x) {
+#if defined(__INTEL_COMPILER_BUILD_DATE)
+    if (__INTEL_COMPILER_BUILD_DATE<=ver) {
+        sink(x);
+    }
+#endif
 }
+
+} // namespace compat
-- 
GitLab