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 (at) lunarg.com> 26 */ 27 28 #include "toy_compiler.h" 29 30 /** 31 * Dump an operand. 32 */ 33 static void 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 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 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 * 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 * 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 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 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 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 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 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