Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5563 | serge | 1 | /* |
2 | * Mesa 3-D graphics library |
||
3 | * |
||
4 | * Copyright (C) 2012-2013 LunarG, Inc. |
||
5 | * |
||
6 | * Permission is hereby granted, free of charge, to any person obtaining a |
||
7 | * copy of this software and associated documentation files (the "Software"), |
||
8 | * to deal in the Software without restriction, including without limitation |
||
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||
10 | * and/or sell copies of the Software, and to permit persons to whom the |
||
11 | * Software is furnished to do so, subject to the following conditions: |
||
12 | * |
||
13 | * The above copyright notice and this permission notice shall be included |
||
14 | * in all 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 |
||
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||
21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||
22 | * DEALINGS IN THE SOFTWARE. |
||
23 | * |
||
24 | * Authors: |
||
25 | * Chia-I Wu |
||
26 | */ |
||
27 | |||
28 | #include "tgsi/tgsi_parse.h" |
||
29 | #include "tgsi/tgsi_info.h" |
||
30 | #include "tgsi/tgsi_strings.h" |
||
31 | #include "util/u_hash_table.h" |
||
32 | #include "toy_helpers.h" |
||
33 | #include "toy_tgsi.h" |
||
34 | |||
35 | /* map TGSI opcode to GEN opcode 1-to-1 */ |
||
36 | static const struct { |
||
37 | int opcode; |
||
38 | int num_dst; |
||
39 | int num_src; |
||
40 | } aos_simple_opcode_map[TGSI_OPCODE_LAST] = { |
||
41 | [TGSI_OPCODE_ARL] = { BRW_OPCODE_RNDD, 1, 1 }, |
||
42 | [TGSI_OPCODE_MOV] = { BRW_OPCODE_MOV, 1, 1 }, |
||
43 | [TGSI_OPCODE_RCP] = { TOY_OPCODE_INV, 1, 1 }, |
||
44 | [TGSI_OPCODE_RSQ] = { TOY_OPCODE_RSQ, 1, 1 }, |
||
45 | [TGSI_OPCODE_MUL] = { BRW_OPCODE_MUL, 1, 2 }, |
||
46 | [TGSI_OPCODE_ADD] = { BRW_OPCODE_ADD, 1, 2 }, |
||
47 | [TGSI_OPCODE_DP3] = { BRW_OPCODE_DP3, 1, 2 }, |
||
48 | [TGSI_OPCODE_DP4] = { BRW_OPCODE_DP4, 1, 2 }, |
||
49 | [TGSI_OPCODE_MIN] = { BRW_OPCODE_SEL, 1, 2 }, |
||
50 | [TGSI_OPCODE_MAX] = { BRW_OPCODE_SEL, 1, 2 }, |
||
51 | /* a later pass will move src[2] to accumulator */ |
||
52 | [TGSI_OPCODE_MAD] = { BRW_OPCODE_MAC, 1, 3 }, |
||
53 | [TGSI_OPCODE_SUB] = { BRW_OPCODE_ADD, 1, 2 }, |
||
54 | [TGSI_OPCODE_SQRT] = { TOY_OPCODE_SQRT, 1, 1 }, |
||
55 | [TGSI_OPCODE_FRC] = { BRW_OPCODE_FRC, 1, 1 }, |
||
56 | [TGSI_OPCODE_FLR] = { BRW_OPCODE_RNDD, 1, 1 }, |
||
57 | [TGSI_OPCODE_ROUND] = { BRW_OPCODE_RNDE, 1, 1 }, |
||
58 | [TGSI_OPCODE_EX2] = { TOY_OPCODE_EXP, 1, 1 }, |
||
59 | [TGSI_OPCODE_LG2] = { TOY_OPCODE_LOG, 1, 1 }, |
||
60 | [TGSI_OPCODE_POW] = { TOY_OPCODE_POW, 1, 2 }, |
||
61 | [TGSI_OPCODE_ABS] = { BRW_OPCODE_MOV, 1, 1 }, |
||
62 | [TGSI_OPCODE_DPH] = { BRW_OPCODE_DPH, 1, 2 }, |
||
63 | [TGSI_OPCODE_COS] = { TOY_OPCODE_COS, 1, 1 }, |
||
64 | [TGSI_OPCODE_KILL] = { TOY_OPCODE_KIL, 0, 0 }, |
||
65 | [TGSI_OPCODE_SIN] = { TOY_OPCODE_SIN, 1, 1 }, |
||
66 | [TGSI_OPCODE_ARR] = { BRW_OPCODE_RNDZ, 1, 1 }, |
||
67 | [TGSI_OPCODE_DP2] = { BRW_OPCODE_DP2, 1, 2 }, |
||
68 | [TGSI_OPCODE_IF] = { BRW_OPCODE_IF, 0, 1 }, |
||
69 | [TGSI_OPCODE_UIF] = { BRW_OPCODE_IF, 0, 1 }, |
||
70 | [TGSI_OPCODE_ELSE] = { BRW_OPCODE_ELSE, 0, 0 }, |
||
71 | [TGSI_OPCODE_ENDIF] = { BRW_OPCODE_ENDIF, 0, 0 }, |
||
72 | [TGSI_OPCODE_I2F] = { BRW_OPCODE_MOV, 1, 1 }, |
||
73 | [TGSI_OPCODE_NOT] = { BRW_OPCODE_NOT, 1, 1 }, |
||
74 | [TGSI_OPCODE_TRUNC] = { BRW_OPCODE_RNDZ, 1, 1 }, |
||
75 | [TGSI_OPCODE_SHL] = { BRW_OPCODE_SHL, 1, 2 }, |
||
76 | [TGSI_OPCODE_AND] = { BRW_OPCODE_AND, 1, 2 }, |
||
77 | [TGSI_OPCODE_OR] = { BRW_OPCODE_OR, 1, 2 }, |
||
78 | [TGSI_OPCODE_MOD] = { TOY_OPCODE_INT_DIV_REMAINDER, 1, 2 }, |
||
79 | [TGSI_OPCODE_XOR] = { BRW_OPCODE_XOR, 1, 2 }, |
||
80 | [TGSI_OPCODE_EMIT] = { TOY_OPCODE_EMIT, 0, 0 }, |
||
81 | [TGSI_OPCODE_ENDPRIM] = { TOY_OPCODE_ENDPRIM, 0, 0 }, |
||
82 | [TGSI_OPCODE_NOP] = { BRW_OPCODE_NOP, 0, 0 }, |
||
83 | [TGSI_OPCODE_KILL_IF] = { TOY_OPCODE_KIL, 0, 1 }, |
||
84 | [TGSI_OPCODE_END] = { BRW_OPCODE_NOP, 0, 0 }, |
||
85 | [TGSI_OPCODE_F2I] = { BRW_OPCODE_MOV, 1, 1 }, |
||
86 | [TGSI_OPCODE_IDIV] = { TOY_OPCODE_INT_DIV_QUOTIENT, 1, 2 }, |
||
87 | [TGSI_OPCODE_IMAX] = { BRW_OPCODE_SEL, 1, 2 }, |
||
88 | [TGSI_OPCODE_IMIN] = { BRW_OPCODE_SEL, 1, 2 }, |
||
89 | [TGSI_OPCODE_INEG] = { BRW_OPCODE_MOV, 1, 1 }, |
||
90 | [TGSI_OPCODE_ISHR] = { BRW_OPCODE_ASR, 1, 2 }, |
||
91 | [TGSI_OPCODE_F2U] = { BRW_OPCODE_MOV, 1, 1 }, |
||
92 | [TGSI_OPCODE_U2F] = { BRW_OPCODE_MOV, 1, 1 }, |
||
93 | [TGSI_OPCODE_UADD] = { BRW_OPCODE_ADD, 1, 2 }, |
||
94 | [TGSI_OPCODE_UDIV] = { TOY_OPCODE_INT_DIV_QUOTIENT, 1, 2 }, |
||
95 | /* a later pass will move src[2] to accumulator */ |
||
96 | [TGSI_OPCODE_UMAD] = { BRW_OPCODE_MAC, 1, 3 }, |
||
97 | [TGSI_OPCODE_UMAX] = { BRW_OPCODE_SEL, 1, 2 }, |
||
98 | [TGSI_OPCODE_UMIN] = { BRW_OPCODE_SEL, 1, 2 }, |
||
99 | [TGSI_OPCODE_UMOD] = { TOY_OPCODE_INT_DIV_REMAINDER, 1, 2 }, |
||
100 | [TGSI_OPCODE_UMUL] = { BRW_OPCODE_MUL, 1, 2 }, |
||
101 | [TGSI_OPCODE_USHR] = { BRW_OPCODE_SHR, 1, 2 }, |
||
102 | [TGSI_OPCODE_UARL] = { BRW_OPCODE_MOV, 1, 1 }, |
||
103 | [TGSI_OPCODE_IABS] = { BRW_OPCODE_MOV, 1, 1 }, |
||
104 | }; |
||
105 | |||
106 | static void |
||
107 | aos_simple(struct toy_compiler *tc, |
||
108 | const struct tgsi_full_instruction *tgsi_inst, |
||
109 | struct toy_dst *dst, |
||
110 | struct toy_src *src) |
||
111 | { |
||
112 | struct toy_inst *inst; |
||
113 | int opcode; |
||
114 | int cond_modifier = BRW_CONDITIONAL_NONE; |
||
115 | int num_dst = tgsi_inst->Instruction.NumDstRegs; |
||
116 | int num_src = tgsi_inst->Instruction.NumSrcRegs; |
||
117 | int i; |
||
118 | |||
119 | opcode = aos_simple_opcode_map[tgsi_inst->Instruction.Opcode].opcode; |
||
120 | assert(num_dst == aos_simple_opcode_map[tgsi_inst->Instruction.Opcode].num_dst); |
||
121 | assert(num_src == aos_simple_opcode_map[tgsi_inst->Instruction.Opcode].num_src); |
||
122 | if (!opcode) { |
||
123 | assert(!"invalid aos_simple() call"); |
||
124 | return; |
||
125 | } |
||
126 | |||
127 | /* no need to emit nop */ |
||
128 | if (opcode == BRW_OPCODE_NOP) |
||
129 | return; |
||
130 | |||
131 | inst = tc_add(tc); |
||
132 | if (!inst) |
||
133 | return; |
||
134 | |||
135 | inst->opcode = opcode; |
||
136 | |||
137 | switch (tgsi_inst->Instruction.Opcode) { |
||
138 | case TGSI_OPCODE_MIN: |
||
139 | case TGSI_OPCODE_IMIN: |
||
140 | case TGSI_OPCODE_UMIN: |
||
141 | cond_modifier = BRW_CONDITIONAL_L; |
||
142 | break; |
||
143 | case TGSI_OPCODE_MAX: |
||
144 | case TGSI_OPCODE_IMAX: |
||
145 | case TGSI_OPCODE_UMAX: |
||
146 | cond_modifier = BRW_CONDITIONAL_GE; |
||
147 | break; |
||
148 | case TGSI_OPCODE_SUB: |
||
149 | src[1] = tsrc_negate(src[1]); |
||
150 | break; |
||
151 | case TGSI_OPCODE_ABS: |
||
152 | case TGSI_OPCODE_IABS: |
||
153 | src[0] = tsrc_absolute(src[0]); |
||
154 | break; |
||
155 | case TGSI_OPCODE_IF: |
||
156 | cond_modifier = BRW_CONDITIONAL_NEQ; |
||
157 | num_src = 2; |
||
158 | assert(src[0].type == TOY_TYPE_F); |
||
159 | src[0] = tsrc_swizzle1(src[0], TOY_SWIZZLE_X); |
||
160 | src[1] = tsrc_imm_f(0.0f); |
||
161 | break; |
||
162 | case TGSI_OPCODE_UIF: |
||
163 | cond_modifier = BRW_CONDITIONAL_NEQ; |
||
164 | num_src = 2; |
||
165 | assert(src[0].type == TOY_TYPE_UD); |
||
166 | src[0] = tsrc_swizzle1(src[0], TOY_SWIZZLE_X); |
||
167 | src[1] = tsrc_imm_d(0); |
||
168 | break; |
||
169 | case TGSI_OPCODE_INEG: |
||
170 | src[0] = tsrc_negate(src[0]); |
||
171 | break; |
||
172 | case TGSI_OPCODE_RCP: |
||
173 | case TGSI_OPCODE_RSQ: |
||
174 | case TGSI_OPCODE_EX2: |
||
175 | case TGSI_OPCODE_LG2: |
||
176 | case TGSI_OPCODE_COS: |
||
177 | case TGSI_OPCODE_SIN: |
||
178 | src[0] = tsrc_swizzle1(src[0], TOY_SWIZZLE_X); |
||
179 | break; |
||
180 | case TGSI_OPCODE_POW: |
||
181 | src[0] = tsrc_swizzle1(src[0], TOY_SWIZZLE_X); |
||
182 | src[1] = tsrc_swizzle1(src[1], TOY_SWIZZLE_X); |
||
183 | break; |
||
184 | } |
||
185 | |||
186 | inst->cond_modifier = cond_modifier; |
||
187 | |||
188 | if (num_dst) { |
||
189 | assert(num_dst == 1); |
||
190 | inst->dst = dst[0]; |
||
191 | } |
||
192 | |||
193 | assert(num_src <= Elements(inst->src)); |
||
194 | for (i = 0; i < num_src; i++) |
||
195 | inst->src[i] = src[i]; |
||
196 | } |
||
197 | |||
198 | static void |
||
199 | aos_set_on_cond(struct toy_compiler *tc, |
||
200 | const struct tgsi_full_instruction *tgsi_inst, |
||
201 | struct toy_dst *dst, |
||
202 | struct toy_src *src) |
||
203 | { |
||
204 | struct toy_inst *inst; |
||
205 | int cond; |
||
206 | struct toy_src zero, one; |
||
207 | |||
208 | switch (tgsi_inst->Instruction.Opcode) { |
||
209 | case TGSI_OPCODE_SLT: |
||
210 | case TGSI_OPCODE_ISLT: |
||
211 | case TGSI_OPCODE_USLT: |
||
212 | cond = BRW_CONDITIONAL_L; |
||
213 | break; |
||
214 | case TGSI_OPCODE_SGE: |
||
215 | case TGSI_OPCODE_ISGE: |
||
216 | case TGSI_OPCODE_USGE: |
||
217 | cond = BRW_CONDITIONAL_GE; |
||
218 | break; |
||
219 | case TGSI_OPCODE_SEQ: |
||
220 | case TGSI_OPCODE_USEQ: |
||
221 | cond = BRW_CONDITIONAL_EQ; |
||
222 | break; |
||
223 | case TGSI_OPCODE_SGT: |
||
224 | cond = BRW_CONDITIONAL_G; |
||
225 | break; |
||
226 | case TGSI_OPCODE_SLE: |
||
227 | cond = BRW_CONDITIONAL_LE; |
||
228 | break; |
||
229 | case TGSI_OPCODE_SNE: |
||
230 | case TGSI_OPCODE_USNE: |
||
231 | cond = BRW_CONDITIONAL_NEQ; |
||
232 | break; |
||
233 | default: |
||
234 | assert(!"invalid aos_set_on_cond() call"); |
||
235 | return; |
||
236 | } |
||
237 | |||
238 | /* note that for integer versions, all bits are set */ |
||
239 | switch (dst[0].type) { |
||
240 | case TOY_TYPE_F: |
||
241 | default: |
||
242 | zero = tsrc_imm_f(0.0f); |
||
243 | one = tsrc_imm_f(1.0f); |
||
244 | break; |
||
245 | case TOY_TYPE_D: |
||
246 | zero = tsrc_imm_d(0); |
||
247 | one = tsrc_imm_d(-1); |
||
248 | break; |
||
249 | case TOY_TYPE_UD: |
||
250 | zero = tsrc_imm_ud(0); |
||
251 | one = tsrc_imm_ud(~0); |
||
252 | break; |
||
253 | } |
||
254 | |||
255 | tc_MOV(tc, dst[0], zero); |
||
256 | tc_CMP(tc, tdst_null(), src[0], src[1], cond); |
||
257 | inst = tc_MOV(tc, dst[0], one); |
||
258 | inst->pred_ctrl = BRW_PREDICATE_NORMAL; |
||
259 | } |
||
260 | |||
261 | static void |
||
262 | aos_compare(struct toy_compiler *tc, |
||
263 | const struct tgsi_full_instruction *tgsi_inst, |
||
264 | struct toy_dst *dst, |
||
265 | struct toy_src *src) |
||
266 | { |
||
267 | struct toy_inst *inst; |
||
268 | struct toy_src zero; |
||
269 | |||
270 | switch (tgsi_inst->Instruction.Opcode) { |
||
271 | case TGSI_OPCODE_CMP: |
||
272 | zero = tsrc_imm_f(0.0f); |
||
273 | break; |
||
274 | case TGSI_OPCODE_UCMP: |
||
275 | zero = tsrc_imm_ud(0); |
||
276 | break; |
||
277 | default: |
||
278 | assert(!"invalid aos_compare() call"); |
||
279 | return; |
||
280 | } |
||
281 | |||
282 | tc_CMP(tc, tdst_null(), src[0], zero, BRW_CONDITIONAL_L); |
||
283 | inst = tc_SEL(tc, dst[0], src[1], src[2], BRW_CONDITIONAL_NONE); |
||
284 | inst->pred_ctrl = BRW_PREDICATE_NORMAL; |
||
285 | } |
||
286 | |||
287 | static void |
||
288 | aos_set_sign(struct toy_compiler *tc, |
||
289 | const struct tgsi_full_instruction *tgsi_inst, |
||
290 | struct toy_dst *dst, |
||
291 | struct toy_src *src) |
||
292 | { |
||
293 | struct toy_inst *inst; |
||
294 | struct toy_src zero, one, neg_one; |
||
295 | |||
296 | switch (tgsi_inst->Instruction.Opcode) { |
||
297 | case TGSI_OPCODE_SSG: |
||
298 | zero = tsrc_imm_f(0.0f); |
||
299 | one = tsrc_imm_f(1.0f); |
||
300 | neg_one = tsrc_imm_f(-1.0f); |
||
301 | break; |
||
302 | case TGSI_OPCODE_ISSG: |
||
303 | zero = tsrc_imm_d(0); |
||
304 | one = tsrc_imm_d(1); |
||
305 | neg_one = tsrc_imm_d(-1); |
||
306 | break; |
||
307 | default: |
||
308 | assert(!"invalid aos_set_sign() call"); |
||
309 | return; |
||
310 | } |
||
311 | |||
312 | tc_MOV(tc, dst[0], zero); |
||
313 | |||
314 | tc_CMP(tc, tdst_null(), src[0], zero, BRW_CONDITIONAL_G); |
||
315 | inst = tc_MOV(tc, dst[0], one); |
||
316 | inst->pred_ctrl = BRW_PREDICATE_NORMAL; |
||
317 | |||
318 | tc_CMP(tc, tdst_null(), src[0], zero, BRW_CONDITIONAL_L); |
||
319 | inst = tc_MOV(tc, dst[0], neg_one); |
||
320 | inst->pred_ctrl = BRW_PREDICATE_NORMAL; |
||
321 | } |
||
322 | |||
323 | static void |
||
324 | aos_tex(struct toy_compiler *tc, |
||
325 | const struct tgsi_full_instruction *tgsi_inst, |
||
326 | struct toy_dst *dst, |
||
327 | struct toy_src *src) |
||
328 | { |
||
329 | struct toy_inst *inst; |
||
330 | enum toy_opcode opcode; |
||
331 | int i; |
||
332 | |||
333 | switch (tgsi_inst->Instruction.Opcode) { |
||
334 | case TGSI_OPCODE_TEX: |
||
335 | opcode = TOY_OPCODE_TGSI_TEX; |
||
336 | break; |
||
337 | case TGSI_OPCODE_TXD: |
||
338 | opcode = TOY_OPCODE_TGSI_TXD; |
||
339 | break; |
||
340 | case TGSI_OPCODE_TXP: |
||
341 | opcode = TOY_OPCODE_TGSI_TXP; |
||
342 | break; |
||
343 | case TGSI_OPCODE_TXB: |
||
344 | opcode = TOY_OPCODE_TGSI_TXB; |
||
345 | break; |
||
346 | case TGSI_OPCODE_TXL: |
||
347 | opcode = TOY_OPCODE_TGSI_TXL; |
||
348 | break; |
||
349 | case TGSI_OPCODE_TXF: |
||
350 | opcode = TOY_OPCODE_TGSI_TXF; |
||
351 | break; |
||
352 | case TGSI_OPCODE_TXQ: |
||
353 | opcode = TOY_OPCODE_TGSI_TXQ; |
||
354 | break; |
||
355 | case TGSI_OPCODE_TXQ_LZ: |
||
356 | opcode = TOY_OPCODE_TGSI_TXQ_LZ; |
||
357 | break; |
||
358 | case TGSI_OPCODE_TEX2: |
||
359 | opcode = TOY_OPCODE_TGSI_TEX2; |
||
360 | break; |
||
361 | case TGSI_OPCODE_TXB2: |
||
362 | opcode = TOY_OPCODE_TGSI_TXB2; |
||
363 | break; |
||
364 | case TGSI_OPCODE_TXL2: |
||
365 | opcode = TOY_OPCODE_TGSI_TXL2; |
||
366 | break; |
||
367 | default: |
||
368 | assert(!"unsupported texturing opcode"); |
||
369 | return; |
||
370 | break; |
||
371 | } |
||
372 | |||
373 | assert(tgsi_inst->Instruction.Texture); |
||
374 | |||
375 | inst = tc_add(tc); |
||
376 | inst->opcode = opcode; |
||
377 | inst->tex.target = tgsi_inst->Texture.Texture; |
||
378 | |||
379 | assert(tgsi_inst->Instruction.NumSrcRegs <= Elements(inst->src)); |
||
380 | assert(tgsi_inst->Instruction.NumDstRegs == 1); |
||
381 | |||
382 | inst->dst = dst[0]; |
||
383 | for (i = 0; i < tgsi_inst->Instruction.NumSrcRegs; i++) |
||
384 | inst->src[i] = src[i]; |
||
385 | |||
386 | for (i = 0; i < tgsi_inst->Texture.NumOffsets; i++) |
||
387 | tc_fail(tc, "texelFetchOffset unsupported"); |
||
388 | } |
||
389 | |||
390 | static void |
||
391 | aos_sample(struct toy_compiler *tc, |
||
392 | const struct tgsi_full_instruction *tgsi_inst, |
||
393 | struct toy_dst *dst, |
||
394 | struct toy_src *src) |
||
395 | { |
||
396 | struct toy_inst *inst; |
||
397 | enum toy_opcode opcode; |
||
398 | int i; |
||
399 | |||
400 | assert(!"sampling untested"); |
||
401 | |||
402 | switch (tgsi_inst->Instruction.Opcode) { |
||
403 | case TGSI_OPCODE_SAMPLE: |
||
404 | opcode = TOY_OPCODE_TGSI_SAMPLE; |
||
405 | break; |
||
406 | case TGSI_OPCODE_SAMPLE_I: |
||
407 | opcode = TOY_OPCODE_TGSI_SAMPLE_I; |
||
408 | break; |
||
409 | case TGSI_OPCODE_SAMPLE_I_MS: |
||
410 | opcode = TOY_OPCODE_TGSI_SAMPLE_I_MS; |
||
411 | break; |
||
412 | case TGSI_OPCODE_SAMPLE_B: |
||
413 | opcode = TOY_OPCODE_TGSI_SAMPLE_B; |
||
414 | break; |
||
415 | case TGSI_OPCODE_SAMPLE_C: |
||
416 | opcode = TOY_OPCODE_TGSI_SAMPLE_C; |
||
417 | break; |
||
418 | case TGSI_OPCODE_SAMPLE_C_LZ: |
||
419 | opcode = TOY_OPCODE_TGSI_SAMPLE_C_LZ; |
||
420 | break; |
||
421 | case TGSI_OPCODE_SAMPLE_D: |
||
422 | opcode = TOY_OPCODE_TGSI_SAMPLE_D; |
||
423 | break; |
||
424 | case TGSI_OPCODE_SAMPLE_L: |
||
425 | opcode = TOY_OPCODE_TGSI_SAMPLE_L; |
||
426 | break; |
||
427 | case TGSI_OPCODE_GATHER4: |
||
428 | opcode = TOY_OPCODE_TGSI_GATHER4; |
||
429 | break; |
||
430 | case TGSI_OPCODE_SVIEWINFO: |
||
431 | opcode = TOY_OPCODE_TGSI_SVIEWINFO; |
||
432 | break; |
||
433 | case TGSI_OPCODE_SAMPLE_POS: |
||
434 | opcode = TOY_OPCODE_TGSI_SAMPLE_POS; |
||
435 | break; |
||
436 | case TGSI_OPCODE_SAMPLE_INFO: |
||
437 | opcode = TOY_OPCODE_TGSI_SAMPLE_INFO; |
||
438 | break; |
||
439 | default: |
||
440 | assert(!"unsupported sampling opcode"); |
||
441 | return; |
||
442 | break; |
||
443 | } |
||
444 | |||
445 | inst = tc_add(tc); |
||
446 | inst->opcode = opcode; |
||
447 | |||
448 | assert(tgsi_inst->Instruction.NumSrcRegs <= Elements(inst->src)); |
||
449 | assert(tgsi_inst->Instruction.NumDstRegs == 1); |
||
450 | |||
451 | inst->dst = dst[0]; |
||
452 | for (i = 0; i < tgsi_inst->Instruction.NumSrcRegs; i++) |
||
453 | inst->src[i] = src[i]; |
||
454 | } |
||
455 | |||
456 | static void |
||
457 | aos_LIT(struct toy_compiler *tc, |
||
458 | const struct tgsi_full_instruction *tgsi_inst, |
||
459 | struct toy_dst *dst, |
||
460 | struct toy_src *src) |
||
461 | { |
||
462 | struct toy_inst *inst; |
||
463 | |||
464 | tc_MOV(tc, tdst_writemask(dst[0], TOY_WRITEMASK_XW), tsrc_imm_f(1.0f)); |
||
465 | |||
466 | if (!(dst[0].writemask & TOY_WRITEMASK_YZ)) |
||
467 | return; |
||
468 | |||
469 | tc_MOV(tc, tdst_writemask(dst[0], TOY_WRITEMASK_YZ), tsrc_imm_f(0.0f)); |
||
470 | |||
471 | tc_CMP(tc, tdst_null(), |
||
472 | tsrc_swizzle1(src[0], TOY_SWIZZLE_X), |
||
473 | tsrc_imm_f(0.0f), |
||
474 | BRW_CONDITIONAL_G); |
||
475 | |||
476 | inst = tc_MOV(tc, |
||
477 | tdst_writemask(dst[0], TOY_WRITEMASK_Y), |
||
478 | tsrc_swizzle1(src[0], TOY_SWIZZLE_X)); |
||
479 | inst->pred_ctrl = BRW_PREDICATE_NORMAL; |
||
480 | |||
481 | /* clamp W to (-128, 128)? */ |
||
482 | inst = tc_POW(tc, |
||
483 | tdst_writemask(dst[0], TOY_WRITEMASK_Z), |
||
484 | tsrc_swizzle1(src[0], TOY_SWIZZLE_Y), |
||
485 | tsrc_swizzle1(src[0], TOY_SWIZZLE_W)); |
||
486 | inst->pred_ctrl = BRW_PREDICATE_NORMAL; |
||
487 | } |
||
488 | |||
489 | static void |
||
490 | aos_EXP(struct toy_compiler *tc, |
||
491 | const struct tgsi_full_instruction *tgsi_inst, |
||
492 | struct toy_dst *dst, |
||
493 | struct toy_src *src) |
||
494 | { |
||
495 | struct toy_src src0 = tsrc_swizzle1(src[0], TOY_SWIZZLE_X); |
||
496 | |||
497 | if (dst[0].writemask & TOY_WRITEMASK_X) { |
||
498 | struct toy_dst tmp = |
||
499 | tdst_d(tdst_writemask(tc_alloc_tmp(tc), TOY_WRITEMASK_X)); |
||
500 | |||
501 | tc_RNDD(tc, tmp, src0); |
||
502 | |||
503 | /* construct the floating point number manually */ |
||
504 | tc_ADD(tc, tmp, tsrc_from(tmp), tsrc_imm_d(127)); |
||
505 | tc_SHL(tc, tdst_d(tdst_writemask(dst[0], TOY_WRITEMASK_X)), |
||
506 | tsrc_from(tmp), tsrc_imm_d(23)); |
||
507 | } |
||
508 | |||
509 | tc_FRC(tc, tdst_writemask(dst[0], TOY_WRITEMASK_Y), src0); |
||
510 | tc_EXP(tc, tdst_writemask(dst[0], TOY_WRITEMASK_Z), src0); |
||
511 | tc_MOV(tc, tdst_writemask(dst[0], TOY_WRITEMASK_W), tsrc_imm_f(1.0f)); |
||
512 | } |
||
513 | |||
514 | static void |
||
515 | aos_LOG(struct toy_compiler *tc, |
||
516 | const struct tgsi_full_instruction *tgsi_inst, |
||
517 | struct toy_dst *dst, |
||
518 | struct toy_src *src) |
||
519 | { |
||
520 | struct toy_src src0 = tsrc_swizzle1(src[0], TOY_SWIZZLE_X); |
||
521 | |||
522 | if (dst[0].writemask & TOY_WRITEMASK_XY) { |
||
523 | struct toy_dst tmp; |
||
524 | |||
525 | tmp = tdst_d(tdst_writemask(tc_alloc_tmp(tc), TOY_WRITEMASK_X)); |
||
526 | |||
527 | /* exponent */ |
||
528 | tc_SHR(tc, tmp, tsrc_absolute(tsrc_d(src0)), tsrc_imm_d(23)); |
||
529 | tc_ADD(tc, tdst_writemask(dst[0], TOY_WRITEMASK_X), |
||
530 | tsrc_from(tmp), tsrc_imm_d(-127)); |
||
531 | |||
532 | /* mantissa */ |
||
533 | tc_AND(tc, tmp, tsrc_d(src0), tsrc_imm_d((1 << 23) - 1)); |
||
534 | tc_OR(tc, tdst_writemask(tdst_d(dst[0]), TOY_WRITEMASK_Y), |
||
535 | tsrc_from(tmp), tsrc_imm_d(127 << 23)); |
||
536 | } |
||
537 | |||
538 | tc_LOG(tc, tdst_writemask(dst[0], TOY_WRITEMASK_Z), src0); |
||
539 | tc_MOV(tc, tdst_writemask(dst[0], TOY_WRITEMASK_W), tsrc_imm_f(1.0f)); |
||
540 | } |
||
541 | |||
542 | static void |
||
543 | aos_DST(struct toy_compiler *tc, |
||
544 | const struct tgsi_full_instruction *tgsi_inst, |
||
545 | struct toy_dst *dst, |
||
546 | struct toy_src *src) |
||
547 | { |
||
548 | tc_MOV(tc, tdst_writemask(dst[0], TOY_WRITEMASK_X), tsrc_imm_f(1.0f)); |
||
549 | tc_MUL(tc, tdst_writemask(dst[0], TOY_WRITEMASK_Y), src[0], src[1]); |
||
550 | tc_MOV(tc, tdst_writemask(dst[0], TOY_WRITEMASK_Z), src[0]); |
||
551 | tc_MOV(tc, tdst_writemask(dst[0], TOY_WRITEMASK_W), src[1]); |
||
552 | } |
||
553 | |||
554 | static void |
||
555 | aos_LRP(struct toy_compiler *tc, |
||
556 | const struct tgsi_full_instruction *tgsi_inst, |
||
557 | struct toy_dst *dst, |
||
558 | struct toy_src *src) |
||
559 | { |
||
560 | struct toy_dst tmp = tc_alloc_tmp(tc); |
||
561 | |||
562 | tc_ADD(tc, tmp, tsrc_negate(src[0]), tsrc_imm_f(1.0f)); |
||
563 | tc_MUL(tc, tmp, tsrc_from(tmp), src[2]); |
||
564 | tc_MAC(tc, dst[0], src[0], src[1], tsrc_from(tmp)); |
||
565 | } |
||
566 | |||
567 | static void |
||
568 | aos_CND(struct toy_compiler *tc, |
||
569 | const struct tgsi_full_instruction *tgsi_inst, |
||
570 | struct toy_dst *dst, |
||
571 | struct toy_src *src) |
||
572 | { |
||
573 | struct toy_inst *inst; |
||
574 | |||
575 | assert(!"CND untested"); |
||
576 | |||
577 | tc_CMP(tc, tdst_null(), src[2], tsrc_imm_f(0.5f), BRW_CONDITIONAL_G); |
||
578 | inst = tc_SEL(tc, dst[0], src[0], src[1], BRW_CONDITIONAL_NONE); |
||
579 | inst->pred_ctrl = BRW_PREDICATE_NORMAL; |
||
580 | } |
||
581 | |||
582 | static void |
||
583 | aos_DP2A(struct toy_compiler *tc, |
||
584 | const struct tgsi_full_instruction *tgsi_inst, |
||
585 | struct toy_dst *dst, |
||
586 | struct toy_src *src) |
||
587 | { |
||
588 | struct toy_dst tmp = tc_alloc_tmp(tc); |
||
589 | |||
590 | assert(!"DP2A untested"); |
||
591 | |||
592 | tc_DP2(tc, tmp, src[0], src[1]); |
||
593 | tc_ADD(tc, dst[0], tsrc_swizzle1(tsrc_from(tmp), TOY_SWIZZLE_X), src[2]); |
||
594 | } |
||
595 | |||
596 | static void |
||
597 | aos_CLAMP(struct toy_compiler *tc, |
||
598 | const struct tgsi_full_instruction *tgsi_inst, |
||
599 | struct toy_dst *dst, |
||
600 | struct toy_src *src) |
||
601 | { |
||
602 | assert(!"CLAMP untested"); |
||
603 | |||
604 | tc_SEL(tc, dst[0], src[0], src[1], BRW_CONDITIONAL_GE); |
||
605 | tc_SEL(tc, dst[0], src[2], tsrc_from(dst[0]), BRW_CONDITIONAL_L); |
||
606 | } |
||
607 | |||
608 | static void |
||
609 | aos_XPD(struct toy_compiler *tc, |
||
610 | const struct tgsi_full_instruction *tgsi_inst, |
||
611 | struct toy_dst *dst, |
||
612 | struct toy_src *src) |
||
613 | { |
||
614 | struct toy_dst tmp = tc_alloc_tmp(tc); |
||
615 | |||
616 | tc_MUL(tc, tdst_writemask(tmp, TOY_WRITEMASK_XYZ), |
||
617 | tsrc_swizzle(src[0], TOY_SWIZZLE_Z, TOY_SWIZZLE_X, |
||
618 | TOY_SWIZZLE_Y, TOY_SWIZZLE_W), |
||
619 | tsrc_swizzle(src[1], TOY_SWIZZLE_Y, TOY_SWIZZLE_Z, |
||
620 | TOY_SWIZZLE_X, TOY_SWIZZLE_W)); |
||
621 | |||
622 | tc_MAC(tc, tdst_writemask(dst[0], TOY_WRITEMASK_XYZ), |
||
623 | tsrc_swizzle(src[0], TOY_SWIZZLE_Y, TOY_SWIZZLE_Z, |
||
624 | TOY_SWIZZLE_X, TOY_SWIZZLE_W), |
||
625 | tsrc_swizzle(src[1], TOY_SWIZZLE_Z, TOY_SWIZZLE_X, |
||
626 | TOY_SWIZZLE_Y, TOY_SWIZZLE_W), |
||
627 | tsrc_negate(tsrc_from(tmp))); |
||
628 | |||
629 | tc_MOV(tc, tdst_writemask(dst[0], TOY_WRITEMASK_W), |
||
630 | tsrc_imm_f(1.0f)); |
||
631 | } |
||
632 | |||
633 | static void |
||
634 | aos_PK2H(struct toy_compiler *tc, |
||
635 | const struct tgsi_full_instruction *tgsi_inst, |
||
636 | struct toy_dst *dst, |
||
637 | struct toy_src *src) |
||
638 | { |
||
639 | const struct toy_src h1 = tsrc_ud(tsrc_swizzle1(src[0], TOY_SWIZZLE_X)); |
||
640 | const struct toy_src h2 = tsrc_ud(tsrc_swizzle1(src[0], TOY_SWIZZLE_Y)); |
||
641 | struct toy_dst tmp = tdst_ud(tc_alloc_tmp(tc)); |
||
642 | |||
643 | assert(!"PK2H untested"); |
||
644 | |||
645 | tc_SHL(tc, tmp, h2, tsrc_imm_ud(16)); |
||
646 | tc_OR(tc, tdst_ud(dst[0]), h1, tsrc_from(tmp)); |
||
647 | } |
||
648 | |||
649 | static void |
||
650 | aos_SFL(struct toy_compiler *tc, |
||
651 | const struct tgsi_full_instruction *tgsi_inst, |
||
652 | struct toy_dst *dst, |
||
653 | struct toy_src *src) |
||
654 | { |
||
655 | assert(!"SFL untested"); |
||
656 | |||
657 | tc_MOV(tc, dst[0], tsrc_imm_f(0.0f)); |
||
658 | } |
||
659 | |||
660 | static void |
||
661 | aos_STR(struct toy_compiler *tc, |
||
662 | const struct tgsi_full_instruction *tgsi_inst, |
||
663 | struct toy_dst *dst, |
||
664 | struct toy_src *src) |
||
665 | { |
||
666 | assert(!"STR untested"); |
||
667 | |||
668 | tc_MOV(tc, dst[0], tsrc_imm_f(1.0f)); |
||
669 | } |
||
670 | |||
671 | static void |
||
672 | aos_UP2H(struct toy_compiler *tc, |
||
673 | const struct tgsi_full_instruction *tgsi_inst, |
||
674 | struct toy_dst *dst, |
||
675 | struct toy_src *src) |
||
676 | { |
||
677 | assert(!"UP2H untested"); |
||
678 | |||
679 | tc_AND(tc, tdst_writemask(tdst_ud(dst[0]), TOY_WRITEMASK_XZ), |
||
680 | tsrc_ud(src[0]), tsrc_imm_ud(0xffff)); |
||
681 | tc_SHR(tc, tdst_writemask(tdst_ud(dst[0]), TOY_WRITEMASK_YW), |
||
682 | tsrc_ud(src[0]), tsrc_imm_ud(16)); |
||
683 | } |
||
684 | |||
685 | static void |
||
686 | aos_SCS(struct toy_compiler *tc, |
||
687 | const struct tgsi_full_instruction *tgsi_inst, |
||
688 | struct toy_dst *dst, |
||
689 | struct toy_src *src) |
||
690 | { |
||
691 | assert(!"SCS untested"); |
||
692 | |||
693 | tc_add1(tc, TOY_OPCODE_COS, |
||
694 | tdst_writemask(dst[0], TOY_WRITEMASK_X), src[0]); |
||
695 | |||
696 | tc_add1(tc, TOY_OPCODE_SIN, |
||
697 | tdst_writemask(dst[0], TOY_WRITEMASK_Y), src[0]); |
||
698 | |||
699 | tc_MOV(tc, tdst_writemask(dst[0], TOY_WRITEMASK_Z), tsrc_imm_f(0.0f)); |
||
700 | tc_MOV(tc, tdst_writemask(dst[0], TOY_WRITEMASK_W), tsrc_imm_f(1.0f)); |
||
701 | } |
||
702 | |||
703 | static void |
||
704 | aos_NRM(struct toy_compiler *tc, |
||
705 | const struct tgsi_full_instruction *tgsi_inst, |
||
706 | struct toy_dst *dst, |
||
707 | struct toy_src *src) |
||
708 | { |
||
709 | struct toy_dst tmp = tc_alloc_tmp(tc); |
||
710 | |||
711 | assert(!"NRM untested"); |
||
712 | |||
713 | tc_DP3(tc, tmp, src[0], src[0]); |
||
714 | tc_INV(tc, tmp, tsrc_from(tmp)); |
||
715 | tc_MUL(tc, tdst_writemask(dst[0], TOY_WRITEMASK_XYZ), |
||
716 | src[0], tsrc_from(tmp)); |
||
717 | |||
718 | tc_MOV(tc, tdst_writemask(dst[0], TOY_WRITEMASK_W), tsrc_imm_f(1.0f)); |
||
719 | } |
||
720 | |||
721 | static void |
||
722 | aos_DIV(struct toy_compiler *tc, |
||
723 | const struct tgsi_full_instruction *tgsi_inst, |
||
724 | struct toy_dst *dst, |
||
725 | struct toy_src *src) |
||
726 | { |
||
727 | struct toy_dst tmp = tc_alloc_tmp(tc); |
||
728 | |||
729 | assert(!"DIV untested"); |
||
730 | |||
731 | tc_INV(tc, tmp, src[1]); |
||
732 | tc_MUL(tc, dst[0], src[0], tsrc_from(tmp)); |
||
733 | } |
||
734 | |||
735 | static void |
||
736 | aos_BRK(struct toy_compiler *tc, |
||
737 | const struct tgsi_full_instruction *tgsi_inst, |
||
738 | struct toy_dst *dst, |
||
739 | struct toy_src *src) |
||
740 | { |
||
741 | tc_add0(tc, BRW_OPCODE_BREAK); |
||
742 | } |
||
743 | |||
744 | static void |
||
745 | aos_CEIL(struct toy_compiler *tc, |
||
746 | const struct tgsi_full_instruction *tgsi_inst, |
||
747 | struct toy_dst *dst, |
||
748 | struct toy_src *src) |
||
749 | { |
||
750 | struct toy_dst tmp = tc_alloc_tmp(tc); |
||
751 | |||
752 | tc_RNDD(tc, tmp, tsrc_negate(src[0])); |
||
753 | tc_MOV(tc, dst[0], tsrc_negate(tsrc_from(tmp))); |
||
754 | } |
||
755 | |||
756 | static void |
||
757 | aos_SAD(struct toy_compiler *tc, |
||
758 | const struct tgsi_full_instruction *tgsi_inst, |
||
759 | struct toy_dst *dst, |
||
760 | struct toy_src *src) |
||
761 | { |
||
762 | struct toy_dst tmp = tc_alloc_tmp(tc); |
||
763 | |||
764 | assert(!"SAD untested"); |
||
765 | |||
766 | tc_ADD(tc, tmp, src[0], tsrc_negate(src[1])); |
||
767 | tc_ADD(tc, dst[0], tsrc_absolute(tsrc_from(tmp)), src[2]); |
||
768 | } |
||
769 | |||
770 | static void |
||
771 | aos_CONT(struct toy_compiler *tc, |
||
772 | const struct tgsi_full_instruction *tgsi_inst, |
||
773 | struct toy_dst *dst, |
||
774 | struct toy_src *src) |
||
775 | { |
||
776 | tc_add0(tc, BRW_OPCODE_CONTINUE); |
||
777 | } |
||
778 | |||
779 | static void |
||
780 | aos_BGNLOOP(struct toy_compiler *tc, |
||
781 | const struct tgsi_full_instruction *tgsi_inst, |
||
782 | struct toy_dst *dst, |
||
783 | struct toy_src *src) |
||
784 | { |
||
785 | struct toy_inst *inst; |
||
786 | |||
787 | inst = tc_add0(tc, BRW_OPCODE_DO); |
||
788 | /* this is just a marker */ |
||
789 | inst->marker = true; |
||
790 | } |
||
791 | |||
792 | static void |
||
793 | aos_ENDLOOP(struct toy_compiler *tc, |
||
794 | const struct tgsi_full_instruction *tgsi_inst, |
||
795 | struct toy_dst *dst, |
||
796 | struct toy_src *src) |
||
797 | { |
||
798 | tc_add0(tc, BRW_OPCODE_WHILE); |
||
799 | } |
||
800 | |||
801 | static void |
||
802 | aos_NRM4(struct toy_compiler *tc, |
||
803 | const struct tgsi_full_instruction *tgsi_inst, |
||
804 | struct toy_dst *dst, |
||
805 | struct toy_src *src) |
||
806 | { |
||
807 | struct toy_dst tmp = tc_alloc_tmp(tc); |
||
808 | |||
809 | assert(!"NRM4 untested"); |
||
810 | |||
811 | tc_DP4(tc, tmp, src[0], src[0]); |
||
812 | tc_INV(tc, tmp, tsrc_from(tmp)); |
||
813 | tc_MUL(tc, dst[0], tsrc_swizzle1(src[0], TOY_SWIZZLE_X), tsrc_from(tmp)); |
||
814 | } |
||
815 | |||
816 | static void |
||
817 | aos_unsupported(struct toy_compiler *tc, |
||
818 | const struct tgsi_full_instruction *tgsi_inst, |
||
819 | struct toy_dst *dst, |
||
820 | struct toy_src *src) |
||
821 | { |
||
822 | const char *name = tgsi_get_opcode_name(tgsi_inst->Instruction.Opcode); |
||
823 | |||
824 | ilo_warn("unsupported TGSI opcode: TGSI_OPCODE_%s\n", name); |
||
825 | |||
826 | tc_fail(tc, "unsupported TGSI instruction"); |
||
827 | } |
||
828 | |||
829 | static const toy_tgsi_translate aos_translate_table[TGSI_OPCODE_LAST] = { |
||
830 | [TGSI_OPCODE_ARL] = aos_simple, |
||
831 | [TGSI_OPCODE_MOV] = aos_simple, |
||
832 | [TGSI_OPCODE_LIT] = aos_LIT, |
||
833 | [TGSI_OPCODE_RCP] = aos_simple, |
||
834 | [TGSI_OPCODE_RSQ] = aos_simple, |
||
835 | [TGSI_OPCODE_EXP] = aos_EXP, |
||
836 | [TGSI_OPCODE_LOG] = aos_LOG, |
||
837 | [TGSI_OPCODE_MUL] = aos_simple, |
||
838 | [TGSI_OPCODE_ADD] = aos_simple, |
||
839 | [TGSI_OPCODE_DP3] = aos_simple, |
||
840 | [TGSI_OPCODE_DP4] = aos_simple, |
||
841 | [TGSI_OPCODE_DST] = aos_DST, |
||
842 | [TGSI_OPCODE_MIN] = aos_simple, |
||
843 | [TGSI_OPCODE_MAX] = aos_simple, |
||
844 | [TGSI_OPCODE_SLT] = aos_set_on_cond, |
||
845 | [TGSI_OPCODE_SGE] = aos_set_on_cond, |
||
846 | [TGSI_OPCODE_MAD] = aos_simple, |
||
847 | [TGSI_OPCODE_SUB] = aos_simple, |
||
848 | [TGSI_OPCODE_LRP] = aos_LRP, |
||
849 | [TGSI_OPCODE_CND] = aos_CND, |
||
850 | [TGSI_OPCODE_SQRT] = aos_simple, |
||
851 | [TGSI_OPCODE_DP2A] = aos_DP2A, |
||
852 | [22] = aos_unsupported, |
||
853 | [23] = aos_unsupported, |
||
854 | [TGSI_OPCODE_FRC] = aos_simple, |
||
855 | [TGSI_OPCODE_CLAMP] = aos_CLAMP, |
||
856 | [TGSI_OPCODE_FLR] = aos_simple, |
||
857 | [TGSI_OPCODE_ROUND] = aos_simple, |
||
858 | [TGSI_OPCODE_EX2] = aos_simple, |
||
859 | [TGSI_OPCODE_LG2] = aos_simple, |
||
860 | [TGSI_OPCODE_POW] = aos_simple, |
||
861 | [TGSI_OPCODE_XPD] = aos_XPD, |
||
862 | [32] = aos_unsupported, |
||
863 | [TGSI_OPCODE_ABS] = aos_simple, |
||
864 | [TGSI_OPCODE_RCC] = aos_unsupported, |
||
865 | [TGSI_OPCODE_DPH] = aos_simple, |
||
866 | [TGSI_OPCODE_COS] = aos_simple, |
||
867 | [TGSI_OPCODE_DDX] = aos_unsupported, |
||
868 | [TGSI_OPCODE_DDY] = aos_unsupported, |
||
869 | [TGSI_OPCODE_KILL] = aos_simple, |
||
870 | [TGSI_OPCODE_PK2H] = aos_PK2H, |
||
871 | [TGSI_OPCODE_PK2US] = aos_unsupported, |
||
872 | [TGSI_OPCODE_PK4B] = aos_unsupported, |
||
873 | [TGSI_OPCODE_PK4UB] = aos_unsupported, |
||
874 | [TGSI_OPCODE_RFL] = aos_unsupported, |
||
875 | [TGSI_OPCODE_SEQ] = aos_set_on_cond, |
||
876 | [TGSI_OPCODE_SFL] = aos_SFL, |
||
877 | [TGSI_OPCODE_SGT] = aos_set_on_cond, |
||
878 | [TGSI_OPCODE_SIN] = aos_simple, |
||
879 | [TGSI_OPCODE_SLE] = aos_set_on_cond, |
||
880 | [TGSI_OPCODE_SNE] = aos_set_on_cond, |
||
881 | [TGSI_OPCODE_STR] = aos_STR, |
||
882 | [TGSI_OPCODE_TEX] = aos_tex, |
||
883 | [TGSI_OPCODE_TXD] = aos_tex, |
||
884 | [TGSI_OPCODE_TXP] = aos_tex, |
||
885 | [TGSI_OPCODE_UP2H] = aos_UP2H, |
||
886 | [TGSI_OPCODE_UP2US] = aos_unsupported, |
||
887 | [TGSI_OPCODE_UP4B] = aos_unsupported, |
||
888 | [TGSI_OPCODE_UP4UB] = aos_unsupported, |
||
889 | [TGSI_OPCODE_X2D] = aos_unsupported, |
||
890 | [TGSI_OPCODE_ARA] = aos_unsupported, |
||
891 | [TGSI_OPCODE_ARR] = aos_simple, |
||
892 | [TGSI_OPCODE_BRA] = aos_unsupported, |
||
893 | [TGSI_OPCODE_CAL] = aos_unsupported, |
||
894 | [TGSI_OPCODE_RET] = aos_unsupported, |
||
895 | [TGSI_OPCODE_SSG] = aos_set_sign, |
||
896 | [TGSI_OPCODE_CMP] = aos_compare, |
||
897 | [TGSI_OPCODE_SCS] = aos_SCS, |
||
898 | [TGSI_OPCODE_TXB] = aos_tex, |
||
899 | [TGSI_OPCODE_NRM] = aos_NRM, |
||
900 | [TGSI_OPCODE_DIV] = aos_DIV, |
||
901 | [TGSI_OPCODE_DP2] = aos_simple, |
||
902 | [TGSI_OPCODE_TXL] = aos_tex, |
||
903 | [TGSI_OPCODE_BRK] = aos_BRK, |
||
904 | [TGSI_OPCODE_IF] = aos_simple, |
||
905 | [TGSI_OPCODE_UIF] = aos_simple, |
||
906 | [76] = aos_unsupported, |
||
907 | [TGSI_OPCODE_ELSE] = aos_simple, |
||
908 | [TGSI_OPCODE_ENDIF] = aos_simple, |
||
909 | [79] = aos_unsupported, |
||
910 | [80] = aos_unsupported, |
||
911 | [TGSI_OPCODE_PUSHA] = aos_unsupported, |
||
912 | [TGSI_OPCODE_POPA] = aos_unsupported, |
||
913 | [TGSI_OPCODE_CEIL] = aos_CEIL, |
||
914 | [TGSI_OPCODE_I2F] = aos_simple, |
||
915 | [TGSI_OPCODE_NOT] = aos_simple, |
||
916 | [TGSI_OPCODE_TRUNC] = aos_simple, |
||
917 | [TGSI_OPCODE_SHL] = aos_simple, |
||
918 | [88] = aos_unsupported, |
||
919 | [TGSI_OPCODE_AND] = aos_simple, |
||
920 | [TGSI_OPCODE_OR] = aos_simple, |
||
921 | [TGSI_OPCODE_MOD] = aos_simple, |
||
922 | [TGSI_OPCODE_XOR] = aos_simple, |
||
923 | [TGSI_OPCODE_SAD] = aos_SAD, |
||
924 | [TGSI_OPCODE_TXF] = aos_tex, |
||
925 | [TGSI_OPCODE_TXQ] = aos_tex, |
||
926 | [TGSI_OPCODE_CONT] = aos_CONT, |
||
927 | [TGSI_OPCODE_EMIT] = aos_simple, |
||
928 | [TGSI_OPCODE_ENDPRIM] = aos_simple, |
||
929 | [TGSI_OPCODE_BGNLOOP] = aos_BGNLOOP, |
||
930 | [TGSI_OPCODE_BGNSUB] = aos_unsupported, |
||
931 | [TGSI_OPCODE_ENDLOOP] = aos_ENDLOOP, |
||
932 | [TGSI_OPCODE_ENDSUB] = aos_unsupported, |
||
933 | [TGSI_OPCODE_TXQ_LZ] = aos_tex, |
||
934 | [104] = aos_unsupported, |
||
935 | [105] = aos_unsupported, |
||
936 | [106] = aos_unsupported, |
||
937 | [TGSI_OPCODE_NOP] = aos_simple, |
||
938 | [108] = aos_unsupported, |
||
939 | [109] = aos_unsupported, |
||
940 | [110] = aos_unsupported, |
||
941 | [111] = aos_unsupported, |
||
942 | [TGSI_OPCODE_NRM4] = aos_NRM4, |
||
943 | [TGSI_OPCODE_CALLNZ] = aos_unsupported, |
||
944 | [TGSI_OPCODE_BREAKC] = aos_unsupported, |
||
945 | [TGSI_OPCODE_KILL_IF] = aos_simple, |
||
946 | [TGSI_OPCODE_END] = aos_simple, |
||
947 | [118] = aos_unsupported, |
||
948 | [TGSI_OPCODE_F2I] = aos_simple, |
||
949 | [TGSI_OPCODE_IDIV] = aos_simple, |
||
950 | [TGSI_OPCODE_IMAX] = aos_simple, |
||
951 | [TGSI_OPCODE_IMIN] = aos_simple, |
||
952 | [TGSI_OPCODE_INEG] = aos_simple, |
||
953 | [TGSI_OPCODE_ISGE] = aos_set_on_cond, |
||
954 | [TGSI_OPCODE_ISHR] = aos_simple, |
||
955 | [TGSI_OPCODE_ISLT] = aos_set_on_cond, |
||
956 | [TGSI_OPCODE_F2U] = aos_simple, |
||
957 | [TGSI_OPCODE_U2F] = aos_simple, |
||
958 | [TGSI_OPCODE_UADD] = aos_simple, |
||
959 | [TGSI_OPCODE_UDIV] = aos_simple, |
||
960 | [TGSI_OPCODE_UMAD] = aos_simple, |
||
961 | [TGSI_OPCODE_UMAX] = aos_simple, |
||
962 | [TGSI_OPCODE_UMIN] = aos_simple, |
||
963 | [TGSI_OPCODE_UMOD] = aos_simple, |
||
964 | [TGSI_OPCODE_UMUL] = aos_simple, |
||
965 | [TGSI_OPCODE_USEQ] = aos_set_on_cond, |
||
966 | [TGSI_OPCODE_USGE] = aos_set_on_cond, |
||
967 | [TGSI_OPCODE_USHR] = aos_simple, |
||
968 | [TGSI_OPCODE_USLT] = aos_set_on_cond, |
||
969 | [TGSI_OPCODE_USNE] = aos_set_on_cond, |
||
970 | [TGSI_OPCODE_SWITCH] = aos_unsupported, |
||
971 | [TGSI_OPCODE_CASE] = aos_unsupported, |
||
972 | [TGSI_OPCODE_DEFAULT] = aos_unsupported, |
||
973 | [TGSI_OPCODE_ENDSWITCH] = aos_unsupported, |
||
974 | [TGSI_OPCODE_SAMPLE] = aos_sample, |
||
975 | [TGSI_OPCODE_SAMPLE_I] = aos_sample, |
||
976 | [TGSI_OPCODE_SAMPLE_I_MS] = aos_sample, |
||
977 | [TGSI_OPCODE_SAMPLE_B] = aos_sample, |
||
978 | [TGSI_OPCODE_SAMPLE_C] = aos_sample, |
||
979 | [TGSI_OPCODE_SAMPLE_C_LZ] = aos_sample, |
||
980 | [TGSI_OPCODE_SAMPLE_D] = aos_sample, |
||
981 | [TGSI_OPCODE_SAMPLE_L] = aos_sample, |
||
982 | [TGSI_OPCODE_GATHER4] = aos_sample, |
||
983 | [TGSI_OPCODE_SVIEWINFO] = aos_sample, |
||
984 | [TGSI_OPCODE_SAMPLE_POS] = aos_sample, |
||
985 | [TGSI_OPCODE_SAMPLE_INFO] = aos_sample, |
||
986 | [TGSI_OPCODE_UARL] = aos_simple, |
||
987 | [TGSI_OPCODE_UCMP] = aos_compare, |
||
988 | [TGSI_OPCODE_IABS] = aos_simple, |
||
989 | [TGSI_OPCODE_ISSG] = aos_set_sign, |
||
990 | [TGSI_OPCODE_LOAD] = aos_unsupported, |
||
991 | [TGSI_OPCODE_STORE] = aos_unsupported, |
||
992 | [TGSI_OPCODE_MFENCE] = aos_unsupported, |
||
993 | [TGSI_OPCODE_LFENCE] = aos_unsupported, |
||
994 | [TGSI_OPCODE_SFENCE] = aos_unsupported, |
||
995 | [TGSI_OPCODE_BARRIER] = aos_unsupported, |
||
996 | [TGSI_OPCODE_ATOMUADD] = aos_unsupported, |
||
997 | [TGSI_OPCODE_ATOMXCHG] = aos_unsupported, |
||
998 | [TGSI_OPCODE_ATOMCAS] = aos_unsupported, |
||
999 | [TGSI_OPCODE_ATOMAND] = aos_unsupported, |
||
1000 | [TGSI_OPCODE_ATOMOR] = aos_unsupported, |
||
1001 | [TGSI_OPCODE_ATOMXOR] = aos_unsupported, |
||
1002 | [TGSI_OPCODE_ATOMUMIN] = aos_unsupported, |
||
1003 | [TGSI_OPCODE_ATOMUMAX] = aos_unsupported, |
||
1004 | [TGSI_OPCODE_ATOMIMIN] = aos_unsupported, |
||
1005 | [TGSI_OPCODE_ATOMIMAX] = aos_unsupported, |
||
1006 | [TGSI_OPCODE_TEX2] = aos_tex, |
||
1007 | [TGSI_OPCODE_TXB2] = aos_tex, |
||
1008 | [TGSI_OPCODE_TXL2] = aos_tex, |
||
1009 | }; |
||
1010 | |||
1011 | static void |
||
1012 | soa_passthrough(struct toy_compiler *tc, |
||
1013 | const struct tgsi_full_instruction *tgsi_inst, |
||
1014 | struct toy_dst *dst_, |
||
1015 | struct toy_src *src_) |
||
1016 | { |
||
1017 | const toy_tgsi_translate translate = |
||
1018 | aos_translate_table[tgsi_inst->Instruction.Opcode]; |
||
1019 | |||
1020 | translate(tc, tgsi_inst, dst_, src_); |
||
1021 | } |
||
1022 | |||
1023 | static void |
||
1024 | soa_per_channel(struct toy_compiler *tc, |
||
1025 | const struct tgsi_full_instruction *tgsi_inst, |
||
1026 | struct toy_dst *dst_, |
||
1027 | struct toy_src *src_) |
||
1028 | { |
||
1029 | struct toy_dst dst[TGSI_FULL_MAX_DST_REGISTERS][4]; |
||
1030 | struct toy_src src[TGSI_FULL_MAX_SRC_REGISTERS][4]; |
||
1031 | int i, ch; |
||
1032 | |||
1033 | for (i = 0; i < tgsi_inst->Instruction.NumDstRegs; i++) |
||
1034 | tdst_transpose(dst_[i], dst[i]); |
||
1035 | for (i = 0; i < tgsi_inst->Instruction.NumSrcRegs; i++) |
||
1036 | tsrc_transpose(src_[i], src[i]); |
||
1037 | |||
1038 | /* emit the same instruction four times for the four channels */ |
||
1039 | for (ch = 0; ch < 4; ch++) { |
||
1040 | struct toy_dst aos_dst[TGSI_FULL_MAX_DST_REGISTERS]; |
||
1041 | struct toy_src aos_src[TGSI_FULL_MAX_SRC_REGISTERS]; |
||
1042 | |||
1043 | for (i = 0; i < tgsi_inst->Instruction.NumDstRegs; i++) |
||
1044 | aos_dst[i] = dst[i][ch]; |
||
1045 | for (i = 0; i < tgsi_inst->Instruction.NumSrcRegs; i++) |
||
1046 | aos_src[i] = src[i][ch]; |
||
1047 | |||
1048 | aos_translate_table[tgsi_inst->Instruction.Opcode](tc, |
||
1049 | tgsi_inst, aos_dst, aos_src); |
||
1050 | } |
||
1051 | } |
||
1052 | |||
1053 | static void |
||
1054 | soa_scalar_replicate(struct toy_compiler *tc, |
||
1055 | const struct tgsi_full_instruction *tgsi_inst, |
||
1056 | struct toy_dst *dst_, |
||
1057 | struct toy_src *src_) |
||
1058 | { |
||
1059 | struct toy_dst dst0[4], tmp; |
||
1060 | struct toy_src srcx[TGSI_FULL_MAX_SRC_REGISTERS]; |
||
1061 | int opcode, i; |
||
1062 | |||
1063 | assert(tgsi_inst->Instruction.NumDstRegs == 1); |
||
1064 | |||
1065 | tdst_transpose(dst_[0], dst0); |
||
1066 | for (i = 0; i < tgsi_inst->Instruction.NumSrcRegs; i++) { |
||
1067 | struct toy_src tmp[4]; |
||
1068 | |||
1069 | tsrc_transpose(src_[i], tmp); |
||
1070 | /* only the X channels */ |
||
1071 | srcx[i] = tmp[0]; |
||
1072 | } |
||
1073 | |||
1074 | tmp = tc_alloc_tmp(tc); |
||
1075 | |||
1076 | opcode = aos_simple_opcode_map[tgsi_inst->Instruction.Opcode].opcode; |
||
1077 | assert(opcode); |
||
1078 | |||
1079 | switch (tgsi_inst->Instruction.Opcode) { |
||
1080 | case TGSI_OPCODE_RCP: |
||
1081 | case TGSI_OPCODE_RSQ: |
||
1082 | case TGSI_OPCODE_SQRT: |
||
1083 | case TGSI_OPCODE_EX2: |
||
1084 | case TGSI_OPCODE_LG2: |
||
1085 | case TGSI_OPCODE_COS: |
||
1086 | case TGSI_OPCODE_SIN: |
||
1087 | tc_add1(tc, opcode, tmp, srcx[0]); |
||
1088 | break; |
||
1089 | case TGSI_OPCODE_POW: |
||
1090 | tc_add2(tc, opcode, tmp, srcx[0], srcx[1]); |
||
1091 | break; |
||
1092 | default: |
||
1093 | assert(!"invalid soa_scalar_replicate() call"); |
||
1094 | return; |
||
1095 | } |
||
1096 | |||
1097 | /* replicate the result */ |
||
1098 | for (i = 0; i < 4; i++) |
||
1099 | tc_MOV(tc, dst0[i], tsrc_from(tmp)); |
||
1100 | } |
||
1101 | |||
1102 | static void |
||
1103 | soa_dot_product(struct toy_compiler *tc, |
||
1104 | const struct tgsi_full_instruction *tgsi_inst, |
||
1105 | struct toy_dst *dst_, |
||
1106 | struct toy_src *src_) |
||
1107 | { |
||
1108 | struct toy_dst dst0[4], tmp; |
||
1109 | struct toy_src src[TGSI_FULL_MAX_SRC_REGISTERS][4]; |
||
1110 | int i; |
||
1111 | |||
1112 | tdst_transpose(dst_[0], dst0); |
||
1113 | for (i = 0; i < tgsi_inst->Instruction.NumSrcRegs; i++) |
||
1114 | tsrc_transpose(src_[i], src[i]); |
||
1115 | |||
1116 | tmp = tc_alloc_tmp(tc); |
||
1117 | |||
1118 | switch (tgsi_inst->Instruction.Opcode) { |
||
1119 | case TGSI_OPCODE_DP2: |
||
1120 | tc_MUL(tc, tmp, src[0][1], src[1][1]); |
||
1121 | tc_MAC(tc, tmp, src[0][0], src[1][0], tsrc_from(tmp)); |
||
1122 | break; |
||
1123 | case TGSI_OPCODE_DP2A: |
||
1124 | tc_MAC(tc, tmp, src[0][1], src[1][1], src[2][0]); |
||
1125 | tc_MAC(tc, tmp, src[0][0], src[1][0], tsrc_from(tmp)); |
||
1126 | break; |
||
1127 | case TGSI_OPCODE_DP3: |
||
1128 | tc_MUL(tc, tmp, src[0][2], src[1][2]); |
||
1129 | tc_MAC(tc, tmp, src[0][1], src[1][1], tsrc_from(tmp)); |
||
1130 | tc_MAC(tc, tmp, src[0][0], src[1][0], tsrc_from(tmp)); |
||
1131 | break; |
||
1132 | case TGSI_OPCODE_DPH: |
||
1133 | tc_MAC(tc, tmp, src[0][2], src[1][2], src[1][3]); |
||
1134 | tc_MAC(tc, tmp, src[0][1], src[1][1], tsrc_from(tmp)); |
||
1135 | tc_MAC(tc, tmp, src[0][0], src[1][0], tsrc_from(tmp)); |
||
1136 | break; |
||
1137 | case TGSI_OPCODE_DP4: |
||
1138 | tc_MUL(tc, tmp, src[0][3], src[1][3]); |
||
1139 | tc_MAC(tc, tmp, src[0][2], src[1][2], tsrc_from(tmp)); |
||
1140 | tc_MAC(tc, tmp, src[0][1], src[1][1], tsrc_from(tmp)); |
||
1141 | tc_MAC(tc, tmp, src[0][0], src[1][0], tsrc_from(tmp)); |
||
1142 | break; |
||
1143 | default: |
||
1144 | assert(!"invalid soa_dot_product() call"); |
||
1145 | return; |
||
1146 | } |
||
1147 | |||
1148 | for (i = 0; i < 4; i++) |
||
1149 | tc_MOV(tc, dst0[i], tsrc_from(tmp)); |
||
1150 | } |
||
1151 | |||
1152 | static void |
||
1153 | soa_partial_derivative(struct toy_compiler *tc, |
||
1154 | const struct tgsi_full_instruction *tgsi_inst, |
||
1155 | struct toy_dst *dst_, |
||
1156 | struct toy_src *src_) |
||
1157 | { |
||
1158 | if (tgsi_inst->Instruction.Opcode == TGSI_OPCODE_DDX) |
||
1159 | tc_add1(tc, TOY_OPCODE_DDX, dst_[0], src_[0]); |
||
1160 | else |
||
1161 | tc_add1(tc, TOY_OPCODE_DDY, dst_[0], src_[0]); |
||
1162 | } |
||
1163 | |||
1164 | static void |
||
1165 | soa_if(struct toy_compiler *tc, |
||
1166 | const struct tgsi_full_instruction *tgsi_inst, |
||
1167 | struct toy_dst *dst_, |
||
1168 | struct toy_src *src_) |
||
1169 | { |
||
1170 | struct toy_src src0[4]; |
||
1171 | |||
1172 | assert(tsrc_is_swizzle1(src_[0])); |
||
1173 | tsrc_transpose(src_[0], src0); |
||
1174 | |||
1175 | if (tgsi_inst->Instruction.Opcode == TGSI_OPCODE_IF) |
||
1176 | tc_IF(tc, tdst_null(), src0[0], tsrc_imm_f(0.0f), BRW_CONDITIONAL_NEQ); |
||
1177 | else |
||
1178 | tc_IF(tc, tdst_null(), src0[0], tsrc_imm_d(0), BRW_CONDITIONAL_NEQ); |
||
1179 | } |
||
1180 | |||
1181 | static void |
||
1182 | soa_LIT(struct toy_compiler *tc, |
||
1183 | const struct tgsi_full_instruction *tgsi_inst, |
||
1184 | struct toy_dst *dst_, |
||
1185 | struct toy_src *src_) |
||
1186 | { |
||
1187 | struct toy_inst *inst; |
||
1188 | struct toy_dst dst0[4]; |
||
1189 | struct toy_src src0[4]; |
||
1190 | |||
1191 | tdst_transpose(dst_[0], dst0); |
||
1192 | tsrc_transpose(src_[0], src0); |
||
1193 | |||
1194 | tc_MOV(tc, dst0[0], tsrc_imm_f(1.0f)); |
||
1195 | tc_MOV(tc, dst0[1], src0[0]); |
||
1196 | tc_POW(tc, dst0[2], src0[1], src0[3]); |
||
1197 | tc_MOV(tc, dst0[3], tsrc_imm_f(1.0f)); |
||
1198 | |||
1199 | /* |
||
1200 | * POW is calculated first because math with pred_ctrl is broken here. |
||
1201 | * But, why? |
||
1202 | */ |
||
1203 | tc_CMP(tc, tdst_null(), src0[0], tsrc_imm_f(0.0f), BRW_CONDITIONAL_L); |
||
1204 | inst = tc_MOV(tc, dst0[1], tsrc_imm_f(0.0f)); |
||
1205 | inst->pred_ctrl = BRW_PREDICATE_NORMAL; |
||
1206 | inst = tc_MOV(tc, dst0[2], tsrc_imm_f(0.0f)); |
||
1207 | inst->pred_ctrl = BRW_PREDICATE_NORMAL; |
||
1208 | } |
||
1209 | |||
1210 | static void |
||
1211 | soa_EXP(struct toy_compiler *tc, |
||
1212 | const struct tgsi_full_instruction *tgsi_inst, |
||
1213 | struct toy_dst *dst_, |
||
1214 | struct toy_src *src_) |
||
1215 | { |
||
1216 | struct toy_dst dst0[4]; |
||
1217 | struct toy_src src0[4]; |
||
1218 | |||
1219 | assert(!"SoA EXP untested"); |
||
1220 | |||
1221 | tdst_transpose(dst_[0], dst0); |
||
1222 | tsrc_transpose(src_[0], src0); |
||
1223 | |||
1224 | if (!tdst_is_null(dst0[0])) { |
||
1225 | struct toy_dst tmp = tdst_d(tc_alloc_tmp(tc)); |
||
1226 | |||
1227 | tc_RNDD(tc, tmp, src0[0]); |
||
1228 | |||
1229 | /* construct the floating point number manually */ |
||
1230 | tc_ADD(tc, tmp, tsrc_from(tmp), tsrc_imm_d(127)); |
||
1231 | tc_SHL(tc, tdst_d(dst0[0]), tsrc_from(tmp), tsrc_imm_d(23)); |
||
1232 | } |
||
1233 | |||
1234 | tc_FRC(tc, dst0[1], src0[0]); |
||
1235 | tc_EXP(tc, dst0[2], src0[0]); |
||
1236 | tc_MOV(tc, dst0[3], tsrc_imm_f(1.0f)); |
||
1237 | } |
||
1238 | |||
1239 | static void |
||
1240 | soa_LOG(struct toy_compiler *tc, |
||
1241 | const struct tgsi_full_instruction *tgsi_inst, |
||
1242 | struct toy_dst *dst_, |
||
1243 | struct toy_src *src_) |
||
1244 | { |
||
1245 | struct toy_dst dst0[4]; |
||
1246 | struct toy_src src0[4]; |
||
1247 | |||
1248 | assert(!"SoA LOG untested"); |
||
1249 | |||
1250 | tdst_transpose(dst_[0], dst0); |
||
1251 | tsrc_transpose(src_[0], src0); |
||
1252 | |||
1253 | if (dst_[0].writemask & TOY_WRITEMASK_XY) { |
||
1254 | struct toy_dst tmp = tdst_d(tc_alloc_tmp(tc)); |
||
1255 | |||
1256 | /* exponent */ |
||
1257 | tc_SHR(tc, tmp, tsrc_absolute(tsrc_d(src0[0])), tsrc_imm_d(23)); |
||
1258 | tc_ADD(tc, dst0[0], tsrc_from(tmp), tsrc_imm_d(-127)); |
||
1259 | |||
1260 | /* mantissa */ |
||
1261 | tc_AND(tc, tmp, tsrc_d(src0[0]), tsrc_imm_d((1 << 23) - 1)); |
||
1262 | tc_OR(tc, dst0[1], tsrc_from(tmp), tsrc_imm_d(127 << 23)); |
||
1263 | } |
||
1264 | |||
1265 | tc_LOG(tc, dst0[2], src0[0]); |
||
1266 | tc_MOV(tc, dst0[3], tsrc_imm_f(1.0f)); |
||
1267 | } |
||
1268 | |||
1269 | static void |
||
1270 | soa_DST(struct toy_compiler *tc, |
||
1271 | const struct tgsi_full_instruction *tgsi_inst, |
||
1272 | struct toy_dst *dst_, |
||
1273 | struct toy_src *src_) |
||
1274 | { |
||
1275 | struct toy_dst dst0[4]; |
||
1276 | struct toy_src src[2][4]; |
||
1277 | |||
1278 | tdst_transpose(dst_[0], dst0); |
||
1279 | tsrc_transpose(src_[0], src[0]); |
||
1280 | tsrc_transpose(src_[1], src[1]); |
||
1281 | |||
1282 | tc_MOV(tc, dst0[0], tsrc_imm_f(1.0f)); |
||
1283 | tc_MUL(tc, dst0[1], src[0][1], src[1][1]); |
||
1284 | tc_MOV(tc, dst0[2], src[0][2]); |
||
1285 | tc_MOV(tc, dst0[3], src[1][3]); |
||
1286 | } |
||
1287 | |||
1288 | static void |
||
1289 | soa_XPD(struct toy_compiler *tc, |
||
1290 | const struct tgsi_full_instruction *tgsi_inst, |
||
1291 | struct toy_dst *dst_, |
||
1292 | struct toy_src *src_) |
||
1293 | { |
||
1294 | struct toy_dst dst0[4]; |
||
1295 | struct toy_src src[2][4]; |
||
1296 | |||
1297 | tdst_transpose(dst_[0], dst0); |
||
1298 | tsrc_transpose(src_[0], src[0]); |
||
1299 | tsrc_transpose(src_[1], src[1]); |
||
1300 | |||
1301 | /* dst.x = src0.y * src1.z - src1.y * src0.z */ |
||
1302 | tc_MUL(tc, dst0[0], src[0][2], src[1][1]); |
||
1303 | tc_MAC(tc, dst0[0], src[0][1], src[1][2], tsrc_negate(tsrc_from(dst0[0]))); |
||
1304 | |||
1305 | /* dst.y = src0.z * src1.x - src1.z * src0.x */ |
||
1306 | tc_MUL(tc, dst0[1], src[0][0], src[1][2]); |
||
1307 | tc_MAC(tc, dst0[1], src[0][2], src[1][0], tsrc_negate(tsrc_from(dst0[1]))); |
||
1308 | |||
1309 | /* dst.z = src0.x * src1.y - src1.x * src0.y */ |
||
1310 | tc_MUL(tc, dst0[2], src[0][1], src[1][0]); |
||
1311 | tc_MAC(tc, dst0[2], src[0][0], src[1][1], tsrc_negate(tsrc_from(dst0[2]))); |
||
1312 | |||
1313 | tc_MOV(tc, dst0[3], tsrc_imm_f(1.0f)); |
||
1314 | } |
||
1315 | |||
1316 | static void |
||
1317 | soa_PK2H(struct toy_compiler *tc, |
||
1318 | const struct tgsi_full_instruction *tgsi_inst, |
||
1319 | struct toy_dst *dst_, |
||
1320 | struct toy_src *src_) |
||
1321 | { |
||
1322 | struct toy_dst tmp = tdst_ud(tc_alloc_tmp(tc)); |
||
1323 | struct toy_dst dst0[4]; |
||
1324 | struct toy_src src0[4]; |
||
1325 | int i; |
||
1326 | |||
1327 | assert(!"SoA PK2H untested"); |
||
1328 | |||
1329 | tdst_transpose(dst_[0], dst0); |
||
1330 | tsrc_transpose(src_[0], src0); |
||
1331 | |||
1332 | tc_SHL(tc, tmp, src0[1], tsrc_imm_ud(16)); |
||
1333 | tc_OR(tc, tmp, src0[0], tsrc_from(tmp)); |
||
1334 | |||
1335 | for (i = 0; i < 4; i++) |
||
1336 | tc_MOV(tc, dst0[i], tsrc_from(tmp)); |
||
1337 | } |
||
1338 | |||
1339 | static void |
||
1340 | soa_UP2H(struct toy_compiler *tc, |
||
1341 | const struct tgsi_full_instruction *tgsi_inst, |
||
1342 | struct toy_dst *dst_, |
||
1343 | struct toy_src *src_) |
||
1344 | { |
||
1345 | struct toy_dst dst0[4]; |
||
1346 | struct toy_src src0[4]; |
||
1347 | |||
1348 | assert(!"SoA UP2H untested"); |
||
1349 | |||
1350 | tdst_transpose(dst_[0], dst0); |
||
1351 | tsrc_transpose(src_[0], src0); |
||
1352 | |||
1353 | tc_AND(tc, tdst_ud(dst0[0]), tsrc_ud(src0[0]), tsrc_imm_ud(0xffff)); |
||
1354 | tc_SHR(tc, tdst_ud(dst0[1]), tsrc_ud(src0[1]), tsrc_imm_ud(16)); |
||
1355 | tc_AND(tc, tdst_ud(dst0[2]), tsrc_ud(src0[2]), tsrc_imm_ud(0xffff)); |
||
1356 | tc_SHR(tc, tdst_ud(dst0[3]), tsrc_ud(src0[3]), tsrc_imm_ud(16)); |
||
1357 | |||
1358 | } |
||
1359 | |||
1360 | static void |
||
1361 | soa_SCS(struct toy_compiler *tc, |
||
1362 | const struct tgsi_full_instruction *tgsi_inst, |
||
1363 | struct toy_dst *dst_, |
||
1364 | struct toy_src *src_) |
||
1365 | { |
||
1366 | struct toy_dst dst0[4]; |
||
1367 | struct toy_src src0[4]; |
||
1368 | |||
1369 | tdst_transpose(dst_[0], dst0); |
||
1370 | tsrc_transpose(src_[0], src0); |
||
1371 | |||
1372 | tc_add1(tc, TOY_OPCODE_COS, dst0[0], src0[0]); |
||
1373 | tc_add1(tc, TOY_OPCODE_SIN, dst0[1], src0[0]); |
||
1374 | tc_MOV(tc, dst0[2], tsrc_imm_f(0.0f)); |
||
1375 | tc_MOV(tc, dst0[3], tsrc_imm_f(1.0f)); |
||
1376 | } |
||
1377 | |||
1378 | static void |
||
1379 | soa_NRM(struct toy_compiler *tc, |
||
1380 | const struct tgsi_full_instruction *tgsi_inst, |
||
1381 | struct toy_dst *dst_, |
||
1382 | struct toy_src *src_) |
||
1383 | { |
||
1384 | const struct toy_dst tmp = tc_alloc_tmp(tc); |
||
1385 | struct toy_dst dst0[4]; |
||
1386 | struct toy_src src0[4]; |
||
1387 | |||
1388 | assert(!"SoA NRM untested"); |
||
1389 | |||
1390 | tdst_transpose(dst_[0], dst0); |
||
1391 | tsrc_transpose(src_[0], src0); |
||
1392 | |||
1393 | tc_MUL(tc, tmp, src0[2], src0[2]); |
||
1394 | tc_MAC(tc, tmp, src0[1], src0[1], tsrc_from(tmp)); |
||
1395 | tc_MAC(tc, tmp, src0[0], src0[0], tsrc_from(tmp)); |
||
1396 | tc_INV(tc, tmp, tsrc_from(tmp)); |
||
1397 | |||
1398 | tc_MUL(tc, dst0[0], src0[0], tsrc_from(tmp)); |
||
1399 | tc_MUL(tc, dst0[1], src0[1], tsrc_from(tmp)); |
||
1400 | tc_MUL(tc, dst0[2], src0[2], tsrc_from(tmp)); |
||
1401 | tc_MOV(tc, dst0[3], tsrc_imm_f(1.0f)); |
||
1402 | } |
||
1403 | |||
1404 | static void |
||
1405 | soa_NRM4(struct toy_compiler *tc, |
||
1406 | const struct tgsi_full_instruction *tgsi_inst, |
||
1407 | struct toy_dst *dst_, |
||
1408 | struct toy_src *src_) |
||
1409 | { |
||
1410 | const struct toy_dst tmp = tc_alloc_tmp(tc); |
||
1411 | struct toy_dst dst0[4]; |
||
1412 | struct toy_src src0[4]; |
||
1413 | int i; |
||
1414 | |||
1415 | assert(!"SoA NRM4 untested"); |
||
1416 | |||
1417 | tdst_transpose(dst_[0], dst0); |
||
1418 | tsrc_transpose(src_[0], src0); |
||
1419 | |||
1420 | tc_MUL(tc, tmp, src0[3], src0[3]); |
||
1421 | tc_MAC(tc, tmp, src0[2], src0[2], tsrc_from(tmp)); |
||
1422 | tc_MAC(tc, tmp, src0[1], src0[1], tsrc_from(tmp)); |
||
1423 | tc_MAC(tc, tmp, src0[0], src0[0], tsrc_from(tmp)); |
||
1424 | tc_INV(tc, tmp, tsrc_from(tmp)); |
||
1425 | |||
1426 | for (i = 0; i < 4; i++) |
||
1427 | tc_MUL(tc, dst0[i], src0[0], tsrc_from(tmp)); |
||
1428 | } |
||
1429 | |||
1430 | static void |
||
1431 | soa_unsupported(struct toy_compiler *tc, |
||
1432 | const struct tgsi_full_instruction *tgsi_inst, |
||
1433 | struct toy_dst *dst_, |
||
1434 | struct toy_src *src_) |
||
1435 | { |
||
1436 | const struct tgsi_opcode_info *info = |
||
1437 | tgsi_get_opcode_info(tgsi_inst->Instruction.Opcode); |
||
1438 | |||
1439 | ilo_warn("unsupported TGSI opcode in SoA form: TGSI_OPCODE_%s\n", |
||
1440 | info->mnemonic); |
||
1441 | |||
1442 | tc_fail(tc, "unsupported TGSI instruction in SoA form"); |
||
1443 | } |
||
1444 | |||
1445 | static const toy_tgsi_translate soa_translate_table[TGSI_OPCODE_LAST] = { |
||
1446 | [TGSI_OPCODE_ARL] = soa_per_channel, |
||
1447 | [TGSI_OPCODE_MOV] = soa_per_channel, |
||
1448 | [TGSI_OPCODE_LIT] = soa_LIT, |
||
1449 | [TGSI_OPCODE_RCP] = soa_scalar_replicate, |
||
1450 | [TGSI_OPCODE_RSQ] = soa_scalar_replicate, |
||
1451 | [TGSI_OPCODE_EXP] = soa_EXP, |
||
1452 | [TGSI_OPCODE_LOG] = soa_LOG, |
||
1453 | [TGSI_OPCODE_MUL] = soa_per_channel, |
||
1454 | [TGSI_OPCODE_ADD] = soa_per_channel, |
||
1455 | [TGSI_OPCODE_DP3] = soa_dot_product, |
||
1456 | [TGSI_OPCODE_DP4] = soa_dot_product, |
||
1457 | [TGSI_OPCODE_DST] = soa_DST, |
||
1458 | [TGSI_OPCODE_MIN] = soa_per_channel, |
||
1459 | [TGSI_OPCODE_MAX] = soa_per_channel, |
||
1460 | [TGSI_OPCODE_SLT] = soa_per_channel, |
||
1461 | [TGSI_OPCODE_SGE] = soa_per_channel, |
||
1462 | [TGSI_OPCODE_MAD] = soa_per_channel, |
||
1463 | [TGSI_OPCODE_SUB] = soa_per_channel, |
||
1464 | [TGSI_OPCODE_LRP] = soa_per_channel, |
||
1465 | [TGSI_OPCODE_CND] = soa_per_channel, |
||
1466 | [TGSI_OPCODE_SQRT] = soa_scalar_replicate, |
||
1467 | [TGSI_OPCODE_DP2A] = soa_dot_product, |
||
1468 | [22] = soa_unsupported, |
||
1469 | [23] = soa_unsupported, |
||
1470 | [TGSI_OPCODE_FRC] = soa_per_channel, |
||
1471 | [TGSI_OPCODE_CLAMP] = soa_per_channel, |
||
1472 | [TGSI_OPCODE_FLR] = soa_per_channel, |
||
1473 | [TGSI_OPCODE_ROUND] = soa_per_channel, |
||
1474 | [TGSI_OPCODE_EX2] = soa_scalar_replicate, |
||
1475 | [TGSI_OPCODE_LG2] = soa_scalar_replicate, |
||
1476 | [TGSI_OPCODE_POW] = soa_scalar_replicate, |
||
1477 | [TGSI_OPCODE_XPD] = soa_XPD, |
||
1478 | [32] = soa_unsupported, |
||
1479 | [TGSI_OPCODE_ABS] = soa_per_channel, |
||
1480 | [TGSI_OPCODE_RCC] = soa_unsupported, |
||
1481 | [TGSI_OPCODE_DPH] = soa_dot_product, |
||
1482 | [TGSI_OPCODE_COS] = soa_scalar_replicate, |
||
1483 | [TGSI_OPCODE_DDX] = soa_partial_derivative, |
||
1484 | [TGSI_OPCODE_DDY] = soa_partial_derivative, |
||
1485 | [TGSI_OPCODE_KILL] = soa_passthrough, |
||
1486 | [TGSI_OPCODE_PK2H] = soa_PK2H, |
||
1487 | [TGSI_OPCODE_PK2US] = soa_unsupported, |
||
1488 | [TGSI_OPCODE_PK4B] = soa_unsupported, |
||
1489 | [TGSI_OPCODE_PK4UB] = soa_unsupported, |
||
1490 | [TGSI_OPCODE_RFL] = soa_unsupported, |
||
1491 | [TGSI_OPCODE_SEQ] = soa_per_channel, |
||
1492 | [TGSI_OPCODE_SFL] = soa_per_channel, |
||
1493 | [TGSI_OPCODE_SGT] = soa_per_channel, |
||
1494 | [TGSI_OPCODE_SIN] = soa_scalar_replicate, |
||
1495 | [TGSI_OPCODE_SLE] = soa_per_channel, |
||
1496 | [TGSI_OPCODE_SNE] = soa_per_channel, |
||
1497 | [TGSI_OPCODE_STR] = soa_per_channel, |
||
1498 | [TGSI_OPCODE_TEX] = soa_passthrough, |
||
1499 | [TGSI_OPCODE_TXD] = soa_passthrough, |
||
1500 | [TGSI_OPCODE_TXP] = soa_passthrough, |
||
1501 | [TGSI_OPCODE_UP2H] = soa_UP2H, |
||
1502 | [TGSI_OPCODE_UP2US] = soa_unsupported, |
||
1503 | [TGSI_OPCODE_UP4B] = soa_unsupported, |
||
1504 | [TGSI_OPCODE_UP4UB] = soa_unsupported, |
||
1505 | [TGSI_OPCODE_X2D] = soa_unsupported, |
||
1506 | [TGSI_OPCODE_ARA] = soa_unsupported, |
||
1507 | [TGSI_OPCODE_ARR] = soa_per_channel, |
||
1508 | [TGSI_OPCODE_BRA] = soa_unsupported, |
||
1509 | [TGSI_OPCODE_CAL] = soa_unsupported, |
||
1510 | [TGSI_OPCODE_RET] = soa_unsupported, |
||
1511 | [TGSI_OPCODE_SSG] = soa_per_channel, |
||
1512 | [TGSI_OPCODE_CMP] = soa_per_channel, |
||
1513 | [TGSI_OPCODE_SCS] = soa_SCS, |
||
1514 | [TGSI_OPCODE_TXB] = soa_passthrough, |
||
1515 | [TGSI_OPCODE_NRM] = soa_NRM, |
||
1516 | [TGSI_OPCODE_DIV] = soa_per_channel, |
||
1517 | [TGSI_OPCODE_DP2] = soa_dot_product, |
||
1518 | [TGSI_OPCODE_TXL] = soa_passthrough, |
||
1519 | [TGSI_OPCODE_BRK] = soa_passthrough, |
||
1520 | [TGSI_OPCODE_IF] = soa_if, |
||
1521 | [TGSI_OPCODE_UIF] = soa_if, |
||
1522 | [76] = soa_unsupported, |
||
1523 | [TGSI_OPCODE_ELSE] = soa_passthrough, |
||
1524 | [TGSI_OPCODE_ENDIF] = soa_passthrough, |
||
1525 | [79] = soa_unsupported, |
||
1526 | [80] = soa_unsupported, |
||
1527 | [TGSI_OPCODE_PUSHA] = soa_unsupported, |
||
1528 | [TGSI_OPCODE_POPA] = soa_unsupported, |
||
1529 | [TGSI_OPCODE_CEIL] = soa_per_channel, |
||
1530 | [TGSI_OPCODE_I2F] = soa_per_channel, |
||
1531 | [TGSI_OPCODE_NOT] = soa_per_channel, |
||
1532 | [TGSI_OPCODE_TRUNC] = soa_per_channel, |
||
1533 | [TGSI_OPCODE_SHL] = soa_per_channel, |
||
1534 | [88] = soa_unsupported, |
||
1535 | [TGSI_OPCODE_AND] = soa_per_channel, |
||
1536 | [TGSI_OPCODE_OR] = soa_per_channel, |
||
1537 | [TGSI_OPCODE_MOD] = soa_per_channel, |
||
1538 | [TGSI_OPCODE_XOR] = soa_per_channel, |
||
1539 | [TGSI_OPCODE_SAD] = soa_per_channel, |
||
1540 | [TGSI_OPCODE_TXF] = soa_passthrough, |
||
1541 | [TGSI_OPCODE_TXQ] = soa_passthrough, |
||
1542 | [TGSI_OPCODE_CONT] = soa_passthrough, |
||
1543 | [TGSI_OPCODE_EMIT] = soa_unsupported, |
||
1544 | [TGSI_OPCODE_ENDPRIM] = soa_unsupported, |
||
1545 | [TGSI_OPCODE_BGNLOOP] = soa_passthrough, |
||
1546 | [TGSI_OPCODE_BGNSUB] = soa_unsupported, |
||
1547 | [TGSI_OPCODE_ENDLOOP] = soa_passthrough, |
||
1548 | [TGSI_OPCODE_ENDSUB] = soa_unsupported, |
||
1549 | [TGSI_OPCODE_TXQ_LZ] = soa_passthrough, |
||
1550 | [104] = soa_unsupported, |
||
1551 | [105] = soa_unsupported, |
||
1552 | [106] = soa_unsupported, |
||
1553 | [TGSI_OPCODE_NOP] = soa_passthrough, |
||
1554 | [108] = soa_unsupported, |
||
1555 | [109] = soa_unsupported, |
||
1556 | [110] = soa_unsupported, |
||
1557 | [111] = soa_unsupported, |
||
1558 | [TGSI_OPCODE_NRM4] = soa_NRM4, |
||
1559 | [TGSI_OPCODE_CALLNZ] = soa_unsupported, |
||
1560 | [TGSI_OPCODE_BREAKC] = soa_unsupported, |
||
1561 | [TGSI_OPCODE_KILL_IF] = soa_passthrough, |
||
1562 | [TGSI_OPCODE_END] = soa_passthrough, |
||
1563 | [118] = soa_unsupported, |
||
1564 | [TGSI_OPCODE_F2I] = soa_per_channel, |
||
1565 | [TGSI_OPCODE_IDIV] = soa_per_channel, |
||
1566 | [TGSI_OPCODE_IMAX] = soa_per_channel, |
||
1567 | [TGSI_OPCODE_IMIN] = soa_per_channel, |
||
1568 | [TGSI_OPCODE_INEG] = soa_per_channel, |
||
1569 | [TGSI_OPCODE_ISGE] = soa_per_channel, |
||
1570 | [TGSI_OPCODE_ISHR] = soa_per_channel, |
||
1571 | [TGSI_OPCODE_ISLT] = soa_per_channel, |
||
1572 | [TGSI_OPCODE_F2U] = soa_per_channel, |
||
1573 | [TGSI_OPCODE_U2F] = soa_per_channel, |
||
1574 | [TGSI_OPCODE_UADD] = soa_per_channel, |
||
1575 | [TGSI_OPCODE_UDIV] = soa_per_channel, |
||
1576 | [TGSI_OPCODE_UMAD] = soa_per_channel, |
||
1577 | [TGSI_OPCODE_UMAX] = soa_per_channel, |
||
1578 | [TGSI_OPCODE_UMIN] = soa_per_channel, |
||
1579 | [TGSI_OPCODE_UMOD] = soa_per_channel, |
||
1580 | [TGSI_OPCODE_UMUL] = soa_per_channel, |
||
1581 | [TGSI_OPCODE_USEQ] = soa_per_channel, |
||
1582 | [TGSI_OPCODE_USGE] = soa_per_channel, |
||
1583 | [TGSI_OPCODE_USHR] = soa_per_channel, |
||
1584 | [TGSI_OPCODE_USLT] = soa_per_channel, |
||
1585 | [TGSI_OPCODE_USNE] = soa_per_channel, |
||
1586 | [TGSI_OPCODE_SWITCH] = soa_unsupported, |
||
1587 | [TGSI_OPCODE_CASE] = soa_unsupported, |
||
1588 | [TGSI_OPCODE_DEFAULT] = soa_unsupported, |
||
1589 | [TGSI_OPCODE_ENDSWITCH] = soa_unsupported, |
||
1590 | [TGSI_OPCODE_SAMPLE] = soa_passthrough, |
||
1591 | [TGSI_OPCODE_SAMPLE_I] = soa_passthrough, |
||
1592 | [TGSI_OPCODE_SAMPLE_I_MS] = soa_passthrough, |
||
1593 | [TGSI_OPCODE_SAMPLE_B] = soa_passthrough, |
||
1594 | [TGSI_OPCODE_SAMPLE_C] = soa_passthrough, |
||
1595 | [TGSI_OPCODE_SAMPLE_C_LZ] = soa_passthrough, |
||
1596 | [TGSI_OPCODE_SAMPLE_D] = soa_passthrough, |
||
1597 | [TGSI_OPCODE_SAMPLE_L] = soa_passthrough, |
||
1598 | [TGSI_OPCODE_GATHER4] = soa_passthrough, |
||
1599 | [TGSI_OPCODE_SVIEWINFO] = soa_passthrough, |
||
1600 | [TGSI_OPCODE_SAMPLE_POS] = soa_passthrough, |
||
1601 | [TGSI_OPCODE_SAMPLE_INFO] = soa_passthrough, |
||
1602 | [TGSI_OPCODE_UARL] = soa_per_channel, |
||
1603 | [TGSI_OPCODE_UCMP] = soa_per_channel, |
||
1604 | [TGSI_OPCODE_IABS] = soa_per_channel, |
||
1605 | [TGSI_OPCODE_ISSG] = soa_per_channel, |
||
1606 | [TGSI_OPCODE_LOAD] = soa_unsupported, |
||
1607 | [TGSI_OPCODE_STORE] = soa_unsupported, |
||
1608 | [TGSI_OPCODE_MFENCE] = soa_unsupported, |
||
1609 | [TGSI_OPCODE_LFENCE] = soa_unsupported, |
||
1610 | [TGSI_OPCODE_SFENCE] = soa_unsupported, |
||
1611 | [TGSI_OPCODE_BARRIER] = soa_unsupported, |
||
1612 | [TGSI_OPCODE_ATOMUADD] = soa_unsupported, |
||
1613 | [TGSI_OPCODE_ATOMXCHG] = soa_unsupported, |
||
1614 | [TGSI_OPCODE_ATOMCAS] = soa_unsupported, |
||
1615 | [TGSI_OPCODE_ATOMAND] = soa_unsupported, |
||
1616 | [TGSI_OPCODE_ATOMOR] = soa_unsupported, |
||
1617 | [TGSI_OPCODE_ATOMXOR] = soa_unsupported, |
||
1618 | [TGSI_OPCODE_ATOMUMIN] = soa_unsupported, |
||
1619 | [TGSI_OPCODE_ATOMUMAX] = soa_unsupported, |
||
1620 | [TGSI_OPCODE_ATOMIMIN] = soa_unsupported, |
||
1621 | [TGSI_OPCODE_ATOMIMAX] = soa_unsupported, |
||
1622 | [TGSI_OPCODE_TEX2] = soa_passthrough, |
||
1623 | [TGSI_OPCODE_TXB2] = soa_passthrough, |
||
1624 | [TGSI_OPCODE_TXL2] = soa_passthrough, |
||
1625 | }; |
||
1626 | |||
1627 | static bool |
||
1628 | ra_dst_is_indirect(const struct tgsi_full_dst_register *d) |
||
1629 | { |
||
1630 | return (d->Register.Indirect || |
||
1631 | (d->Register.Dimension && d->Dimension.Indirect)); |
||
1632 | } |
||
1633 | |||
1634 | static int |
||
1635 | ra_dst_index(const struct tgsi_full_dst_register *d) |
||
1636 | { |
||
1637 | assert(!d->Register.Indirect); |
||
1638 | return d->Register.Index; |
||
1639 | } |
||
1640 | |||
1641 | static int |
||
1642 | ra_dst_dimension(const struct tgsi_full_dst_register *d) |
||
1643 | { |
||
1644 | if (d->Register.Dimension) { |
||
1645 | assert(!d->Dimension.Indirect); |
||
1646 | return d->Dimension.Index; |
||
1647 | } |
||
1648 | else { |
||
1649 | return 0; |
||
1650 | } |
||
1651 | } |
||
1652 | |||
1653 | static bool |
||
1654 | ra_is_src_indirect(const struct tgsi_full_src_register *s) |
||
1655 | { |
||
1656 | return (s->Register.Indirect || |
||
1657 | (s->Register.Dimension && s->Dimension.Indirect)); |
||
1658 | } |
||
1659 | |||
1660 | static int |
||
1661 | ra_src_index(const struct tgsi_full_src_register *s) |
||
1662 | { |
||
1663 | assert(!s->Register.Indirect); |
||
1664 | return s->Register.Index; |
||
1665 | } |
||
1666 | |||
1667 | static int |
||
1668 | ra_src_dimension(const struct tgsi_full_src_register *s) |
||
1669 | { |
||
1670 | if (s->Register.Dimension) { |
||
1671 | assert(!s->Dimension.Indirect); |
||
1672 | return s->Dimension.Index; |
||
1673 | } |
||
1674 | else { |
||
1675 | return 0; |
||
1676 | } |
||
1677 | } |
||
1678 | |||
1679 | /** |
||
1680 | * Infer the type of either the sources or the destination. |
||
1681 | */ |
||
1682 | static enum toy_type |
||
1683 | ra_infer_opcode_type(int tgsi_opcode, bool is_dst) |
||
1684 | { |
||
1685 | enum tgsi_opcode_type type; |
||
1686 | |||
1687 | if (is_dst) |
||
1688 | type = tgsi_opcode_infer_dst_type(tgsi_opcode); |
||
1689 | else |
||
1690 | type = tgsi_opcode_infer_src_type(tgsi_opcode); |
||
1691 | |||
1692 | switch (type) { |
||
1693 | case TGSI_TYPE_UNSIGNED: |
||
1694 | return TOY_TYPE_UD; |
||
1695 | case TGSI_TYPE_SIGNED: |
||
1696 | return TOY_TYPE_D; |
||
1697 | case TGSI_TYPE_FLOAT: |
||
1698 | return TOY_TYPE_F; |
||
1699 | case TGSI_TYPE_UNTYPED: |
||
1700 | case TGSI_TYPE_VOID: |
||
1701 | case TGSI_TYPE_DOUBLE: |
||
1702 | default: |
||
1703 | assert(!"unsupported TGSI type"); |
||
1704 | return TOY_TYPE_UD; |
||
1705 | } |
||
1706 | } |
||
1707 | |||
1708 | /** |
||
1709 | * Return the type of an operand of the specified instruction. |
||
1710 | */ |
||
1711 | static enum toy_type |
||
1712 | ra_get_type(struct toy_tgsi *tgsi, const struct tgsi_full_instruction *tgsi_inst, |
||
1713 | int operand, bool is_dst) |
||
1714 | { |
||
1715 | enum toy_type type; |
||
1716 | enum tgsi_file_type file; |
||
1717 | |||
1718 | /* we need to look at both src and dst for MOV */ |
||
1719 | /* XXX it should not be this complex */ |
||
1720 | if (tgsi_inst->Instruction.Opcode == TGSI_OPCODE_MOV) { |
||
1721 | const enum tgsi_file_type dst_file = tgsi_inst->Dst[0].Register.File; |
||
1722 | const enum tgsi_file_type src_file = tgsi_inst->Src[0].Register.File; |
||
1723 | |||
1724 | if (dst_file == TGSI_FILE_ADDRESS || src_file == TGSI_FILE_ADDRESS) { |
||
1725 | type = TOY_TYPE_D; |
||
1726 | } |
||
1727 | else if (src_file == TGSI_FILE_IMMEDIATE && |
||
1728 | !tgsi_inst->Src[0].Register.Indirect) { |
||
1729 | const int src_idx = tgsi_inst->Src[0].Register.Index; |
||
1730 | type = tgsi->imm_data.types[src_idx]; |
||
1731 | } |
||
1732 | else { |
||
1733 | /* this is the best we can do */ |
||
1734 | type = TOY_TYPE_F; |
||
1735 | } |
||
1736 | |||
1737 | return type; |
||
1738 | } |
||
1739 | else if (tgsi_inst->Instruction.Opcode == TGSI_OPCODE_UCMP) { |
||
1740 | if (!is_dst && operand == 0) |
||
1741 | type = TOY_TYPE_UD; |
||
1742 | else |
||
1743 | type = TOY_TYPE_F; |
||
1744 | |||
1745 | return type; |
||
1746 | } |
||
1747 | |||
1748 | type = ra_infer_opcode_type(tgsi_inst->Instruction.Opcode, is_dst); |
||
1749 | |||
1750 | /* fix the type */ |
||
1751 | file = (is_dst) ? |
||
1752 | tgsi_inst->Dst[operand].Register.File : |
||
1753 | tgsi_inst->Src[operand].Register.File; |
||
1754 | switch (file) { |
||
1755 | case TGSI_FILE_SAMPLER: |
||
1756 | case TGSI_FILE_RESOURCE: |
||
1757 | case TGSI_FILE_SAMPLER_VIEW: |
||
1758 | type = TOY_TYPE_D; |
||
1759 | break; |
||
1760 | case TGSI_FILE_ADDRESS: |
||
1761 | assert(type == TOY_TYPE_D); |
||
1762 | break; |
||
1763 | default: |
||
1764 | break; |
||
1765 | } |
||
1766 | |||
1767 | return type; |
||
1768 | } |
||
1769 | |||
1770 | /** |
||
1771 | * Allocate a VRF register. |
||
1772 | */ |
||
1773 | static int |
||
1774 | ra_alloc_reg(struct toy_tgsi *tgsi, enum tgsi_file_type file) |
||
1775 | { |
||
1776 | const int count = (tgsi->aos) ? 1 : 4; |
||
1777 | return tc_alloc_vrf(tgsi->tc, count); |
||
1778 | } |
||
1779 | |||
1780 | /** |
||
1781 | * Construct the key for VRF mapping look-up. |
||
1782 | */ |
||
1783 | static void * |
||
1784 | ra_get_map_key(enum tgsi_file_type file, unsigned dim, unsigned index) |
||
1785 | { |
||
1786 | intptr_t key; |
||
1787 | |||
1788 | /* this is ugly... */ |
||
1789 | assert(file < 1 << 4); |
||
1790 | assert(dim < 1 << 12); |
||
1791 | assert(index < 1 << 16); |
||
1792 | key = (file << 28) | (dim << 16) | index; |
||
1793 | |||
1794 | return intptr_to_pointer(key); |
||
1795 | } |
||
1796 | |||
1797 | /** |
||
1798 | * Map a TGSI register to a VRF register. |
||
1799 | */ |
||
1800 | static int |
||
1801 | ra_map_reg(struct toy_tgsi *tgsi, enum tgsi_file_type file, |
||
1802 | int dim, int index, bool *is_new) |
||
1803 | { |
||
1804 | void *key, *val; |
||
1805 | intptr_t vrf; |
||
1806 | |||
1807 | key = ra_get_map_key(file, dim, index); |
||
1808 | |||
1809 | /* |
||
1810 | * because we allocate vrf from 1 and on, val is never NULL as long as the |
||
1811 | * key exists |
||
1812 | */ |
||
1813 | val = util_hash_table_get(tgsi->reg_mapping, key); |
||
1814 | if (val) { |
||
1815 | vrf = pointer_to_intptr(val); |
||
1816 | |||
1817 | if (is_new) |
||
1818 | *is_new = false; |
||
1819 | } |
||
1820 | else { |
||
1821 | vrf = (intptr_t) ra_alloc_reg(tgsi, file); |
||
1822 | |||
1823 | /* add to the mapping */ |
||
1824 | val = intptr_to_pointer(vrf); |
||
1825 | util_hash_table_set(tgsi->reg_mapping, key, val); |
||
1826 | |||
1827 | if (is_new) |
||
1828 | *is_new = true; |
||
1829 | } |
||
1830 | |||
1831 | return (int) vrf; |
||
1832 | } |
||
1833 | |||
1834 | /** |
||
1835 | * Return true if the destination aliases any of the sources. |
||
1836 | */ |
||
1837 | static bool |
||
1838 | ra_dst_is_aliasing(const struct tgsi_full_instruction *tgsi_inst, int dst_index) |
||
1839 | { |
||
1840 | const struct tgsi_full_dst_register *d = &tgsi_inst->Dst[dst_index]; |
||
1841 | int i; |
||
1842 | |||
1843 | /* we need a scratch register for indirect dst anyway */ |
||
1844 | if (ra_dst_is_indirect(d)) |
||
1845 | return true; |
||
1846 | |||
1847 | for (i = 0; i < tgsi_inst->Instruction.NumSrcRegs; i++) { |
||
1848 | const struct tgsi_full_src_register *s = &tgsi_inst->Src[i]; |
||
1849 | |||
1850 | if (s->Register.File != d->Register.File) |
||
1851 | continue; |
||
1852 | |||
1853 | /* |
||
1854 | * we can go on to check dimension and index respectively, but |
||
1855 | * keep it simple for now |
||
1856 | */ |
||
1857 | if (ra_is_src_indirect(s)) |
||
1858 | return true; |
||
1859 | if (ra_src_dimension(s) == ra_dst_dimension(d) && |
||
1860 | ra_src_index(s) == ra_dst_index(d)) |
||
1861 | return true; |
||
1862 | } |
||
1863 | |||
1864 | return false; |
||
1865 | } |
||
1866 | |||
1867 | /** |
||
1868 | * Return the toy register for a TGSI destination operand. |
||
1869 | */ |
||
1870 | static struct toy_dst |
||
1871 | ra_get_dst(struct toy_tgsi *tgsi, |
||
1872 | const struct tgsi_full_instruction *tgsi_inst, int dst_index, |
||
1873 | bool *is_scratch) |
||
1874 | { |
||
1875 | const struct tgsi_full_dst_register *d = &tgsi_inst->Dst[dst_index]; |
||
1876 | bool need_vrf = false; |
||
1877 | struct toy_dst dst; |
||
1878 | |||
1879 | switch (d->Register.File) { |
||
1880 | case TGSI_FILE_NULL: |
||
1881 | dst = tdst_null(); |
||
1882 | break; |
||
1883 | case TGSI_FILE_OUTPUT: |
||
1884 | case TGSI_FILE_TEMPORARY: |
||
1885 | case TGSI_FILE_ADDRESS: |
||
1886 | case TGSI_FILE_PREDICATE: |
||
1887 | need_vrf = true; |
||
1888 | break; |
||
1889 | default: |
||
1890 | assert(!"unhandled dst file"); |
||
1891 | dst = tdst_null(); |
||
1892 | break; |
||
1893 | } |
||
1894 | |||
1895 | if (need_vrf) { |
||
1896 | /* XXX we do not always need a scratch given the conditions... */ |
||
1897 | const bool need_scratch = |
||
1898 | (ra_dst_is_indirect(d) || ra_dst_is_aliasing(tgsi_inst, dst_index) || |
||
1899 | tgsi_inst->Instruction.Saturate); |
||
1900 | const enum toy_type type = ra_get_type(tgsi, tgsi_inst, dst_index, true); |
||
1901 | int vrf; |
||
1902 | |||
1903 | if (need_scratch) { |
||
1904 | vrf = ra_alloc_reg(tgsi, d->Register.File); |
||
1905 | } |
||
1906 | else { |
||
1907 | vrf = ra_map_reg(tgsi, d->Register.File, |
||
1908 | ra_dst_dimension(d), ra_dst_index(d), NULL); |
||
1909 | } |
||
1910 | |||
1911 | if (is_scratch) |
||
1912 | *is_scratch = need_scratch; |
||
1913 | |||
1914 | dst = tdst_full(TOY_FILE_VRF, type, TOY_RECT_LINEAR, |
||
1915 | false, 0, d->Register.WriteMask, vrf * TOY_REG_WIDTH); |
||
1916 | } |
||
1917 | |||
1918 | return dst; |
||
1919 | } |
||
1920 | |||
1921 | static struct toy_src |
||
1922 | ra_get_src_for_vrf(const struct tgsi_full_src_register *s, |
||
1923 | enum toy_type type, int vrf) |
||
1924 | { |
||
1925 | return tsrc_full(TOY_FILE_VRF, type, TOY_RECT_LINEAR, |
||
1926 | false, 0, |
||
1927 | s->Register.SwizzleX, s->Register.SwizzleY, |
||
1928 | s->Register.SwizzleZ, s->Register.SwizzleW, |
||
1929 | s->Register.Absolute, s->Register.Negate, |
||
1930 | vrf * TOY_REG_WIDTH); |
||
1931 | } |
||
1932 | |||
1933 | static int |
||
1934 | init_tgsi_reg(struct toy_tgsi *tgsi, struct toy_inst *inst, |
||
1935 | enum tgsi_file_type file, int index, |
||
1936 | const struct tgsi_ind_register *indirect, |
||
1937 | const struct tgsi_dimension *dimension, |
||
1938 | const struct tgsi_ind_register *dim_indirect) |
||
1939 | { |
||
1940 | struct toy_src src; |
||
1941 | int num_src = 0; |
||
1942 | |||
1943 | /* src[0]: TGSI file */ |
||
1944 | inst->src[num_src++] = tsrc_imm_d(file); |
||
1945 | |||
1946 | /* src[1]: TGSI dimension */ |
||
1947 | inst->src[num_src++] = tsrc_imm_d((dimension) ? dimension->Index : 0); |
||
1948 | |||
1949 | /* src[2]: TGSI dimension indirection */ |
||
1950 | if (dim_indirect) { |
||
1951 | const int vrf = ra_map_reg(tgsi, dim_indirect->File, 0, |
||
1952 | dim_indirect->Index, NULL); |
||
1953 | |||
1954 | src = tsrc(TOY_FILE_VRF, vrf, 0); |
||
1955 | src = tsrc_swizzle1(tsrc_d(src), indirect->Swizzle); |
||
1956 | } |
||
1957 | else { |
||
1958 | src = tsrc_imm_d(0); |
||
1959 | } |
||
1960 | |||
1961 | inst->src[num_src++] = src; |
||
1962 | |||
1963 | /* src[3]: TGSI index */ |
||
1964 | inst->src[num_src++] = tsrc_imm_d(index); |
||
1965 | |||
1966 | /* src[4]: TGSI index indirection */ |
||
1967 | if (indirect) { |
||
1968 | const int vrf = ra_map_reg(tgsi, indirect->File, 0, |
||
1969 | indirect->Index, NULL); |
||
1970 | |||
1971 | src = tsrc(TOY_FILE_VRF, vrf, 0); |
||
1972 | src = tsrc_swizzle1(tsrc_d(src), indirect->Swizzle); |
||
1973 | } |
||
1974 | else { |
||
1975 | src = tsrc_imm_d(0); |
||
1976 | } |
||
1977 | |||
1978 | inst->src[num_src++] = src; |
||
1979 | |||
1980 | return num_src; |
||
1981 | } |
||
1982 | |||
1983 | static struct toy_src |
||
1984 | ra_get_src_indirect(struct toy_tgsi *tgsi, |
||
1985 | const struct tgsi_full_instruction *tgsi_inst, |
||
1986 | int src_index) |
||
1987 | { |
||
1988 | const struct tgsi_full_src_register *s = &tgsi_inst->Src[src_index]; |
||
1989 | bool need_vrf = false, is_resource = false; |
||
1990 | struct toy_src src; |
||
1991 | |||
1992 | switch (s->Register.File) { |
||
1993 | case TGSI_FILE_NULL: |
||
1994 | src = tsrc_null(); |
||
1995 | break; |
||
1996 | case TGSI_FILE_SAMPLER: |
||
1997 | case TGSI_FILE_RESOURCE: |
||
1998 | case TGSI_FILE_SAMPLER_VIEW: |
||
1999 | is_resource = true; |
||
2000 | /* fall through */ |
||
2001 | case TGSI_FILE_CONSTANT: |
||
2002 | case TGSI_FILE_INPUT: |
||
2003 | case TGSI_FILE_SYSTEM_VALUE: |
||
2004 | case TGSI_FILE_TEMPORARY: |
||
2005 | case TGSI_FILE_ADDRESS: |
||
2006 | case TGSI_FILE_IMMEDIATE: |
||
2007 | case TGSI_FILE_PREDICATE: |
||
2008 | need_vrf = true; |
||
2009 | break; |
||
2010 | default: |
||
2011 | assert(!"unhandled src file"); |
||
2012 | src = tsrc_null(); |
||
2013 | break; |
||
2014 | } |
||
2015 | |||
2016 | if (need_vrf) { |
||
2017 | const enum toy_type type = ra_get_type(tgsi, tgsi_inst, src_index, false); |
||
2018 | int vrf; |
||
2019 | |||
2020 | if (is_resource) { |
||
2021 | assert(!s->Register.Dimension); |
||
2022 | assert(s->Register.Indirect); |
||
2023 | |||
2024 | vrf = ra_map_reg(tgsi, s->Indirect.File, 0, s->Indirect.Index, NULL); |
||
2025 | } |
||
2026 | else { |
||
2027 | vrf = ra_alloc_reg(tgsi, s->Register.File); |
||
2028 | } |
||
2029 | |||
2030 | src = ra_get_src_for_vrf(s, type, vrf); |
||
2031 | |||
2032 | /* emit indirect fetch */ |
||
2033 | if (!is_resource) { |
||
2034 | struct toy_inst *inst; |
||
2035 | |||
2036 | inst = tc_add(tgsi->tc); |
||
2037 | inst->opcode = TOY_OPCODE_TGSI_INDIRECT_FETCH; |
||
2038 | inst->dst = tdst_from(src); |
||
2039 | inst->dst.writemask = TOY_WRITEMASK_XYZW; |
||
2040 | |||
2041 | init_tgsi_reg(tgsi, inst, s->Register.File, s->Register.Index, |
||
2042 | (s->Register.Indirect) ? &s->Indirect : NULL, |
||
2043 | (s->Register.Dimension) ? &s->Dimension : NULL, |
||
2044 | (s->Dimension.Indirect) ? &s->DimIndirect : NULL); |
||
2045 | } |
||
2046 | } |
||
2047 | |||
2048 | return src; |
||
2049 | } |
||
2050 | |||
2051 | /** |
||
2052 | * Return the toy register for a TGSI source operand. |
||
2053 | */ |
||
2054 | static struct toy_src |
||
2055 | ra_get_src(struct toy_tgsi *tgsi, |
||
2056 | const struct tgsi_full_instruction *tgsi_inst, |
||
2057 | int src_index) |
||
2058 | { |
||
2059 | const struct tgsi_full_src_register *s = &tgsi_inst->Src[src_index]; |
||
2060 | bool need_vrf = false; |
||
2061 | struct toy_src src; |
||
2062 | |||
2063 | if (ra_is_src_indirect(s)) |
||
2064 | return ra_get_src_indirect(tgsi, tgsi_inst, src_index); |
||
2065 | |||
2066 | switch (s->Register.File) { |
||
2067 | case TGSI_FILE_NULL: |
||
2068 | src = tsrc_null(); |
||
2069 | break; |
||
2070 | case TGSI_FILE_CONSTANT: |
||
2071 | case TGSI_FILE_INPUT: |
||
2072 | case TGSI_FILE_SYSTEM_VALUE: |
||
2073 | need_vrf = true; |
||
2074 | break; |
||
2075 | case TGSI_FILE_TEMPORARY: |
||
2076 | case TGSI_FILE_ADDRESS: |
||
2077 | case TGSI_FILE_PREDICATE: |
||
2078 | need_vrf = true; |
||
2079 | break; |
||
2080 | case TGSI_FILE_SAMPLER: |
||
2081 | case TGSI_FILE_RESOURCE: |
||
2082 | case TGSI_FILE_SAMPLER_VIEW: |
||
2083 | assert(!s->Register.Dimension); |
||
2084 | src = tsrc_imm_d(s->Register.Index); |
||
2085 | break; |
||
2086 | case TGSI_FILE_IMMEDIATE: |
||
2087 | { |
||
2088 | const uint32_t *imm; |
||
2089 | enum toy_type imm_type; |
||
2090 | bool is_scalar; |
||
2091 | |||
2092 | imm = toy_tgsi_get_imm(tgsi, s->Register.Index, &imm_type); |
||
2093 | |||
2094 | is_scalar = |
||
2095 | (imm[s->Register.SwizzleX] == imm[s->Register.SwizzleY] && |
||
2096 | imm[s->Register.SwizzleX] == imm[s->Register.SwizzleZ] && |
||
2097 | imm[s->Register.SwizzleX] == imm[s->Register.SwizzleW]); |
||
2098 | |||
2099 | if (is_scalar) { |
||
2100 | const enum toy_type type = |
||
2101 | ra_get_type(tgsi, tgsi_inst, src_index, false); |
||
2102 | |||
2103 | /* ignore imm_type */ |
||
2104 | src = tsrc_imm_ud(imm[s->Register.SwizzleX]); |
||
2105 | src.type = type; |
||
2106 | src.absolute = s->Register.Absolute; |
||
2107 | src.negate = s->Register.Negate; |
||
2108 | } |
||
2109 | else { |
||
2110 | need_vrf = true; |
||
2111 | } |
||
2112 | } |
||
2113 | break; |
||
2114 | default: |
||
2115 | assert(!"unhandled src file"); |
||
2116 | src = tsrc_null(); |
||
2117 | break; |
||
2118 | } |
||
2119 | |||
2120 | if (need_vrf) { |
||
2121 | const enum toy_type type = ra_get_type(tgsi, tgsi_inst, src_index, false); |
||
2122 | bool is_new; |
||
2123 | int vrf; |
||
2124 | |||
2125 | vrf = ra_map_reg(tgsi, s->Register.File, |
||
2126 | ra_src_dimension(s), ra_src_index(s), &is_new); |
||
2127 | |||
2128 | src = ra_get_src_for_vrf(s, type, vrf); |
||
2129 | |||
2130 | if (is_new) { |
||
2131 | switch (s->Register.File) { |
||
2132 | case TGSI_FILE_TEMPORARY: |
||
2133 | case TGSI_FILE_ADDRESS: |
||
2134 | case TGSI_FILE_PREDICATE: |
||
2135 | { |
||
2136 | struct toy_dst dst = tdst_from(src); |
||
2137 | dst.writemask = TOY_WRITEMASK_XYZW; |
||
2138 | |||
2139 | /* always initialize registers before use */ |
||
2140 | if (tgsi->aos) { |
||
2141 | tc_MOV(tgsi->tc, dst, tsrc_type(tsrc_imm_d(0), type)); |
||
2142 | } |
||
2143 | else { |
||
2144 | struct toy_dst tdst[4]; |
||
2145 | int i; |
||
2146 | |||
2147 | tdst_transpose(dst, tdst); |
||
2148 | |||
2149 | for (i = 0; i < 4; i++) { |
||
2150 | tc_MOV(tgsi->tc, tdst[i], |
||
2151 | tsrc_type(tsrc_imm_d(0), type)); |
||
2152 | } |
||
2153 | } |
||
2154 | } |
||
2155 | break; |
||
2156 | default: |
||
2157 | break; |
||
2158 | } |
||
2159 | } |
||
2160 | |||
2161 | } |
||
2162 | |||
2163 | return src; |
||
2164 | } |
||
2165 | |||
2166 | static void |
||
2167 | parse_instruction(struct toy_tgsi *tgsi, |
||
2168 | const struct tgsi_full_instruction *tgsi_inst) |
||
2169 | { |
||
2170 | struct toy_dst dst[TGSI_FULL_MAX_DST_REGISTERS]; |
||
2171 | struct toy_src src[TGSI_FULL_MAX_SRC_REGISTERS]; |
||
2172 | bool dst_is_scratch[TGSI_FULL_MAX_DST_REGISTERS]; |
||
2173 | toy_tgsi_translate translate; |
||
2174 | int i; |
||
2175 | |||
2176 | /* convert TGSI registers to toy registers */ |
||
2177 | for (i = 0; i < tgsi_inst->Instruction.NumSrcRegs; i++) |
||
2178 | src[i] = ra_get_src(tgsi, tgsi_inst, i); |
||
2179 | for (i = 0; i < tgsi_inst->Instruction.NumDstRegs; i++) |
||
2180 | dst[i] = ra_get_dst(tgsi, tgsi_inst, i, &dst_is_scratch[i]); |
||
2181 | |||
2182 | /* translate the instruction */ |
||
2183 | translate = tgsi->translate_table[tgsi_inst->Instruction.Opcode]; |
||
2184 | translate(tgsi->tc, tgsi_inst, dst, src); |
||
2185 | |||
2186 | /* write the result to the real destinations if needed */ |
||
2187 | for (i = 0; i < tgsi_inst->Instruction.NumDstRegs; i++) { |
||
2188 | const struct tgsi_full_dst_register *d = &tgsi_inst->Dst[i]; |
||
2189 | |||
2190 | if (!dst_is_scratch[i]) |
||
2191 | continue; |
||
2192 | |||
2193 | if (tgsi_inst->Instruction.Saturate == TGSI_SAT_MINUS_PLUS_ONE) |
||
2194 | tc_fail(tgsi->tc, "TGSI_SAT_MINUS_PLUS_ONE unhandled"); |
||
2195 | |||
2196 | tgsi->tc->templ.saturate = tgsi_inst->Instruction.Saturate; |
||
2197 | |||
2198 | /* emit indirect store */ |
||
2199 | if (ra_dst_is_indirect(d)) { |
||
2200 | struct toy_inst *inst; |
||
2201 | |||
2202 | inst = tc_add(tgsi->tc); |
||
2203 | inst->opcode = TOY_OPCODE_TGSI_INDIRECT_STORE; |
||
2204 | inst->dst = dst[i]; |
||
2205 | |||
2206 | init_tgsi_reg(tgsi, inst, d->Register.File, d->Register.Index, |
||
2207 | (d->Register.Indirect) ? &d->Indirect : NULL, |
||
2208 | (d->Register.Dimension) ? &d->Dimension : NULL, |
||
2209 | (d->Dimension.Indirect) ? &d->DimIndirect : NULL); |
||
2210 | } |
||
2211 | else { |
||
2212 | const enum toy_type type = ra_get_type(tgsi, tgsi_inst, i, true); |
||
2213 | struct toy_dst real_dst; |
||
2214 | int vrf; |
||
2215 | |||
2216 | vrf = ra_map_reg(tgsi, d->Register.File, |
||
2217 | ra_dst_dimension(d), ra_dst_index(d), NULL); |
||
2218 | real_dst = tdst_full(TOY_FILE_VRF, type, TOY_RECT_LINEAR, |
||
2219 | false, 0, d->Register.WriteMask, vrf * TOY_REG_WIDTH); |
||
2220 | |||
2221 | if (tgsi->aos) { |
||
2222 | tc_MOV(tgsi->tc, real_dst, tsrc_from(dst[i])); |
||
2223 | } |
||
2224 | else { |
||
2225 | struct toy_dst tdst[4]; |
||
2226 | struct toy_src tsrc[4]; |
||
2227 | int j; |
||
2228 | |||
2229 | tdst_transpose(real_dst, tdst); |
||
2230 | tsrc_transpose(tsrc_from(dst[i]), tsrc); |
||
2231 | |||
2232 | for (j = 0; j < 4; j++) |
||
2233 | tc_MOV(tgsi->tc, tdst[j], tsrc[j]); |
||
2234 | } |
||
2235 | } |
||
2236 | |||
2237 | tgsi->tc->templ.saturate = false; |
||
2238 | } |
||
2239 | |||
2240 | switch (tgsi_inst->Instruction.Opcode) { |
||
2241 | case TGSI_OPCODE_KILL_IF: |
||
2242 | case TGSI_OPCODE_KILL: |
||
2243 | tgsi->uses_kill = true; |
||
2244 | break; |
||
2245 | } |
||
2246 | |||
2247 | /* remember channels written */ |
||
2248 | for (i = 0; i < tgsi_inst->Instruction.NumDstRegs; i++) { |
||
2249 | const struct tgsi_full_dst_register *d = &tgsi_inst->Dst[i]; |
||
2250 | |||
2251 | if (d->Register.File != TGSI_FILE_OUTPUT) |
||
2252 | continue; |
||
2253 | for (i = 0; i < tgsi->num_outputs; i++) { |
||
2254 | if (tgsi->outputs[i].index == d->Register.Index) { |
||
2255 | tgsi->outputs[i].undefined_mask &= ~d->Register.WriteMask; |
||
2256 | break; |
||
2257 | } |
||
2258 | } |
||
2259 | } |
||
2260 | } |
||
2261 | |||
2262 | static void |
||
2263 | decl_add_in(struct toy_tgsi *tgsi, const struct tgsi_full_declaration *decl) |
||
2264 | { |
||
2265 | static const struct tgsi_declaration_interp default_interp = { |
||
2266 | TGSI_INTERPOLATE_PERSPECTIVE, false, 0, |
||
2267 | }; |
||
2268 | const struct tgsi_declaration_interp *interp = |
||
2269 | (decl->Declaration.Interpolate) ? &decl->Interp: &default_interp; |
||
2270 | int index; |
||
2271 | |||
2272 | if (decl->Range.Last >= Elements(tgsi->inputs)) { |
||
2273 | assert(!"invalid IN"); |
||
2274 | return; |
||
2275 | } |
||
2276 | |||
2277 | for (index = decl->Range.First; index <= decl->Range.Last; index++) { |
||
2278 | const int slot = tgsi->num_inputs++; |
||
2279 | |||
2280 | tgsi->inputs[slot].index = index; |
||
2281 | tgsi->inputs[slot].usage_mask = decl->Declaration.UsageMask; |
||
2282 | if (decl->Declaration.Semantic) { |
||
2283 | tgsi->inputs[slot].semantic_name = decl->Semantic.Name; |
||
2284 | tgsi->inputs[slot].semantic_index = decl->Semantic.Index; |
||
2285 | } |
||
2286 | else { |
||
2287 | tgsi->inputs[slot].semantic_name = TGSI_SEMANTIC_GENERIC; |
||
2288 | tgsi->inputs[slot].semantic_index = index; |
||
2289 | } |
||
2290 | tgsi->inputs[slot].interp = interp->Interpolate; |
||
2291 | tgsi->inputs[slot].centroid = interp->Centroid; |
||
2292 | } |
||
2293 | } |
||
2294 | |||
2295 | static void |
||
2296 | decl_add_out(struct toy_tgsi *tgsi, const struct tgsi_full_declaration *decl) |
||
2297 | { |
||
2298 | int index; |
||
2299 | |||
2300 | if (decl->Range.Last >= Elements(tgsi->outputs)) { |
||
2301 | assert(!"invalid OUT"); |
||
2302 | return; |
||
2303 | } |
||
2304 | |||
2305 | assert(decl->Declaration.Semantic); |
||
2306 | |||
2307 | for (index = decl->Range.First; index <= decl->Range.Last; index++) { |
||
2308 | const int slot = tgsi->num_outputs++; |
||
2309 | |||
2310 | tgsi->outputs[slot].index = index; |
||
2311 | tgsi->outputs[slot].undefined_mask = TOY_WRITEMASK_XYZW; |
||
2312 | tgsi->outputs[slot].usage_mask = decl->Declaration.UsageMask; |
||
2313 | tgsi->outputs[slot].semantic_name = decl->Semantic.Name; |
||
2314 | tgsi->outputs[slot].semantic_index = decl->Semantic.Index; |
||
2315 | } |
||
2316 | } |
||
2317 | |||
2318 | static void |
||
2319 | decl_add_sv(struct toy_tgsi *tgsi, const struct tgsi_full_declaration *decl) |
||
2320 | { |
||
2321 | int index; |
||
2322 | |||
2323 | if (decl->Range.Last >= Elements(tgsi->system_values)) { |
||
2324 | assert(!"invalid SV"); |
||
2325 | return; |
||
2326 | } |
||
2327 | |||
2328 | for (index = decl->Range.First; index <= decl->Range.Last; index++) { |
||
2329 | const int slot = tgsi->num_system_values++; |
||
2330 | |||
2331 | tgsi->system_values[slot].index = index; |
||
2332 | if (decl->Declaration.Semantic) { |
||
2333 | tgsi->system_values[slot].semantic_name = decl->Semantic.Name; |
||
2334 | tgsi->system_values[slot].semantic_index = decl->Semantic.Index; |
||
2335 | } |
||
2336 | else { |
||
2337 | tgsi->system_values[slot].semantic_name = TGSI_SEMANTIC_GENERIC; |
||
2338 | tgsi->system_values[slot].semantic_index = index; |
||
2339 | } |
||
2340 | } |
||
2341 | } |
||
2342 | |||
2343 | /** |
||
2344 | * Emit an instruction to fetch the value of a TGSI register. |
||
2345 | */ |
||
2346 | static void |
||
2347 | fetch_source(struct toy_tgsi *tgsi, enum tgsi_file_type file, int dim, int idx) |
||
2348 | { |
||
2349 | struct toy_dst dst; |
||
2350 | int vrf; |
||
2351 | enum toy_opcode opcode; |
||
2352 | enum toy_type type = TOY_TYPE_F; |
||
2353 | |||
2354 | switch (file) { |
||
2355 | case TGSI_FILE_INPUT: |
||
2356 | opcode = TOY_OPCODE_TGSI_IN; |
||
2357 | break; |
||
2358 | case TGSI_FILE_CONSTANT: |
||
2359 | opcode = TOY_OPCODE_TGSI_CONST; |
||
2360 | break; |
||
2361 | case TGSI_FILE_SYSTEM_VALUE: |
||
2362 | opcode = TOY_OPCODE_TGSI_SV; |
||
2363 | break; |
||
2364 | case TGSI_FILE_IMMEDIATE: |
||
2365 | opcode = TOY_OPCODE_TGSI_IMM; |
||
2366 | toy_tgsi_get_imm(tgsi, idx, &type); |
||
2367 | break; |
||
2368 | default: |
||
2369 | /* no need to fetch */ |
||
2370 | return; |
||
2371 | break; |
||
2372 | } |
||
2373 | |||
2374 | vrf = ra_map_reg(tgsi, file, dim, idx, NULL); |
||
2375 | dst = tdst(TOY_FILE_VRF, vrf, 0); |
||
2376 | dst = tdst_type(dst, type); |
||
2377 | |||
2378 | tc_add2(tgsi->tc, opcode, dst, tsrc_imm_d(dim), tsrc_imm_d(idx)); |
||
2379 | } |
||
2380 | |||
2381 | static void |
||
2382 | parse_declaration(struct toy_tgsi *tgsi, |
||
2383 | const struct tgsi_full_declaration *decl) |
||
2384 | { |
||
2385 | int i; |
||
2386 | |||
2387 | switch (decl->Declaration.File) { |
||
2388 | case TGSI_FILE_INPUT: |
||
2389 | decl_add_in(tgsi, decl); |
||
2390 | break; |
||
2391 | case TGSI_FILE_OUTPUT: |
||
2392 | decl_add_out(tgsi, decl); |
||
2393 | break; |
||
2394 | case TGSI_FILE_SYSTEM_VALUE: |
||
2395 | decl_add_sv(tgsi, decl); |
||
2396 | break; |
||
2397 | case TGSI_FILE_IMMEDIATE: |
||
2398 | /* immediates should be declared with TGSI_TOKEN_TYPE_IMMEDIATE */ |
||
2399 | assert(!"unexpected immediate declaration"); |
||
2400 | break; |
||
2401 | case TGSI_FILE_NULL: |
||
2402 | case TGSI_FILE_CONSTANT: |
||
2403 | case TGSI_FILE_TEMPORARY: |
||
2404 | case TGSI_FILE_SAMPLER: |
||
2405 | case TGSI_FILE_PREDICATE: |
||
2406 | case TGSI_FILE_ADDRESS: |
||
2407 | case TGSI_FILE_RESOURCE: |
||
2408 | case TGSI_FILE_SAMPLER_VIEW: |
||
2409 | /* nothing to do */ |
||
2410 | break; |
||
2411 | default: |
||
2412 | assert(!"unhandled TGSI file"); |
||
2413 | break; |
||
2414 | } |
||
2415 | |||
2416 | /* fetch the registers now */ |
||
2417 | for (i = decl->Range.First; i <= decl->Range.Last; i++) { |
||
2418 | const int dim = (decl->Declaration.Dimension) ? decl->Dim.Index2D : 0; |
||
2419 | fetch_source(tgsi, decl->Declaration.File, dim, i); |
||
2420 | } |
||
2421 | } |
||
2422 | |||
2423 | static int |
||
2424 | add_imm(struct toy_tgsi *tgsi, enum toy_type type, const uint32_t *buf) |
||
2425 | { |
||
2426 | /* reallocate the buffer if necessary */ |
||
2427 | if (tgsi->imm_data.cur >= tgsi->imm_data.size) { |
||
2428 | const int cur_size = tgsi->imm_data.size; |
||
2429 | int new_size; |
||
2430 | enum toy_type *new_types; |
||
2431 | uint32_t (*new_buf)[4]; |
||
2432 | |||
2433 | new_size = (cur_size) ? cur_size << 1 : 16; |
||
2434 | while (new_size <= tgsi->imm_data.cur) |
||
2435 | new_size <<= 1; |
||
2436 | |||
2437 | new_buf = REALLOC(tgsi->imm_data.buf, |
||
2438 | cur_size * sizeof(new_buf[0]), |
||
2439 | new_size * sizeof(new_buf[0])); |
||
2440 | new_types = REALLOC(tgsi->imm_data.types, |
||
2441 | cur_size * sizeof(new_types[0]), |
||
2442 | new_size * sizeof(new_types[0])); |
||
2443 | if (!new_buf || !new_types) { |
||
2444 | if (new_buf) |
||
2445 | FREE(new_buf); |
||
2446 | if (new_types) |
||
2447 | FREE(new_types); |
||
2448 | return -1; |
||
2449 | } |
||
2450 | |||
2451 | tgsi->imm_data.buf = new_buf; |
||
2452 | tgsi->imm_data.types = new_types; |
||
2453 | tgsi->imm_data.size = new_size; |
||
2454 | } |
||
2455 | |||
2456 | tgsi->imm_data.types[tgsi->imm_data.cur] = type; |
||
2457 | memcpy(&tgsi->imm_data.buf[tgsi->imm_data.cur], |
||
2458 | buf, sizeof(tgsi->imm_data.buf[0])); |
||
2459 | |||
2460 | return tgsi->imm_data.cur++; |
||
2461 | } |
||
2462 | |||
2463 | static void |
||
2464 | parse_immediate(struct toy_tgsi *tgsi, const struct tgsi_full_immediate *imm) |
||
2465 | { |
||
2466 | enum toy_type type; |
||
2467 | uint32_t imm_buf[4]; |
||
2468 | int idx; |
||
2469 | |||
2470 | switch (imm->Immediate.DataType) { |
||
2471 | case TGSI_IMM_FLOAT32: |
||
2472 | type = TOY_TYPE_F; |
||
2473 | imm_buf[0] = fui(imm->u[0].Float); |
||
2474 | imm_buf[1] = fui(imm->u[1].Float); |
||
2475 | imm_buf[2] = fui(imm->u[2].Float); |
||
2476 | imm_buf[3] = fui(imm->u[3].Float); |
||
2477 | break; |
||
2478 | case TGSI_IMM_INT32: |
||
2479 | type = TOY_TYPE_D; |
||
2480 | imm_buf[0] = (uint32_t) imm->u[0].Int; |
||
2481 | imm_buf[1] = (uint32_t) imm->u[1].Int; |
||
2482 | imm_buf[2] = (uint32_t) imm->u[2].Int; |
||
2483 | imm_buf[3] = (uint32_t) imm->u[3].Int; |
||
2484 | break; |
||
2485 | case TGSI_IMM_UINT32: |
||
2486 | type = TOY_TYPE_UD; |
||
2487 | imm_buf[0] = imm->u[0].Uint; |
||
2488 | imm_buf[1] = imm->u[1].Uint; |
||
2489 | imm_buf[2] = imm->u[2].Uint; |
||
2490 | imm_buf[3] = imm->u[3].Uint; |
||
2491 | break; |
||
2492 | default: |
||
2493 | assert(!"unhandled TGSI imm type"); |
||
2494 | type = TOY_TYPE_F; |
||
2495 | memset(imm_buf, 0, sizeof(imm_buf)); |
||
2496 | break; |
||
2497 | } |
||
2498 | |||
2499 | idx = add_imm(tgsi, type, imm_buf); |
||
2500 | if (idx >= 0) |
||
2501 | fetch_source(tgsi, TGSI_FILE_IMMEDIATE, 0, idx); |
||
2502 | else |
||
2503 | tc_fail(tgsi->tc, "failed to add TGSI imm"); |
||
2504 | } |
||
2505 | |||
2506 | static void |
||
2507 | parse_property(struct toy_tgsi *tgsi, const struct tgsi_full_property *prop) |
||
2508 | { |
||
2509 | switch (prop->Property.PropertyName) { |
||
2510 | case TGSI_PROPERTY_VS_PROHIBIT_UCPS: |
||
2511 | tgsi->props.vs_prohibit_ucps = prop->u[0].Data; |
||
2512 | break; |
||
2513 | case TGSI_PROPERTY_FS_COORD_ORIGIN: |
||
2514 | tgsi->props.fs_coord_origin = prop->u[0].Data; |
||
2515 | break; |
||
2516 | case TGSI_PROPERTY_FS_COORD_PIXEL_CENTER: |
||
2517 | tgsi->props.fs_coord_pixel_center = prop->u[0].Data; |
||
2518 | break; |
||
2519 | case TGSI_PROPERTY_FS_COLOR0_WRITES_ALL_CBUFS: |
||
2520 | tgsi->props.fs_color0_writes_all_cbufs = prop->u[0].Data; |
||
2521 | break; |
||
2522 | case TGSI_PROPERTY_FS_DEPTH_LAYOUT: |
||
2523 | tgsi->props.fs_depth_layout = prop->u[0].Data; |
||
2524 | break; |
||
2525 | case TGSI_PROPERTY_GS_INPUT_PRIM: |
||
2526 | tgsi->props.gs_input_prim = prop->u[0].Data; |
||
2527 | break; |
||
2528 | case TGSI_PROPERTY_GS_OUTPUT_PRIM: |
||
2529 | tgsi->props.gs_output_prim = prop->u[0].Data; |
||
2530 | break; |
||
2531 | case TGSI_PROPERTY_GS_MAX_OUTPUT_VERTICES: |
||
2532 | tgsi->props.gs_max_output_vertices = prop->u[0].Data; |
||
2533 | break; |
||
2534 | default: |
||
2535 | assert(!"unhandled TGSI property"); |
||
2536 | break; |
||
2537 | } |
||
2538 | } |
||
2539 | |||
2540 | static void |
||
2541 | parse_token(struct toy_tgsi *tgsi, const union tgsi_full_token *token) |
||
2542 | { |
||
2543 | switch (token->Token.Type) { |
||
2544 | case TGSI_TOKEN_TYPE_DECLARATION: |
||
2545 | parse_declaration(tgsi, &token->FullDeclaration); |
||
2546 | break; |
||
2547 | case TGSI_TOKEN_TYPE_IMMEDIATE: |
||
2548 | parse_immediate(tgsi, &token->FullImmediate); |
||
2549 | break; |
||
2550 | case TGSI_TOKEN_TYPE_INSTRUCTION: |
||
2551 | parse_instruction(tgsi, &token->FullInstruction); |
||
2552 | break; |
||
2553 | case TGSI_TOKEN_TYPE_PROPERTY: |
||
2554 | parse_property(tgsi, &token->FullProperty); |
||
2555 | break; |
||
2556 | default: |
||
2557 | assert(!"unhandled TGSI token type"); |
||
2558 | break; |
||
2559 | } |
||
2560 | } |
||
2561 | |||
2562 | static enum pipe_error |
||
2563 | dump_reg_mapping(void *key, void *val, void *data) |
||
2564 | { |
||
2565 | int tgsi_file, tgsi_dim, tgsi_index; |
||
2566 | uint32_t sig, vrf; |
||
2567 | |||
2568 | sig = (uint32_t) pointer_to_intptr(key); |
||
2569 | vrf = (uint32_t) pointer_to_intptr(val); |
||
2570 | |||
2571 | /* see ra_get_map_key() */ |
||
2572 | tgsi_file = (sig >> 28) & 0xf; |
||
2573 | tgsi_dim = (sig >> 16) & 0xfff; |
||
2574 | tgsi_index = (sig >> 0) & 0xffff; |
||
2575 | |||
2576 | if (tgsi_dim) { |
||
2577 | ilo_printf(" v%d:\t%s[%d][%d]\n", vrf, |
||
2578 | tgsi_file_name(tgsi_file), tgsi_dim, tgsi_index); |
||
2579 | } |
||
2580 | else { |
||
2581 | ilo_printf(" v%d:\t%s[%d]\n", vrf, |
||
2582 | tgsi_file_name(tgsi_file), tgsi_index); |
||
2583 | } |
||
2584 | |||
2585 | return PIPE_OK; |
||
2586 | } |
||
2587 | |||
2588 | /** |
||
2589 | * Dump the TGSI translator, currently only the register mapping. |
||
2590 | */ |
||
2591 | void |
||
2592 | toy_tgsi_dump(const struct toy_tgsi *tgsi) |
||
2593 | { |
||
2594 | util_hash_table_foreach(tgsi->reg_mapping, dump_reg_mapping, NULL); |
||
2595 | } |
||
2596 | |||
2597 | /** |
||
2598 | * Clean up the TGSI translator. |
||
2599 | */ |
||
2600 | void |
||
2601 | toy_tgsi_cleanup(struct toy_tgsi *tgsi) |
||
2602 | { |
||
2603 | FREE(tgsi->imm_data.buf); |
||
2604 | FREE(tgsi->imm_data.types); |
||
2605 | |||
2606 | util_hash_table_destroy(tgsi->reg_mapping); |
||
2607 | } |
||
2608 | |||
2609 | static unsigned |
||
2610 | reg_mapping_hash(void *key) |
||
2611 | { |
||
2612 | return (unsigned) pointer_to_intptr(key); |
||
2613 | } |
||
2614 | |||
2615 | static int |
||
2616 | reg_mapping_compare(void *key1, void *key2) |
||
2617 | { |
||
2618 | return (key1 != key2); |
||
2619 | } |
||
2620 | |||
2621 | /** |
||
2622 | * Initialize the TGSI translator. |
||
2623 | */ |
||
2624 | static bool |
||
2625 | init_tgsi(struct toy_tgsi *tgsi, struct toy_compiler *tc, bool aos) |
||
2626 | { |
||
2627 | memset(tgsi, 0, sizeof(*tgsi)); |
||
2628 | |||
2629 | tgsi->tc = tc; |
||
2630 | tgsi->aos = aos; |
||
2631 | tgsi->translate_table = (aos) ? aos_translate_table : soa_translate_table; |
||
2632 | |||
2633 | /* create a mapping of TGSI registers to VRF reigsters */ |
||
2634 | tgsi->reg_mapping = |
||
2635 | util_hash_table_create(reg_mapping_hash, reg_mapping_compare); |
||
2636 | |||
2637 | return (tgsi->reg_mapping != NULL); |
||
2638 | } |
||
2639 | |||
2640 | /** |
||
2641 | * Translate TGSI tokens into toy instructions. |
||
2642 | */ |
||
2643 | void |
||
2644 | toy_compiler_translate_tgsi(struct toy_compiler *tc, |
||
2645 | const struct tgsi_token *tokens, bool aos, |
||
2646 | struct toy_tgsi *tgsi) |
||
2647 | { |
||
2648 | struct tgsi_parse_context parse; |
||
2649 | |||
2650 | if (!init_tgsi(tgsi, tc, aos)) { |
||
2651 | tc_fail(tc, "failed to initialize TGSI translator"); |
||
2652 | return; |
||
2653 | } |
||
2654 | |||
2655 | tgsi_parse_init(&parse, tokens); |
||
2656 | while (!tgsi_parse_end_of_tokens(&parse)) { |
||
2657 | tgsi_parse_token(&parse); |
||
2658 | parse_token(tgsi, &parse.FullToken); |
||
2659 | } |
||
2660 | tgsi_parse_free(&parse); |
||
2661 | } |
||
2662 | |||
2663 | /** |
||
2664 | * Map the TGSI register to VRF register. |
||
2665 | */ |
||
2666 | int |
||
2667 | toy_tgsi_get_vrf(const struct toy_tgsi *tgsi, |
||
2668 | enum tgsi_file_type file, int dimension, int index) |
||
2669 | { |
||
2670 | void *key, *val; |
||
2671 | |||
2672 | key = ra_get_map_key(file, dimension, index); |
||
2673 | |||
2674 | val = util_hash_table_get(tgsi->reg_mapping, key); |
||
2675 | |||
2676 | return (val) ? pointer_to_intptr(val) : -1; |
||
2677 | }=><=>=>><>=>=>=>=>>>>>>>>>><>><>><>>><>>><>>>>><>><>>>>>>>>>>><>><>>=>>>=>>=> |