1/* 2 * Copyright © 2014 Broadcom 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23 24#include "util/u_memory.h" 25#include "util/ralloc.h" 26 27#include "vc4_qir.h" 28#include "vc4_qpu.h" 29 30struct qir_op_info { 31 const char *name; 32 uint8_t ndst, nsrc; 33 bool has_side_effects; 34}; 35 36static const struct qir_op_info qir_op_info[] = { 37 [QOP_MOV] = { "mov", 1, 1 }, 38 [QOP_FMOV] = { "fmov", 1, 1 }, 39 [QOP_MMOV] = { "mmov", 1, 1 }, 40 [QOP_FADD] = { "fadd", 1, 2 }, 41 [QOP_FSUB] = { "fsub", 1, 2 }, 42 [QOP_FMUL] = { "fmul", 1, 2 }, 43 [QOP_MUL24] = { "mul24", 1, 2 }, 44 [QOP_V8MULD] = {"v8muld", 1, 2 }, 45 [QOP_V8MIN] = {"v8min", 1, 2 }, 46 [QOP_V8MAX] = {"v8max", 1, 2 }, 47 [QOP_V8ADDS] = {"v8adds", 1, 2 }, 48 [QOP_V8SUBS] = {"v8subs", 1, 2 }, 49 [QOP_FMIN] = { "fmin", 1, 2 }, 50 [QOP_FMAX] = { "fmax", 1, 2 }, 51 [QOP_FMINABS] = { "fminabs", 1, 2 }, 52 [QOP_FMAXABS] = { "fmaxabs", 1, 2 }, 53 [QOP_FTOI] = { "ftoi", 1, 1 }, 54 [QOP_ITOF] = { "itof", 1, 1 }, 55 [QOP_ADD] = { "add", 1, 2 }, 56 [QOP_SUB] = { "sub", 1, 2 }, 57 [QOP_SHR] = { "shr", 1, 2 }, 58 [QOP_ASR] = { "asr", 1, 2 }, 59 [QOP_SHL] = { "shl", 1, 2 }, 60 [QOP_MIN] = { "min", 1, 2 }, 61 [QOP_MIN_NOIMM] = { "min_noimm", 1, 2 }, 62 [QOP_MAX] = { "max", 1, 2 }, 63 [QOP_AND] = { "and", 1, 2 }, 64 [QOP_OR] = { "or", 1, 2 }, 65 [QOP_XOR] = { "xor", 1, 2 }, 66 [QOP_NOT] = { "not", 1, 1 }, 67 68 [QOP_RCP] = { "rcp", 1, 1 }, 69 [QOP_RSQ] = { "rsq", 1, 1 }, 70 [QOP_EXP2] = { "exp2", 1, 1 }, 71 [QOP_LOG2] = { "log2", 1, 1 }, 72 [QOP_TLB_COLOR_READ] = { "tlb_color_read", 1, 0 }, 73 [QOP_MS_MASK] = { "ms_mask", 0, 1, true }, 74 [QOP_VARY_ADD_C] = { "vary_add_c", 1, 1 }, 75 76 [QOP_FRAG_Z] = { "frag_z", 1, 0 }, 77 [QOP_FRAG_W] = { "frag_w", 1, 0 }, 78 79 [QOP_TEX_RESULT] = { "tex_result", 1, 0, true }, 80 81 [QOP_THRSW] = { "thrsw", 0, 0, true }, 82 83 [QOP_LOAD_IMM] = { "load_imm", 0, 1 }, 84 [QOP_LOAD_IMM_U2] = { "load_imm_u2", 0, 1 }, 85 [QOP_LOAD_IMM_I2] = { "load_imm_i2", 0, 1 }, 86 87 [QOP_ROT_MUL] = { "rot_mul", 0, 2 }, 88 89 [QOP_BRANCH] = { "branch", 0, 0, true }, 90 [QOP_UNIFORMS_RESET] = { "uniforms_reset", 0, 2, true }, 91}; 92 93static const char * 94qir_get_op_name(enum qop qop) 95{ 96 if (qop < ARRAY_SIZE(qir_op_info) && qir_op_info[qop].name) 97 return qir_op_info[qop].name; 98 else 99 return "???"; 100} 101 102int 103qir_get_non_sideband_nsrc(struct qinst *inst) 104{ 105 assert(qir_op_info[inst->op].name); 106 return qir_op_info[inst->op].nsrc; 107} 108 109int 110qir_get_nsrc(struct qinst *inst) 111{ 112 assert(qir_op_info[inst->op].name); 113 114 int nsrc = qir_get_non_sideband_nsrc(inst); 115 116 /* Normal (non-direct) texture coordinate writes also implicitly load 117 * a uniform for the texture parameters. 118 */ 119 if (qir_is_tex(inst) && inst->dst.file != QFILE_TEX_S_DIRECT) 120 nsrc++; 121 122 return nsrc; 123} 124 125/* The sideband uniform for textures gets stored after the normal ALU 126 * arguments. 127 */ 128int 129qir_get_tex_uniform_src(struct qinst *inst) 130{ 131 return qir_get_nsrc(inst) - 1; 132} 133 134/** 135 * Returns whether the instruction has any side effects that must be 136 * preserved. 137 */ 138bool 139qir_has_side_effects(struct vc4_compile *c, struct qinst *inst) 140{ 141 switch (inst->dst.file) { 142 case QFILE_TLB_Z_WRITE: 143 case QFILE_TLB_COLOR_WRITE: 144 case QFILE_TLB_COLOR_WRITE_MS: 145 case QFILE_TLB_STENCIL_SETUP: 146 case QFILE_TEX_S_DIRECT: 147 case QFILE_TEX_S: 148 case QFILE_TEX_T: 149 case QFILE_TEX_R: 150 case QFILE_TEX_B: 151 return true; 152 default: 153 break; 154 } 155 156 return qir_op_info[inst->op].has_side_effects; 157} 158 159bool 160qir_has_side_effect_reads(struct vc4_compile *c, struct qinst *inst) 161{ 162 /* We can dead-code eliminate varyings, because we only tell the VS 163 * about the live ones at the end. But we have to preserve the 164 * point/line coordinates reads, because they're generated by 165 * fixed-function hardware. 166 */ 167 for (int i = 0; i < qir_get_nsrc(inst); i++) { 168 if (inst->src[i].file == QFILE_VARY && 169 c->input_slots[inst->src[i].index].slot == 0xff) { 170 return true; 171 } 172 173 if (inst->src[i].file == QFILE_VPM) 174 return true; 175 } 176 177 if (inst->dst.file == QFILE_VPM) 178 return true; 179 180 return false; 181} 182 183bool 184qir_has_uniform_read(struct qinst *inst) 185{ 186 for (int i = 0; i < qir_get_nsrc(inst); i++) { 187 if (inst->src[i].file == QFILE_UNIF) 188 return true; 189 } 190 191 return false; 192} 193 194bool 195qir_is_mul(struct qinst *inst) 196{ 197 switch (inst->op) { 198 case QOP_MMOV: 199 case QOP_FMUL: 200 case QOP_MUL24: 201 case QOP_V8MULD: 202 case QOP_V8MIN: 203 case QOP_V8MAX: 204 case QOP_V8ADDS: 205 case QOP_V8SUBS: 206 case QOP_ROT_MUL: 207 return true; 208 default: 209 return false; 210 } 211} 212 213bool 214qir_is_float_input(struct qinst *inst) 215{ 216 switch (inst->op) { 217 case QOP_FMOV: 218 case QOP_FMUL: 219 case QOP_FADD: 220 case QOP_FSUB: 221 case QOP_FMIN: 222 case QOP_FMAX: 223 case QOP_FMINABS: 224 case QOP_FMAXABS: 225 case QOP_FTOI: 226 return true; 227 default: 228 return false; 229 } 230} 231 232bool 233qir_is_raw_mov(struct qinst *inst) 234{ 235 return ((inst->op == QOP_MOV || 236 inst->op == QOP_FMOV || 237 inst->op == QOP_MMOV) && 238 inst->cond == QPU_COND_ALWAYS && 239 !inst->dst.pack && 240 !inst->src[0].pack); 241} 242 243bool 244qir_is_tex(struct qinst *inst) 245{ 246 switch (inst->dst.file) { 247 case QFILE_TEX_S_DIRECT: 248 case QFILE_TEX_S: 249 case QFILE_TEX_T: 250 case QFILE_TEX_R: 251 case QFILE_TEX_B: 252 return true; 253 default: 254 return false; 255 } 256} 257 258bool 259qir_has_implicit_tex_uniform(struct qinst *inst) 260{ 261 switch (inst->dst.file) { 262 case QFILE_TEX_S: 263 case QFILE_TEX_T: 264 case QFILE_TEX_R: 265 case QFILE_TEX_B: 266 return true; 267 default: 268 return false; 269 } 270} 271 272bool 273qir_depends_on_flags(struct qinst *inst) 274{ 275 if (inst->op == QOP_BRANCH) { 276 return inst->cond != QPU_COND_BRANCH_ALWAYS; 277 } else { 278 return (inst->cond != QPU_COND_ALWAYS && 279 inst->cond != QPU_COND_NEVER); 280 } 281} 282 283bool 284qir_writes_r4(struct qinst *inst) 285{ 286 switch (inst->op) { 287 case QOP_TEX_RESULT: 288 case QOP_TLB_COLOR_READ: 289 case QOP_RCP: 290 case QOP_RSQ: 291 case QOP_EXP2: 292 case QOP_LOG2: 293 return true; 294 default: 295 return false; 296 } 297} 298 299uint8_t 300qir_channels_written(struct qinst *inst) 301{ 302 if (qir_is_mul(inst)) { 303 switch (inst->dst.pack) { 304 case QPU_PACK_MUL_NOP: 305 case QPU_PACK_MUL_8888: 306 return 0xf; 307 case QPU_PACK_MUL_8A: 308 return 0x1; 309 case QPU_PACK_MUL_8B: 310 return 0x2; 311 case QPU_PACK_MUL_8C: 312 return 0x4; 313 case QPU_PACK_MUL_8D: 314 return 0x8; 315 } 316 } else { 317 switch (inst->dst.pack) { 318 case QPU_PACK_A_NOP: 319 case QPU_PACK_A_8888: 320 case QPU_PACK_A_8888_SAT: 321 case QPU_PACK_A_32_SAT: 322 return 0xf; 323 case QPU_PACK_A_8A: 324 case QPU_PACK_A_8A_SAT: 325 return 0x1; 326 case QPU_PACK_A_8B: 327 case QPU_PACK_A_8B_SAT: 328 return 0x2; 329 case QPU_PACK_A_8C: 330 case QPU_PACK_A_8C_SAT: 331 return 0x4; 332 case QPU_PACK_A_8D: 333 case QPU_PACK_A_8D_SAT: 334 return 0x8; 335 case QPU_PACK_A_16A: 336 case QPU_PACK_A_16A_SAT: 337 return 0x3; 338 case QPU_PACK_A_16B: 339 case QPU_PACK_A_16B_SAT: 340 return 0xc; 341 } 342 } 343 unreachable("Bad pack field"); 344} 345 346char * 347qir_describe_uniform(enum quniform_contents contents, uint32_t data, 348 const uint32_t *uniforms) 349{ 350 static const char *quniform_names[] = { 351 [QUNIFORM_VIEWPORT_X_SCALE] = "vp_x_scale", 352 [QUNIFORM_VIEWPORT_Y_SCALE] = "vp_y_scale", 353 [QUNIFORM_VIEWPORT_Z_OFFSET] = "vp_z_offset", 354 [QUNIFORM_VIEWPORT_Z_SCALE] = "vp_z_scale", 355 [QUNIFORM_TEXTURE_CONFIG_P0] = "tex_p0", 356 [QUNIFORM_TEXTURE_CONFIG_P1] = "tex_p1", 357 [QUNIFORM_TEXTURE_CONFIG_P2] = "tex_p2", 358 [QUNIFORM_TEXTURE_FIRST_LEVEL] = "tex_first_level", 359 }; 360 361 switch (contents) { 362 case QUNIFORM_CONSTANT: 363 return ralloc_asprintf(NULL, "0x%08x / %f", data, uif(data)); 364 case QUNIFORM_UNIFORM: 365 if (uniforms) { 366 uint32_t unif = uniforms[data]; 367 return ralloc_asprintf(NULL, "unif[%d] = 0x%08x / %f", 368 data, unif, uif(unif)); 369 } else { 370 return ralloc_asprintf(NULL, "unif[%d]", data); 371 } 372 373 case QUNIFORM_TEXTURE_CONFIG_P0: 374 case QUNIFORM_TEXTURE_CONFIG_P1: 375 case QUNIFORM_TEXTURE_CONFIG_P2: 376 case QUNIFORM_TEXTURE_FIRST_LEVEL: 377 return ralloc_asprintf(NULL, "%s[%d]", 378 quniform_names[contents], data); 379 380 default: 381 if (contents < ARRAY_SIZE(quniform_names) && 382 quniform_names[contents]) { 383 return ralloc_asprintf(NULL, "%s", 384 quniform_names[contents]); 385 } else { 386 return ralloc_asprintf(NULL, "??? %d", contents); 387 } 388 } 389} 390 391static void 392qir_print_reg(struct vc4_compile *c, struct qreg reg, bool write) 393{ 394 static const char *files[] = { 395 [QFILE_TEMP] = "t", 396 [QFILE_VARY] = "v", 397 [QFILE_TLB_COLOR_WRITE] = "tlb_c", 398 [QFILE_TLB_COLOR_WRITE_MS] = "tlb_c_ms", 399 [QFILE_TLB_Z_WRITE] = "tlb_z", 400 [QFILE_TLB_STENCIL_SETUP] = "tlb_stencil", 401 [QFILE_FRAG_X] = "frag_x", 402 [QFILE_FRAG_Y] = "frag_y", 403 [QFILE_FRAG_REV_FLAG] = "frag_rev_flag", 404 [QFILE_QPU_ELEMENT] = "elem", 405 [QFILE_TEX_S_DIRECT] = "tex_s_direct", 406 [QFILE_TEX_S] = "tex_s", 407 [QFILE_TEX_T] = "tex_t", 408 [QFILE_TEX_R] = "tex_r", 409 [QFILE_TEX_B] = "tex_b", 410 }; 411 412 switch (reg.file) { 413 414 case QFILE_NULL: 415 fprintf(stderr, "null"); 416 break; 417 418 case QFILE_LOAD_IMM: 419 fprintf(stderr, "0x%08x (%f)", reg.index, uif(reg.index)); 420 break; 421 422 case QFILE_SMALL_IMM: 423 if ((int)reg.index >= -16 && (int)reg.index <= 15) 424 fprintf(stderr, "%d", reg.index); 425 else 426 fprintf(stderr, "%f", uif(reg.index)); 427 break; 428 429 case QFILE_VPM: 430 if (write) { 431 fprintf(stderr, "vpm"); 432 } else { 433 fprintf(stderr, "vpm%d.%d", 434 reg.index / 4, reg.index % 4); 435 } 436 break; 437 438 case QFILE_TLB_COLOR_WRITE: 439 case QFILE_TLB_COLOR_WRITE_MS: 440 case QFILE_TLB_Z_WRITE: 441 case QFILE_TLB_STENCIL_SETUP: 442 case QFILE_TEX_S_DIRECT: 443 case QFILE_TEX_S: 444 case QFILE_TEX_T: 445 case QFILE_TEX_R: 446 case QFILE_TEX_B: 447 fprintf(stderr, "%s", files[reg.file]); 448 break; 449 450 case QFILE_UNIF: { 451 char *desc = qir_describe_uniform(c->uniform_contents[reg.index], 452 c->uniform_data[reg.index], 453 NULL); 454 fprintf(stderr, "u%d (%s)", reg.index, desc); 455 ralloc_free(desc); 456 break; 457 } 458 459 default: 460 fprintf(stderr, "%s%d", files[reg.file], reg.index); 461 break; 462 } 463} 464 465void 466qir_dump_inst(struct vc4_compile *c, struct qinst *inst) 467{ 468 fprintf(stderr, "%s", qir_get_op_name(inst->op)); 469 if (inst->op == QOP_BRANCH) 470 vc4_qpu_disasm_cond_branch(stderr, inst->cond); 471 else 472 vc4_qpu_disasm_cond(stderr, inst->cond); 473 if (inst->sf) 474 fprintf(stderr, ".sf"); 475 fprintf(stderr, " "); 476 477 if (inst->op != QOP_BRANCH) { 478 qir_print_reg(c, inst->dst, true); 479 if (inst->dst.pack) { 480 if (inst->dst.pack) { 481 if (qir_is_mul(inst)) 482 vc4_qpu_disasm_pack_mul(stderr, inst->dst.pack); 483 else 484 vc4_qpu_disasm_pack_a(stderr, inst->dst.pack); 485 } 486 } 487 } 488 489 for (int i = 0; i < qir_get_nsrc(inst); i++) { 490 fprintf(stderr, ", "); 491 qir_print_reg(c, inst->src[i], false); 492 vc4_qpu_disasm_unpack(stderr, inst->src[i].pack); 493 } 494} 495 496void 497qir_dump(struct vc4_compile *c) 498{ 499 int ip = 0; 500 int pressure = 0; 501 502 qir_for_each_block(block, c) { 503 fprintf(stderr, "BLOCK %d:\n", block->index); 504 qir_for_each_inst(inst, block) { 505 if (c->temp_start) { 506 bool first = true; 507 508 fprintf(stderr, "%3d ", pressure); 509 510 for (int i = 0; i < c->num_temps; i++) { 511 if (c->temp_start[i] != ip) 512 continue; 513 514 if (first) { 515 first = false; 516 } else { 517 fprintf(stderr, ", "); 518 } 519 fprintf(stderr, "S%4d", i); 520 pressure++; 521 } 522 523 if (first) 524 fprintf(stderr, " "); 525 else 526 fprintf(stderr, " "); 527 } 528 529 if (c->temp_end) { 530 bool first = true; 531 532 for (int i = 0; i < c->num_temps; i++) { 533 if (c->temp_end[i] != ip) 534 continue; 535 536 if (first) { 537 first = false; 538 } else { 539 fprintf(stderr, ", "); 540 } 541 fprintf(stderr, "E%4d", i); 542 pressure--; 543 } 544 545 if (first) 546 fprintf(stderr, " "); 547 else 548 fprintf(stderr, " "); 549 } 550 551 qir_dump_inst(c, inst); 552 fprintf(stderr, "\n"); 553 ip++; 554 } 555 if (block->successors[1]) { 556 fprintf(stderr, "-> BLOCK %d, %d\n", 557 block->successors[0]->index, 558 block->successors[1]->index); 559 } else if (block->successors[0]) { 560 fprintf(stderr, "-> BLOCK %d\n", 561 block->successors[0]->index); 562 } 563 } 564} 565 566struct qreg 567qir_get_temp(struct vc4_compile *c) 568{ 569 struct qreg reg; 570 571 reg.file = QFILE_TEMP; 572 reg.index = c->num_temps++; 573 reg.pack = 0; 574 575 if (c->num_temps > c->defs_array_size) { 576 uint32_t old_size = c->defs_array_size; 577 c->defs_array_size = MAX2(old_size * 2, 16); 578 c->defs = reralloc(c, c->defs, struct qinst *, 579 c->defs_array_size); 580 memset(&c->defs[old_size], 0, 581 sizeof(c->defs[0]) * (c->defs_array_size - old_size)); 582 } 583 584 return reg; 585} 586 587struct qinst * 588qir_inst(enum qop op, struct qreg dst, struct qreg src0, struct qreg src1) 589{ 590 struct qinst *inst = CALLOC_STRUCT(qinst); 591 592 inst->op = op; 593 inst->dst = dst; 594 inst->src[0] = src0; 595 inst->src[1] = src1; 596 inst->cond = QPU_COND_ALWAYS; 597 598 return inst; 599} 600 601static void 602qir_emit(struct vc4_compile *c, struct qinst *inst) 603{ 604 list_addtail(&inst->link, &c->cur_block->instructions); 605} 606 607/* Updates inst to write to a new temporary, emits it, and notes the def. */ 608struct qreg 609qir_emit_def(struct vc4_compile *c, struct qinst *inst) 610{ 611 assert(inst->dst.file == QFILE_NULL); 612 613 inst->dst = qir_get_temp(c); 614 615 if (inst->dst.file == QFILE_TEMP) 616 c->defs[inst->dst.index] = inst; 617 618 qir_emit(c, inst); 619 620 return inst->dst; 621} 622 623struct qinst * 624qir_emit_nondef(struct vc4_compile *c, struct qinst *inst) 625{ 626 if (inst->dst.file == QFILE_TEMP) 627 c->defs[inst->dst.index] = NULL; 628 629 qir_emit(c, inst); 630 631 return inst; 632} 633 634bool 635qir_reg_equals(struct qreg a, struct qreg b) 636{ 637 return a.file == b.file && a.index == b.index && a.pack == b.pack; 638} 639 640struct qblock * 641qir_new_block(struct vc4_compile *c) 642{ 643 struct qblock *block = rzalloc(c, struct qblock); 644 645 list_inithead(&block->instructions); 646 list_inithead(&block->qpu_inst_list); 647 648 block->predecessors = _mesa_set_create(block, 649 _mesa_hash_pointer, 650 _mesa_key_pointer_equal); 651 652 block->index = c->next_block_index++; 653 654 return block; 655} 656 657void 658qir_set_emit_block(struct vc4_compile *c, struct qblock *block) 659{ 660 c->cur_block = block; 661 list_addtail(&block->link, &c->blocks); 662} 663 664struct qblock * 665qir_entry_block(struct vc4_compile *c) 666{ 667 return list_first_entry(&c->blocks, struct qblock, link); 668} 669 670struct qblock * 671qir_exit_block(struct vc4_compile *c) 672{ 673 return list_last_entry(&c->blocks, struct qblock, link); 674} 675 676void 677qir_link_blocks(struct qblock *predecessor, struct qblock *successor) 678{ 679 _mesa_set_add(successor->predecessors, predecessor); 680 if (predecessor->successors[0]) { 681 assert(!predecessor->successors[1]); 682 predecessor->successors[1] = successor; 683 } else { 684 predecessor->successors[0] = successor; 685 } 686} 687 688struct vc4_compile * 689qir_compile_init(void) 690{ 691 struct vc4_compile *c = rzalloc(NULL, struct vc4_compile); 692 693 list_inithead(&c->blocks); 694 qir_set_emit_block(c, qir_new_block(c)); 695 c->last_top_block = c->cur_block; 696 697 c->output_position_index = -1; 698 c->output_color_index = -1; 699 c->output_point_size_index = -1; 700 c->output_sample_mask_index = -1; 701 702 c->def_ht = _mesa_hash_table_create(c, _mesa_hash_pointer, 703 _mesa_key_pointer_equal); 704 705 return c; 706} 707 708void 709qir_remove_instruction(struct vc4_compile *c, struct qinst *qinst) 710{ 711 if (qinst->dst.file == QFILE_TEMP) 712 c->defs[qinst->dst.index] = NULL; 713 714 list_del(&qinst->link); 715 free(qinst); 716} 717 718struct qreg 719qir_follow_movs(struct vc4_compile *c, struct qreg reg) 720{ 721 int pack = reg.pack; 722 723 while (reg.file == QFILE_TEMP && 724 c->defs[reg.index] && 725 (c->defs[reg.index]->op == QOP_MOV || 726 c->defs[reg.index]->op == QOP_FMOV || 727 c->defs[reg.index]->op == QOP_MMOV)&& 728 !c->defs[reg.index]->dst.pack && 729 !c->defs[reg.index]->src[0].pack) { 730 reg = c->defs[reg.index]->src[0]; 731 } 732 733 reg.pack = pack; 734 return reg; 735} 736 737void 738qir_compile_destroy(struct vc4_compile *c) 739{ 740 qir_for_each_block(block, c) { 741 while (!list_is_empty(&block->instructions)) { 742 struct qinst *qinst = 743 list_first_entry(&block->instructions, 744 struct qinst, link); 745 qir_remove_instruction(c, qinst); 746 } 747 } 748 749 ralloc_free(c); 750} 751 752const char * 753qir_get_stage_name(enum qstage stage) 754{ 755 static const char *names[] = { 756 [QSTAGE_FRAG] = "FS", 757 [QSTAGE_VERT] = "VS", 758 [QSTAGE_COORD] = "CS", 759 }; 760 761 return names[stage]; 762} 763 764struct qreg 765qir_uniform(struct vc4_compile *c, 766 enum quniform_contents contents, 767 uint32_t data) 768{ 769 for (int i = 0; i < c->num_uniforms; i++) { 770 if (c->uniform_contents[i] == contents && 771 c->uniform_data[i] == data) { 772 return qir_reg(QFILE_UNIF, i); 773 } 774 } 775 776 uint32_t uniform = c->num_uniforms++; 777 778 if (uniform >= c->uniform_array_size) { 779 c->uniform_array_size = MAX2(MAX2(16, uniform + 1), 780 c->uniform_array_size * 2); 781 782 c->uniform_data = reralloc(c, c->uniform_data, 783 uint32_t, 784 c->uniform_array_size); 785 c->uniform_contents = reralloc(c, c->uniform_contents, 786 enum quniform_contents, 787 c->uniform_array_size); 788 } 789 790 c->uniform_contents[uniform] = contents; 791 c->uniform_data[uniform] = data; 792 793 return qir_reg(QFILE_UNIF, uniform); 794} 795 796void 797qir_SF(struct vc4_compile *c, struct qreg src) 798{ 799 struct qinst *last_inst = NULL; 800 801 if (!list_is_empty(&c->cur_block->instructions)) 802 last_inst = (struct qinst *)c->cur_block->instructions.prev; 803 804 /* We don't have any way to guess which kind of MOV is implied. */ 805 assert(!src.pack); 806 807 if (src.file != QFILE_TEMP || 808 !c->defs[src.index] || 809 last_inst != c->defs[src.index]) { 810 last_inst = qir_MOV_dest(c, qir_reg(QFILE_NULL, 0), src); 811 } 812 last_inst->sf = true; 813} 814 815#define OPTPASS(func) \ 816 do { \ 817 bool stage_progress = func(c); \ 818 if (stage_progress) { \ 819 progress = true; \ 820 if (print_opt_debug) { \ 821 fprintf(stderr, \ 822 "QIR opt pass %2d: %s progress\n", \ 823 pass, #func); \ 824 } \ 825 qir_validate(c); \ 826 } \ 827 } while (0) 828 829void 830qir_optimize(struct vc4_compile *c) 831{ 832 bool print_opt_debug = false; 833 int pass = 1; 834 835 while (true) { 836 bool progress = false; 837 838 OPTPASS(qir_opt_algebraic); 839 OPTPASS(qir_opt_constant_folding); 840 OPTPASS(qir_opt_copy_propagation); 841 OPTPASS(qir_opt_peephole_sf); 842 OPTPASS(qir_opt_dead_code); 843 OPTPASS(qir_opt_small_immediates); 844 OPTPASS(qir_opt_vpm); 845 OPTPASS(qir_opt_coalesce_ff_writes); 846 847 if (!progress) 848 break; 849 850 pass++; 851 } 852} 853