• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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