Imported Upstream version 1.12.0
[platform/core/ml/nnfw.git] / compute / ARMComputeEx / src / core / CL / cl_kernels / pixelwise_mul_quantized.cl
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd. 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 /*
18  * Copyright (c) 2016, 2017 ARM Limited.
19  *
20  * SPDX-License-Identifier: MIT
21  *
22  * Permission is hereby granted, free of charge, to any person obtaining a copy
23  * of this software and associated documentation files (the "Software"), to
24  * deal in the Software without restriction, including without limitation the
25  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
26  * sell copies of the Software, and to permit persons to whom the Software is
27  * furnished to do so, subject to the following conditions:
28  *
29  * The above copyright notice and this permission notice shall be included in all
30  * copies or substantial portions of the Software.
31  *
32  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
38  * SOFTWARE.
39  */
40
41 #include "helpers_asymm.h"
42
43 #ifdef SATURATE
44 #define CONVERT_OP_FLOAT_STR(x, type, round) (convert_##type##_sat##round(x))
45 #else /* SATURATE */
46 #define CONVERT_OP_FLOAT_STR(x, type, round) (convert_##type##round(x))
47 #endif /* SATURATE */
48 #define CONVERT_OP_FLOAT(x, type, round) CONVERT_OP_FLOAT_STR(x, type, round)
49
50 #if defined(RESULT_OFFSET) && defined(RESULT_MULT_INT) && defined(RESULT_SHIFT)
51 /** Performs a pixelwise multiplication used to quantize down the int32 accumulator values of
52  *  GEMMLowp to QASYMM8
53  *
54  * The following computations will be performed by the kernel:
55  *
56  *  -# Add offset terms to inputs
57  *  -# Multiply inputs
58  *  -# Add offset terms to final result
59  *  -# Multiply each entry of result by result_mult_int
60  *  -# Shift the int32 accumulator by result_shift
61  *  -# Clamp the resulting int32 values to the [0..255] range and cast to QASYMM8.
62  *
63  * @attention The inputs and output data types need to be passed at compile time using
64  *            -DDATA_TYPE_IN1, -DDATA_TYPE_IN2 and -DDATA_TYPE_OUT:
65  *            e.g. -DDATA_TYPE_IN1=uchar -DDATA_TYPE_IN2=uchar -DDATA_TYPE_OUT=uchar
66  * @attention The offset factor of inputs must be passed at compile time using -DIN1_OFFSET and
67  *            -DIN2_OFFSET
68  * @attention The offset, scalar scale factor and number of bits to shift right of output tensor
69  *            must be passed at compile time using -DRESULT_OFFSET, -RESULT_MULT_INT and
70  *            -DRESULT_SHIFT
71  *
72  * @param[in]  in1_ptr                           Pointer to the source image. Supported data types:
73  *                                               U8
74  * @param[in]  in1_stride_x                      Stride of the source image in X dimension (in
75  *                                               bytes)
76  * @param[in]  in1_step_x                        in1_stride_x * number of elements along X processed
77  *                                               per workitem(in bytes)
78  * @param[in]  in1_stride_y                      Stride of the source image in Y dimension (in
79  *                                               bytes)
80  * @param[in]  in1_step_y                        in1_stride_y * number of elements along Y processed
81  *                                               per workitem(in bytes)
82  * @param[in]  in1_stride_z                      Stride of the source image in Y dimension (in
83  *                                               bytes)
84  * @param[in]  in1_step_z                        in1_stride_z * number of elements along Y processed
85  *                                               per workitem(in bytes)
86  * @param[in]  in1_offset_first_element_in_bytes The offset of the first element in the source image
87  * @param[in]  in2_ptr                           Pointer to the source image. Supported data types:
88  *                                               U8
89  * @param[in]  in2_stride_x                      Stride of the source image in X dimension (in
90  *                                               bytes)
91  * @param[in]  in2_step_x                        in2_stride_x * number of elements along X processed
92  *                                               per workitem(in bytes)
93  * @param[in]  in2_stride_y                      Stride of the source image in Y dimension (in
94  *                                               bytes)
95  * @param[in]  in2_step_y                        in2_stride_y * number of elements along Y processed
96  *                                               per workitem(in bytes)
97  * @param[in]  in2_stride_z                      Stride of the source image in Y dimension (in
98  *                                               bytes)
99  * @param[in]  in2_step_z                        in2_stride_z * number of elements along Y processed
100  *                                               per workitem(in bytes)
101  * @param[in]  in2_offset_first_element_in_bytes The offset of the first element in the source image
102  * @param[out] out_ptr                           Pointer to the destination image. Supported data
103  *                                               types: U8
104  * @param[in]  out_stride_x                      Stride of the destination image in X dimension (in
105  *                                               bytes)
106  * @param[in]  out_step_x                        out_stride_x * number of elements along X processed
107  *                                               per workitem(in bytes)
108  * @param[in]  out_stride_y                      Stride of the destination image in Y dimension (in
109  *                                              bytes)
110  * @param[in]  out_step_y                        out_stride_y * number of elements along Y processed
111  *                                               per workitem(in bytes)
112  * @param[in]  out_stride_z                      Stride of the destination image in Y dimension (in
113  *                                               bytes)
114  * @param[in]  out_step_z                        out_stride_z * number of elements along Y processed
115  *                                               per workitem(in bytes)
116  * @param[in]  out_offset_first_element_in_bytes The offset of the first element in the destination
117  *                                               image
118  * @param[in]  scale                             Float scaling factor. Supported data types: F32
119  */
120 __kernel void pixelwise_mul_qasymm8(TENSOR3D_DECLARATION(in1), TENSOR3D_DECLARATION(in2),
121                                     TENSOR3D_DECLARATION(out), const float scale)
122 {
123   // Get pixels pointer
124   Tensor3D in1 = CONVERT_TO_TENSOR3D_STRUCT(in1);
125   Tensor3D in2 = CONVERT_TO_TENSOR3D_STRUCT(in2);
126   Tensor3D out = CONVERT_TO_TENSOR3D_STRUCT(out);
127
128   // Load data
129   VEC_DATA_TYPE(int, 16)
130   in1_data = CONVERT(vload16(0, (__global DATA_TYPE_IN1 *)in1.ptr), VEC_DATA_TYPE(int, 16));
131   VEC_DATA_TYPE(int, 16)
132   in2_data = CONVERT(vload16(0, (__global DATA_TYPE_IN2 *)in2.ptr), VEC_DATA_TYPE(int, 16));
133
134   // Perform multiplication of two inputs
135   VEC_DATA_TYPE(int, 16) in1_val = in1_data + (VEC_DATA_TYPE(int, 16))(IN1_OFFSET);
136   VEC_DATA_TYPE(int, 16) in2_val = in2_data + (VEC_DATA_TYPE(int, 16))(IN2_OFFSET);
137   VEC_DATA_TYPE(int, 16) out_val = in1_val * in2_val;
138
139   // Multiply with a multiplier smaller than 1
140   out_val =
141     ASYMM_MULT_BY_QUANT_MULTIPLIER_LESS_THAN_ONE(out_val, RESULT_MULT_INT, RESULT_SHIFT, 16);
142   out_val += (VEC_DATA_TYPE(int, 16))(RESULT_OFFSET);
143
144   VEC_DATA_TYPE(uchar, 16) res = CONVERT(out_val, VEC_DATA_TYPE(uchar, 16));
145
146   // TODO: Apply min-max BOUND to support fuse with relu.
147   /*
148   #if defined(MIN_BOUND)
149       res = max(res, (uchar16)MIN_BOUND);
150   #endif // defined(MIN_BOUND)
151   #if defined(MAX_BOUND)
152       res = min(res, (uchar16)MAX_BOUND);
153   #endif // defined(MAX_BOUND)
154   */
155
156   // Store result
157   VSTORE(16)(CONVERT(res, VEC_DATA_TYPE(DATA_TYPE_OUT, 16)), 0, (__global DATA_TYPE_OUT *)out.ptr);
158 }
159 #endif // defined(RESULT_OFFSET) && defined(RESULT_MULT_INT) && defined(RESULT_SHIFT)