blob: dccd3b218d7268f87c0f64981a37f51ecdb32615 [file]
// 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_