master
c 226 lines 7.79 KB
Raw
1 /*
2 * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 #include <stdio.h>
8 #include <stdint.h>
9 #include <stdbool.h>
10 #include <string.h>
11 #include <hexagon_types.h>
12 #include <hvx_hexagon_protos.h>
13
14 int err;
15 #include "hvx_misc.h"
16
17 #if __HEXAGON_ARCH__ > 75
18 #error "After v75, compiler will replace some FP HVX instructions."
19 #endif
20
21 /******************************************************************************
22 * NAN handling
23 *****************************************************************************/
24
25 #define isnan(X) \
26 (sizeof(X) == bytes_hf ? ((raw_hf(X) & ~0x8000) > 0x7c00) : \
27 ((raw_sf(X) & ~(1 << 31)) > 0x7f800000UL))
28
29 #define CHECK_NAN(A, DEF_NAN) (isnan(A) ? DEF_NAN : (A))
30 #define NAN_SF float_sf(0x7FFFFFFF)
31 #define NAN_HF float_hf(0x7FFF)
32 #define NAN_BF float_hf(0x7FFF)
33
34 /******************************************************************************
35 * Binary operations
36 *****************************************************************************/
37
38 #define DEF_TEST_OP_2(vop, op, type_res, type_arg) \
39 static void test_##vop##_##type_res##_##type_arg(void) \
40 { \
41 memset(expect, 0xff, sizeof(expect)); \
42 memset(output, 0xff, sizeof(output)); \
43 for (int i = 0; i < BUFSIZE; i++) { \
44 HVX_Vector *hvx_output = (HVX_Vector *)&output[i]; \
45 HVX_Vector hvx_buffer0 = *(HVX_Vector *)&buffer0[i]; \
46 HVX_Vector hvx_buffer1 = *(HVX_Vector *)&buffer1[i]; \
47 *hvx_output = \
48 Q6_V##type_res##_##vop##_V##type_arg##V##type_arg(hvx_buffer0, \
49 hvx_buffer1); \
50 for (int j = 0; j < MAX_VEC_SIZE_BYTES / bytes_##type_res; j++) { \
51 expect[i].type_res[j] = \
52 raw_##type_res(op(float_##type_arg(buffer0[i].type_arg[j]), \
53 float_##type_arg(buffer1[i].type_arg[j]))); \
54 } \
55 } \
56 check_output_##type_res(__LINE__, BUFSIZE); \
57 }
58
59 #define SUM(X, Y, DEF_NAN) CHECK_NAN((X) + (Y), DEF_NAN)
60 #define SUB(X, Y, DEF_NAN) CHECK_NAN((X) - (Y), DEF_NAN)
61 #define MULT(X, Y, DEF_NAN) CHECK_NAN((X) * (Y), DEF_NAN)
62
63 #define SUM_SF(X, Y) SUM(X, Y, NAN_SF)
64 #define SUM_HF(X, Y) SUM(X, Y, NAN_HF)
65 #define SUB_SF(X, Y) SUB(X, Y, NAN_SF)
66 #define SUB_HF(X, Y) SUB(X, Y, NAN_HF)
67 #define MULT_SF(X, Y) MULT(X, Y, NAN_SF)
68 #define MULT_HF(X, Y) MULT(X, Y, NAN_HF)
69
70 DEF_TEST_OP_2(vadd, SUM_SF, sf, sf);
71 DEF_TEST_OP_2(vadd, SUM_HF, hf, hf);
72 DEF_TEST_OP_2(vsub, SUB_SF, sf, sf);
73 DEF_TEST_OP_2(vsub, SUB_HF, hf, hf);
74 DEF_TEST_OP_2(vmpy, MULT_SF, sf, sf);
75 DEF_TEST_OP_2(vmpy, MULT_HF, hf, hf);
76
77 #define signbit_fp(X) \
78 (sizeof(X) == bytes_hf ? ((raw_hf(X) & 0x8000) != 0) : \
79 ((raw_sf(X) & 0x80000000) != 0))
80
81 #define STD_MIN(X, Y) ((X) < (Y) ? (X) : (Y))
82 #define STD_MAX(X, Y) ((X) > (Y) ? (X) : (Y))
83
84 #define MIN(X, Y, DEF_NAN) \
85 ((isnan(X) || isnan(Y)) ? DEF_NAN : \
86 ((X) != (Y)) ? STD_MIN(X, Y) : (signbit_fp(X) ? (X) : (Y))) /* -0 < +0 */
87 #define MAX(X, Y, DEF_NAN) \
88 ((isnan(X) || isnan(Y)) ? DEF_NAN : \
89 ((X) != (Y)) ? STD_MAX(X, Y) : (signbit_fp(X) ? (Y) : (X))) /* -0 < +0 */
90
91 #define MIN_HF(X, Y) MIN(X, Y, NAN_HF)
92 #define MAX_HF(X, Y) MAX(X, Y, NAN_HF)
93 #define MIN_SF(X, Y) MIN(X, Y, NAN_SF)
94 #define MAX_SF(X, Y) MAX(X, Y, NAN_SF)
95 #define MIN_BF(X, Y) MIN(X, Y, NAN_BF)
96 #define MAX_BF(X, Y) MAX(X, Y, NAN_BF)
97
98 DEF_TEST_OP_2(vfmin, MIN_SF, sf, sf);
99 DEF_TEST_OP_2(vfmax, MAX_SF, sf, sf);
100 DEF_TEST_OP_2(vfmin, MIN_HF, hf, hf);
101 DEF_TEST_OP_2(vfmax, MAX_HF, hf, hf);
102 DEF_TEST_OP_2(vmin, MIN_BF, bf, bf);
103 DEF_TEST_OP_2(vmax, MAX_BF, bf, bf);
104
105 #define DEF_TEST_OP_2_INTERLEAVED(vop, op, type_res, type_arg) \
106 static void test_##vop##_##type_res##_##type_arg(void) \
107 { \
108 memset(expect, 0xff, sizeof(expect)); \
109 memset(output, 0xff, sizeof(output)); \
110 for (int i = 0; i < BUFSIZE / 2; i++) { \
111 HVX_VectorPair *hvx_output = (HVX_VectorPair *)&output[2 * i]; \
112 HVX_Vector hvx_buffer0 = *(HVX_Vector *)&buffer0[i]; \
113 HVX_Vector hvx_buffer1 = *(HVX_Vector *)&buffer1[i]; \
114 *hvx_output = \
115 Q6_W##type_res##_##vop##_V##type_arg##V##type_arg(hvx_buffer0, \
116 hvx_buffer1); \
117 for (int j = 0; j < MAX_VEC_SIZE_BYTES / bytes_##type_res; j++) { \
118 expect[2 * i].type_res[j] = \
119 raw_##type_res(op(float_##type_arg(buffer0[i].type_arg[2 * j]), \
120 float_##type_arg(buffer1[i].type_arg[2 * j]))); \
121 expect[2 * i + 1].type_res[j] = \
122 raw_##type_res(op(float_##type_arg(buffer0[i].type_arg[2 * j + 1]), \
123 float_##type_arg(buffer1[i].type_arg[2 * j + 1]))); \
124 } \
125 } \
126 check_output_##type_res(__LINE__, BUFSIZE); \
127 }
128
129 DEF_TEST_OP_2_INTERLEAVED(vadd, SUM_SF, sf, bf);
130 DEF_TEST_OP_2_INTERLEAVED(vsub, SUB_SF, sf, bf);
131 DEF_TEST_OP_2_INTERLEAVED(vmpy, MULT_SF, sf, bf);
132
133 /******************************************************************************
134 * Other tests
135 *****************************************************************************/
136
137 static void test_vdmpy_sf_hf(bool acc)
138 {
139 memset(expect, 0xff, sizeof(expect));
140
141 for (int i = 0; i < BUFSIZE; i++) {
142 HVX_Vector hvx_buffer0 = *(HVX_Vector *)&buffer0[i];
143 HVX_Vector hvx_buffer1 = *(HVX_Vector *)&buffer1[i];
144 HVX_Vector *hvx_output = (HVX_Vector *)&output[i];
145
146 uint32_t PREFIL_VAL = 0x111222;
147 *hvx_output = Q6_V_vsplat_R(PREFIL_VAL);
148
149 if (!acc) {
150 *hvx_output = Q6_Vsf_vdmpy_VhfVhf(hvx_buffer0, hvx_buffer1);
151 } else {
152 *hvx_output = Q6_Vsf_vdmpyacc_VsfVhfVhf(*hvx_output, hvx_buffer0,
153 hvx_buffer1);
154 }
155
156 for (int j = 0; j < MAX_VEC_SIZE_BYTES / 4; j++) {
157 float a1 = float_hf_to_sf(float_hf(buffer0[i].hf[2 * j + 1]));
158 float a2 = float_hf_to_sf(float_hf(buffer0[i].hf[2 * j]));
159 float a3 = float_hf_to_sf(float_hf(buffer1[i].hf[2 * j + 1]));
160 float a4 = float_hf_to_sf(float_hf(buffer1[i].hf[2 * j]));
161 /*
162 * Note, IEEE FP specifies +0.0 + -0.0 == +0.0. So we use -0.0 in
163 * the default case to preserve the zero sign.
164 */
165 float prev = acc ? float_sf(PREFIL_VAL) : -0.0;
166 expect[i].sf[j] = raw_sf(CHECK_NAN((a1 * a3) + (a2 * a4) + prev, NAN_SF));
167 }
168 }
169 check_output_sf(__LINE__, BUFSIZE);
170 }
171
172 static void test_new(void)
173 {
174 asm volatile("r0 = #%2\n"
175 "v0 = vsplat(r0)\n"
176 "vmem(%1 + #0) = v0\n"
177 "r1 = #%3\n"
178 "v1 = vsplat(r1)\n"
179 "v2 = vsplat(r1)\n"
180 "{\n"
181 " v0.sf = vadd(v1.sf, v2.sf)\n"
182 " vmem(%0 + #0) = v0.new\n"
183 "}\n"
184 :
185 : "r"(output), "r"(expect), "i"(SF_two), "i"(SF_one)
186 : "r0", "r1", "v0", "v1", "v2", "memory");
187 check_output_w(__LINE__, 1);
188 }
189
190 int main(void)
191 {
192 init_buffers_fp();
193
194 /* add/sub */
195 test_vadd_sf_sf();
196 test_vadd_hf_hf();
197 test_vsub_sf_sf();
198 test_vsub_hf_hf();
199
200 /* multiply */
201 test_vmpy_sf_sf();
202 test_vmpy_hf_hf();
203
204 /* dot product */
205 test_vdmpy_sf_hf(false);
206 test_vdmpy_sf_hf(true);
207
208 test_new();
209
210 /* min/max */
211 test_vfmin_sf_sf();
212 test_vfmin_hf_hf();
213 test_vfmax_sf_sf();
214 test_vfmax_hf_hf();
215
216 /* bfloat */
217 init_buffers_bf();
218 test_vmin_bf_bf();
219 test_vmax_bf_bf();
220 test_vadd_sf_bf();
221 test_vsub_sf_bf();
222 test_vmpy_sf_bf();
223
224 puts(err ? "FAIL" : "PASS");
225 return err ? 1 : 0;
226 }