1 /**
2 * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved.
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 AICPU_UTILS_KERNEL_UTIL_H_
18 #define AICPU_UTILS_KERNEL_UTIL_H_
19
20 #include <climits>
21 #include <cmath>
22 #include <sstream>
23 #include <string>
24 #include <vector>
25 #include <map>
26 #include <memory>
27
28 #include "inc/cpu_context.h"
29 #include "inc/kernel_log.h"
30 #include "context/common/status.h"
31
32 namespace aicpu {
33 constexpr uint32_t kResvCpuNum = 2;
34 constexpr uint32_t kThreadNum = 32;
35 constexpr uint32_t kFirstInputIndex = 0;
36 constexpr uint32_t kSecondInputIndex = 1;
37 constexpr uint32_t kThirdInputIndex = 2;
38 constexpr uint32_t kFourthInputIndex = 3;
39 constexpr uint32_t kFirstOutputIndex = 0;
40 constexpr uint32_t kSecondOutputIndex = 1;
41 constexpr uint32_t kDynamicInput = -1;
42 constexpr uint32_t kDynamicOutput = -2;
43 constexpr uint64_t kEigenAlignmentBytes = 16;
44
45 constexpr uint64_t kFormatNCHWIndexN = 0;
46 constexpr uint64_t kFormatNCHWIndexC = 1;
47 constexpr uint64_t kFormatNCHWIndexH = 2;
48 constexpr uint64_t kFormatNCHWIndexW = 3;
49
50 constexpr uint64_t kFormatNC1HWC0IndexN = 0;
51 constexpr uint64_t kFormatNC1HWC0IndexC1 = 1;
52 constexpr uint64_t kFormatNC1HWC0IndexH = 2;
53 constexpr uint64_t kFormatNC1HWC0IndexW = 3;
54 constexpr uint64_t kFormatNC1HWC0IndexC0 = 4;
55
56 constexpr uint64_t kFormatCHWIndexC = 0;
57 constexpr uint64_t kFormatCHWIndexH = 1;
58 constexpr uint64_t kFormatCHWIndexW = 2;
59
60 constexpr uint64_t kFormatNHWCIndexN = 0;
61 constexpr uint64_t kFormatNHWCIndexH = 1;
62 constexpr uint64_t kFormatNHWCIndexW = 2;
63 constexpr uint64_t kFormatNHWCIndexC = 3;
64
65 constexpr uint64_t kFormatHWCIndexH = 0;
66 constexpr uint64_t kFormatHWCIndexW = 1;
67 constexpr uint64_t kFormatHWCIndexC = 2;
68
69 const size_t INPUT_NUM0 = 0;
70 const size_t INPUT_NUM1 = 1;
71 const size_t INPUT_NUM2 = 2;
72 const size_t INPUT_NUM3 = 3;
73 const size_t INPUT_NUM4 = 4;
74 const size_t INPUT_NUM5 = 5;
75 const size_t INPUT_NUM6 = 6;
76 const size_t INPUT_NUM7 = 7;
77 const size_t INPUT_NUM8 = 8;
78 const size_t INPUT_NUM9 = 9;
79 const size_t INPUT_NUM32 = 32;
80
81 using TensorShapePtr = std::shared_ptr<TensorShape>;
82
83 /*
84 * str cat util function
85 * param[in] params need concat to string
86 * return concatted string
87 */
88 template <typename T>
ConcatString(T arg)89 std::string ConcatString(T arg) {
90 std::ostringstream oss;
91 oss << arg;
92 return oss.str();
93 }
94
95 template <typename T, typename... Ts>
ConcatString(T arg,Ts...arg_left)96 std::string ConcatString(T arg, Ts... arg_left) {
97 std::ostringstream oss;
98 oss << arg;
99 oss << ConcatString(arg_left...);
100 return oss.str();
101 }
102
103 /**
104 * @brief get debug string of vector
105 * @param values values in vector
106 * @return string of values
107 */
108 template <typename T>
VectorToString(const std::vector<T> & values)109 inline std::string VectorToString(const std::vector<T> &values) {
110 std::stringstream ss;
111 for (auto iter = values.begin(); iter != values.end(); ++iter) {
112 ss << *iter;
113 if (iter != values.end() - 1) {
114 ss << ", ";
115 }
116 }
117 return ss.str();
118 }
119
120 template <typename T>
FmtToStr(const T & t)121 std::string FmtToStr(const T &t) {
122 std::string fmt;
123 std::stringstream st;
124 st << "[" << t << "]";
125 fmt = st.str();
126 return fmt;
127 }
128
129 std::string FormatToSerialString(CpuKernelContext &ctx, Format format);
130
131 /**
132 * Get primary-format from format,
133 * in bits field:
134 * ------------------------------------------
135 * | 1 byte | 2 bytes | 1 byt |
136 * |----------|------------|----------------|
137 * | reserved | sub-format | primary-format |
138 * ------------------------------------------
139 * @param format
140 * @return
141 */
GetPrimaryFormat(int32_t format)142 inline int32_t GetPrimaryFormat(int32_t format) { return static_cast<int32_t>(static_cast<uint32_t>(format) & 0xff); }
143
GetSubFormat(int32_t format)144 inline int32_t GetSubFormat(int32_t format) {
145 return static_cast<int32_t>((static_cast<uint32_t>(format) & 0xffff00) >> 8);
146 }
147
HasSubFormat(int32_t format)148 inline bool HasSubFormat(int32_t format) { return GetSubFormat(format) > 0; }
149
150 /**
151 * @brief Judge whether tensor is empty
152 * @param tensor need judged tensor
153 * @return true: is empty tensor, false: isn't empty tensor
154 */
155 bool IsEmptyTensor(Tensor *tensor);
156
157 /**
158 * @brief multiply two nonnegative int64's
159 * @param x mul value x
160 * @param y mul value y
161 * @param xy product of x and y
162 * @return true: normal, false: overflow
163 */
MulWithoutOverflow(CpuKernelContext & ctx,const int64_t x,const int64_t y,int64_t & xy)164 inline bool MulWithoutOverflow(CpuKernelContext &ctx, const int64_t x, const int64_t y, int64_t &xy) {
165 // Multiply in uint64 rather than int64 since signed overflow is undefined.
166 // Negative values will wrap around to large unsigned values in the casts
167 // (see section 4.7 [conv.integral] of the C++14 standard).
168 const uint64_t ux = static_cast<uint64_t>(x);
169 const uint64_t uy = static_cast<uint64_t>(y);
170 const uint64_t uxy = ux * uy;
171
172 // Check if we overflow uint64, using a cheap check if both inputs are small
173 if ((ux | uy) >> 32 != 0) {
174 // Ensure nonnegativity. Note that negative numbers will appear "large"
175 // to the unsigned comparisons above.
176 if (x < 0 || y < 0) {
177 CUST_KERNEL_LOG_ERROR(ctx, "Can't multiply negative numbers.");
178 return false;
179 }
180
181 // Otherwise, detect overflow using a division
182 if (ux != 0 && uxy / ux != uy) {
183 return false;
184 }
185 }
186
187 // Cast back to signed. Any negative value will signal an error.
188 xy = static_cast<int64_t>(uxy);
189 return true;
190 }
191
192 /**
193 * @brief add two int64's
194 * @param x add value x
195 * @param y add value y
196 * @param sum sum of x and y
197 * @return true: normal, false: overflow
198 */
AddWithoutOverflow(const int64_t x,const int64_t y,int64_t & sum)199 inline bool AddWithoutOverflow(const int64_t x, const int64_t y, int64_t &sum) {
200 const uint64_t ux = static_cast<uint64_t>(x);
201 const uint64_t uy = static_cast<uint64_t>(y);
202 const uint64_t usum = ux + uy;
203 sum = static_cast<int64_t>(usum);
204
205 return !(((x >= 0) == (y >= 0)) && ((sum >= 0) != (x >= 0)));
206 }
207
208 /**
209 * @brief check two shape vector are same
210 * @param shape shape
211 * @param check_shape check_shape
212 * @return true: same, false: different
213 */
ShapeVectorIsSame(const std::vector<int64_t> & shape,const std::vector<int64_t> & check_shape)214 inline bool ShapeVectorIsSame(const std::vector<int64_t> &shape, const std::vector<int64_t> &check_shape) {
215 if (shape.size() != check_shape.size()) {
216 return false;
217 } else {
218 for (size_t index = 0; index < shape.size(); ++index) {
219 if (shape[index] != check_shape[index]) {
220 return false;
221 }
222 }
223 }
224 return true;
225 }
226
227 /**
228 * @brief normal check for calculation
229 * @param ctx context
230 * @return status code
231 */
232 uint32_t NormalMathCheck(CpuKernelContext &ctx);
233
234 /**
235 * @brief normal check for kernel
236 * @param ctx context
237 * @param inputs_num num of inputs
238 * @param outputs_num num of outputs
239 * @return status code
240 */
241 uint32_t NormalCheck(CpuKernelContext &ctx, const uint32_t inputs_num, const uint32_t outputs_num);
242
243 /**
244 * @brief normal check for kernel
245 * @param ctx context
246 * @param inputs_num num of inputs
247 * @param outputs_num num of outputs
248 * @param attr_names names of attrs
249 * @return status code
250 */
251 uint32_t NormalCheck(CpuKernelContext &ctx, const uint32_t inputs_num, const uint32_t outputs_num,
252 const std::vector<std::string> &attr_names);
253
254 bool IsScalar(const std::vector<int64_t> &shape);
255
256 bool IsMatrix(const std::vector<int64_t> &shape);
257
258 bool IsVector(const std::vector<int64_t> &shape);
259
260 bool IsSquareMatrix(const std::vector<int64_t> &shape);
261 /**
262 * @brief check if addr is aligned
263 * @param addr address for check
264 * @return true: aligned, false: not aligned
265 */
266 bool AddrAlignedCheck(const void *addr, uint64_t alignment = kEigenAlignmentBytes);
267
268 bool IsVectorOrHigher(const std::vector<int64_t> &shape);
269
270 /**
271 * @brief get data type from string
272 * @param dtype_str string of data type
273 * @return DataType
274 */
275 DataType DType(std::string dtype_str);
276
277 /**
278 * @brief get string from data type
279 * @param dtype data type
280 * @return string of data type
281 */
282 std::string DTypeStr(DataType dtype);
283
284 /**
285 * @brief check tensor type is same
286 * @param types a map with name and data type
287 * @param check_type check_type
288 * @param prim_name ops name
289 * @return status code
290 */
291 uint32_t CheckTensorTypeSame(CpuKernelContext &ctx, const std::map<std::string, DataType> &types,
292 const DataType &check_type, const std::string &prim_name);
293
294 /**
295 * @brief check tensor type is same
296 * @param shapes a map with name and shape
297 * @param check_type check_shape
298 * @param prim_name ops name
299 * @return status code
300 */
301 uint32_t CheckTensorShapeSame(CpuKernelContext &ctx, const std::map<std::string, TensorShapePtr> &shapes,
302 const std::vector<int64_t> &check_shape, const std::string &prim_name);
303
IntToSize(CpuKernelContext & ctx,int u)304 inline size_t IntToSize(CpuKernelContext &ctx, int u) {
305 if (u < 0) {
306 CUST_AICPU_LOGE(ctx, "The int value [%d] is less than 0.", u);
307 return SIZE_MAX;
308 }
309 return static_cast<size_t>(u);
310 }
311
SizeToInt(CpuKernelContext & ctx,size_t u)312 inline int SizeToInt(CpuKernelContext &ctx, size_t u) {
313 if (u > static_cast<size_t>((std::numeric_limits<int>::max)())) {
314 CUST_AICPU_LOGE(ctx, "The size_t value [%lu] exceeds the maximum value of int.", u);
315 return INT_MAX;
316 }
317 return static_cast<int>(u);
318 }
319
LongToSize(CpuKernelContext & ctx,int64_t u)320 inline size_t LongToSize(CpuKernelContext &ctx, int64_t u) {
321 if (u < 0) {
322 CUST_AICPU_LOGE(ctx, "The int64_t value [%ld] is less than 0.", u);
323 return SIZE_MAX;
324 }
325 return static_cast<size_t>(u);
326 }
327
LongToInt(CpuKernelContext & ctx,int64_t u)328 inline int32_t LongToInt(CpuKernelContext &ctx, int64_t u) {
329 if (u > static_cast<int64_t>((std::numeric_limits<int32_t>::max)())) {
330 CUST_AICPU_LOGE(ctx, "The size_t value [%ld] exceeds the maximum value of int.", u);
331 return INT_MAX;
332 }
333 return static_cast<int32_t>(u);
334 }
335 } // namespace aicpu
336 #endif
337