1/* 2 * Copyright (C) 2009 Nicolai Haehnle. 3 * Copyright 2010 Tom Stellard <tstellar@gmail.com> 4 * 5 * All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining 8 * a copy of this software and associated documentation files (the 9 * "Software"), to deal in the Software without restriction, including 10 * without limitation the rights to use, copy, modify, merge, publish, 11 * distribute, sublicense, and/or sell copies of the Software, and to 12 * permit persons to whom the Software is furnished to do so, subject to 13 * the following conditions: 14 * 15 * The above copyright notice and this permission notice (including the 16 * next paragraph) shall be included in all copies or substantial 17 * portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE 23 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 24 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 * 27 */ 28 29#include "radeon_dataflow.h" 30 31#include "radeon_compiler.h" 32#include "radeon_compiler_util.h" 33#include "radeon_program.h" 34 35struct read_write_mask_data { 36 void * UserData; 37 rc_read_write_mask_fn Cb; 38}; 39 40static void reads_normal_callback( 41 void * userdata, 42 struct rc_instruction * fullinst, 43 struct rc_src_register * src) 44{ 45 struct read_write_mask_data * cb_data = userdata; 46 unsigned int refmask = 0; 47 unsigned int chan; 48 for(chan = 0; chan < 4; chan++) { 49 refmask |= 1 << GET_SWZ(src->Swizzle, chan); 50 } 51 refmask &= RC_MASK_XYZW; 52 53 if (refmask) { 54 cb_data->Cb(cb_data->UserData, fullinst, src->File, 55 src->Index, refmask); 56 } 57 58 if (refmask && src->RelAddr) { 59 cb_data->Cb(cb_data->UserData, fullinst, RC_FILE_ADDRESS, 0, 60 RC_MASK_X); 61 } 62} 63 64static void pair_get_src_refmasks(unsigned int * refmasks, 65 struct rc_pair_instruction * inst, 66 unsigned int swz, unsigned int src) 67{ 68 if (swz >= 4) 69 return; 70 71 if (swz == RC_SWIZZLE_X || swz == RC_SWIZZLE_Y || swz == RC_SWIZZLE_Z) { 72 if(src == RC_PAIR_PRESUB_SRC) { 73 unsigned int i; 74 int srcp_regs = 75 rc_presubtract_src_reg_count( 76 inst->RGB.Src[src].Index); 77 for(i = 0; i < srcp_regs; i++) { 78 refmasks[i] |= 1 << swz; 79 } 80 } 81 else { 82 refmasks[src] |= 1 << swz; 83 } 84 } 85 86 if (swz == RC_SWIZZLE_W) { 87 if (src == RC_PAIR_PRESUB_SRC) { 88 unsigned int i; 89 int srcp_regs = rc_presubtract_src_reg_count( 90 inst->Alpha.Src[src].Index); 91 for(i = 0; i < srcp_regs; i++) { 92 refmasks[i] |= 1 << swz; 93 } 94 } 95 else { 96 refmasks[src] |= 1 << swz; 97 } 98 } 99} 100 101static void reads_pair(struct rc_instruction * fullinst, rc_read_write_mask_fn cb, void * userdata) 102{ 103 struct rc_pair_instruction * inst = &fullinst->U.P; 104 unsigned int refmasks[3] = { 0, 0, 0 }; 105 106 unsigned int arg; 107 108 for(arg = 0; arg < 3; ++arg) { 109 unsigned int chan; 110 for(chan = 0; chan < 3; ++chan) { 111 unsigned int swz_rgb = 112 GET_SWZ(inst->RGB.Arg[arg].Swizzle, chan); 113 unsigned int swz_alpha = 114 GET_SWZ(inst->Alpha.Arg[arg].Swizzle, chan); 115 pair_get_src_refmasks(refmasks, inst, swz_rgb, 116 inst->RGB.Arg[arg].Source); 117 pair_get_src_refmasks(refmasks, inst, swz_alpha, 118 inst->Alpha.Arg[arg].Source); 119 } 120 } 121 122 for(unsigned int src = 0; src < 3; ++src) { 123 if (inst->RGB.Src[src].Used && (refmasks[src] & RC_MASK_XYZ)) 124 cb(userdata, fullinst, inst->RGB.Src[src].File, inst->RGB.Src[src].Index, 125 refmasks[src] & RC_MASK_XYZ); 126 127 if (inst->Alpha.Src[src].Used && (refmasks[src] & RC_MASK_W)) 128 cb(userdata, fullinst, inst->Alpha.Src[src].File, inst->Alpha.Src[src].Index, RC_MASK_W); 129 } 130} 131 132static void pair_sub_for_all_args( 133 struct rc_instruction * fullinst, 134 struct rc_pair_sub_instruction * sub, 135 rc_pair_read_arg_fn cb, 136 void * userdata) 137{ 138 int i; 139 const struct rc_opcode_info * info = rc_get_opcode_info(sub->Opcode); 140 141 for(i = 0; i < info->NumSrcRegs; i++) { 142 unsigned int src_type; 143 144 src_type = rc_source_type_swz(sub->Arg[i].Swizzle); 145 146 if (src_type == RC_SOURCE_NONE) 147 continue; 148 149 if (sub->Arg[i].Source == RC_PAIR_PRESUB_SRC) { 150 unsigned int presub_type; 151 unsigned int presub_src_count; 152 struct rc_pair_instruction_source * src_array; 153 unsigned int j; 154 155 if (src_type & RC_SOURCE_RGB) { 156 presub_type = fullinst-> 157 U.P.RGB.Src[RC_PAIR_PRESUB_SRC].Index; 158 src_array = fullinst->U.P.RGB.Src; 159 } else { 160 presub_type = fullinst-> 161 U.P.Alpha.Src[RC_PAIR_PRESUB_SRC].Index; 162 src_array = fullinst->U.P.Alpha.Src; 163 } 164 presub_src_count 165 = rc_presubtract_src_reg_count(presub_type); 166 for(j = 0; j < presub_src_count; j++) { 167 cb(userdata, fullinst, &sub->Arg[i], 168 &src_array[j]); 169 } 170 } else { 171 struct rc_pair_instruction_source * src = 172 rc_pair_get_src(&fullinst->U.P, &sub->Arg[i]); 173 if (src) { 174 cb(userdata, fullinst, &sub->Arg[i], src); 175 } 176 } 177 } 178} 179 180/* This function calls the callback function (cb) for each source used by 181 * the instruction. 182 * */ 183void rc_for_all_reads_src( 184 struct rc_instruction * inst, 185 rc_read_src_fn cb, 186 void * userdata) 187{ 188 const struct rc_opcode_info * opcode = 189 rc_get_opcode_info(inst->U.I.Opcode); 190 191 /* This function only works with normal instructions. */ 192 if (inst->Type != RC_INSTRUCTION_NORMAL) { 193 assert(0); 194 return; 195 } 196 197 for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src) { 198 199 if (inst->U.I.SrcReg[src].File == RC_FILE_NONE) 200 continue; 201 202 if (inst->U.I.SrcReg[src].File == RC_FILE_PRESUB) { 203 unsigned int i; 204 unsigned int srcp_regs = rc_presubtract_src_reg_count( 205 inst->U.I.PreSub.Opcode); 206 for( i = 0; i < srcp_regs; i++) { 207 cb(userdata, inst, &inst->U.I.PreSub.SrcReg[i]); 208 } 209 } else { 210 cb(userdata, inst, &inst->U.I.SrcReg[src]); 211 } 212 } 213} 214 215/** 216 * This function calls the callback function (cb) for each arg of the RGB and 217 * alpha components. 218 */ 219void rc_pair_for_all_reads_arg( 220 struct rc_instruction * inst, 221 rc_pair_read_arg_fn cb, 222 void * userdata) 223{ 224 /* This function only works with pair instructions. */ 225 if (inst->Type != RC_INSTRUCTION_PAIR) { 226 assert(0); 227 return; 228 } 229 230 pair_sub_for_all_args(inst, &inst->U.P.RGB, cb, userdata); 231 pair_sub_for_all_args(inst, &inst->U.P.Alpha, cb, userdata); 232} 233 234/** 235 * Calls a callback function for all register reads. 236 * 237 * This is conservative, i.e. if the same register is referenced multiple times, 238 * the callback may also be called multiple times. 239 * Also, the writemask of the instruction is not taken into account. 240 */ 241void rc_for_all_reads_mask(struct rc_instruction * inst, rc_read_write_mask_fn cb, void * userdata) 242{ 243 if (inst->Type == RC_INSTRUCTION_NORMAL) { 244 struct read_write_mask_data cb_data; 245 cb_data.UserData = userdata; 246 cb_data.Cb = cb; 247 248 rc_for_all_reads_src(inst, reads_normal_callback, &cb_data); 249 } else { 250 reads_pair(inst, cb, userdata); 251 } 252} 253 254 255 256static void writes_normal(struct rc_instruction * fullinst, rc_read_write_mask_fn cb, void * userdata) 257{ 258 struct rc_sub_instruction * inst = &fullinst->U.I; 259 const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->Opcode); 260 261 if (opcode->HasDstReg && inst->DstReg.WriteMask) 262 cb(userdata, fullinst, inst->DstReg.File, inst->DstReg.Index, inst->DstReg.WriteMask); 263 264 if (inst->WriteALUResult) 265 cb(userdata, fullinst, RC_FILE_SPECIAL, RC_SPECIAL_ALU_RESULT, RC_MASK_X); 266} 267 268static void writes_pair(struct rc_instruction * fullinst, rc_read_write_mask_fn cb, void * userdata) 269{ 270 struct rc_pair_instruction * inst = &fullinst->U.P; 271 272 if (inst->RGB.WriteMask) 273 cb(userdata, fullinst, RC_FILE_TEMPORARY, inst->RGB.DestIndex, inst->RGB.WriteMask); 274 275 if (inst->Alpha.WriteMask) 276 cb(userdata, fullinst, RC_FILE_TEMPORARY, inst->Alpha.DestIndex, RC_MASK_W); 277 278 if (inst->WriteALUResult) 279 cb(userdata, fullinst, RC_FILE_SPECIAL, RC_SPECIAL_ALU_RESULT, RC_MASK_X); 280} 281 282/** 283 * Calls a callback function for all register writes in the instruction, 284 * reporting writemasks to the callback function. 285 * 286 * \warning Does not report output registers for paired instructions! 287 */ 288void rc_for_all_writes_mask(struct rc_instruction * inst, rc_read_write_mask_fn cb, void * userdata) 289{ 290 if (inst->Type == RC_INSTRUCTION_NORMAL) { 291 writes_normal(inst, cb, userdata); 292 } else { 293 writes_pair(inst, cb, userdata); 294 } 295} 296 297 298struct mask_to_chan_data { 299 void * UserData; 300 rc_read_write_chan_fn Fn; 301}; 302 303static void mask_to_chan_cb(void * data, struct rc_instruction * inst, 304 rc_register_file file, unsigned int index, unsigned int mask) 305{ 306 struct mask_to_chan_data * d = data; 307 for(unsigned int chan = 0; chan < 4; ++chan) { 308 if (GET_BIT(mask, chan)) 309 d->Fn(d->UserData, inst, file, index, chan); 310 } 311} 312 313/** 314 * Calls a callback function for all sourced register channels. 315 * 316 * This is conservative, i.e. channels may be called multiple times, 317 * and the writemask of the instruction is not taken into account. 318 */ 319void rc_for_all_reads_chan(struct rc_instruction * inst, rc_read_write_chan_fn cb, void * userdata) 320{ 321 struct mask_to_chan_data d; 322 d.UserData = userdata; 323 d.Fn = cb; 324 rc_for_all_reads_mask(inst, &mask_to_chan_cb, &d); 325} 326 327/** 328 * Calls a callback function for all written register channels. 329 * 330 * \warning Does not report output registers for paired instructions! 331 */ 332void rc_for_all_writes_chan(struct rc_instruction * inst, rc_read_write_chan_fn cb, void * userdata) 333{ 334 struct mask_to_chan_data d; 335 d.UserData = userdata; 336 d.Fn = cb; 337 rc_for_all_writes_mask(inst, &mask_to_chan_cb, &d); 338} 339 340static void remap_normal_instruction(struct rc_instruction * fullinst, 341 rc_remap_register_fn cb, void * userdata) 342{ 343 struct rc_sub_instruction * inst = &fullinst->U.I; 344 const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->Opcode); 345 unsigned int remapped_presub = 0; 346 347 if (opcode->HasDstReg) { 348 rc_register_file file = inst->DstReg.File; 349 unsigned int index = inst->DstReg.Index; 350 351 cb(userdata, fullinst, &file, &index); 352 353 inst->DstReg.File = file; 354 inst->DstReg.Index = index; 355 } 356 357 for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src) { 358 rc_register_file file = inst->SrcReg[src].File; 359 unsigned int index = inst->SrcReg[src].Index; 360 361 if (file == RC_FILE_PRESUB) { 362 unsigned int i; 363 unsigned int srcp_srcs = rc_presubtract_src_reg_count( 364 inst->PreSub.Opcode); 365 /* Make sure we only remap presubtract sources once in 366 * case more than one source register reads the 367 * presubtract result. */ 368 if (remapped_presub) 369 continue; 370 371 for(i = 0; i < srcp_srcs; i++) { 372 file = inst->PreSub.SrcReg[i].File; 373 index = inst->PreSub.SrcReg[i].Index; 374 cb(userdata, fullinst, &file, &index); 375 inst->PreSub.SrcReg[i].File = file; 376 inst->PreSub.SrcReg[i].Index = index; 377 } 378 remapped_presub = 1; 379 } 380 else { 381 cb(userdata, fullinst, &file, &index); 382 383 inst->SrcReg[src].File = file; 384 inst->SrcReg[src].Index = index; 385 } 386 } 387} 388 389static void remap_pair_instruction(struct rc_instruction * fullinst, 390 rc_remap_register_fn cb, void * userdata) 391{ 392 struct rc_pair_instruction * inst = &fullinst->U.P; 393 394 if (inst->RGB.WriteMask) { 395 rc_register_file file = RC_FILE_TEMPORARY; 396 unsigned int index = inst->RGB.DestIndex; 397 398 cb(userdata, fullinst, &file, &index); 399 400 inst->RGB.DestIndex = index; 401 } 402 403 if (inst->Alpha.WriteMask) { 404 rc_register_file file = RC_FILE_TEMPORARY; 405 unsigned int index = inst->Alpha.DestIndex; 406 407 cb(userdata, fullinst, &file, &index); 408 409 inst->Alpha.DestIndex = index; 410 } 411 412 for(unsigned int src = 0; src < 3; ++src) { 413 if (inst->RGB.Src[src].Used) { 414 rc_register_file file = inst->RGB.Src[src].File; 415 unsigned int index = inst->RGB.Src[src].Index; 416 417 cb(userdata, fullinst, &file, &index); 418 419 inst->RGB.Src[src].File = file; 420 inst->RGB.Src[src].Index = index; 421 } 422 423 if (inst->Alpha.Src[src].Used) { 424 rc_register_file file = inst->Alpha.Src[src].File; 425 unsigned int index = inst->Alpha.Src[src].Index; 426 427 cb(userdata, fullinst, &file, &index); 428 429 inst->Alpha.Src[src].File = file; 430 inst->Alpha.Src[src].Index = index; 431 } 432 } 433} 434 435 436/** 437 * Remap all register accesses according to the given function. 438 * That is, call the function \p cb for each referenced register (both read and written) 439 * and update the given instruction \p inst accordingly 440 * if it modifies its \ref pfile and \ref pindex contents. 441 */ 442void rc_remap_registers(struct rc_instruction * inst, rc_remap_register_fn cb, void * userdata) 443{ 444 if (inst->Type == RC_INSTRUCTION_NORMAL) 445 remap_normal_instruction(inst, cb, userdata); 446 else 447 remap_pair_instruction(inst, cb, userdata); 448} 449 450struct branch_write_mask { 451 unsigned int IfWriteMask:4; 452 unsigned int ElseWriteMask:4; 453 unsigned int HasElse:1; 454}; 455 456union get_readers_read_cb { 457 rc_read_src_fn I; 458 rc_pair_read_arg_fn P; 459}; 460 461struct get_readers_callback_data { 462 struct radeon_compiler * C; 463 struct rc_reader_data * ReaderData; 464 rc_read_src_fn ReadNormalCB; 465 rc_pair_read_arg_fn ReadPairCB; 466 rc_read_write_mask_fn WriteCB; 467 rc_register_file DstFile; 468 unsigned int DstIndex; 469 unsigned int DstMask; 470 unsigned int AliveWriteMask; 471 /* For convenience, this is indexed starting at 1 */ 472 struct branch_write_mask BranchMasks[R500_PFS_MAX_BRANCH_DEPTH_FULL + 1]; 473}; 474 475static struct rc_reader * add_reader( 476 struct memory_pool * pool, 477 struct rc_reader_data * data, 478 struct rc_instruction * inst, 479 unsigned int mask) 480{ 481 struct rc_reader * new; 482 memory_pool_array_reserve(pool, struct rc_reader, data->Readers, 483 data->ReaderCount, data->ReadersReserved, 1); 484 new = &data->Readers[data->ReaderCount++]; 485 new->Inst = inst; 486 new->WriteMask = mask; 487 return new; 488} 489 490static void add_reader_normal( 491 struct memory_pool * pool, 492 struct rc_reader_data * data, 493 struct rc_instruction * inst, 494 unsigned int mask, 495 struct rc_src_register * src) 496{ 497 struct rc_reader * new = add_reader(pool, data, inst, mask); 498 new->U.I.Src = src; 499} 500 501 502static void add_reader_pair( 503 struct memory_pool * pool, 504 struct rc_reader_data * data, 505 struct rc_instruction * inst, 506 unsigned int mask, 507 struct rc_pair_instruction_arg * arg, 508 struct rc_pair_instruction_source * src) 509{ 510 struct rc_reader * new = add_reader(pool, data, inst, mask); 511 new->U.P.Src = src; 512 new->U.P.Arg = arg; 513} 514 515static unsigned int get_readers_read_callback( 516 struct get_readers_callback_data * cb_data, 517 unsigned int has_rel_addr, 518 rc_register_file file, 519 unsigned int index, 520 unsigned int swizzle) 521{ 522 unsigned int shared_mask, read_mask; 523 524 if (has_rel_addr) { 525 cb_data->ReaderData->Abort = 1; 526 return RC_MASK_NONE; 527 } 528 529 shared_mask = rc_src_reads_dst_mask(file, index, swizzle, 530 cb_data->DstFile, cb_data->DstIndex, cb_data->AliveWriteMask); 531 532 if (shared_mask == RC_MASK_NONE) 533 return shared_mask; 534 535 /* If we make it this far, it means that this source reads from the 536 * same register written to by d->ReaderData->Writer. */ 537 538 read_mask = rc_swizzle_to_writemask(swizzle); 539 if (cb_data->ReaderData->AbortOnRead & read_mask) { 540 cb_data->ReaderData->Abort = 1; 541 return shared_mask; 542 } 543 544 if (cb_data->ReaderData->LoopDepth > 0) { 545 cb_data->ReaderData->AbortOnWrite |= 546 (read_mask & cb_data->AliveWriteMask); 547 } 548 549 /* XXX The behavior in this case should be configurable. */ 550 if ((read_mask & cb_data->AliveWriteMask) != read_mask) { 551 cb_data->ReaderData->Abort = 1; 552 return shared_mask; 553 } 554 555 return shared_mask; 556} 557 558static void get_readers_pair_read_callback( 559 void * userdata, 560 struct rc_instruction * inst, 561 struct rc_pair_instruction_arg * arg, 562 struct rc_pair_instruction_source * src) 563{ 564 unsigned int shared_mask; 565 struct get_readers_callback_data * d = userdata; 566 567 shared_mask = get_readers_read_callback(d, 568 0 /*Pair Instructions don't use RelAddr*/, 569 src->File, src->Index, arg->Swizzle); 570 571 if (shared_mask == RC_MASK_NONE) 572 return; 573 574 if (d->ReadPairCB) 575 d->ReadPairCB(d->ReaderData, inst, arg, src); 576 577 if (d->ReaderData->ExitOnAbort && d->ReaderData->Abort) 578 return; 579 580 add_reader_pair(&d->C->Pool, d->ReaderData, inst, shared_mask, arg, src); 581} 582 583/** 584 * This function is used by rc_get_readers_normal() to determine whether inst 585 * is a reader of userdata->ReaderData->Writer 586 */ 587static void get_readers_normal_read_callback( 588 void * userdata, 589 struct rc_instruction * inst, 590 struct rc_src_register * src) 591{ 592 struct get_readers_callback_data * d = userdata; 593 unsigned int shared_mask; 594 595 shared_mask = get_readers_read_callback(d, 596 src->RelAddr, src->File, src->Index, src->Swizzle); 597 598 if (shared_mask == RC_MASK_NONE) 599 return; 600 /* The callback function could potentially clear d->ReaderData->Abort, 601 * so we need to call it before we return. */ 602 if (d->ReadNormalCB) 603 d->ReadNormalCB(d->ReaderData, inst, src); 604 605 if (d->ReaderData->ExitOnAbort && d->ReaderData->Abort) 606 return; 607 608 add_reader_normal(&d->C->Pool, d->ReaderData, inst, shared_mask, src); 609} 610 611/** 612 * This function is used by rc_get_readers_normal() to determine when 613 * userdata->ReaderData->Writer is dead (i. e. All compontents of its 614 * destination register have been overwritten by other instructions). 615 */ 616static void get_readers_write_callback( 617 void *userdata, 618 struct rc_instruction * inst, 619 rc_register_file file, 620 unsigned int index, 621 unsigned int mask) 622{ 623 struct get_readers_callback_data * d = userdata; 624 625 if (index == d->DstIndex && file == d->DstFile) { 626 unsigned int shared_mask = mask & d->DstMask; 627 d->ReaderData->AbortOnRead &= ~shared_mask; 628 d->AliveWriteMask &= ~shared_mask; 629 if (d->ReaderData->AbortOnWrite & shared_mask) { 630 d->ReaderData->Abort = 1; 631 } 632 } 633 634 if(d->WriteCB) 635 d->WriteCB(d->ReaderData, inst, file, index, mask); 636} 637 638static void push_branch_mask( 639 struct get_readers_callback_data * d, 640 unsigned int * branch_depth) 641{ 642 (*branch_depth)++; 643 if (*branch_depth > R500_PFS_MAX_BRANCH_DEPTH_FULL) { 644 d->ReaderData->Abort = 1; 645 return; 646 } 647 d->BranchMasks[*branch_depth].IfWriteMask = 648 d->AliveWriteMask; 649} 650 651static void pop_branch_mask( 652 struct get_readers_callback_data * d, 653 unsigned int * branch_depth) 654{ 655 struct branch_write_mask * masks = &d->BranchMasks[*branch_depth]; 656 657 if (masks->HasElse) { 658 /* Abort on read for components that were written in the IF 659 * block. */ 660 d->ReaderData->AbortOnRead |= 661 masks->IfWriteMask & ~masks->ElseWriteMask; 662 /* Abort on read for components that were written in the ELSE 663 * block. */ 664 d->ReaderData->AbortOnRead |= 665 masks->ElseWriteMask & ~d->AliveWriteMask; 666 667 d->AliveWriteMask = masks->IfWriteMask 668 ^ ((masks->IfWriteMask ^ masks->ElseWriteMask) 669 & (masks->IfWriteMask ^ d->AliveWriteMask)); 670 } else { 671 d->ReaderData->AbortOnRead |= 672 masks->IfWriteMask & ~d->AliveWriteMask; 673 d->AliveWriteMask = masks->IfWriteMask; 674 675 } 676 memset(masks, 0, sizeof(struct branch_write_mask)); 677 (*branch_depth)--; 678} 679 680static void get_readers_for_single_write( 681 void * userdata, 682 struct rc_instruction * writer, 683 rc_register_file dst_file, 684 unsigned int dst_index, 685 unsigned int dst_mask) 686{ 687 struct rc_instruction * tmp; 688 unsigned int branch_depth = 0; 689 struct rc_instruction * endloop = NULL; 690 unsigned int abort_on_read_at_endloop = 0; 691 struct get_readers_callback_data * d = userdata; 692 693 d->ReaderData->Writer = writer; 694 d->ReaderData->AbortOnRead = 0; 695 d->ReaderData->AbortOnWrite = 0; 696 d->ReaderData->LoopDepth = 0; 697 d->ReaderData->InElse = 0; 698 d->DstFile = dst_file; 699 d->DstIndex = dst_index; 700 d->DstMask = dst_mask; 701 d->AliveWriteMask = dst_mask; 702 memset(d->BranchMasks, 0, sizeof(d->BranchMasks)); 703 704 if (!dst_mask) 705 return; 706 707 for(tmp = writer->Next; tmp != &d->C->Program.Instructions; 708 tmp = tmp->Next){ 709 rc_opcode opcode = rc_get_flow_control_inst(tmp); 710 switch(opcode) { 711 case RC_OPCODE_BGNLOOP: 712 d->ReaderData->LoopDepth++; 713 push_branch_mask(d, &branch_depth); 714 break; 715 case RC_OPCODE_ENDLOOP: 716 if (d->ReaderData->LoopDepth > 0) { 717 d->ReaderData->LoopDepth--; 718 if (d->ReaderData->LoopDepth == 0) { 719 d->ReaderData->AbortOnWrite = 0; 720 } 721 pop_branch_mask(d, &branch_depth); 722 } else { 723 /* Here we have reached an ENDLOOP without 724 * seeing its BGNLOOP. These means that 725 * the writer was written inside of a loop, 726 * so it could have readers that are above it 727 * (i.e. they have a lower IP). To find these 728 * readers we jump to the BGNLOOP instruction 729 * and check each instruction until we get 730 * back to the writer. 731 */ 732 endloop = tmp; 733 tmp = rc_match_endloop(tmp); 734 if (!tmp) { 735 rc_error(d->C, "Failed to match endloop.\n"); 736 d->ReaderData->Abort = 1; 737 return; 738 } 739 abort_on_read_at_endloop = d->ReaderData->AbortOnRead; 740 d->ReaderData->AbortOnRead |= d->AliveWriteMask; 741 continue; 742 } 743 break; 744 case RC_OPCODE_IF: 745 push_branch_mask(d, &branch_depth); 746 break; 747 case RC_OPCODE_ELSE: 748 if (branch_depth == 0) { 749 d->ReaderData->InElse = 1; 750 } else { 751 unsigned int temp_mask = d->AliveWriteMask; 752 d->AliveWriteMask = 753 d->BranchMasks[branch_depth].IfWriteMask; 754 d->BranchMasks[branch_depth].ElseWriteMask = 755 temp_mask; 756 d->BranchMasks[branch_depth].HasElse = 1; 757 } 758 break; 759 case RC_OPCODE_ENDIF: 760 if (branch_depth == 0) { 761 d->ReaderData->AbortOnRead = d->AliveWriteMask; 762 d->ReaderData->InElse = 0; 763 } 764 else { 765 pop_branch_mask(d, &branch_depth); 766 } 767 break; 768 default: 769 break; 770 } 771 772 if (d->ReaderData->InElse) 773 continue; 774 775 if (tmp->Type == RC_INSTRUCTION_NORMAL) { 776 rc_for_all_reads_src(tmp, 777 get_readers_normal_read_callback, d); 778 } else { 779 rc_pair_for_all_reads_arg(tmp, 780 get_readers_pair_read_callback, d); 781 } 782 783 /* This can happen when we jump from an ENDLOOP to BGNLOOP */ 784 if (tmp == writer) { 785 tmp = endloop; 786 endloop = NULL; 787 d->ReaderData->AbortOnRead = abort_on_read_at_endloop; 788 continue; 789 } 790 rc_for_all_writes_mask(tmp, get_readers_write_callback, d); 791 792 if (d->ReaderData->ExitOnAbort && d->ReaderData->Abort) 793 return; 794 795 if (branch_depth == 0 && !d->AliveWriteMask) 796 return; 797 } 798} 799 800static void init_get_readers_callback_data( 801 struct get_readers_callback_data * d, 802 struct rc_reader_data * reader_data, 803 struct radeon_compiler * c, 804 rc_read_src_fn read_normal_cb, 805 rc_pair_read_arg_fn read_pair_cb, 806 rc_read_write_mask_fn write_cb) 807{ 808 reader_data->Abort = 0; 809 reader_data->ReaderCount = 0; 810 reader_data->ReadersReserved = 0; 811 reader_data->Readers = NULL; 812 813 d->C = c; 814 d->ReaderData = reader_data; 815 d->ReadNormalCB = read_normal_cb; 816 d->ReadPairCB = read_pair_cb; 817 d->WriteCB = write_cb; 818} 819 820/** 821 * This function will create a list of readers via the rc_reader_data struct. 822 * This function will abort (set the flag data->Abort) and return if it 823 * encounters an instruction that reads from @param writer and also a different 824 * instruction. Here are some examples: 825 * 826 * writer = instruction 0; 827 * 0 MOV TEMP[0].xy, TEMP[1].xy 828 * 1 MOV TEMP[0].zw, TEMP[2].xy 829 * 2 MOV TEMP[3], TEMP[0] 830 * The Abort flag will be set on instruction 2, because it reads values written 831 * by instructions 0 and 1. 832 * 833 * writer = instruction 1; 834 * 0 IF TEMP[0].x 835 * 1 MOV TEMP[1], TEMP[2] 836 * 2 ELSE 837 * 3 MOV TEMP[1], TEMP[2] 838 * 4 ENDIF 839 * 5 MOV TEMP[3], TEMP[1] 840 * The Abort flag will be set on instruction 5, because it could read from the 841 * value written by either instruction 1 or 3, depending on the jump decision 842 * made at instruction 0. 843 * 844 * writer = instruction 0; 845 * 0 MOV TEMP[0], TEMP[1] 846 * 2 BGNLOOP 847 * 3 ADD TEMP[0], TEMP[0], none.1 848 * 4 ENDLOOP 849 * The Abort flag will be set on instruction 3, because in the first iteration 850 * of the loop it reads the value written by instruction 0 and in all other 851 * iterations it reads the value written by instruction 3. 852 * 853 * @param read_cb This function will be called for for every instruction that 854 * has been determined to be a reader of writer. 855 * @param write_cb This function will be called for every instruction after 856 * writer. 857 */ 858void rc_get_readers( 859 struct radeon_compiler * c, 860 struct rc_instruction * writer, 861 struct rc_reader_data * data, 862 rc_read_src_fn read_normal_cb, 863 rc_pair_read_arg_fn read_pair_cb, 864 rc_read_write_mask_fn write_cb) 865{ 866 struct get_readers_callback_data d; 867 868 init_get_readers_callback_data(&d, data, c, read_normal_cb, 869 read_pair_cb, write_cb); 870 871 rc_for_all_writes_mask(writer, get_readers_for_single_write, &d); 872} 873 874void rc_get_readers_sub( 875 struct radeon_compiler * c, 876 struct rc_instruction * writer, 877 struct rc_pair_sub_instruction * sub_writer, 878 struct rc_reader_data * data, 879 rc_read_src_fn read_normal_cb, 880 rc_pair_read_arg_fn read_pair_cb, 881 rc_read_write_mask_fn write_cb) 882{ 883 struct get_readers_callback_data d; 884 885 init_get_readers_callback_data(&d, data, c, read_normal_cb, 886 read_pair_cb, write_cb); 887 888 if (sub_writer->WriteMask) { 889 get_readers_for_single_write(&d, writer, RC_FILE_TEMPORARY, 890 sub_writer->DestIndex, sub_writer->WriteMask); 891 } 892} 893