xref: /qemu/tests/tcg/hexagon/hvx_misc.h (revision 7c1f51bf)
1 /*
2  *  Copyright(c) 2021-2023 Qualcomm Innovation Center, Inc. All Rights Reserved.
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef HVX_MISC_H
19 #define HVX_MISC_H
20 
21 static inline void check(int line, int i, int j,
22                          uint64_t result, uint64_t expect)
23 {
24     if (result != expect) {
25         printf("ERROR at line %d: [%d][%d] 0x%016llx != 0x%016llx\n",
26                line, i, j, result, expect);
27         err++;
28     }
29 }
30 
31 #define MAX_VEC_SIZE_BYTES         128
32 
33 typedef union {
34     uint64_t ud[MAX_VEC_SIZE_BYTES / 8];
35     int64_t   d[MAX_VEC_SIZE_BYTES / 8];
36     uint32_t uw[MAX_VEC_SIZE_BYTES / 4];
37     int32_t   w[MAX_VEC_SIZE_BYTES / 4];
38     uint16_t uh[MAX_VEC_SIZE_BYTES / 2];
39     int16_t   h[MAX_VEC_SIZE_BYTES / 2];
40     uint8_t  ub[MAX_VEC_SIZE_BYTES / 1];
41     int8_t    b[MAX_VEC_SIZE_BYTES / 1];
42 } MMVector;
43 
44 #define BUFSIZE      16
45 #define OUTSIZE      16
46 #define MASKMOD      3
47 
48 MMVector buffer0[BUFSIZE] __attribute__((aligned(MAX_VEC_SIZE_BYTES)));
49 MMVector buffer1[BUFSIZE] __attribute__((aligned(MAX_VEC_SIZE_BYTES)));
50 MMVector mask[BUFSIZE] __attribute__((aligned(MAX_VEC_SIZE_BYTES)));
51 MMVector output[OUTSIZE] __attribute__((aligned(MAX_VEC_SIZE_BYTES)));
52 MMVector expect[OUTSIZE] __attribute__((aligned(MAX_VEC_SIZE_BYTES)));
53 
54 #define CHECK_OUTPUT_FUNC(FIELD, FIELDSZ) \
55 static inline void check_output_##FIELD(int line, size_t num_vectors) \
56 { \
57     for (int i = 0; i < num_vectors; i++) { \
58         for (int j = 0; j < MAX_VEC_SIZE_BYTES / FIELDSZ; j++) { \
59             check(line, i, j, output[i].FIELD[j], expect[i].FIELD[j]); \
60         } \
61     } \
62 }
63 
64 CHECK_OUTPUT_FUNC(d,  8)
65 CHECK_OUTPUT_FUNC(w,  4)
66 CHECK_OUTPUT_FUNC(h,  2)
67 CHECK_OUTPUT_FUNC(b,  1)
68 
69 static inline void init_buffers(void)
70 {
71     int counter0 = 0;
72     int counter1 = 17;
73     for (int i = 0; i < BUFSIZE; i++) {
74         for (int j = 0; j < MAX_VEC_SIZE_BYTES; j++) {
75             buffer0[i].b[j] = counter0++;
76             buffer1[i].b[j] = counter1++;
77         }
78         for (int j = 0; j < MAX_VEC_SIZE_BYTES / 4; j++) {
79             mask[i].w[j] = (i + j % MASKMOD == 0) ? 0 : 1;
80         }
81     }
82 }
83 
84 #define VEC_OP1(ASM, EL, IN, OUT) \
85     asm("v2 = vmem(%0 + #0)\n\t" \
86         "v2" #EL " = " #ASM "(v2" #EL ")\n\t" \
87         "vmem(%1 + #0) = v2\n\t" \
88         : : "r"(IN), "r"(OUT) : "v2", "memory")
89 
90 #define VEC_OP2(ASM, EL, IN0, IN1, OUT) \
91     asm("v2 = vmem(%0 + #0)\n\t" \
92         "v3 = vmem(%1 + #0)\n\t" \
93         "v2" #EL " = " #ASM "(v2" #EL ", v3" #EL ")\n\t" \
94         "vmem(%2 + #0) = v2\n\t" \
95         : : "r"(IN0), "r"(IN1), "r"(OUT) : "v2", "v3", "memory")
96 
97 #define TEST_VEC_OP1(NAME, ASM, EL, FIELD, FIELDSZ, OP) \
98 static inline void test_##NAME(void) \
99 { \
100     void *pin = buffer0; \
101     void *pout = output; \
102     for (int i = 0; i < BUFSIZE; i++) { \
103         VEC_OP1(ASM, EL, pin, pout); \
104         pin += sizeof(MMVector); \
105         pout += sizeof(MMVector); \
106     } \
107     for (int i = 0; i < BUFSIZE; i++) { \
108         for (int j = 0; j < MAX_VEC_SIZE_BYTES / FIELDSZ; j++) { \
109             expect[i].FIELD[j] = OP buffer0[i].FIELD[j]; \
110         } \
111     } \
112     check_output_##FIELD(__LINE__, BUFSIZE); \
113 }
114 
115 #define TEST_VEC_OP2(NAME, ASM, EL, FIELD, FIELDSZ, OP) \
116 static inline void test_##NAME(void) \
117 { \
118     void *p0 = buffer0; \
119     void *p1 = buffer1; \
120     void *pout = output; \
121     for (int i = 0; i < BUFSIZE; i++) { \
122         VEC_OP2(ASM, EL, p0, p1, pout); \
123         p0 += sizeof(MMVector); \
124         p1 += sizeof(MMVector); \
125         pout += sizeof(MMVector); \
126     } \
127     for (int i = 0; i < BUFSIZE; i++) { \
128         for (int j = 0; j < MAX_VEC_SIZE_BYTES / FIELDSZ; j++) { \
129             expect[i].FIELD[j] = buffer0[i].FIELD[j] OP buffer1[i].FIELD[j]; \
130         } \
131     } \
132     check_output_##FIELD(__LINE__, BUFSIZE); \
133 }
134 
135 #define THRESHOLD        31
136 
137 #define PRED_OP2(ASM, IN0, IN1, OUT, INV) \
138     asm("r4 = #%3\n\t" \
139         "v1.b = vsplat(r4)\n\t" \
140         "v2 = vmem(%0 + #0)\n\t" \
141         "q0 = vcmp.gt(v2.b, v1.b)\n\t" \
142         "v3 = vmem(%1 + #0)\n\t" \
143         "q1 = vcmp.gt(v3.b, v1.b)\n\t" \
144         "q2 = " #ASM "(q0, " INV "q1)\n\t" \
145         "r4 = #0xff\n\t" \
146         "v1.b = vsplat(r4)\n\t" \
147         "if (q2) vmem(%2 + #0) = v1\n\t" \
148         : : "r"(IN0), "r"(IN1), "r"(OUT), "i"(THRESHOLD) \
149         : "r4", "v1", "v2", "v3", "q0", "q1", "q2", "memory")
150 
151 #define TEST_PRED_OP2(NAME, ASM, OP, INV) \
152 static inline void test_##NAME(bool invert) \
153 { \
154     void *p0 = buffer0; \
155     void *p1 = buffer1; \
156     void *pout = output; \
157     memset(output, 0, sizeof(expect)); \
158     for (int i = 0; i < BUFSIZE; i++) { \
159         PRED_OP2(ASM, p0, p1, pout, INV); \
160         p0 += sizeof(MMVector); \
161         p1 += sizeof(MMVector); \
162         pout += sizeof(MMVector); \
163     } \
164     for (int i = 0; i < BUFSIZE; i++) { \
165         for (int j = 0; j < MAX_VEC_SIZE_BYTES; j++) { \
166             bool p0 = (buffer0[i].b[j] > THRESHOLD); \
167             bool p1 = (buffer1[i].b[j] > THRESHOLD); \
168             if (invert) { \
169                 expect[i].b[j] = (p0 OP !p1) ? 0xff : 0x00; \
170             } else { \
171                 expect[i].b[j] = (p0 OP p1) ? 0xff : 0x00; \
172             } \
173         } \
174     } \
175     check_output_b(__LINE__, BUFSIZE); \
176 }
177 
178 #endif
179