ef854dc60c143e32d62066471a53d0b06e304fa0
[mesa.git] / src / panfrost / midgard / helpers.h
1 /* Copyright (c) 2018-2019 Alyssa Rosenzweig (alyssa@rosenzweig.io)
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to deal
5 * in the Software without restriction, including without limitation the rights
6 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 * copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 * THE SOFTWARE.
20 */
21
22 #ifndef __MDG_HELPERS_H
23 #define __MDG_HELPERS_H
24
25 #include "util/macros.h"
26 #include <string.h>
27
28 #define OP_IS_STORE_VARY(op) (\
29 op == midgard_op_st_vary_16 || \
30 op == midgard_op_st_vary_32 \
31 )
32
33 #define OP_IS_STORE(op) (\
34 OP_IS_STORE_VARY(op) || \
35 op == midgard_op_st_cubemap_coords \
36 )
37
38 #define OP_IS_MOVE(op) ( \
39 op == midgard_alu_op_fmov || \
40 op == midgard_alu_op_imov \
41 )
42
43 /* ALU control words are single bit fields with a lot of space */
44
45 #define ALU_ENAB_VEC_MUL (1 << 17)
46 #define ALU_ENAB_SCAL_ADD (1 << 19)
47 #define ALU_ENAB_VEC_ADD (1 << 21)
48 #define ALU_ENAB_SCAL_MUL (1 << 23)
49 #define ALU_ENAB_VEC_LUT (1 << 25)
50 #define ALU_ENAB_BR_COMPACT (1 << 26)
51 #define ALU_ENAB_BRANCH (1 << 27)
52
53 /* Other opcode properties that don't conflict with the ALU_ENABs, non-ISA */
54
55 /* Denotes an opcode that takes a vector input with a fixed-number of
56 * channels, but outputs to only a single output channel, like dot products.
57 * For these, to determine the effective mask, this quirk can be set. We have
58 * an intentional off-by-one (a la MALI_POSITIVE), since 0-channel makes no
59 * sense but we need to fit 4 channels in 2-bits. Similarly, 1-channel doesn't
60 * make sense (since then why are we quirked?), so that corresponds to "no
61 * count set" */
62
63 #define OP_CHANNEL_COUNT(c) ((c - 1) << 0)
64 #define GET_CHANNEL_COUNT(c) ((c & (0x3 << 0)) ? ((c & (0x3 << 0)) + 1) : 0)
65
66 /* For instructions that take a single argument, normally the first argument
67 * slot is used for the argument and the second slot is a dummy #0 constant.
68 * However, there are exceptions: instructions like fmov store their argument
69 * in the _second_ slot and store a dummy r24 in the first slot, designated by
70 * QUIRK_FLIPPED_R24 */
71
72 #define QUIRK_FLIPPED_R24 (1 << 2)
73
74 /* Is the op commutative? */
75 #define OP_COMMUTES (1 << 3)
76
77 /* Does the op convert types between int- and float- space (i2f/f2u/etc) */
78 #define OP_TYPE_CONVERT (1 << 4)
79
80 /* Vector-independant shorthands for the above; these numbers are arbitrary and
81 * not from the ISA. Convert to the above with unit_enum_to_midgard */
82
83 #define UNIT_MUL 0
84 #define UNIT_ADD 1
85 #define UNIT_LUT 2
86
87 /* 4-bit type tags */
88
89 #define TAG_TEXTURE_4_VTX 0x2
90 #define TAG_TEXTURE_4 0x3
91 #define TAG_LOAD_STORE_4 0x5
92 #define TAG_ALU_4 0x8
93 #define TAG_ALU_8 0x9
94 #define TAG_ALU_12 0xA
95 #define TAG_ALU_16 0xB
96
97 static inline int
98 quadword_size(int tag)
99 {
100 switch (tag) {
101 case TAG_ALU_4:
102 case TAG_LOAD_STORE_4:
103 case TAG_TEXTURE_4:
104 case TAG_TEXTURE_4_VTX:
105 return 1;
106 case TAG_ALU_8:
107 return 2;
108 case TAG_ALU_12:
109 return 3;
110 case TAG_ALU_16:
111 return 4;
112 default:
113 unreachable("Unknown tag");
114 }
115 }
116
117 #define IS_ALU(tag) (tag == TAG_ALU_4 || tag == TAG_ALU_8 || \
118 tag == TAG_ALU_12 || tag == TAG_ALU_16)
119
120 /* Special register aliases */
121
122 #define MAX_WORK_REGISTERS 16
123
124 /* Uniforms are begin at (REGISTER_UNIFORMS - uniform_count) */
125 #define REGISTER_UNIFORMS 24
126
127 #define REGISTER_UNUSED 24
128 #define REGISTER_CONSTANT 26
129 #define REGISTER_VARYING_BASE 26
130 #define REGISTER_OFFSET 27
131 #define REGISTER_TEXTURE_BASE 28
132 #define REGISTER_SELECT 31
133
134 /* SSA helper aliases to mimic the registers. UNUSED_0 encoded as an inline
135 * constant. UNUSED_1 encoded as REGISTER_UNUSED */
136
137 #define SSA_UNUSED_0 0
138 #define SSA_UNUSED_1 -2
139
140 #define SSA_FIXED_SHIFT 24
141 #define SSA_FIXED_REGISTER(reg) ((1 + reg) << SSA_FIXED_SHIFT)
142 #define SSA_REG_FROM_FIXED(reg) ((reg >> SSA_FIXED_SHIFT) - 1)
143 #define SSA_FIXED_MINIMUM SSA_FIXED_REGISTER(0)
144
145 /* Swizzle support */
146
147 #define SWIZZLE(A, B, C, D) ((D << 6) | (C << 4) | (B << 2) | (A << 0))
148 #define SWIZZLE_FROM_ARRAY(r) SWIZZLE(r[0], r[1], r[2], r[3])
149 #define COMPONENT_X 0x0
150 #define COMPONENT_Y 0x1
151 #define COMPONENT_Z 0x2
152 #define COMPONENT_W 0x3
153
154 #define SWIZZLE_XXXX SWIZZLE(COMPONENT_X, COMPONENT_X, COMPONENT_X, COMPONENT_X)
155 #define SWIZZLE_XYXX SWIZZLE(COMPONENT_X, COMPONENT_Y, COMPONENT_X, COMPONENT_X)
156 #define SWIZZLE_XYZX SWIZZLE(COMPONENT_X, COMPONENT_Y, COMPONENT_Z, COMPONENT_X)
157 #define SWIZZLE_XYZW SWIZZLE(COMPONENT_X, COMPONENT_Y, COMPONENT_Z, COMPONENT_W)
158 #define SWIZZLE_XYXZ SWIZZLE(COMPONENT_X, COMPONENT_Y, COMPONENT_X, COMPONENT_Z)
159 #define SWIZZLE_XYZZ SWIZZLE(COMPONENT_X, COMPONENT_Y, COMPONENT_Z, COMPONENT_Z)
160 #define SWIZZLE_WWWW SWIZZLE(COMPONENT_W, COMPONENT_W, COMPONENT_W, COMPONENT_W)
161
162 static inline unsigned
163 swizzle_of(unsigned comp)
164 {
165 switch (comp) {
166 case 1:
167 return SWIZZLE_XXXX;
168 case 2:
169 return SWIZZLE_XYXX;
170 case 3:
171 return SWIZZLE_XYZX;
172 case 4:
173 return SWIZZLE_XYZW;
174 default:
175 unreachable("Invalid component count");
176 }
177 }
178
179 static inline unsigned
180 mask_of(unsigned nr_comp)
181 {
182 return (1 << nr_comp) - 1;
183 }
184
185
186 /* See ISA notes */
187
188 #define LDST_NOP (3)
189
190 /* There are five ALU units: VMUL, VADD, SMUL, SADD, LUT. A given opcode is
191 * implemented on some subset of these units (or occassionally all of them).
192 * This table encodes a bit mask of valid units for each opcode, so the
193 * scheduler can figure where to plonk the instruction. */
194
195 /* Shorthands for each unit */
196 #define UNIT_VMUL ALU_ENAB_VEC_MUL
197 #define UNIT_SADD ALU_ENAB_SCAL_ADD
198 #define UNIT_VADD ALU_ENAB_VEC_ADD
199 #define UNIT_SMUL ALU_ENAB_SCAL_MUL
200 #define UNIT_VLUT ALU_ENAB_VEC_LUT
201
202 /* Shorthands for usual combinations of units */
203
204 #define UNITS_MUL (UNIT_VMUL | UNIT_SMUL)
205 #define UNITS_ADD (UNIT_VADD | UNIT_SADD)
206 #define UNITS_MOST (UNITS_MUL | UNITS_ADD)
207 #define UNITS_ALL (UNITS_MOST | UNIT_VLUT)
208 #define UNITS_SCALAR (UNIT_SADD | UNIT_SMUL)
209 #define UNITS_VECTOR (UNIT_VMUL | UNIT_VADD)
210 #define UNITS_ANY_VECTOR (UNITS_VECTOR | UNIT_VLUT)
211
212 struct mir_op_props {
213 const char *name;
214 unsigned props;
215 };
216
217 /* This file is common, so don't define the tables themselves. #include
218 * midgard_op.h if you need that, or edit midgard_ops.c directly */
219
220 /* Duplicate bits to convert a 4-bit writemask to duplicated 8-bit format,
221 * which is used for 32-bit vector units */
222
223 static inline unsigned
224 expand_writemask_32(unsigned mask)
225 {
226 unsigned o = 0;
227
228 for (int i = 0; i < 4; ++i)
229 if (mask & (1 << i))
230 o |= (3 << (2 * i));
231
232 return o;
233 }
234
235 /* Coerce structs to integer */
236
237 static inline unsigned
238 vector_alu_srco_unsigned(midgard_vector_alu_src src)
239 {
240 unsigned u;
241 memcpy(&u, &src, sizeof(src));
242 return u;
243 }
244
245 static inline midgard_vector_alu_src
246 vector_alu_from_unsigned(unsigned u)
247 {
248 midgard_vector_alu_src s;
249 memcpy(&s, &u, sizeof(s));
250 return s;
251 }
252
253 /* Composes two swizzles */
254 static inline unsigned
255 pan_compose_swizzle(unsigned left, unsigned right)
256 {
257 unsigned out = 0;
258
259 for (unsigned c = 0; c < 4; ++c) {
260 unsigned s = (left >> (2*c)) & 0x3;
261 unsigned q = (right >> (2*s)) & 0x3;
262
263 out |= (q << (2*c));
264 }
265
266 return out;
267 }
268
269 /* Applies a swizzle to an ALU source */
270
271 static inline unsigned
272 vector_alu_apply_swizzle(unsigned src, unsigned swizzle)
273 {
274 midgard_vector_alu_src s =
275 vector_alu_from_unsigned(src);
276
277 s.swizzle = pan_compose_swizzle(s.swizzle, swizzle);
278
279 return vector_alu_srco_unsigned(s);
280 }
281
282 #endif