1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/*******************************************************************************
* Copyright 2016 Intel Corporation
*
* 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 CPU_REORDER_CPU_REORDER_PD_HPP
#define CPU_REORDER_CPU_REORDER_PD_HPP
#include <assert.h>
#include "common/c_types_map.hpp"
#include "common/reorder_pd.hpp"
#include "common/utils.hpp"
#include "cpu/cpu_engine.hpp"
namespace dnnl {
namespace impl {
namespace cpu {
struct cpu_reorder_pd_t : public reorder_pd_t {
using reorder_pd_t::reorder_pd_t;
status_t init(
engine_t *engine, engine_t *src_engine, engine_t *dst_engine) {
const auto &post_ops = attr()->post_ops_;
bool args_ok = IMPLICATION(post_ops.len() != 0,
post_ops.len() == 1
&& post_ops.entry_[0].kind == primitive_kind::sum);
VDISPATCH_REORDER(args_ok, VERBOSE_UNSUPPORTED_POSTOP);
auto gpu_zp = memory_extra_flags::compensation_gpu_conv_asymmetric_src;
VDISPATCH_REORDER(!(dst_md()->extra.flags & gpu_zp),
VERBOSE_UNSUPPORTED_MD_FLAG, "extra");
return status::success;
}
// The function splits dimension products based on input mask and returns
// them as `D_start`, `D_mask` and `D_rest`.
// Its used to estimate amount of memory for scratchpad and precomputed
// destination scales.
void get_D_values(const memory_desc_wrapper &input_d, int mask,
dim_t *D_start, dim_t *D_mask, dim_t *D_rest) const {
int ndims = input_d.ndims();
int ndims_start = 0, ndims_mask = 0;
// XXX: Currently user can pass a mask that has non-zero values in
// dimensions that do not exist in a md. Since attributes are created
// separately mask can't be validated.
// This line truncates a given mask in range [0, 1 << ndims - 1]
// TODO: Such masks can be either prohibited at pd creation step at
// API level or checked by each implementation that relies on it.
mask &= (1 << ndims) - 1;
for (; mask > 0 && !(mask & 0x1); mask >>= 1)
++ndims_start;
for (; mask > 0 && mask & 0x1; mask >>= 1)
++ndims_mask;
assert(mask == 0);
if (D_start)
*D_start = utils::array_product(input_d.dims(), ndims_start);
if (D_mask) {
*D_mask = utils::array_product(
input_d.dims() + ndims_start, ndims_mask);
assert(*D_mask >= 1);
}
if (D_rest && D_start && D_mask)
*D_rest = input_d.nelems() / (*D_start * *D_mask);
}
// The function serves same purpose as `dnnl::impl::cpu::precompute_scales`.
// The reason it's dedicated to reorder is it's the only primitive so far
// that utilizes `mask > 0` for destination scales.
const float *precompute_scales(const memory_tracking::grantor_t &scratchpad,
const primitive_attr_t *attr, size_t count,
const float *dst_scales) const {
using namespace dnnl::impl::memory_tracking::names;
if (attr->scales_.has_default_values(DNNL_ARG_DST)) {
return dst_scales;
}
// It's possible that mask > 0 but `count` is still `1`. This case is
// covered by `DEFINE_ARG_SCALES_BUFFER` macro and no need to inverse
// in such case.
int mask = attr->scales_.get_mask(DNNL_ARG_DST);
if (mask > 0 && count > 1) {
auto loc_scales = scratchpad.template get<float>(
key_reorder_precomputed_dst_scales);
if (!loc_scales) return nullptr;
PRAGMA_OMP_SIMD()
for (size_t c = 0; c < count; c++)
loc_scales[c] = 1.f / dst_scales[c];
return loc_scales;
} else {
return dst_scales;
}
}
};
} // namespace cpu
} // namespace impl
} // namespace dnnl
#endif
// vim: et ts=4 sw=4 cindent cino+=l0,\:4,N-s