1/* 2 * Copyright © 2011 Intel Corporation 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 "brw_vec4.h" 25extern "C" { 26#include "main/macros.h" 27#include "program/prog_parameter.h" 28} 29 30#define MAX_INSTRUCTION (1 << 30) 31 32namespace brw { 33 34/** 35 * Common helper for constructing swizzles. When only a subset of 36 * channels of a vec4 are used, we don't want to reference the other 37 * channels, as that will tell optimization passes that those other 38 * channels are used. 39 */ 40unsigned 41swizzle_for_size(int size) 42{ 43 static const unsigned size_swizzles[4] = { 44 BRW_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X), 45 BRW_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Y, SWIZZLE_Y), 46 BRW_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_Z), 47 BRW_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W), 48 }; 49 50 assert((size >= 1) && (size <= 4)); 51 return size_swizzles[size - 1]; 52} 53 54void 55src_reg::init() 56{ 57 memset(this, 0, sizeof(*this)); 58 59 this->file = BAD_FILE; 60} 61 62src_reg::src_reg(register_file file, int reg, const glsl_type *type) 63{ 64 init(); 65 66 this->file = file; 67 this->reg = reg; 68 if (type && (type->is_scalar() || type->is_vector() || type->is_matrix())) 69 this->swizzle = swizzle_for_size(type->vector_elements); 70 else 71 this->swizzle = SWIZZLE_XYZW; 72} 73 74/** Generic unset register constructor. */ 75src_reg::src_reg() 76{ 77 init(); 78} 79 80src_reg::src_reg(float f) 81{ 82 init(); 83 84 this->file = IMM; 85 this->type = BRW_REGISTER_TYPE_F; 86 this->imm.f = f; 87} 88 89src_reg::src_reg(uint32_t u) 90{ 91 init(); 92 93 this->file = IMM; 94 this->type = BRW_REGISTER_TYPE_UD; 95 this->imm.u = u; 96} 97 98src_reg::src_reg(int32_t i) 99{ 100 init(); 101 102 this->file = IMM; 103 this->type = BRW_REGISTER_TYPE_D; 104 this->imm.i = i; 105} 106 107src_reg::src_reg(dst_reg reg) 108{ 109 init(); 110 111 this->file = reg.file; 112 this->reg = reg.reg; 113 this->reg_offset = reg.reg_offset; 114 this->type = reg.type; 115 this->reladdr = reg.reladdr; 116 this->fixed_hw_reg = reg.fixed_hw_reg; 117 118 int swizzles[4]; 119 int next_chan = 0; 120 int last = 0; 121 122 for (int i = 0; i < 4; i++) { 123 if (!(reg.writemask & (1 << i))) 124 continue; 125 126 swizzles[next_chan++] = last = i; 127 } 128 129 for (; next_chan < 4; next_chan++) { 130 swizzles[next_chan] = last; 131 } 132 133 this->swizzle = BRW_SWIZZLE4(swizzles[0], swizzles[1], 134 swizzles[2], swizzles[3]); 135} 136 137bool 138vec4_instruction::is_tex() 139{ 140 return (opcode == SHADER_OPCODE_TEX || 141 opcode == SHADER_OPCODE_TXD || 142 opcode == SHADER_OPCODE_TXF || 143 opcode == SHADER_OPCODE_TXL || 144 opcode == SHADER_OPCODE_TXS); 145} 146 147void 148dst_reg::init() 149{ 150 memset(this, 0, sizeof(*this)); 151 this->file = BAD_FILE; 152 this->writemask = WRITEMASK_XYZW; 153} 154 155dst_reg::dst_reg() 156{ 157 init(); 158} 159 160dst_reg::dst_reg(register_file file, int reg) 161{ 162 init(); 163 164 this->file = file; 165 this->reg = reg; 166} 167 168dst_reg::dst_reg(register_file file, int reg, const glsl_type *type, 169 int writemask) 170{ 171 init(); 172 173 this->file = file; 174 this->reg = reg; 175 this->type = brw_type_for_base_type(type); 176 this->writemask = writemask; 177} 178 179dst_reg::dst_reg(struct brw_reg reg) 180{ 181 init(); 182 183 this->file = HW_REG; 184 this->fixed_hw_reg = reg; 185} 186 187dst_reg::dst_reg(src_reg reg) 188{ 189 init(); 190 191 this->file = reg.file; 192 this->reg = reg.reg; 193 this->reg_offset = reg.reg_offset; 194 this->type = reg.type; 195 this->writemask = WRITEMASK_XYZW; 196 this->reladdr = reg.reladdr; 197 this->fixed_hw_reg = reg.fixed_hw_reg; 198} 199 200bool 201vec4_instruction::is_math() 202{ 203 return (opcode == SHADER_OPCODE_RCP || 204 opcode == SHADER_OPCODE_RSQ || 205 opcode == SHADER_OPCODE_SQRT || 206 opcode == SHADER_OPCODE_EXP2 || 207 opcode == SHADER_OPCODE_LOG2 || 208 opcode == SHADER_OPCODE_SIN || 209 opcode == SHADER_OPCODE_COS || 210 opcode == SHADER_OPCODE_INT_QUOTIENT || 211 opcode == SHADER_OPCODE_INT_REMAINDER || 212 opcode == SHADER_OPCODE_POW); 213} 214/** 215 * Returns how many MRFs an opcode will write over. 216 * 217 * Note that this is not the 0 or 1 implied writes in an actual gen 218 * instruction -- the generate_* functions generate additional MOVs 219 * for setup. 220 */ 221int 222vec4_visitor::implied_mrf_writes(vec4_instruction *inst) 223{ 224 if (inst->mlen == 0) 225 return 0; 226 227 switch (inst->opcode) { 228 case SHADER_OPCODE_RCP: 229 case SHADER_OPCODE_RSQ: 230 case SHADER_OPCODE_SQRT: 231 case SHADER_OPCODE_EXP2: 232 case SHADER_OPCODE_LOG2: 233 case SHADER_OPCODE_SIN: 234 case SHADER_OPCODE_COS: 235 return 1; 236 case SHADER_OPCODE_POW: 237 return 2; 238 case VS_OPCODE_URB_WRITE: 239 return 1; 240 case VS_OPCODE_PULL_CONSTANT_LOAD: 241 return 2; 242 case VS_OPCODE_SCRATCH_READ: 243 return 2; 244 case VS_OPCODE_SCRATCH_WRITE: 245 return 3; 246 default: 247 assert(!"not reached"); 248 return inst->mlen; 249 } 250} 251 252bool 253src_reg::equals(src_reg *r) 254{ 255 return (file == r->file && 256 reg == r->reg && 257 reg_offset == r->reg_offset && 258 type == r->type && 259 negate == r->negate && 260 abs == r->abs && 261 swizzle == r->swizzle && 262 !reladdr && !r->reladdr && 263 memcmp(&fixed_hw_reg, &r->fixed_hw_reg, 264 sizeof(fixed_hw_reg)) == 0 && 265 imm.u == r->imm.u); 266} 267 268void 269vec4_visitor::calculate_live_intervals() 270{ 271 int *def = ralloc_array(mem_ctx, int, virtual_grf_count); 272 int *use = ralloc_array(mem_ctx, int, virtual_grf_count); 273 int loop_depth = 0; 274 int loop_start = 0; 275 276 if (this->live_intervals_valid) 277 return; 278 279 for (int i = 0; i < virtual_grf_count; i++) { 280 def[i] = MAX_INSTRUCTION; 281 use[i] = -1; 282 } 283 284 int ip = 0; 285 foreach_list(node, &this->instructions) { 286 vec4_instruction *inst = (vec4_instruction *)node; 287 288 if (inst->opcode == BRW_OPCODE_DO) { 289 if (loop_depth++ == 0) 290 loop_start = ip; 291 } else if (inst->opcode == BRW_OPCODE_WHILE) { 292 loop_depth--; 293 294 if (loop_depth == 0) { 295 /* Patches up the use of vars marked for being live across 296 * the whole loop. 297 */ 298 for (int i = 0; i < virtual_grf_count; i++) { 299 if (use[i] == loop_start) { 300 use[i] = ip; 301 } 302 } 303 } 304 } else { 305 for (unsigned int i = 0; i < 3; i++) { 306 if (inst->src[i].file == GRF) { 307 int reg = inst->src[i].reg; 308 309 if (!loop_depth) { 310 use[reg] = ip; 311 } else { 312 def[reg] = MIN2(loop_start, def[reg]); 313 use[reg] = loop_start; 314 315 /* Nobody else is going to go smash our start to 316 * later in the loop now, because def[reg] now 317 * points before the bb header. 318 */ 319 } 320 } 321 } 322 if (inst->dst.file == GRF) { 323 int reg = inst->dst.reg; 324 325 if (!loop_depth) { 326 def[reg] = MIN2(def[reg], ip); 327 } else { 328 def[reg] = MIN2(def[reg], loop_start); 329 } 330 } 331 } 332 333 ip++; 334 } 335 336 ralloc_free(this->virtual_grf_def); 337 ralloc_free(this->virtual_grf_use); 338 this->virtual_grf_def = def; 339 this->virtual_grf_use = use; 340 341 this->live_intervals_valid = true; 342} 343 344bool 345vec4_visitor::virtual_grf_interferes(int a, int b) 346{ 347 int start = MAX2(this->virtual_grf_def[a], this->virtual_grf_def[b]); 348 int end = MIN2(this->virtual_grf_use[a], this->virtual_grf_use[b]); 349 350 /* We can't handle dead register writes here, without iterating 351 * over the whole instruction stream to find every single dead 352 * write to that register to compare to the live interval of the 353 * other register. Just assert that dead_code_eliminate() has been 354 * called. 355 */ 356 assert((this->virtual_grf_use[a] != -1 || 357 this->virtual_grf_def[a] == MAX_INSTRUCTION) && 358 (this->virtual_grf_use[b] != -1 || 359 this->virtual_grf_def[b] == MAX_INSTRUCTION)); 360 361 return start < end; 362} 363 364/** 365 * Must be called after calculate_live_intervales() to remove unused 366 * writes to registers -- register allocation will fail otherwise 367 * because something deffed but not used won't be considered to 368 * interfere with other regs. 369 */ 370bool 371vec4_visitor::dead_code_eliminate() 372{ 373 bool progress = false; 374 int pc = 0; 375 376 calculate_live_intervals(); 377 378 foreach_list_safe(node, &this->instructions) { 379 vec4_instruction *inst = (vec4_instruction *)node; 380 381 if (inst->dst.file == GRF && this->virtual_grf_use[inst->dst.reg] <= pc) { 382 inst->remove(); 383 progress = true; 384 } 385 386 pc++; 387 } 388 389 if (progress) 390 live_intervals_valid = false; 391 392 return progress; 393} 394 395void 396vec4_visitor::split_uniform_registers() 397{ 398 /* Prior to this, uniforms have been in an array sized according to 399 * the number of vector uniforms present, sparsely filled (so an 400 * aggregate results in reg indices being skipped over). Now we're 401 * going to cut those aggregates up so each .reg index is one 402 * vector. The goal is to make elimination of unused uniform 403 * components easier later. 404 */ 405 foreach_list(node, &this->instructions) { 406 vec4_instruction *inst = (vec4_instruction *)node; 407 408 for (int i = 0 ; i < 3; i++) { 409 if (inst->src[i].file != UNIFORM) 410 continue; 411 412 assert(!inst->src[i].reladdr); 413 414 inst->src[i].reg += inst->src[i].reg_offset; 415 inst->src[i].reg_offset = 0; 416 } 417 } 418 419 /* Update that everything is now vector-sized. */ 420 for (int i = 0; i < this->uniforms; i++) { 421 this->uniform_size[i] = 1; 422 } 423} 424 425void 426vec4_visitor::pack_uniform_registers() 427{ 428 bool uniform_used[this->uniforms]; 429 int new_loc[this->uniforms]; 430 int new_chan[this->uniforms]; 431 432 memset(uniform_used, 0, sizeof(uniform_used)); 433 memset(new_loc, 0, sizeof(new_loc)); 434 memset(new_chan, 0, sizeof(new_chan)); 435 436 /* Find which uniform vectors are actually used by the program. We 437 * expect unused vector elements when we've moved array access out 438 * to pull constants, and from some GLSL code generators like wine. 439 */ 440 foreach_list(node, &this->instructions) { 441 vec4_instruction *inst = (vec4_instruction *)node; 442 443 for (int i = 0 ; i < 3; i++) { 444 if (inst->src[i].file != UNIFORM) 445 continue; 446 447 uniform_used[inst->src[i].reg] = true; 448 } 449 } 450 451 int new_uniform_count = 0; 452 453 /* Now, figure out a packing of the live uniform vectors into our 454 * push constants. 455 */ 456 for (int src = 0; src < uniforms; src++) { 457 int size = this->uniform_vector_size[src]; 458 459 if (!uniform_used[src]) { 460 this->uniform_vector_size[src] = 0; 461 continue; 462 } 463 464 int dst; 465 /* Find the lowest place we can slot this uniform in. */ 466 for (dst = 0; dst < src; dst++) { 467 if (this->uniform_vector_size[dst] + size <= 4) 468 break; 469 } 470 471 if (src == dst) { 472 new_loc[src] = dst; 473 new_chan[src] = 0; 474 } else { 475 new_loc[src] = dst; 476 new_chan[src] = this->uniform_vector_size[dst]; 477 478 /* Move the references to the data */ 479 for (int j = 0; j < size; j++) { 480 c->prog_data.param[dst * 4 + new_chan[src] + j] = 481 c->prog_data.param[src * 4 + j]; 482 } 483 484 this->uniform_vector_size[dst] += size; 485 this->uniform_vector_size[src] = 0; 486 } 487 488 new_uniform_count = MAX2(new_uniform_count, dst + 1); 489 } 490 491 this->uniforms = new_uniform_count; 492 493 /* Now, update the instructions for our repacked uniforms. */ 494 foreach_list(node, &this->instructions) { 495 vec4_instruction *inst = (vec4_instruction *)node; 496 497 for (int i = 0 ; i < 3; i++) { 498 int src = inst->src[i].reg; 499 500 if (inst->src[i].file != UNIFORM) 501 continue; 502 503 inst->src[i].reg = new_loc[src]; 504 505 int sx = BRW_GET_SWZ(inst->src[i].swizzle, 0) + new_chan[src]; 506 int sy = BRW_GET_SWZ(inst->src[i].swizzle, 1) + new_chan[src]; 507 int sz = BRW_GET_SWZ(inst->src[i].swizzle, 2) + new_chan[src]; 508 int sw = BRW_GET_SWZ(inst->src[i].swizzle, 3) + new_chan[src]; 509 inst->src[i].swizzle = BRW_SWIZZLE4(sx, sy, sz, sw); 510 } 511 } 512} 513 514bool 515src_reg::is_zero() const 516{ 517 if (file != IMM) 518 return false; 519 520 if (type == BRW_REGISTER_TYPE_F) { 521 return imm.f == 0.0; 522 } else { 523 return imm.i == 0; 524 } 525} 526 527bool 528src_reg::is_one() const 529{ 530 if (file != IMM) 531 return false; 532 533 if (type == BRW_REGISTER_TYPE_F) { 534 return imm.f == 1.0; 535 } else { 536 return imm.i == 1; 537 } 538} 539 540/** 541 * Does algebraic optimizations (0 * a = 0, 1 * a = a, a + 0 = a). 542 * 543 * While GLSL IR also performs this optimization, we end up with it in 544 * our instruction stream for a couple of reasons. One is that we 545 * sometimes generate silly instructions, for example in array access 546 * where we'll generate "ADD offset, index, base" even if base is 0. 547 * The other is that GLSL IR's constant propagation doesn't track the 548 * components of aggregates, so some VS patterns (initialize matrix to 549 * 0, accumulate in vertex blending factors) end up breaking down to 550 * instructions involving 0. 551 */ 552bool 553vec4_visitor::opt_algebraic() 554{ 555 bool progress = false; 556 557 foreach_list(node, &this->instructions) { 558 vec4_instruction *inst = (vec4_instruction *)node; 559 560 switch (inst->opcode) { 561 case BRW_OPCODE_ADD: 562 if (inst->src[1].is_zero()) { 563 inst->opcode = BRW_OPCODE_MOV; 564 inst->src[1] = src_reg(); 565 progress = true; 566 } 567 break; 568 569 case BRW_OPCODE_MUL: 570 if (inst->src[1].is_zero()) { 571 inst->opcode = BRW_OPCODE_MOV; 572 switch (inst->src[0].type) { 573 case BRW_REGISTER_TYPE_F: 574 inst->src[0] = src_reg(0.0f); 575 break; 576 case BRW_REGISTER_TYPE_D: 577 inst->src[0] = src_reg(0); 578 break; 579 case BRW_REGISTER_TYPE_UD: 580 inst->src[0] = src_reg(0u); 581 break; 582 default: 583 assert(!"not reached"); 584 inst->src[0] = src_reg(0.0f); 585 break; 586 } 587 inst->src[1] = src_reg(); 588 progress = true; 589 } else if (inst->src[1].is_one()) { 590 inst->opcode = BRW_OPCODE_MOV; 591 inst->src[1] = src_reg(); 592 progress = true; 593 } 594 break; 595 default: 596 break; 597 } 598 } 599 600 if (progress) 601 this->live_intervals_valid = false; 602 603 return progress; 604} 605 606/** 607 * Only a limited number of hardware registers may be used for push 608 * constants, so this turns access to the overflowed constants into 609 * pull constants. 610 */ 611void 612vec4_visitor::move_push_constants_to_pull_constants() 613{ 614 int pull_constant_loc[this->uniforms]; 615 616 /* Only allow 32 registers (256 uniform components) as push constants, 617 * which is the limit on gen6. 618 */ 619 int max_uniform_components = 32 * 8; 620 if (this->uniforms * 4 <= max_uniform_components) 621 return; 622 623 /* Make some sort of choice as to which uniforms get sent to pull 624 * constants. We could potentially do something clever here like 625 * look for the most infrequently used uniform vec4s, but leave 626 * that for later. 627 */ 628 for (int i = 0; i < this->uniforms * 4; i += 4) { 629 pull_constant_loc[i / 4] = -1; 630 631 if (i >= max_uniform_components) { 632 const float **values = &prog_data->param[i]; 633 634 /* Try to find an existing copy of this uniform in the pull 635 * constants if it was part of an array access already. 636 */ 637 for (unsigned int j = 0; j < prog_data->nr_pull_params; j += 4) { 638 int matches; 639 640 for (matches = 0; matches < 4; matches++) { 641 if (prog_data->pull_param[j + matches] != values[matches]) 642 break; 643 } 644 645 if (matches == 4) { 646 pull_constant_loc[i / 4] = j / 4; 647 break; 648 } 649 } 650 651 if (pull_constant_loc[i / 4] == -1) { 652 assert(prog_data->nr_pull_params % 4 == 0); 653 pull_constant_loc[i / 4] = prog_data->nr_pull_params / 4; 654 655 for (int j = 0; j < 4; j++) { 656 prog_data->pull_param[prog_data->nr_pull_params++] = values[j]; 657 } 658 } 659 } 660 } 661 662 /* Now actually rewrite usage of the things we've moved to pull 663 * constants. 664 */ 665 foreach_list_safe(node, &this->instructions) { 666 vec4_instruction *inst = (vec4_instruction *)node; 667 668 for (int i = 0 ; i < 3; i++) { 669 if (inst->src[i].file != UNIFORM || 670 pull_constant_loc[inst->src[i].reg] == -1) 671 continue; 672 673 int uniform = inst->src[i].reg; 674 675 dst_reg temp = dst_reg(this, glsl_type::vec4_type); 676 677 emit_pull_constant_load(inst, temp, inst->src[i], 678 pull_constant_loc[uniform]); 679 680 inst->src[i].file = temp.file; 681 inst->src[i].reg = temp.reg; 682 inst->src[i].reg_offset = temp.reg_offset; 683 inst->src[i].reladdr = NULL; 684 } 685 } 686 687 /* Repack push constants to remove the now-unused ones. */ 688 pack_uniform_registers(); 689} 690 691/* 692 * Tries to reduce extra MOV instructions by taking GRFs that get just 693 * written and then MOVed into an MRF and making the original write of 694 * the GRF write directly to the MRF instead. 695 */ 696bool 697vec4_visitor::opt_compute_to_mrf() 698{ 699 bool progress = false; 700 int next_ip = 0; 701 702 calculate_live_intervals(); 703 704 foreach_list_safe(node, &this->instructions) { 705 vec4_instruction *inst = (vec4_instruction *)node; 706 707 int ip = next_ip; 708 next_ip++; 709 710 if (inst->opcode != BRW_OPCODE_MOV || 711 inst->predicate || 712 inst->dst.file != MRF || inst->src[0].file != GRF || 713 inst->dst.type != inst->src[0].type || 714 inst->src[0].abs || inst->src[0].negate || inst->src[0].reladdr) 715 continue; 716 717 int mrf = inst->dst.reg; 718 719 /* Can't compute-to-MRF this GRF if someone else was going to 720 * read it later. 721 */ 722 if (this->virtual_grf_use[inst->src[0].reg] > ip) 723 continue; 724 725 /* We need to check interference with the MRF between this 726 * instruction and the earliest instruction involved in writing 727 * the GRF we're eliminating. To do that, keep track of which 728 * of our source channels we've seen initialized. 729 */ 730 bool chans_needed[4] = {false, false, false, false}; 731 int chans_remaining = 0; 732 for (int i = 0; i < 4; i++) { 733 int chan = BRW_GET_SWZ(inst->src[0].swizzle, i); 734 735 if (!(inst->dst.writemask & (1 << i))) 736 continue; 737 738 /* We don't handle compute-to-MRF across a swizzle. We would 739 * need to be able to rewrite instructions above to output 740 * results to different channels. 741 */ 742 if (chan != i) 743 chans_remaining = 5; 744 745 if (!chans_needed[chan]) { 746 chans_needed[chan] = true; 747 chans_remaining++; 748 } 749 } 750 if (chans_remaining > 4) 751 continue; 752 753 /* Now walk up the instruction stream trying to see if we can 754 * rewrite everything writing to the GRF into the MRF instead. 755 */ 756 vec4_instruction *scan_inst; 757 for (scan_inst = (vec4_instruction *)inst->prev; 758 scan_inst->prev != NULL; 759 scan_inst = (vec4_instruction *)scan_inst->prev) { 760 if (scan_inst->dst.file == GRF && 761 scan_inst->dst.reg == inst->src[0].reg && 762 scan_inst->dst.reg_offset == inst->src[0].reg_offset) { 763 /* Found something writing to the reg we want to turn into 764 * a compute-to-MRF. 765 */ 766 767 /* SEND instructions can't have MRF as a destination. */ 768 if (scan_inst->mlen) 769 break; 770 771 if (intel->gen >= 6) { 772 /* gen6 math instructions must have the destination be 773 * GRF, so no compute-to-MRF for them. 774 */ 775 if (scan_inst->is_math()) { 776 break; 777 } 778 } 779 780 /* Mark which channels we found unconditional writes for. */ 781 if (!scan_inst->predicate) { 782 for (int i = 0; i < 4; i++) { 783 if (scan_inst->dst.writemask & (1 << i) && 784 chans_needed[i]) { 785 chans_needed[i] = false; 786 chans_remaining--; 787 } 788 } 789 } 790 791 if (chans_remaining == 0) 792 break; 793 } 794 795 /* We don't handle flow control here. Most computation of 796 * values that end up in MRFs are shortly before the MRF 797 * write anyway. 798 */ 799 if (scan_inst->opcode == BRW_OPCODE_DO || 800 scan_inst->opcode == BRW_OPCODE_WHILE || 801 scan_inst->opcode == BRW_OPCODE_ELSE || 802 scan_inst->opcode == BRW_OPCODE_ENDIF) { 803 break; 804 } 805 806 /* You can't read from an MRF, so if someone else reads our 807 * MRF's source GRF that we wanted to rewrite, that stops us. 808 */ 809 bool interfered = false; 810 for (int i = 0; i < 3; i++) { 811 if (scan_inst->src[i].file == GRF && 812 scan_inst->src[i].reg == inst->src[0].reg && 813 scan_inst->src[i].reg_offset == inst->src[0].reg_offset) { 814 interfered = true; 815 } 816 } 817 if (interfered) 818 break; 819 820 /* If somebody else writes our MRF here, we can't 821 * compute-to-MRF before that. 822 */ 823 if (scan_inst->dst.file == MRF && mrf == scan_inst->dst.reg) 824 break; 825 826 if (scan_inst->mlen > 0) { 827 /* Found a SEND instruction, which means that there are 828 * live values in MRFs from base_mrf to base_mrf + 829 * scan_inst->mlen - 1. Don't go pushing our MRF write up 830 * above it. 831 */ 832 if (mrf >= scan_inst->base_mrf && 833 mrf < scan_inst->base_mrf + scan_inst->mlen) { 834 break; 835 } 836 } 837 } 838 839 if (chans_remaining == 0) { 840 /* If we've made it here, we have an inst we want to 841 * compute-to-MRF, and a scan_inst pointing to the earliest 842 * instruction involved in computing the value. Now go 843 * rewrite the instruction stream between the two. 844 */ 845 846 while (scan_inst != inst) { 847 if (scan_inst->dst.file == GRF && 848 scan_inst->dst.reg == inst->src[0].reg && 849 scan_inst->dst.reg_offset == inst->src[0].reg_offset) { 850 scan_inst->dst.file = MRF; 851 scan_inst->dst.reg = mrf; 852 scan_inst->dst.reg_offset = 0; 853 scan_inst->dst.writemask &= inst->dst.writemask; 854 scan_inst->saturate |= inst->saturate; 855 } 856 scan_inst = (vec4_instruction *)scan_inst->next; 857 } 858 inst->remove(); 859 progress = true; 860 } 861 } 862 863 if (progress) 864 live_intervals_valid = false; 865 866 return progress; 867} 868 869} /* namespace brw */ 870