Publishing 2019 R1 content
[platform/upstream/dldt.git] / inference-engine / thirdparty / mkl-dnn / src / common / utils.hpp
1 /*******************************************************************************
2 * Copyright 2016-2018 Intel Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *******************************************************************************/
16
17 #ifndef UTILS_HPP
18 #define UTILS_HPP
19
20 #include <stddef.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <assert.h>
24 #include <stdint.h>
25
26 #if defined(__x86_64__) || defined(_M_X64)
27 #define MKLDNN_X86_64
28 #endif
29
30 #define MSAN_ENABLED 0
31 #if defined(__has_feature)
32 #if __has_feature(memory_sanitizer)
33 #undef MSAN_ENABLED
34 #define MSAN_ENABLED 1
35 #include <sanitizer/msan_interface.h>
36 #endif
37 #endif
38
39 #include "c_types_map.hpp"
40
41 namespace mkldnn {
42 namespace impl {
43
44 // Sanity check for 64 bits
45 static_assert(sizeof(void*) == 8, "Intel(R) MKL-DNN supports 64 bit only");
46
47 #define UNUSED(x) ((void)x)
48 #define MAYBE_UNUSED(x) UNUSED(x)
49
50 #define CHECK(f) do { \
51     status_t status = f; \
52     if (status != status::success) \
53     return status; \
54 } while (0)
55
56 #define IMPLICATION(cause, effect) (!(cause) || !!(effect))
57
58 #if defined(_WIN32) && !defined(__GNUC__)
59 #define __PRETTY_FUNCTION__ __FUNCSIG__
60 #endif
61
62 namespace utils {
63
64 /* a bunch of std:: analogues to be compliant with any msvs version
65  *
66  * Rationale: msvs c++ (and even some c) headers contain special pragma that
67  * injects msvs-version check into object files in order to abi-mismatches
68  * during the static linking. This makes sense if e.g. std:: objects are passed
69  * through between application and library, which is not the case for mkl-dnn
70  * (since there is no any c++-rt dependent stuff, ideally...). */
71
72 /* SFINAE helper -- analogue to std::enable_if */
73 template<bool expr, class T = void> struct enable_if {};
74 template<class T> struct enable_if<true, T> { typedef T type; };
75
76 /* analogue std::conditional */
77 template <bool, typename, typename> struct conditional {};
78 template <typename T, typename F> struct conditional<true, T, F>
79 { typedef T type; };
80 template <typename T, typename F> struct conditional<false, T, F>
81 { typedef F type; };
82
83 template <bool, typename, bool, typename, typename> struct conditional3 {};
84 template <typename T, typename FT, typename FF>
85 struct conditional3<true, T, false, FT, FF> { typedef T type; };
86 template <typename T, typename FT, typename FF>
87 struct conditional3<false, T, true, FT, FF> { typedef FT type; };
88 template <typename T, typename FT, typename FF>
89 struct conditional3<false, T, false, FT, FF> { typedef FF type; };
90
91 template <bool, typename U, U, U> struct conditional_v {};
92 template <typename U, U t, U f> struct conditional_v<true, U, t, f>
93 { static constexpr U value = t; };
94 template <typename U, U t, U f> struct conditional_v<false, U, t, f>
95 { static constexpr U value = f; };
96
97 template <typename T> struct remove_reference { typedef T type; };
98 template <typename T> struct remove_reference<T&> { typedef T type; };
99 template <typename T> struct remove_reference<T&&> { typedef T type; };
100
101 template <typename T>
102 inline T&& forward(typename utils::remove_reference<T>::type &t)
103 { return static_cast<T&&>(t); }
104 template <typename T>
105 inline T&& forward(typename utils::remove_reference<T>::type &&t)
106 { return static_cast<T&&>(t); }
107
108 template <typename T>
109 inline typename remove_reference<T>::type zero()
110 { auto zero = typename remove_reference<T>::type(); return zero; }
111
112 template <typename T, typename P>
113 inline bool everyone_is(T val, P item) { return val == item; }
114 template <typename T, typename P, typename... Args>
115 inline bool everyone_is(T val, P item, Args... item_others) {
116     return val == item && everyone_is(val, item_others...);
117 }
118
119 template <typename T, typename P>
120 constexpr bool one_of(T val, P item) { return val == item; }
121 template <typename T, typename P, typename... Args>
122 constexpr bool one_of(T val, P item, Args... item_others) {
123     return val == item || one_of(val, item_others...);
124 }
125
126 template <typename... Args>
127 inline bool any_null(Args... ptrs) { return one_of(nullptr, ptrs...); }
128
129 template<typename T>
130 inline void array_copy(T *dst, const T *src, size_t size) {
131     for (size_t i = 0; i < size; ++i) dst[i] = src[i];
132 }
133 template<typename T>
134 inline bool array_cmp(const T *a1, const T *a2, size_t size) {
135     for (size_t i = 0; i < size; ++i) if (a1[i] != a2[i]) return false;
136     return true;
137 }
138 template<typename T, typename U>
139 inline void array_set(T *arr, const U& val, size_t size) {
140     for (size_t i = 0; i < size; ++i) arr[i] = static_cast<T>(val);
141 }
142
143 namespace product_impl {
144 template<size_t> struct int2type{};
145
146 template <typename T>
147 constexpr int product_impl(const T *arr, int2type<0>) { return arr[0]; }
148
149 template <typename T, size_t num>
150 inline T product_impl(const T *arr, int2type<num>) {
151     return arr[0]*product_impl(arr+1, int2type<num-1>()); }
152 }
153
154 template <size_t num, typename T>
155 inline T array_product(const T *arr) {
156     return product_impl::product_impl(arr, product_impl::int2type<num-1>());
157 }
158
159 template<typename T, typename R = T>
160 inline R array_product(const T *arr, size_t size) {
161     R prod = 1;
162     for (size_t i = 0; i < size; ++i) prod *= arr[i];
163     return prod;
164 }
165
166 template <typename T, typename U>
167 inline typename remove_reference<T>::type div_up(const T a, const U b) {
168     assert(b);
169     return (a + b - 1) / b;
170 }
171
172 template <typename T, typename U>
173 inline typename remove_reference<T>::type rnd_up(const T a, const U b) {
174     return div_up(a, b) * b;
175 }
176
177 template <typename T, typename U>
178 inline typename remove_reference<T>::type rnd_dn(const T a, const U b) {
179     return (a / b) * b;
180 }
181
182 template <typename T> T *align_ptr(T *ptr, uintptr_t alignment)
183 { return (T *)(((uintptr_t)ptr + alignment - 1) & ~(alignment - 1)); }
184
185 template <typename T, typename U, typename V>
186 inline U this_block_size(const T offset, const U max, const V block_size) {
187     assert(offset < max);
188     // TODO (Roma): can't use nstl::max() due to circular dependency... we
189     // need to fix this
190     const T block_boundary = offset + block_size;
191     if (block_boundary > max)
192         return max - offset;
193     else
194         return block_size;
195 }
196
197 template<typename T>
198 inline T nd_iterator_init(T start) { return start; }
199 template<typename T, typename U, typename W, typename... Args>
200 inline T nd_iterator_init(T start, U &x, const W &X, Args &&... tuple) {
201     start = nd_iterator_init(start, utils::forward<Args>(tuple)...);
202     x = start % X;
203     return start / X;
204 }
205
206 inline bool nd_iterator_step() { return true; }
207 template<typename U, typename W, typename... Args>
208 inline bool nd_iterator_step(U &x, const W &X, Args &&... tuple) {
209     if (nd_iterator_step(utils::forward<Args>(tuple)...) ) {
210         x = (x + 1) % X;
211         return x == 0;
212     }
213     return false;
214 }
215
216 template<typename U, typename W, typename Y>
217 inline bool nd_iterator_jump(U &cur, const U end, W &x, const Y &X)
218 {
219     U max_jump = end - cur;
220     U dim_jump = X - x;
221     if (dim_jump <= max_jump) {
222         x = 0;
223         cur += dim_jump;
224         return true;
225     } else {
226         cur += max_jump;
227         x += max_jump;
228         return false;
229     }
230 }
231 template<typename U, typename W, typename Y, typename... Args>
232 inline bool nd_iterator_jump(U &cur, const U end, W &x, const Y &X,
233         Args &&... tuple)
234 {
235     if (nd_iterator_jump(cur, end, utils::forward<Args>(tuple)...)) {
236         x = (x + 1) % X;
237         return x == 0;
238     }
239     return false;
240 }
241
242 template <typename T>
243 inline T pick(size_t i, const T &x0) { return x0; }
244 template <typename T, typename ...Args>
245 inline T pick(size_t i, const T &x0, Args &&... args) {
246     return i == 0 ? x0 : pick(i - 1, utils::forward<Args>(args)...);
247 }
248
249 template <typename T>
250 T pick_by_prop_kind(prop_kind_t prop_kind, const T &val_fwd_inference,
251         const T &val_fwd_training, const T &val_bwd_d, const T &val_bwd_w) {
252     switch (prop_kind) {
253     case prop_kind::forward_inference: return val_fwd_inference;
254     case prop_kind::forward_training: return val_fwd_training;
255     case prop_kind::backward_data: return val_bwd_d;
256     case prop_kind::backward_weights: return val_bwd_w;
257     default: assert(!"unsupported prop_kind");
258     }
259     return T();
260 }
261
262 template <typename T>
263 T pick_by_prop_kind(prop_kind_t prop_kind,
264         const T &val_fwd, const T &val_bwd_d, const T &val_bwd_w)
265 { return pick_by_prop_kind(prop_kind, val_fwd, val_fwd, val_bwd_d, val_bwd_w); }
266
267 template <typename Telem, size_t Tdims>
268 struct array_offset_calculator {
269     template <typename... Targs>
270     array_offset_calculator(Telem *base, Targs... Fargs) : _dims{ Fargs... }
271     {
272         _base_ptr = base;
273     }
274     template <typename... Targs>
275     inline Telem &operator()(Targs... Fargs)
276     {
277         return *(_base_ptr + _offset(1, Fargs...));
278     }
279
280 private:
281     template <typename... Targs>
282     inline size_t _offset(size_t const dimension, size_t element)
283     {
284         return element;
285     }
286
287     template <typename... Targs>
288     inline size_t _offset(size_t const dimension, size_t theta, size_t element)
289     {
290         return element + (_dims[dimension] * theta);
291     }
292
293     template <typename... Targs>
294     inline size_t _offset(size_t const dimension, size_t theta, size_t element,
295             Targs... Fargs)
296     {
297         size_t t_prime = element + (_dims[dimension] * theta);
298         return _offset(dimension + 1, t_prime, Fargs...);
299     }
300
301     Telem *_base_ptr;
302     const int _dims[Tdims];
303 };
304
305 }
306
307 void *malloc(size_t size, int alignment);
308 void free(void *p);
309 int32_t mkldnn_fetch_and_add(int32_t *dst, int32_t val);
310
311 struct c_compatible {
312     enum { default_alignment = 64 };
313     static void *operator new(size_t sz) {
314         return malloc(sz, default_alignment);
315     }
316     static void *operator new(size_t sz, void *p) { UNUSED(sz); return p; }
317     static void *operator new[](size_t sz) {
318         return malloc(sz, default_alignment);
319     }
320     static void operator delete(void *p) { free(p); }
321     static void operator delete[](void *p) { free(p); }
322 };
323
324 inline void yield_thread() { }
325
326 int mkldnn_getenv(char *value, const char *name, int len);
327 bool mkldnn_jit_dump();
328 FILE *mkldnn_fopen(const char *filename, const char *mode);
329
330 void set_rnd_mode(round_mode_t rnd_mode);
331 void restore_rnd_mode();
332
333 constexpr int msan_enabled = MSAN_ENABLED;
334 inline void msan_unpoison(void *ptr, size_t size) {
335 #if MSAN_ENABLED
336     __msan_unpoison(ptr, size);
337 #endif
338 }
339
340 unsigned int get_cache_size(int level, bool per_core);
341
342 }
343 }
344
345 #endif
346
347 // vim: et ts=4 sw=4 cindent cino^=l0,\:0,N-s