xref: /aosp_15_r20/external/ComputeLibrary/tests/validation/reference/ArithmeticOperations.cpp (revision c217d954acce2dbc11938adb493fc0abd69584f3)
1 /*
2  * Copyright (c) 2017-2020 Arm Limited.
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 #include "ArithmeticOperations.h"
25 
26 #include "arm_compute/core/Types.h"
27 #include "tests/validation/Helpers.h"
28 
29 namespace arm_compute
30 {
31 namespace test
32 {
33 namespace validation
34 {
35 namespace reference
36 {
37 namespace
38 {
39 template <typename T>
arithm_op(ArithmeticOperation op,T src1,T src2,ConvertPolicy convert_policy)40 T arithm_op(ArithmeticOperation op, T src1, T src2, ConvertPolicy convert_policy)
41 {
42     using intermediate_type = typename common_promoted_signed_type<T>::intermediate_type;
43 
44     intermediate_type val = (op == ArithmeticOperation::ADD) ? static_cast<intermediate_type>(src1) + static_cast<intermediate_type>(src2) : static_cast<intermediate_type>
45                             (src1) - static_cast<intermediate_type>(src2);
46 
47     T result = (convert_policy == ConvertPolicy::SATURATE) ? saturate_cast<T>(val) : static_cast<T>(val);
48 
49     return result;
50 }
51 
52 template <size_t dim>
53 struct BroadcastUnroll
54 {
55     template <typename T>
unrollarm_compute::test::validation::reference::__anon8d22d9810111::BroadcastUnroll56     static void unroll(ArithmeticOperation op, const SimpleTensor<T> &src1, const SimpleTensor<T> &src2, SimpleTensor<T> &dst,
57                        ConvertPolicy convert_policy, Coordinates &id_src1, Coordinates &id_src2, Coordinates &id_dst)
58     {
59         const bool src1_is_broadcast = (src1.shape()[dim - 1] != dst.shape()[dim - 1]);
60         const bool src2_is_broadcast = (src2.shape()[dim - 1] != dst.shape()[dim - 1]);
61 
62         id_src1.set(dim - 1, 0);
63         id_src2.set(dim - 1, 0);
64         id_dst.set(dim - 1, 0);
65 #if defined(_OPENMP)
66         #pragma omp parallel for
67 #endif /* _OPENMP */
68         for(size_t i = 0; i < dst.shape()[dim - 1]; ++i)
69         {
70             BroadcastUnroll < dim - 1 >::unroll(op, src1, src2, dst, convert_policy, id_src1, id_src2, id_dst);
71 
72             id_src1[dim - 1] += !src1_is_broadcast;
73             id_src2[dim - 1] += !src2_is_broadcast;
74             ++id_dst[dim - 1];
75         }
76     }
77 };
78 
79 template <>
80 struct BroadcastUnroll<0>
81 {
82     template <typename T>
unrollarm_compute::test::validation::reference::__anon8d22d9810111::BroadcastUnroll83     static void unroll(ArithmeticOperation op, const SimpleTensor<T> &src1, const SimpleTensor<T> &src2, SimpleTensor<T> &dst,
84                        ConvertPolicy convert_policy, Coordinates &id_src1, Coordinates &id_src2, Coordinates &id_dst)
85     {
86         dst[coord2index(dst.shape(), id_dst)] = arithm_op(op, src1[coord2index(src1.shape(), id_src1)], src2[coord2index(src2.shape(), id_src2)], convert_policy);
87     }
88 };
89 } // namespace
90 
91 template <typename T>
arithmetic_operation(ArithmeticOperation op,const SimpleTensor<T> & src1,const SimpleTensor<T> & src2,SimpleTensor<T> & dst,ConvertPolicy convert_policy)92 SimpleTensor<T> arithmetic_operation(ArithmeticOperation op, const SimpleTensor<T> &src1, const SimpleTensor<T> &src2, SimpleTensor<T> &dst, ConvertPolicy convert_policy)
93 {
94     Coordinates id_src1{};
95     Coordinates id_src2{};
96     Coordinates id_dst{};
97 
98     BroadcastUnroll<Coordinates::num_max_dimensions>::unroll(op, src1, src2, dst, convert_policy, id_src1, id_src2, id_dst);
99 
100     return dst;
101 }
102 
103 template <>
arithmetic_operation(ArithmeticOperation op,const SimpleTensor<uint8_t> & src1,const SimpleTensor<uint8_t> & src2,SimpleTensor<uint8_t> & dst,ConvertPolicy convert_policy)104 SimpleTensor<uint8_t> arithmetic_operation(ArithmeticOperation op, const SimpleTensor<uint8_t> &src1, const SimpleTensor<uint8_t> &src2, SimpleTensor<uint8_t> &dst, ConvertPolicy convert_policy)
105 {
106     Coordinates id_src1{};
107     Coordinates id_src2{};
108     Coordinates id_dst{};
109 
110     if(dst.data_type() == DataType::QASYMM8)
111     {
112         SimpleTensor<float> src1_tmp = convert_from_asymmetric(src1);
113         SimpleTensor<float> src2_tmp = convert_from_asymmetric(src2);
114         SimpleTensor<float> dst_tmp(TensorShape::broadcast_shape(src1.shape(), src2.shape()), dst.data_type());
115 
116         BroadcastUnroll<Coordinates::num_max_dimensions>::unroll(op, src1_tmp, src2_tmp, dst_tmp, convert_policy, id_src1, id_src2, id_dst);
117 
118         dst = convert_to_asymmetric<uint8_t>(dst_tmp, dst.quantization_info());
119         return dst;
120     }
121     else
122     {
123         // DataType::U8
124         BroadcastUnroll<Coordinates::num_max_dimensions>::unroll(op, src1, src2, dst, convert_policy, id_src1, id_src2, id_dst);
125 
126         return dst;
127     }
128 }
129 
130 template <>
arithmetic_operation(ArithmeticOperation op,const SimpleTensor<int8_t> & src1,const SimpleTensor<int8_t> & src2,SimpleTensor<int8_t> & dst,ConvertPolicy convert_policy)131 SimpleTensor<int8_t> arithmetic_operation(ArithmeticOperation op, const SimpleTensor<int8_t> &src1, const SimpleTensor<int8_t> &src2, SimpleTensor<int8_t> &dst, ConvertPolicy convert_policy)
132 {
133     Coordinates id_src1{};
134     Coordinates id_src2{};
135     Coordinates id_dst{};
136 
137     if(dst.data_type() == DataType::QASYMM8_SIGNED)
138     {
139         SimpleTensor<float> src1_tmp = convert_from_asymmetric(src1);
140         SimpleTensor<float> src2_tmp = convert_from_asymmetric(src2);
141         SimpleTensor<float> dst_tmp(TensorShape::broadcast_shape(src1.shape(), src2.shape()), dst.data_type());
142 
143         BroadcastUnroll<Coordinates::num_max_dimensions>::unroll(op, src1_tmp, src2_tmp, dst_tmp, convert_policy, id_src1, id_src2, id_dst);
144 
145         dst = convert_to_asymmetric<int8_t>(dst_tmp, dst.quantization_info());
146         return dst;
147     }
148     else
149     {
150         // DataType::S8
151         BroadcastUnroll<Coordinates::num_max_dimensions>::unroll(op, src1, src2, dst, convert_policy, id_src1, id_src2, id_dst);
152 
153         return dst;
154     }
155 }
156 
157 template <>
arithmetic_operation(ArithmeticOperation op,const SimpleTensor<int16_t> & src1,const SimpleTensor<int16_t> & src2,SimpleTensor<int16_t> & dst,ConvertPolicy convert_policy)158 SimpleTensor<int16_t> arithmetic_operation(ArithmeticOperation op, const SimpleTensor<int16_t> &src1, const SimpleTensor<int16_t> &src2, SimpleTensor<int16_t> &dst, ConvertPolicy convert_policy)
159 {
160     Coordinates id_src1{};
161     Coordinates id_src2{};
162     Coordinates id_dst{};
163 
164     if(dst.data_type() == DataType::QSYMM16)
165     {
166         SimpleTensor<float> src1_tmp = convert_from_symmetric<int16_t>(src1);
167         SimpleTensor<float> src2_tmp = convert_from_symmetric<int16_t>(src2);
168         SimpleTensor<float> dst_tmp(TensorShape::broadcast_shape(src1.shape(), src2.shape()), dst.data_type());
169 
170         BroadcastUnroll<Coordinates::num_max_dimensions>::unroll(op, src1_tmp, src2_tmp, dst_tmp, convert_policy, id_src1, id_src2, id_dst);
171 
172         dst = convert_to_symmetric<int16_t>(dst_tmp, dst.quantization_info());
173         return dst;
174     }
175     else
176     {
177         // DataType::S16
178         BroadcastUnroll<Coordinates::num_max_dimensions>::unroll(op, src1, src2, dst, convert_policy, id_src1, id_src2, id_dst);
179         return dst;
180     }
181 }
182 
183 template SimpleTensor<int32_t> arithmetic_operation(ArithmeticOperation op, const SimpleTensor<int32_t> &src1, const SimpleTensor<int32_t> &src2, SimpleTensor<int32_t> &dst, ConvertPolicy convert_policy);
184 template SimpleTensor<half> arithmetic_operation(ArithmeticOperation op, const SimpleTensor<half> &src1, const SimpleTensor<half> &src2, SimpleTensor<half> &dst, ConvertPolicy convert_policy);
185 template SimpleTensor<float> arithmetic_operation(ArithmeticOperation op, const SimpleTensor<float> &src1, const SimpleTensor<float> &src2, SimpleTensor<float> &dst, ConvertPolicy convert_policy);
186 
187 template <typename T>
arithmetic_operation(ArithmeticOperation op,const SimpleTensor<T> & src1,const SimpleTensor<T> & src2,DataType dst_data_type,ConvertPolicy convert_policy)188 SimpleTensor<T> arithmetic_operation(ArithmeticOperation op, const SimpleTensor<T> &src1, const SimpleTensor<T> &src2, DataType dst_data_type, ConvertPolicy convert_policy)
189 {
190     ARM_COMPUTE_ERROR_ON_MSG(is_data_type_quantized(dst_data_type), "For quantized input data types, the quantized output tensor should be passed directly.");
191 
192     SimpleTensor<T> dst(TensorShape::broadcast_shape(src1.shape(), src2.shape()), dst_data_type);
193     arithmetic_operation<T>(op, src1, src2, dst, convert_policy);
194     return dst;
195 }
196 
197 template SimpleTensor<int32_t> arithmetic_operation(ArithmeticOperation op, const SimpleTensor<int32_t> &src1, const SimpleTensor<int32_t> &src2, DataType dst_data_type, ConvertPolicy convert_policy);
198 template SimpleTensor<int16_t> arithmetic_operation(ArithmeticOperation op, const SimpleTensor<int16_t> &src1, const SimpleTensor<int16_t> &src2, DataType dst_data_type, ConvertPolicy convert_policy);
199 template SimpleTensor<int8_t> arithmetic_operation(ArithmeticOperation op, const SimpleTensor<int8_t> &src1, const SimpleTensor<int8_t> &src2, DataType dst_data_type, ConvertPolicy convert_policy);
200 template SimpleTensor<half> arithmetic_operation(ArithmeticOperation op, const SimpleTensor<half> &src1, const SimpleTensor<half> &src2, DataType dst_data_type, ConvertPolicy convert_policy);
201 template SimpleTensor<float> arithmetic_operation(ArithmeticOperation op, const SimpleTensor<float> &src1, const SimpleTensor<float> &src2, DataType dst_data_type, ConvertPolicy convert_policy);
202 
203 } // namespace reference
204 } // namespace validation
205 } // namespace test
206 } // namespace arm_compute
207