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 <olv@lunarg.com>
26 */
27
28 #include "toy_compiler.h"
29
30 /**
31 * Dump an operand.
32 */
33 static void
tc_dump_operand(struct toy_compiler * tc,enum toy_file file,enum toy_type type,enum toy_rect rect,bool indirect,unsigned indirect_subreg,uint32_t val32,bool is_dst)34 tc_dump_operand(struct toy_compiler *tc,
35 enum toy_file file, enum toy_type type, enum toy_rect rect,
36 bool indirect, unsigned indirect_subreg, uint32_t val32,
37 bool is_dst)
38 {
39 static const char *toy_file_names[TOY_FILE_COUNT] = {
40 [TOY_FILE_VRF] = "v",
41 [TOY_FILE_ARF] = "NOT USED",
42 [TOY_FILE_GRF] = "r",
43 [TOY_FILE_MRF] = "m",
44 [TOY_FILE_IMM] = "NOT USED",
45 };
46 const char *name = toy_file_names[file];
47 int reg, subreg;
48
49 if (file != TOY_FILE_IMM) {
50 reg = val32 / TOY_REG_WIDTH;
51 subreg = (val32 % TOY_REG_WIDTH) / toy_type_size(type);
52 }
53
54 switch (file) {
55 case TOY_FILE_GRF:
56 if (indirect) {
57 const int addr_subreg = indirect_subreg / toy_type_size(TOY_TYPE_UW);
58
59 ilo_printf("%s[a0.%d", name, addr_subreg);
60 if (val32)
61 ilo_printf("%+d", (int) val32);
62 ilo_printf("]");
63 break;
64 }
65 /* fall through */
66 case TOY_FILE_VRF:
67 case TOY_FILE_MRF:
68 ilo_printf("%s%d", name, reg);
69 if (subreg)
70 ilo_printf(".%d", subreg);
71 break;
72 case TOY_FILE_ARF:
73 switch (reg) {
74 case GEN6_ARF_NULL:
75 ilo_printf("null");
76 break;
77 case GEN6_ARF_A0:
78 ilo_printf("a0.%d", subreg);
79 break;
80 case GEN6_ARF_ACC0:
81 case GEN6_ARF_ACC0 + 1:
82 ilo_printf("acc%d.%d", (reg & 1), subreg);
83 break;
84 case GEN6_ARF_F0:
85 ilo_printf("f0.%d", subreg);
86 break;
87 case GEN6_ARF_SR0:
88 ilo_printf("sr0.%d", subreg);
89 break;
90 case GEN6_ARF_CR0:
91 ilo_printf("cr0.%d", subreg);
92 break;
93 case GEN6_ARF_N0:
94 case GEN6_ARF_N0 + 1:
95 ilo_printf("n%d.%d", (reg & 1), subreg);
96 break;
97 case GEN6_ARF_IP:
98 ilo_printf("ip");
99 break;
100 }
101 break;
102 case TOY_FILE_IMM:
103 switch (type) {
104 case TOY_TYPE_F:
105 {
106 union fi fi = { .ui = val32 };
107 ilo_printf("%f", fi.f);
108 }
109 break;
110 case TOY_TYPE_D:
111 ilo_printf("%d", (int32_t) val32);
112 break;
113 case TOY_TYPE_UD:
114 ilo_printf("%u", val32);
115 break;
116 case TOY_TYPE_W:
117 ilo_printf("%d", (int16_t) (val32 & 0xffff));
118 break;
119 case TOY_TYPE_UW:
120 ilo_printf("%u", val32 & 0xffff);
121 break;
122 case TOY_TYPE_V:
123 ilo_printf("0x%08x", val32);
124 break;
125 default:
126 assert(!"unknown imm type");
127 break;
128 }
129 break;
130 default:
131 assert(!"unexpected file");
132 break;
133 }
134
135 /* dump the region parameter */
136 if (file != TOY_FILE_IMM) {
137 int vert_stride, width, horz_stride;
138
139 switch (rect) {
140 case TOY_RECT_LINEAR:
141 vert_stride = tc->rect_linear_width;
142 width = tc->rect_linear_width;
143 horz_stride = 1;
144 break;
145 case TOY_RECT_041:
146 vert_stride = 0;
147 width = 4;
148 horz_stride = 1;
149 break;
150 case TOY_RECT_010:
151 vert_stride = 0;
152 width = 1;
153 horz_stride = 0;
154 break;
155 case TOY_RECT_220:
156 vert_stride = 2;
157 width = 2;
158 horz_stride = 0;
159 break;
160 case TOY_RECT_440:
161 vert_stride = 4;
162 width = 4;
163 horz_stride = 0;
164 break;
165 case TOY_RECT_240:
166 vert_stride = 2;
167 width = 4;
168 horz_stride = 0;
169 break;
170 default:
171 assert(!"unknown rect parameter");
172 vert_stride = 0;
173 width = 0;
174 horz_stride = 0;
175 break;
176 }
177
178 if (is_dst)
179 ilo_printf("<%d>", horz_stride);
180 else
181 ilo_printf("<%d;%d,%d>", vert_stride, width, horz_stride);
182 }
183
184 switch (type) {
185 case TOY_TYPE_F:
186 ilo_printf(":f");
187 break;
188 case TOY_TYPE_D:
189 ilo_printf(":d");
190 break;
191 case TOY_TYPE_UD:
192 ilo_printf(":ud");
193 break;
194 case TOY_TYPE_W:
195 ilo_printf(":w");
196 break;
197 case TOY_TYPE_UW:
198 ilo_printf(":uw");
199 break;
200 case TOY_TYPE_V:
201 ilo_printf(":v");
202 break;
203 default:
204 assert(!"unexpected type");
205 break;
206 }
207 }
208
209 /**
210 * Dump a source operand.
211 */
212 static void
tc_dump_src(struct toy_compiler * tc,struct toy_src src)213 tc_dump_src(struct toy_compiler *tc, struct toy_src src)
214 {
215 if (src.negate)
216 ilo_printf("-");
217 if (src.absolute)
218 ilo_printf("|");
219
220 tc_dump_operand(tc, src.file, src.type, src.rect,
221 src.indirect, src.indirect_subreg, src.val32, false);
222
223 if (tsrc_is_swizzled(src)) {
224 const char xyzw[] = "xyzw";
225 ilo_printf(".%c%c%c%c",
226 xyzw[src.swizzle_x],
227 xyzw[src.swizzle_y],
228 xyzw[src.swizzle_z],
229 xyzw[src.swizzle_w]);
230 }
231
232 if (src.absolute)
233 ilo_printf("|");
234 }
235
236 /**
237 * Dump a destination operand.
238 */
239 static void
tc_dump_dst(struct toy_compiler * tc,struct toy_dst dst)240 tc_dump_dst(struct toy_compiler *tc, struct toy_dst dst)
241 {
242 tc_dump_operand(tc, dst.file, dst.type, dst.rect,
243 dst.indirect, dst.indirect_subreg, dst.val32, true);
244
245 if (dst.writemask != TOY_WRITEMASK_XYZW) {
246 ilo_printf(".");
247 if (dst.writemask & TOY_WRITEMASK_X)
248 ilo_printf("x");
249 if (dst.writemask & TOY_WRITEMASK_Y)
250 ilo_printf("y");
251 if (dst.writemask & TOY_WRITEMASK_Z)
252 ilo_printf("z");
253 if (dst.writemask & TOY_WRITEMASK_W)
254 ilo_printf("w");
255 }
256 }
257
258 static const char *
get_opcode_name(unsigned opcode)259 get_opcode_name(unsigned opcode)
260 {
261 switch (opcode) {
262 case GEN6_OPCODE_MOV: return "mov";
263 case GEN6_OPCODE_SEL: return "sel";
264 case GEN6_OPCODE_NOT: return "not";
265 case GEN6_OPCODE_AND: return "and";
266 case GEN6_OPCODE_OR: return "or";
267 case GEN6_OPCODE_XOR: return "xor";
268 case GEN6_OPCODE_SHR: return "shr";
269 case GEN6_OPCODE_SHL: return "shl";
270 case 0xa: return "rsr";
271 case 0xb: return "rsl";
272 case GEN6_OPCODE_ASR: return "asr";
273 case GEN6_OPCODE_CMP: return "cmp";
274 case GEN6_OPCODE_CMPN: return "cmpn";
275 case GEN6_OPCODE_JMPI: return "jmpi";
276 case GEN6_OPCODE_IF: return "if";
277 case 0x23: return "iff";
278 case GEN6_OPCODE_ELSE: return "else";
279 case GEN6_OPCODE_ENDIF: return "endif";
280 case 0x26: return "do";
281 case GEN6_OPCODE_WHILE: return "while";
282 case GEN6_OPCODE_BREAK: return "break";
283 case GEN6_OPCODE_CONT: return "continue";
284 case GEN6_OPCODE_HALT: return "halt";
285 case 0x2c: return "msave";
286 case 0x2d: return "mrestore";
287 case 0x2e: return "push";
288 case 0x2f: return "pop";
289 case GEN6_OPCODE_WAIT: return "wait";
290 case GEN6_OPCODE_SEND: return "send";
291 case GEN6_OPCODE_SENDC: return "sendc";
292 case GEN6_OPCODE_MATH: return "math";
293 case GEN6_OPCODE_ADD: return "add";
294 case GEN6_OPCODE_MUL: return "mul";
295 case GEN6_OPCODE_AVG: return "avg";
296 case GEN6_OPCODE_FRC: return "frc";
297 case GEN6_OPCODE_RNDU: return "rndu";
298 case GEN6_OPCODE_RNDD: return "rndd";
299 case GEN6_OPCODE_RNDE: return "rnde";
300 case GEN6_OPCODE_RNDZ: return "rndz";
301 case GEN6_OPCODE_MAC: return "mac";
302 case GEN6_OPCODE_MACH: return "mach";
303 case GEN6_OPCODE_LZD: return "lzd";
304 case GEN6_OPCODE_SAD2: return "sad2";
305 case GEN6_OPCODE_SADA2: return "sada2";
306 case GEN6_OPCODE_DP4: return "dp4";
307 case GEN6_OPCODE_DPH: return "dph";
308 case GEN6_OPCODE_DP3: return "dp3";
309 case GEN6_OPCODE_DP2: return "dp2";
310 case 0x58: return "dpa2";
311 case GEN6_OPCODE_LINE: return "line";
312 case GEN6_OPCODE_PLN: return "pln";
313 case GEN6_OPCODE_MAD: return "mad";
314 case GEN6_OPCODE_NOP: return "nop";
315 case TOY_OPCODE_DO: return "do";
316 /* TGSI */
317 case TOY_OPCODE_TGSI_IN: return "tgsi.in";
318 case TOY_OPCODE_TGSI_CONST: return "tgsi.const";
319 case TOY_OPCODE_TGSI_SV: return "tgsi.sv";
320 case TOY_OPCODE_TGSI_IMM: return "tgsi.imm";
321 case TOY_OPCODE_TGSI_INDIRECT_FETCH: return "tgsi.indirect_fetch";
322 case TOY_OPCODE_TGSI_INDIRECT_STORE: return "tgsi.indirect_store";
323 case TOY_OPCODE_TGSI_TEX: return "tgsi.tex";
324 case TOY_OPCODE_TGSI_TXB: return "tgsi.txb";
325 case TOY_OPCODE_TGSI_TXD: return "tgsi.txd";
326 case TOY_OPCODE_TGSI_TXL: return "tgsi.txl";
327 case TOY_OPCODE_TGSI_TXP: return "tgsi.txp";
328 case TOY_OPCODE_TGSI_TXF: return "tgsi.txf";
329 case TOY_OPCODE_TGSI_TXQ: return "tgsi.txq";
330 case TOY_OPCODE_TGSI_TXQ_LZ: return "tgsi.txq_lz";
331 case TOY_OPCODE_TGSI_TEX2: return "tgsi.tex2";
332 case TOY_OPCODE_TGSI_TXB2: return "tgsi.txb2";
333 case TOY_OPCODE_TGSI_TXL2: return "tgsi.txl2";
334 case TOY_OPCODE_TGSI_SAMPLE: return "tgsi.sample";
335 case TOY_OPCODE_TGSI_SAMPLE_I: return "tgsi.sample_i";
336 case TOY_OPCODE_TGSI_SAMPLE_I_MS: return "tgsi.sample_i_ms";
337 case TOY_OPCODE_TGSI_SAMPLE_B: return "tgsi.sample_b";
338 case TOY_OPCODE_TGSI_SAMPLE_C: return "tgsi.sample_c";
339 case TOY_OPCODE_TGSI_SAMPLE_C_LZ: return "tgsi.sample_c_lz";
340 case TOY_OPCODE_TGSI_SAMPLE_D: return "tgsi.sample_d";
341 case TOY_OPCODE_TGSI_SAMPLE_L: return "tgsi.sample_l";
342 case TOY_OPCODE_TGSI_GATHER4: return "tgsi.gather4";
343 case TOY_OPCODE_TGSI_SVIEWINFO: return "tgsi.sviewinfo";
344 case TOY_OPCODE_TGSI_SAMPLE_POS: return "tgsi.sample_pos";
345 case TOY_OPCODE_TGSI_SAMPLE_INFO: return "tgsi.sample_info";
346 /* math */
347 case TOY_OPCODE_INV: return "math.inv";
348 case TOY_OPCODE_LOG: return "math.log";
349 case TOY_OPCODE_EXP: return "math.exp";
350 case TOY_OPCODE_SQRT: return "math.sqrt";
351 case TOY_OPCODE_RSQ: return "math.rsq";
352 case TOY_OPCODE_SIN: return "math.sin";
353 case TOY_OPCODE_COS: return "math.cos";
354 case TOY_OPCODE_FDIV: return "math.fdiv";
355 case TOY_OPCODE_POW: return "math.pow";
356 case TOY_OPCODE_INT_DIV_QUOTIENT: return "math.int_div_quotient";
357 case TOY_OPCODE_INT_DIV_REMAINDER: return "math.int_div_remainer";
358 /* urb */
359 case TOY_OPCODE_URB_WRITE: return "urb.urb_write";
360 /* gs */
361 case TOY_OPCODE_EMIT: return "gs.emit";
362 case TOY_OPCODE_ENDPRIM: return "gs.endprim";
363 /* fs */
364 case TOY_OPCODE_DDX: return "fs.ddx";
365 case TOY_OPCODE_DDY: return "fs.ddy";
366 case TOY_OPCODE_FB_WRITE: return "fs.fb_write";
367 case TOY_OPCODE_KIL: return "fs.kil";
368 default: return "unk";
369 }
370 }
371
372 static const char *
get_cond_modifier_name(unsigned opcode,unsigned cond_modifier)373 get_cond_modifier_name(unsigned opcode, unsigned cond_modifier)
374 {
375 switch (opcode) {
376 case GEN6_OPCODE_SEND:
377 case GEN6_OPCODE_SENDC:
378 /* SFID */
379 switch (cond_modifier) {
380 case GEN6_SFID_NULL: return "Null";
381 case GEN6_SFID_SAMPLER: return "Sampling Engine";
382 case GEN6_SFID_GATEWAY: return "Message Gateway";
383 case GEN6_SFID_DP_SAMPLER: return "Data Port Sampler Cache";
384 case GEN6_SFID_DP_RC: return "Data Port Render Cache";
385 case GEN6_SFID_URB: return "URB";
386 case GEN6_SFID_SPAWNER: return "Thread Spawner";
387 case GEN6_SFID_DP_CC: return "Constant Cache";
388 default: return "Unknown";
389 }
390 break;
391 case GEN6_OPCODE_MATH:
392 /* FC */
393 switch (cond_modifier) {
394 case GEN6_MATH_INV: return "INV";
395 case GEN6_MATH_LOG: return "LOG";
396 case GEN6_MATH_EXP: return "EXP";
397 case GEN6_MATH_SQRT: return "SQRT";
398 case GEN6_MATH_RSQ: return "RSQ";
399 case GEN6_MATH_SIN: return "SIN";
400 case GEN6_MATH_COS: return "COS";
401 case GEN6_MATH_FDIV: return "FDIV";
402 case GEN6_MATH_POW: return "POW";
403 case GEN6_MATH_INT_DIV_QUOTIENT: return "INT DIV (quotient)";
404 case GEN6_MATH_INT_DIV_REMAINDER: return "INT DIV (remainder)";
405 default: return "UNK";
406 }
407 break;
408 default:
409 switch (cond_modifier) {
410 case GEN6_COND_NONE: return NULL;
411 case GEN6_COND_Z: return "z";
412 case GEN6_COND_NZ: return "nz";
413 case GEN6_COND_G: return "g";
414 case GEN6_COND_GE: return "ge";
415 case GEN6_COND_L: return "l";
416 case GEN6_COND_LE: return "le";
417 default: return "unk";
418 }
419 break;
420 }
421 }
422
423 /**
424 * Dump an instruction.
425 */
426 static void
tc_dump_inst(struct toy_compiler * tc,const struct toy_inst * inst)427 tc_dump_inst(struct toy_compiler *tc, const struct toy_inst *inst)
428 {
429 const char *name;
430 int i;
431
432 name = get_opcode_name(inst->opcode);
433
434 ilo_printf(" %s", name);
435
436 if (inst->opcode == GEN6_OPCODE_NOP) {
437 ilo_printf("\n");
438 return;
439 }
440
441 if (inst->saturate)
442 ilo_printf(".sat");
443
444 name = get_cond_modifier_name(inst->opcode, inst->cond_modifier);
445 if (name)
446 ilo_printf(".%s", name);
447
448 ilo_printf(" ");
449
450 tc_dump_dst(tc, inst->dst);
451
452 for (i = 0; i < ARRAY_SIZE(inst->src); i++) {
453 if (tsrc_is_null(inst->src[i]))
454 break;
455
456 ilo_printf(", ");
457 tc_dump_src(tc, inst->src[i]);
458 }
459
460 ilo_printf("\n");
461 }
462
463 /**
464 * Dump the instructions added to the compiler.
465 */
466 void
toy_compiler_dump(struct toy_compiler * tc)467 toy_compiler_dump(struct toy_compiler *tc)
468 {
469 struct toy_inst *inst;
470 int pc;
471
472 pc = 0;
473 tc_head(tc);
474 while ((inst = tc_next_no_skip(tc)) != NULL) {
475 /* we do not generate code for markers */
476 if (inst->marker)
477 ilo_printf("marker:");
478 else
479 ilo_printf("%6d:", pc++);
480
481 tc_dump_inst(tc, inst);
482 }
483 }
484
485 /**
486 * Clean up the toy compiler.
487 */
488 void
toy_compiler_cleanup(struct toy_compiler * tc)489 toy_compiler_cleanup(struct toy_compiler *tc)
490 {
491 struct toy_inst *inst, *next;
492
493 LIST_FOR_EACH_ENTRY_SAFE(inst, next, &tc->instructions, list)
494 slab_free_st(&tc->mempool, inst);
495
496 slab_destroy(&tc->mempool);
497 }
498
499 /**
500 * Initialize the instruction template, from which tc_add() initializes the
501 * newly added instructions.
502 */
503 static void
tc_init_inst_templ(struct toy_compiler * tc)504 tc_init_inst_templ(struct toy_compiler *tc)
505 {
506 struct toy_inst *templ = &tc->templ;
507 int i;
508
509 templ->opcode = GEN6_OPCODE_NOP;
510 templ->access_mode = GEN6_ALIGN_1;
511 templ->mask_ctrl = GEN6_MASKCTRL_NORMAL;
512 templ->dep_ctrl = GEN6_DEPCTRL_NORMAL;
513 templ->qtr_ctrl = GEN6_QTRCTRL_1Q;
514 templ->thread_ctrl = GEN6_THREADCTRL_NORMAL;
515 templ->pred_ctrl = GEN6_PREDCTRL_NONE;
516 templ->pred_inv = false;
517 templ->exec_size = GEN6_EXECSIZE_1;
518 templ->cond_modifier = GEN6_COND_NONE;
519 templ->acc_wr_ctrl = false;
520 templ->saturate = false;
521
522 templ->marker = false;
523
524 templ->dst = tdst_null();
525 for (i = 0; i < ARRAY_SIZE(templ->src); i++)
526 templ->src[i] = tsrc_null();
527
528 for (i = 0; i < ARRAY_SIZE(templ->tex.offsets); i++)
529 templ->tex.offsets[i] = tsrc_null();
530
531 list_inithead(&templ->list);
532 }
533
534 /**
535 * Initialize the toy compiler.
536 */
537 void
toy_compiler_init(struct toy_compiler * tc,const struct ilo_dev * dev)538 toy_compiler_init(struct toy_compiler *tc, const struct ilo_dev *dev)
539 {
540 memset(tc, 0, sizeof(*tc));
541
542 tc->dev = dev;
543
544 tc_init_inst_templ(tc);
545
546 slab_create(&tc->mempool, sizeof(struct toy_inst),
547 64);
548
549 list_inithead(&tc->instructions);
550 /* instructions are added to the tail */
551 tc_tail(tc);
552
553 tc->rect_linear_width = 1;
554
555 /* skip 0 so that util_hash_table_get() never returns NULL */
556 tc->next_vrf = 1;
557 }
558