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