6408acf50a
Improve docs for `DoNotOptimize()`, and make it's compile-time diagnostic suggest a possible fix
153 lines
4.8 KiB
C++
153 lines
4.8 KiB
C++
// Copyright 2015 Google Inc. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#ifndef BENCHMARK_UTILS_H_
|
|
#define BENCHMARK_UTILS_H_
|
|
|
|
#include <atomic>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
|
|
#include "benchmark/export.h"
|
|
#include "benchmark/macros.h"
|
|
|
|
namespace benchmark {
|
|
|
|
namespace internal {
|
|
BENCHMARK_EXPORT void UseCharPointer(char const volatile*);
|
|
}
|
|
|
|
#if (!defined(__GNUC__) && !defined(__clang__)) || defined(__pnacl__) || \
|
|
defined(__EMSCRIPTEN__)
|
|
#define BENCHMARK_HAS_NO_INLINE_ASSEMBLY
|
|
#endif
|
|
|
|
inline BENCHMARK_ALWAYS_INLINE void ClobberMemory() {
|
|
std::atomic_signal_fence(std::memory_order_acq_rel);
|
|
}
|
|
|
|
#define BENCHMARK_DONOTOPTIMIZE_CONST_REF_DEPRECATED_MSG \
|
|
"DoNotOptimize(T const&) can permit undesired compiler optimizations. " \
|
|
"Pass a non-const lvalue instead; if the argument is an expression result, " \
|
|
"store it in a local variable first."
|
|
|
|
#ifndef BENCHMARK_HAS_NO_INLINE_ASSEMBLY
|
|
#if !defined(__GNUC__) || defined(__llvm__) || defined(__INTEL_COMPILER)
|
|
template <class Tp>
|
|
BENCHMARK_DEPRECATED_MSG(BENCHMARK_DONOTOPTIMIZE_CONST_REF_DEPRECATED_MSG)
|
|
inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) {
|
|
asm volatile("" : : "r,m"(value) : "memory");
|
|
}
|
|
|
|
template <class Tp>
|
|
inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp& value) {
|
|
#if defined(__clang__)
|
|
asm volatile("" : "+r,m"(value) : : "memory");
|
|
#else
|
|
asm volatile("" : "+m,r"(value) : : "memory");
|
|
#endif
|
|
}
|
|
|
|
template <class Tp>
|
|
inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp&& value) {
|
|
#if defined(__clang__)
|
|
asm volatile("" : "+r,m"(value) : : "memory");
|
|
#else
|
|
asm volatile("" : "+m,r"(value) : : "memory");
|
|
#endif
|
|
}
|
|
#elif (__GNUC__ >= 5)
|
|
template <class Tp>
|
|
BENCHMARK_DEPRECATED_MSG(BENCHMARK_DONOTOPTIMIZE_CONST_REF_DEPRECATED_MSG)
|
|
inline BENCHMARK_ALWAYS_INLINE
|
|
typename std::enable_if<std::is_trivially_copyable<Tp>::value &&
|
|
(sizeof(Tp) <= sizeof(Tp*))>::type
|
|
DoNotOptimize(Tp const& value) {
|
|
asm volatile("" : : "r,m"(value) : "memory");
|
|
}
|
|
|
|
template <class Tp>
|
|
BENCHMARK_DEPRECATED_MSG(BENCHMARK_DONOTOPTIMIZE_CONST_REF_DEPRECATED_MSG)
|
|
inline BENCHMARK_ALWAYS_INLINE
|
|
typename std::enable_if<!std::is_trivially_copyable<Tp>::value ||
|
|
(sizeof(Tp) > sizeof(Tp*))>::type
|
|
DoNotOptimize(Tp const& value) {
|
|
asm volatile("" : : "m"(value) : "memory");
|
|
}
|
|
|
|
template <class Tp>
|
|
inline BENCHMARK_ALWAYS_INLINE
|
|
typename std::enable_if<std::is_trivially_copyable<Tp>::value &&
|
|
(sizeof(Tp) <= sizeof(Tp*))>::type
|
|
DoNotOptimize(Tp& value) {
|
|
asm volatile("" : "+m,r"(value) : : "memory");
|
|
}
|
|
|
|
template <class Tp>
|
|
inline BENCHMARK_ALWAYS_INLINE
|
|
typename std::enable_if<!std::is_trivially_copyable<Tp>::value ||
|
|
(sizeof(Tp) > sizeof(Tp*))>::type
|
|
DoNotOptimize(Tp& value) {
|
|
asm volatile("" : "+m"(value) : : "memory");
|
|
}
|
|
|
|
template <class Tp>
|
|
inline BENCHMARK_ALWAYS_INLINE
|
|
typename std::enable_if<std::is_trivially_copyable<Tp>::value &&
|
|
(sizeof(Tp) <= sizeof(Tp*))>::type
|
|
DoNotOptimize(Tp&& value) {
|
|
asm volatile("" : "+m,r"(value) : : "memory");
|
|
}
|
|
|
|
template <class Tp>
|
|
inline BENCHMARK_ALWAYS_INLINE
|
|
typename std::enable_if<!std::is_trivially_copyable<Tp>::value ||
|
|
(sizeof(Tp) > sizeof(Tp*))>::type
|
|
DoNotOptimize(Tp&& value) {
|
|
asm volatile("" : "+m"(value) : : "memory");
|
|
}
|
|
#endif
|
|
|
|
#elif defined(_MSC_VER)
|
|
template <class Tp>
|
|
BENCHMARK_DEPRECATED_MSG(BENCHMARK_DONOTOPTIMIZE_CONST_REF_DEPRECATED_MSG)
|
|
inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) {
|
|
internal::UseCharPointer(&reinterpret_cast<char const volatile&>(value));
|
|
ClobberMemory();
|
|
}
|
|
|
|
template <class Tp>
|
|
inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp& value) {
|
|
internal::UseCharPointer(&reinterpret_cast<char const volatile&>(value));
|
|
ClobberMemory();
|
|
}
|
|
|
|
template <class Tp>
|
|
inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp&& value) {
|
|
internal::UseCharPointer(&reinterpret_cast<char const volatile&>(value));
|
|
ClobberMemory();
|
|
}
|
|
#else
|
|
template <class Tp>
|
|
inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp&& value) {
|
|
internal::UseCharPointer(&reinterpret_cast<char const volatile&>(value));
|
|
}
|
|
#endif
|
|
|
|
#undef BENCHMARK_DONOTOPTIMIZE_CONST_REF_DEPRECATED_MSG
|
|
|
|
} // end namespace benchmark
|
|
|
|
#endif // BENCHMARK_UTILS_H_
|