benchmark 1.10.0
Loading...
Searching...
No Matches
utils.h
1// Copyright 2015 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#ifndef BENCHMARK_UTILS_H_
16#define BENCHMARK_UTILS_H_
17
18#include <atomic>
19#include <type_traits>
20#include <utility>
21
22#include "benchmark/export.h"
23#include "benchmark/macros.h"
24
25namespace benchmark {
26
27namespace internal {
28BENCHMARK_EXPORT void UseCharPointer(char const volatile*);
29
30// An object of a class type with a const data member has nothing to store
31// into, so gcc and clang reject it as an asm *output* operand (issue #1997).
32// No trait spells that directly; assignability is the closest approximation.
33// Arrays are never assignable but are valid outputs, so allow them outright.
34// A class with a reference data member is also a valid output, but is
35// indistinguishable here and is conservatively treated as an input instead.
36template <class Tp>
38 typedef typename std::remove_reference<Tp>::type T;
39 static const bool value = std::is_array<T>::value ||
40 std::is_copy_assignable<T>::value ||
41 std::is_move_assignable<T>::value;
42};
43} // namespace internal
44
45#if (!defined(__GNUC__) && !defined(__clang__)) || defined(__pnacl__) || \
46 defined(__EMSCRIPTEN__)
47#define BENCHMARK_HAS_NO_INLINE_ASSEMBLY
48#endif
49
50inline BENCHMARK_ALWAYS_INLINE void ClobberMemory() {
51 std::atomic_signal_fence(std::memory_order_acq_rel);
52}
53
54#define BENCHMARK_DONOTOPTIMIZE_CONST_REF_DEPRECATED_MSG \
55 "DoNotOptimize(T const&) can permit undesired compiler optimizations. " \
56 "Pass a non-const lvalue instead; if the argument is an expression result, " \
57 "store it in a local variable first."
58
59#ifndef BENCHMARK_HAS_NO_INLINE_ASSEMBLY
60#if !defined(__GNUC__) || defined(__llvm__) || defined(__INTEL_COMPILER)
61template <class Tp>
62BENCHMARK_DEPRECATED_MSG(BENCHMARK_DONOTOPTIMIZE_CONST_REF_DEPRECATED_MSG)
63inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) {
64 asm volatile("" : : "r,m"(value) : "memory");
65}
66
67template <class Tp>
68inline BENCHMARK_ALWAYS_INLINE
69 typename std::enable_if<internal::IsValidAsmOutput<Tp>::value>::type
70 DoNotOptimize(Tp& value) {
71#if defined(__clang__)
72 asm volatile("" : "+r,m"(value) : : "memory");
73#else
74 asm volatile("" : "+m,r"(value) : : "memory");
75#endif
76}
77
78template <class Tp>
79inline BENCHMARK_ALWAYS_INLINE
80 typename std::enable_if<internal::IsValidAsmOutput<Tp>::value>::type
81 DoNotOptimize(Tp&& value) {
82#if defined(__clang__)
83 asm volatile("" : "+r,m"(value) : : "memory");
84#else
85 asm volatile("" : "+m,r"(value) : : "memory");
86#endif
87}
88
89// Types that cannot be written to are passed as an input operand instead.
90// A forwarding reference covers both lvalues and rvalues here; unlike the
91// read-write overloads above, an input operand needs no separate lvalue form.
92template <class Tp>
93inline BENCHMARK_ALWAYS_INLINE
94 typename std::enable_if<!internal::IsValidAsmOutput<Tp>::value>::type
95 DoNotOptimize(Tp&& value) {
96 asm volatile("" : : "r,m"(value) : "memory");
97}
98#elif (__GNUC__ >= 5)
99template <class Tp>
100BENCHMARK_DEPRECATED_MSG(BENCHMARK_DONOTOPTIMIZE_CONST_REF_DEPRECATED_MSG)
101inline BENCHMARK_ALWAYS_INLINE
102 typename std::enable_if<std::is_trivially_copyable<Tp>::value &&
103 (sizeof(Tp) <= sizeof(Tp*))>::type
104 DoNotOptimize(Tp const& value) {
105 asm volatile("" : : "r,m"(value) : "memory");
106}
107
108template <class Tp>
109BENCHMARK_DEPRECATED_MSG(BENCHMARK_DONOTOPTIMIZE_CONST_REF_DEPRECATED_MSG)
110inline BENCHMARK_ALWAYS_INLINE
111 typename std::enable_if<!std::is_trivially_copyable<Tp>::value ||
112 (sizeof(Tp) > sizeof(Tp*))>::type
113 DoNotOptimize(Tp const& value) {
114 asm volatile("" : : "m"(value) : "memory");
115}
116
117template <class Tp>
118inline BENCHMARK_ALWAYS_INLINE
119 typename std::enable_if<internal::IsValidAsmOutput<Tp>::value &&
120 std::is_trivially_copyable<Tp>::value &&
121 (sizeof(Tp) <= sizeof(Tp*))>::type
122 DoNotOptimize(Tp& value) {
123 asm volatile("" : "+m,r"(value) : : "memory");
124}
125
126template <class Tp>
127inline BENCHMARK_ALWAYS_INLINE
128 typename std::enable_if<internal::IsValidAsmOutput<Tp>::value &&
129 (!std::is_trivially_copyable<Tp>::value ||
130 (sizeof(Tp) > sizeof(Tp*)))>::type
131 DoNotOptimize(Tp& value) {
132 asm volatile("" : "+m"(value) : : "memory");
133}
134
135template <class Tp>
136inline BENCHMARK_ALWAYS_INLINE
137 typename std::enable_if<internal::IsValidAsmOutput<Tp>::value &&
138 std::is_trivially_copyable<Tp>::value &&
139 (sizeof(Tp) <= sizeof(Tp*))>::type
140 DoNotOptimize(Tp&& value) {
141 asm volatile("" : "+m,r"(value) : : "memory");
142}
143
144template <class Tp>
145inline BENCHMARK_ALWAYS_INLINE
146 typename std::enable_if<internal::IsValidAsmOutput<Tp>::value &&
147 (!std::is_trivially_copyable<Tp>::value ||
148 (sizeof(Tp) > sizeof(Tp*)))>::type
149 DoNotOptimize(Tp&& value) {
150 asm volatile("" : "+m"(value) : : "memory");
151}
152
153// Types that cannot be written to are passed as an input operand instead.
154// A forwarding reference covers both lvalues and rvalues here; unlike the
155// read-write overloads above, an input operand needs no separate lvalue form.
156template <class Tp>
157inline BENCHMARK_ALWAYS_INLINE
158 typename std::enable_if<!internal::IsValidAsmOutput<Tp>::value>::type
159 DoNotOptimize(Tp&& value) {
160 asm volatile("" : : "r,m"(value) : "memory");
161}
162#endif
163
164#elif defined(_MSC_VER)
165template <class Tp>
166BENCHMARK_DEPRECATED_MSG(BENCHMARK_DONOTOPTIMIZE_CONST_REF_DEPRECATED_MSG)
167inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) {
168 internal::UseCharPointer(&reinterpret_cast<char const volatile&>(value));
169 ClobberMemory();
170}
171
172template <class Tp>
173inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp& value) {
174 internal::UseCharPointer(&reinterpret_cast<char const volatile&>(value));
175 ClobberMemory();
176}
177
178template <class Tp>
179inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp&& value) {
180 internal::UseCharPointer(&reinterpret_cast<char const volatile&>(value));
181 ClobberMemory();
182}
183#else
184template <class Tp>
185inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp&& value) {
186 internal::UseCharPointer(&reinterpret_cast<char const volatile&>(value));
187}
188#endif
189
190#undef BENCHMARK_DONOTOPTIMIZE_CONST_REF_DEPRECATED_MSG
191
192} // end namespace benchmark
193
194#endif // BENCHMARK_UTILS_H_