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 30 struct qir_op_info { 31 const char *name; 32 uint8_t ndst, nsrc; 33 bool has_side_effects; 34 }; 35 36 static 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 93 static const char * 94 qir_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 102 int 103 qir_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 109 int 110 qir_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 */ 128 int 129 qir_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 */ 138 bool 139 qir_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 159 bool 160 qir_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 183 bool 184 qir_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 194 bool 195 qir_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 213 bool 214 qir_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 232 bool 233 qir_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 243 bool 244 qir_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 258 bool 259 qir_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 272 bool 273 qir_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 283 bool 284 qir_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 299 uint8_t 300 qir_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 346 static void 347 qir_print_reg(struct vc4_compile *c, struct qreg reg, bool write) 348 { 349 static const char *files[] = { 350 [QFILE_TEMP] = "t", 351 [QFILE_VARY] = "v", 352 [QFILE_UNIF] = "u", 353 [QFILE_TLB_COLOR_WRITE] = "tlb_c", 354 [QFILE_TLB_COLOR_WRITE_MS] = "tlb_c_ms", 355 [QFILE_TLB_Z_WRITE] = "tlb_z", 356 [QFILE_TLB_STENCIL_SETUP] = "tlb_stencil", 357 [QFILE_FRAG_X] = "frag_x", 358 [QFILE_FRAG_Y] = "frag_y", 359 [QFILE_FRAG_REV_FLAG] = "frag_rev_flag", 360 [QFILE_QPU_ELEMENT] = "elem", 361 [QFILE_TEX_S_DIRECT] = "tex_s_direct", 362 [QFILE_TEX_S] = "tex_s", 363 [QFILE_TEX_T] = "tex_t", 364 [QFILE_TEX_R] = "tex_r", 365 [QFILE_TEX_B] = "tex_b", 366 }; 367 368 switch (reg.file) { 369 370 case QFILE_NULL: 371 fprintf(stderr, "null"); 372 break; 373 374 case QFILE_LOAD_IMM: 375 fprintf(stderr, "0x%08x (%f)", reg.index, uif(reg.index)); 376 break; 377 378 case QFILE_SMALL_IMM: 379 if ((int)reg.index >= -16 && (int)reg.index <= 15) 380 fprintf(stderr, "%d", reg.index); 381 else 382 fprintf(stderr, "%f", uif(reg.index)); 383 break; 384 385 case QFILE_VPM: 386 if (write) { 387 fprintf(stderr, "vpm"); 388 } else { 389 fprintf(stderr, "vpm%d.%d", 390 reg.index / 4, reg.index % 4); 391 } 392 break; 393 394 case QFILE_TLB_COLOR_WRITE: 395 case QFILE_TLB_COLOR_WRITE_MS: 396 case QFILE_TLB_Z_WRITE: 397 case QFILE_TLB_STENCIL_SETUP: 398 case QFILE_TEX_S_DIRECT: 399 case QFILE_TEX_S: 400 case QFILE_TEX_T: 401 case QFILE_TEX_R: 402 case QFILE_TEX_B: 403 fprintf(stderr, "%s", files[reg.file]); 404 break; 405 406 default: 407 fprintf(stderr, "%s%d", files[reg.file], reg.index); 408 break; 409 } 410 411 if (reg.file == QFILE_UNIF && 412 c->uniform_contents[reg.index] == QUNIFORM_CONSTANT) { 413 fprintf(stderr, " (0x%08x / %f)", 414 c->uniform_data[reg.index], 415 uif(c->uniform_data[reg.index])); 416 } 417 } 418 419 void 420 qir_dump_inst(struct vc4_compile *c, struct qinst *inst) 421 { 422 fprintf(stderr, "%s", qir_get_op_name(inst->op)); 423 if (inst->op == QOP_BRANCH) 424 vc4_qpu_disasm_cond_branch(stderr, inst->cond); 425 else 426 vc4_qpu_disasm_cond(stderr, inst->cond); 427 if (inst->sf) 428 fprintf(stderr, ".sf"); 429 fprintf(stderr, " "); 430 431 if (inst->op != QOP_BRANCH) { 432 qir_print_reg(c, inst->dst, true); 433 if (inst->dst.pack) { 434 if (inst->dst.pack) { 435 if (qir_is_mul(inst)) 436 vc4_qpu_disasm_pack_mul(stderr, inst->dst.pack); 437 else 438 vc4_qpu_disasm_pack_a(stderr, inst->dst.pack); 439 } 440 } 441 } 442 443 for (int i = 0; i < qir_get_nsrc(inst); i++) { 444 fprintf(stderr, ", "); 445 qir_print_reg(c, inst->src[i], false); 446 vc4_qpu_disasm_unpack(stderr, inst->src[i].pack); 447 } 448 } 449 450 void 451 qir_dump(struct vc4_compile *c) 452 { 453 int ip = 0; 454 int pressure = 0; 455 456 qir_for_each_block(block, c) { 457 fprintf(stderr, "BLOCK %d:\n", block->index); 458 qir_for_each_inst(inst, block) { 459 if (c->temp_start) { 460 bool first = true; 461 462 fprintf(stderr, "%3d ", pressure); 463 464 for (int i = 0; i < c->num_temps; i++) { 465 if (c->temp_start[i] != ip) 466 continue; 467 468 if (first) { 469 first = false; 470 } else { 471 fprintf(stderr, ", "); 472 } 473 fprintf(stderr, "S%4d", i); 474 pressure++; 475 } 476 477 if (first) 478 fprintf(stderr, " "); 479 else 480 fprintf(stderr, " "); 481 } 482 483 if (c->temp_end) { 484 bool first = true; 485 486 for (int i = 0; i < c->num_temps; i++) { 487 if (c->temp_end[i] != ip) 488 continue; 489 490 if (first) { 491 first = false; 492 } else { 493 fprintf(stderr, ", "); 494 } 495 fprintf(stderr, "E%4d", i); 496 pressure--; 497 } 498 499 if (first) 500 fprintf(stderr, " "); 501 else 502 fprintf(stderr, " "); 503 } 504 505 qir_dump_inst(c, inst); 506 fprintf(stderr, "\n"); 507 ip++; 508 } 509 if (block->successors[1]) { 510 fprintf(stderr, "-> BLOCK %d, %d\n", 511 block->successors[0]->index, 512 block->successors[1]->index); 513 } else if (block->successors[0]) { 514 fprintf(stderr, "-> BLOCK %d\n", 515 block->successors[0]->index); 516 } 517 } 518 } 519 520 struct qreg 521 qir_get_temp(struct vc4_compile *c) 522 { 523 struct qreg reg; 524 525 reg.file = QFILE_TEMP; 526 reg.index = c->num_temps++; 527 reg.pack = 0; 528 529 if (c->num_temps > c->defs_array_size) { 530 uint32_t old_size = c->defs_array_size; 531 c->defs_array_size = MAX2(old_size * 2, 16); 532 c->defs = reralloc(c, c->defs, struct qinst *, 533 c->defs_array_size); 534 memset(&c->defs[old_size], 0, 535 sizeof(c->defs[0]) * (c->defs_array_size - old_size)); 536 } 537 538 return reg; 539 } 540 541 struct qinst * 542 qir_inst(enum qop op, struct qreg dst, struct qreg src0, struct qreg src1) 543 { 544 struct qinst *inst = CALLOC_STRUCT(qinst); 545 546 inst->op = op; 547 inst->dst = dst; 548 inst->src[0] = src0; 549 inst->src[1] = src1; 550 inst->cond = QPU_COND_ALWAYS; 551 552 return inst; 553 } 554 555 static void 556 qir_emit(struct vc4_compile *c, struct qinst *inst) 557 { 558 list_addtail(&inst->link, &c->cur_block->instructions); 559 } 560 561 /* Updates inst to write to a new temporary, emits it, and notes the def. */ 562 struct qreg 563 qir_emit_def(struct vc4_compile *c, struct qinst *inst) 564 { 565 assert(inst->dst.file == QFILE_NULL); 566 567 inst->dst = qir_get_temp(c); 568 569 if (inst->dst.file == QFILE_TEMP) 570 c->defs[inst->dst.index] = inst; 571 572 qir_emit(c, inst); 573 574 return inst->dst; 575 } 576 577 struct qinst * 578 qir_emit_nondef(struct vc4_compile *c, struct qinst *inst) 579 { 580 if (inst->dst.file == QFILE_TEMP) 581 c->defs[inst->dst.index] = NULL; 582 583 qir_emit(c, inst); 584 585 return inst; 586 } 587 588 bool 589 qir_reg_equals(struct qreg a, struct qreg b) 590 { 591 return a.file == b.file && a.index == b.index && a.pack == b.pack; 592 } 593 594 struct qblock * 595 qir_new_block(struct vc4_compile *c) 596 { 597 struct qblock *block = rzalloc(c, struct qblock); 598 599 list_inithead(&block->instructions); 600 list_inithead(&block->qpu_inst_list); 601 602 block->predecessors = _mesa_set_create(block, 603 _mesa_hash_pointer, 604 _mesa_key_pointer_equal); 605 606 block->index = c->next_block_index++; 607 608 return block; 609 } 610 611 void 612 qir_set_emit_block(struct vc4_compile *c, struct qblock *block) 613 { 614 c->cur_block = block; 615 list_addtail(&block->link, &c->blocks); 616 } 617 618 struct qblock * 619 qir_entry_block(struct vc4_compile *c) 620 { 621 return list_first_entry(&c->blocks, struct qblock, link); 622 } 623 624 struct qblock * 625 qir_exit_block(struct vc4_compile *c) 626 { 627 return list_last_entry(&c->blocks, struct qblock, link); 628 } 629 630 void 631 qir_link_blocks(struct qblock *predecessor, struct qblock *successor) 632 { 633 _mesa_set_add(successor->predecessors, predecessor); 634 if (predecessor->successors[0]) { 635 assert(!predecessor->successors[1]); 636 predecessor->successors[1] = successor; 637 } else { 638 predecessor->successors[0] = successor; 639 } 640 } 641 642 struct vc4_compile * 643 qir_compile_init(void) 644 { 645 struct vc4_compile *c = rzalloc(NULL, struct vc4_compile); 646 647 list_inithead(&c->blocks); 648 qir_set_emit_block(c, qir_new_block(c)); 649 c->last_top_block = c->cur_block; 650 651 c->output_position_index = -1; 652 c->output_color_index = -1; 653 c->output_point_size_index = -1; 654 c->output_sample_mask_index = -1; 655 656 c->def_ht = _mesa_hash_table_create(c, _mesa_hash_pointer, 657 _mesa_key_pointer_equal); 658 659 return c; 660 } 661 662 void 663 qir_remove_instruction(struct vc4_compile *c, struct qinst *qinst) 664 { 665 if (qinst->dst.file == QFILE_TEMP) 666 c->defs[qinst->dst.index] = NULL; 667 668 list_del(&qinst->link); 669 free(qinst); 670 } 671 672 struct qreg 673 qir_follow_movs(struct vc4_compile *c, struct qreg reg) 674 { 675 int pack = reg.pack; 676 677 while (reg.file == QFILE_TEMP && 678 c->defs[reg.index] && 679 (c->defs[reg.index]->op == QOP_MOV || 680 c->defs[reg.index]->op == QOP_FMOV || 681 c->defs[reg.index]->op == QOP_MMOV)&& 682 !c->defs[reg.index]->dst.pack && 683 !c->defs[reg.index]->src[0].pack) { 684 reg = c->defs[reg.index]->src[0]; 685 } 686 687 reg.pack = pack; 688 return reg; 689 } 690 691 void 692 qir_compile_destroy(struct vc4_compile *c) 693 { 694 qir_for_each_block(block, c) { 695 while (!list_empty(&block->instructions)) { 696 struct qinst *qinst = 697 list_first_entry(&block->instructions, 698 struct qinst, link); 699 qir_remove_instruction(c, qinst); 700 } 701 } 702 703 ralloc_free(c); 704 } 705 706 const char * 707 qir_get_stage_name(enum qstage stage) 708 { 709 static const char *names[] = { 710 [QSTAGE_FRAG] = "FS", 711 [QSTAGE_VERT] = "VS", 712 [QSTAGE_COORD] = "CS", 713 }; 714 715 return names[stage]; 716 } 717 718 struct qreg 719 qir_uniform(struct vc4_compile *c, 720 enum quniform_contents contents, 721 uint32_t data) 722 { 723 for (int i = 0; i < c->num_uniforms; i++) { 724 if (c->uniform_contents[i] == contents && 725 c->uniform_data[i] == data) { 726 return qir_reg(QFILE_UNIF, i); 727 } 728 } 729 730 uint32_t uniform = c->num_uniforms++; 731 732 if (uniform >= c->uniform_array_size) { 733 c->uniform_array_size = MAX2(MAX2(16, uniform + 1), 734 c->uniform_array_size * 2); 735 736 c->uniform_data = reralloc(c, c->uniform_data, 737 uint32_t, 738 c->uniform_array_size); 739 c->uniform_contents = reralloc(c, c->uniform_contents, 740 enum quniform_contents, 741 c->uniform_array_size); 742 } 743 744 c->uniform_contents[uniform] = contents; 745 c->uniform_data[uniform] = data; 746 747 return qir_reg(QFILE_UNIF, uniform); 748 } 749 750 void 751 qir_SF(struct vc4_compile *c, struct qreg src) 752 { 753 struct qinst *last_inst = NULL; 754 755 if (!list_empty(&c->cur_block->instructions)) 756 last_inst = (struct qinst *)c->cur_block->instructions.prev; 757 758 /* We don't have any way to guess which kind of MOV is implied. */ 759 assert(!src.pack); 760 761 if (src.file != QFILE_TEMP || 762 !c->defs[src.index] || 763 last_inst != c->defs[src.index]) { 764 last_inst = qir_MOV_dest(c, qir_reg(QFILE_NULL, 0), src); 765 last_inst = (struct qinst *)c->cur_block->instructions.prev; 766 } 767 last_inst->sf = true; 768 } 769 770 #define OPTPASS(func) \ 771 do { \ 772 bool stage_progress = func(c); \ 773 if (stage_progress) { \ 774 progress = true; \ 775 if (print_opt_debug) { \ 776 fprintf(stderr, \ 777 "QIR opt pass %2d: %s progress\n", \ 778 pass, #func); \ 779 } \ 780 qir_validate(c); \ 781 } \ 782 } while (0) 783 784 void 785 qir_optimize(struct vc4_compile *c) 786 { 787 bool print_opt_debug = false; 788 int pass = 1; 789 790 while (true) { 791 bool progress = false; 792 793 OPTPASS(qir_opt_algebraic); 794 OPTPASS(qir_opt_constant_folding); 795 OPTPASS(qir_opt_copy_propagation); 796 OPTPASS(qir_opt_peephole_sf); 797 OPTPASS(qir_opt_dead_code); 798 OPTPASS(qir_opt_small_immediates); 799 OPTPASS(qir_opt_vpm); 800 OPTPASS(qir_opt_coalesce_ff_writes); 801 802 if (!progress) 803 break; 804 805 pass++; 806 } 807 } 808