2 * Copyright (C) 2009 Nicolai Haehnle.
3 * Copyright 2010 Tom Stellard <tstellar@gmail.com>
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:
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.
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.
29 #include "radeon_dataflow.h"
31 #include "radeon_compiler.h"
32 #include "radeon_compiler_util.h"
33 #include "radeon_program.h"
35 struct read_write_mask_data {
37 rc_read_write_mask_fn Cb;
40 static void reads_normal_callback(
42 struct rc_instruction * fullinst,
43 struct rc_src_register * src)
45 struct read_write_mask_data * cb_data = userdata;
46 unsigned int refmask = 0;
48 for(chan = 0; chan < 4; chan++) {
49 refmask |= 1 << GET_SWZ(src->Swizzle, chan);
51 refmask &= RC_MASK_XYZW;
54 cb_data->Cb(cb_data->UserData, fullinst, src->File,
58 if (refmask && src->RelAddr) {
59 cb_data->Cb(cb_data->UserData, fullinst, RC_FILE_ADDRESS, 0,
64 static void pair_get_src_refmasks(unsigned int * refmasks,
65 struct rc_pair_instruction * inst,
66 unsigned int swz, unsigned int src)
71 if (swz == RC_SWIZZLE_X || swz == RC_SWIZZLE_Y || swz == RC_SWIZZLE_Z) {
72 if(src == RC_PAIR_PRESUB_SRC) {
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;
82 refmasks[src] |= 1 << swz;
86 if (swz == RC_SWIZZLE_W) {
87 if (src == RC_PAIR_PRESUB_SRC) {
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;
96 refmasks[src] |= 1 << swz;
101 static void reads_pair(struct rc_instruction * fullinst, rc_read_write_mask_fn cb, void * userdata)
103 struct rc_pair_instruction * inst = &fullinst->U.P;
104 unsigned int refmasks[3] = { 0, 0, 0 };
108 for(arg = 0; arg < 3; ++arg) {
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);
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);
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);
132 static 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,
139 const struct rc_opcode_info * info = rc_get_opcode_info(sub->Opcode);
141 for(i = 0; i < info->NumSrcRegs; i++) {
142 unsigned int src_type;
144 src_type = rc_source_type_swz(sub->Arg[i].Swizzle);
146 if (src_type == RC_SOURCE_NONE)
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;
154 // fprintf(stderr, "Presubtract reader\n");
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;
160 presub_type = fullinst->
161 U.P.Alpha.Src[RC_PAIR_PRESUB_SRC].Index;
162 src_array = fullinst->U.P.Alpha.Src;
165 = rc_presubtract_src_reg_count(presub_type);
166 for(j = 0; j < presub_src_count; j++) {
167 cb(userdata, fullinst, &sub->Arg[i],
169 // fprintf(stderr, "Callback for presub %u type=%u\n", j, src_type);
171 // fprintf(stderr, "Done presubtract reader\n");
173 struct rc_pair_instruction_source * src =
174 rc_pair_get_src(&fullinst->U.P, &sub->Arg[i]);
176 cb(userdata, fullinst, &sub->Arg[i], src);
182 /* This function calls the callback function (cb) for each source used by
185 void rc_for_all_reads_src(
186 struct rc_instruction * inst,
190 const struct rc_opcode_info * opcode =
191 rc_get_opcode_info(inst->U.I.Opcode);
193 /* This function only works with normal instructions. */
194 if (inst->Type != RC_INSTRUCTION_NORMAL) {
199 for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src) {
201 if (inst->U.I.SrcReg[src].File == RC_FILE_NONE)
204 if (inst->U.I.SrcReg[src].File == RC_FILE_PRESUB) {
206 unsigned int srcp_regs = rc_presubtract_src_reg_count(
207 inst->U.I.PreSub.Opcode);
208 for( i = 0; i < srcp_regs; i++) {
209 cb(userdata, inst, &inst->U.I.PreSub.SrcReg[i]);
212 cb(userdata, inst, &inst->U.I.SrcReg[src]);
218 * This function calls the callback function (cb) for each arg of the RGB and
221 void rc_pair_for_all_reads_arg(
222 struct rc_instruction * inst,
223 rc_pair_read_arg_fn cb,
226 /* This function only works with pair instructions. */
227 if (inst->Type != RC_INSTRUCTION_PAIR) {
232 pair_sub_for_all_args(inst, &inst->U.P.RGB, cb, userdata);
233 pair_sub_for_all_args(inst, &inst->U.P.Alpha, cb, userdata);
237 * Calls a callback function for all register reads.
239 * This is conservative, i.e. if the same register is referenced multiple times,
240 * the callback may also be called multiple times.
241 * Also, the writemask of the instruction is not taken into account.
243 void rc_for_all_reads_mask(struct rc_instruction * inst, rc_read_write_mask_fn cb, void * userdata)
245 if (inst->Type == RC_INSTRUCTION_NORMAL) {
246 struct read_write_mask_data cb_data;
247 cb_data.UserData = userdata;
250 rc_for_all_reads_src(inst, reads_normal_callback, &cb_data);
252 reads_pair(inst, cb, userdata);
258 static void writes_normal(struct rc_instruction * fullinst, rc_read_write_mask_fn cb, void * userdata)
260 struct rc_sub_instruction * inst = &fullinst->U.I;
261 const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->Opcode);
263 if (opcode->HasDstReg && inst->DstReg.WriteMask)
264 cb(userdata, fullinst, inst->DstReg.File, inst->DstReg.Index, inst->DstReg.WriteMask);
266 if (inst->WriteALUResult)
267 cb(userdata, fullinst, RC_FILE_SPECIAL, RC_SPECIAL_ALU_RESULT, RC_MASK_X);
270 static void writes_pair(struct rc_instruction * fullinst, rc_read_write_mask_fn cb, void * userdata)
272 struct rc_pair_instruction * inst = &fullinst->U.P;
274 if (inst->RGB.WriteMask)
275 cb(userdata, fullinst, RC_FILE_TEMPORARY, inst->RGB.DestIndex, inst->RGB.WriteMask);
277 if (inst->Alpha.WriteMask)
278 cb(userdata, fullinst, RC_FILE_TEMPORARY, inst->Alpha.DestIndex, RC_MASK_W);
280 if (inst->WriteALUResult)
281 cb(userdata, fullinst, RC_FILE_SPECIAL, RC_SPECIAL_ALU_RESULT, RC_MASK_X);
285 * Calls a callback function for all register writes in the instruction,
286 * reporting writemasks to the callback function.
288 * \warning Does not report output registers for paired instructions!
290 void rc_for_all_writes_mask(struct rc_instruction * inst, rc_read_write_mask_fn cb, void * userdata)
292 if (inst->Type == RC_INSTRUCTION_NORMAL) {
293 writes_normal(inst, cb, userdata);
295 writes_pair(inst, cb, userdata);
300 struct mask_to_chan_data {
302 rc_read_write_chan_fn Fn;
305 static void mask_to_chan_cb(void * data, struct rc_instruction * inst,
306 rc_register_file file, unsigned int index, unsigned int mask)
308 struct mask_to_chan_data * d = data;
309 for(unsigned int chan = 0; chan < 4; ++chan) {
310 if (GET_BIT(mask, chan))
311 d->Fn(d->UserData, inst, file, index, chan);
316 * Calls a callback function for all sourced register channels.
318 * This is conservative, i.e. channels may be called multiple times,
319 * and the writemask of the instruction is not taken into account.
321 void rc_for_all_reads_chan(struct rc_instruction * inst, rc_read_write_chan_fn cb, void * userdata)
323 struct mask_to_chan_data d;
324 d.UserData = userdata;
326 rc_for_all_reads_mask(inst, &mask_to_chan_cb, &d);
330 * Calls a callback function for all written register channels.
332 * \warning Does not report output registers for paired instructions!
334 void rc_for_all_writes_chan(struct rc_instruction * inst, rc_read_write_chan_fn cb, void * userdata)
336 struct mask_to_chan_data d;
337 d.UserData = userdata;
339 rc_for_all_writes_mask(inst, &mask_to_chan_cb, &d);
342 static void remap_normal_instruction(struct rc_instruction * fullinst,
343 rc_remap_register_fn cb, void * userdata)
345 struct rc_sub_instruction * inst = &fullinst->U.I;
346 const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->Opcode);
347 unsigned int remapped_presub = 0;
349 if (opcode->HasDstReg) {
350 rc_register_file file = inst->DstReg.File;
351 unsigned int index = inst->DstReg.Index;
353 cb(userdata, fullinst, &file, &index);
355 inst->DstReg.File = file;
356 inst->DstReg.Index = index;
359 for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src) {
360 rc_register_file file = inst->SrcReg[src].File;
361 unsigned int index = inst->SrcReg[src].Index;
363 if (file == RC_FILE_PRESUB) {
365 unsigned int srcp_srcs = rc_presubtract_src_reg_count(
366 inst->PreSub.Opcode);
367 /* Make sure we only remap presubtract sources once in
368 * case more than one source register reads the
369 * presubtract result. */
373 for(i = 0; i < srcp_srcs; i++) {
374 file = inst->PreSub.SrcReg[i].File;
375 index = inst->PreSub.SrcReg[i].Index;
376 cb(userdata, fullinst, &file, &index);
377 inst->PreSub.SrcReg[i].File = file;
378 inst->PreSub.SrcReg[i].Index = index;
383 cb(userdata, fullinst, &file, &index);
385 inst->SrcReg[src].File = file;
386 inst->SrcReg[src].Index = index;
391 static void remap_pair_instruction(struct rc_instruction * fullinst,
392 rc_remap_register_fn cb, void * userdata)
394 struct rc_pair_instruction * inst = &fullinst->U.P;
396 if (inst->RGB.WriteMask) {
397 rc_register_file file = RC_FILE_TEMPORARY;
398 unsigned int index = inst->RGB.DestIndex;
400 cb(userdata, fullinst, &file, &index);
402 inst->RGB.DestIndex = index;
405 if (inst->Alpha.WriteMask) {
406 rc_register_file file = RC_FILE_TEMPORARY;
407 unsigned int index = inst->Alpha.DestIndex;
409 cb(userdata, fullinst, &file, &index);
411 inst->Alpha.DestIndex = index;
414 for(unsigned int src = 0; src < 3; ++src) {
415 if (inst->RGB.Src[src].Used) {
416 rc_register_file file = inst->RGB.Src[src].File;
417 unsigned int index = inst->RGB.Src[src].Index;
419 cb(userdata, fullinst, &file, &index);
421 inst->RGB.Src[src].File = file;
422 inst->RGB.Src[src].Index = index;
425 if (inst->Alpha.Src[src].Used) {
426 rc_register_file file = inst->Alpha.Src[src].File;
427 unsigned int index = inst->Alpha.Src[src].Index;
429 cb(userdata, fullinst, &file, &index);
431 inst->Alpha.Src[src].File = file;
432 inst->Alpha.Src[src].Index = index;
439 * Remap all register accesses according to the given function.
440 * That is, call the function \p cb for each referenced register (both read and written)
441 * and update the given instruction \p inst accordingly
442 * if it modifies its \ref pfile and \ref pindex contents.
444 void rc_remap_registers(struct rc_instruction * inst, rc_remap_register_fn cb, void * userdata)
446 if (inst->Type == RC_INSTRUCTION_NORMAL)
447 remap_normal_instruction(inst, cb, userdata);
449 remap_pair_instruction(inst, cb, userdata);
452 struct branch_write_mask {
453 unsigned int IfWriteMask:4;
454 unsigned int ElseWriteMask:4;
455 unsigned int HasElse:1;
458 union get_readers_read_cb {
460 rc_pair_read_arg_fn P;
463 struct get_readers_callback_data {
464 struct radeon_compiler * C;
465 struct rc_reader_data * ReaderData;
466 rc_read_src_fn ReadNormalCB;
467 rc_pair_read_arg_fn ReadPairCB;
468 rc_read_write_mask_fn WriteCB;
469 rc_register_file DstFile;
470 unsigned int DstIndex;
471 unsigned int DstMask;
472 unsigned int AliveWriteMask;
473 /* For convenience, this is indexed starting at 1 */
474 struct branch_write_mask BranchMasks[R500_PFS_MAX_BRANCH_DEPTH_FULL + 1];
477 static struct rc_reader * add_reader(
478 struct memory_pool * pool,
479 struct rc_reader_data * data,
480 struct rc_instruction * inst,
483 struct rc_reader * new;
484 memory_pool_array_reserve(pool, struct rc_reader, data->Readers,
485 data->ReaderCount, data->ReadersReserved, 1);
486 new = &data->Readers[data->ReaderCount++];
488 new->WriteMask = mask;
492 static void add_reader_normal(
493 struct memory_pool * pool,
494 struct rc_reader_data * data,
495 struct rc_instruction * inst,
497 struct rc_src_register * src)
499 struct rc_reader * new = add_reader(pool, data, inst, mask);
504 static void add_reader_pair(
505 struct memory_pool * pool,
506 struct rc_reader_data * data,
507 struct rc_instruction * inst,
509 struct rc_pair_instruction_arg * arg,
510 struct rc_pair_instruction_source * src)
512 struct rc_reader * new = add_reader(pool, data, inst, mask);
517 static unsigned int get_readers_read_callback(
518 struct get_readers_callback_data * cb_data,
519 unsigned int has_rel_addr,
520 rc_register_file file,
522 unsigned int swizzle)
524 unsigned int shared_mask, read_mask;
527 cb_data->ReaderData->Abort = 1;
531 shared_mask = rc_src_reads_dst_mask(file, index, swizzle,
532 cb_data->DstFile, cb_data->DstIndex, cb_data->AliveWriteMask);
534 if (shared_mask == RC_MASK_NONE)
537 /* If we make it this far, it means that this source reads from the
538 * same register written to by d->ReaderData->Writer. */
540 read_mask = rc_swizzle_to_writemask(swizzle);
541 if (cb_data->ReaderData->AbortOnRead & read_mask) {
542 cb_data->ReaderData->Abort = 1;
546 if (cb_data->ReaderData->LoopDepth > 0) {
547 cb_data->ReaderData->AbortOnWrite |=
548 (read_mask & cb_data->AliveWriteMask);
551 /* XXX The behavior in this case should be configurable. */
552 if ((read_mask & cb_data->AliveWriteMask) != read_mask) {
553 cb_data->ReaderData->Abort = 1;
560 static void get_readers_pair_read_callback(
562 struct rc_instruction * inst,
563 struct rc_pair_instruction_arg * arg,
564 struct rc_pair_instruction_source * src)
566 unsigned int shared_mask;
567 struct get_readers_callback_data * d = userdata;
569 shared_mask = get_readers_read_callback(d,
570 0 /*Pair Instructions don't use RelAddr*/,
571 src->File, src->Index, arg->Swizzle);
573 // fprintf(stderr, "Shared mask = %u for [%u].%u writemask=%u abort=%u exit=%u\n",
574 // shared_mask, src->Index, arg->Swizzle, d->AliveWriteMask,d->ReaderData->Abort, d->ReaderData->ExitOnAbort);
575 if (shared_mask == RC_MASK_NONE)
579 d->ReadPairCB(d->ReaderData, inst, arg, src);
581 if (d->ReaderData->ExitOnAbort && d->ReaderData->Abort)
584 add_reader_pair(&d->C->Pool, d->ReaderData, inst, shared_mask, arg, src);
588 * This function is used by rc_get_readers_normal() to determine whether inst
589 * is a reader of userdata->ReaderData->Writer
591 static void get_readers_normal_read_callback(
593 struct rc_instruction * inst,
594 struct rc_src_register * src)
596 struct get_readers_callback_data * d = userdata;
597 unsigned int shared_mask;
599 shared_mask = get_readers_read_callback(d,
600 src->RelAddr, src->File, src->Index, src->Swizzle);
602 if (shared_mask == RC_MASK_NONE)
604 /* The callback function could potentially clear d->ReaderData->Abort,
605 * so we need to call it before we return. */
607 d->ReadNormalCB(d->ReaderData, inst, src);
609 if (d->ReaderData->ExitOnAbort && d->ReaderData->Abort)
612 add_reader_normal(&d->C->Pool, d->ReaderData, inst, shared_mask, src);
616 * This function is used by rc_get_readers_normal() to determine when
617 * userdata->ReaderData->Writer is dead (i. e. All compontents of its
618 * destination register have been overwritten by other instructions).
620 static void get_readers_write_callback(
622 struct rc_instruction * inst,
623 rc_register_file file,
627 struct get_readers_callback_data * d = userdata;
629 if (index == d->DstIndex && file == d->DstFile) {
630 unsigned int shared_mask = mask & d->DstMask;
631 d->ReaderData->AbortOnRead &= ~shared_mask;
632 d->AliveWriteMask &= ~shared_mask;
633 if (d->ReaderData->AbortOnWrite & shared_mask) {
634 d->ReaderData->Abort = 1;
639 d->WriteCB(d->ReaderData, inst, file, index, mask);
642 static void push_branch_mask(
643 struct get_readers_callback_data * d,
644 unsigned int * branch_depth)
647 if (*branch_depth > R500_PFS_MAX_BRANCH_DEPTH_FULL) {
648 d->ReaderData->Abort = 1;
651 d->BranchMasks[*branch_depth].IfWriteMask =
655 static void pop_branch_mask(
656 struct get_readers_callback_data * d,
657 unsigned int * branch_depth)
659 struct branch_write_mask * masks = &d->BranchMasks[*branch_depth];
661 if (masks->HasElse) {
662 /* Abort on read for components that were written in the IF
664 d->ReaderData->AbortOnRead |=
665 masks->IfWriteMask & ~masks->ElseWriteMask;
666 /* Abort on read for components that were written in the ELSE
668 d->ReaderData->AbortOnRead |=
669 masks->ElseWriteMask & ~d->AliveWriteMask;
671 d->AliveWriteMask = masks->IfWriteMask
672 ^ ((masks->IfWriteMask ^ masks->ElseWriteMask)
673 & (masks->IfWriteMask ^ d->AliveWriteMask));
675 d->ReaderData->AbortOnRead |=
676 masks->IfWriteMask & ~d->AliveWriteMask;
677 d->AliveWriteMask = masks->IfWriteMask;
680 memset(masks, 0, sizeof(struct branch_write_mask));
684 static void get_readers_for_single_write(
686 struct rc_instruction * writer,
687 rc_register_file dst_file,
688 unsigned int dst_index,
689 unsigned int dst_mask)
691 struct rc_instruction * tmp;
692 unsigned int branch_depth = 0;
693 struct rc_instruction * endloop = NULL;
694 unsigned int abort_on_read_at_endloop;
695 struct get_readers_callback_data * d = userdata;
697 d->ReaderData->Writer = writer;
698 d->ReaderData->AbortOnRead = 0;
699 d->ReaderData->AbortOnWrite = 0;
700 d->ReaderData->LoopDepth = 0;
701 d->ReaderData->InElse = 0;
702 d->DstFile = dst_file;
703 d->DstIndex = dst_index;
704 d->DstMask = dst_mask;
705 d->AliveWriteMask = dst_mask;
706 memset(d->BranchMasks, 0, sizeof(d->BranchMasks));
711 for(tmp = writer->Next; tmp != &d->C->Program.Instructions;
713 rc_opcode opcode = rc_get_flow_control_inst(tmp);
715 case RC_OPCODE_BGNLOOP:
716 d->ReaderData->LoopDepth++;
717 push_branch_mask(d, &branch_depth);
719 case RC_OPCODE_ENDLOOP:
720 if (d->ReaderData->LoopDepth > 0) {
721 d->ReaderData->LoopDepth--;
722 if (d->ReaderData->LoopDepth == 0) {
723 d->ReaderData->AbortOnWrite = 0;
725 pop_branch_mask(d, &branch_depth);
727 /* Here we have reached an ENDLOOP without
728 * seeing its BGNLOOP. These means that
729 * the writer was written inside of a loop,
730 * so it could have readers that are above it
731 * (i.e. they have a lower IP). To find these
732 * readers we jump to the BGNLOOP instruction
733 * and check each instruction until we get
734 * back to the writer.
737 tmp = rc_match_endloop(tmp);
739 rc_error(d->C, "Failed to match endloop.\n");
740 d->ReaderData->Abort = 1;
743 abort_on_read_at_endloop = d->ReaderData->AbortOnRead;
744 d->ReaderData->AbortOnRead |= d->AliveWriteMask;
749 push_branch_mask(d, &branch_depth);
752 if (branch_depth == 0) {
753 d->ReaderData->InElse = 1;
755 unsigned int temp_mask = d->AliveWriteMask;
757 d->BranchMasks[branch_depth].IfWriteMask;
758 d->BranchMasks[branch_depth].ElseWriteMask =
760 d->BranchMasks[branch_depth].HasElse = 1;
763 case RC_OPCODE_ENDIF:
764 if (branch_depth == 0) {
765 d->ReaderData->AbortOnRead = d->AliveWriteMask;
766 d->ReaderData->InElse = 0;
769 pop_branch_mask(d, &branch_depth);
776 if (d->ReaderData->InElse)
779 if (tmp->Type == RC_INSTRUCTION_NORMAL) {
780 rc_for_all_reads_src(tmp,
781 get_readers_normal_read_callback, d);
783 rc_pair_for_all_reads_arg(tmp,
784 get_readers_pair_read_callback, d);
787 /* This can happen when we jump from an ENDLOOP to BGNLOOP */
791 d->ReaderData->AbortOnRead = abort_on_read_at_endloop;
794 rc_for_all_writes_mask(tmp, get_readers_write_callback, d);
796 if (d->ReaderData->ExitOnAbort && d->ReaderData->Abort)
799 if (branch_depth == 0 && !d->AliveWriteMask)
804 static void init_get_readers_callback_data(
805 struct get_readers_callback_data * d,
806 struct rc_reader_data * reader_data,
807 struct radeon_compiler * c,
808 rc_read_src_fn read_normal_cb,
809 rc_pair_read_arg_fn read_pair_cb,
810 rc_read_write_mask_fn write_cb)
812 reader_data->Abort = 0;
813 reader_data->ReaderCount = 0;
814 reader_data->ReadersReserved = 0;
815 reader_data->Readers = NULL;
818 d->ReaderData = reader_data;
819 d->ReadNormalCB = read_normal_cb;
820 d->ReadPairCB = read_pair_cb;
821 d->WriteCB = write_cb;
825 * This function will create a list of readers via the rc_reader_data struct.
826 * This function will abort (set the flag data->Abort) and return if it
827 * encounters an instruction that reads from @param writer and also a different
828 * instruction. Here are some examples:
830 * writer = instruction 0;
831 * 0 MOV TEMP[0].xy, TEMP[1].xy
832 * 1 MOV TEMP[0].zw, TEMP[2].xy
833 * 2 MOV TEMP[3], TEMP[0]
834 * The Abort flag will be set on instruction 2, because it reads values written
835 * by instructions 0 and 1.
837 * writer = instruction 1;
839 * 1 MOV TEMP[1], TEMP[2]
841 * 3 MOV TEMP[1], TEMP[2]
843 * 5 MOV TEMP[3], TEMP[1]
844 * The Abort flag will be set on instruction 5, because it could read from the
845 * value written by either instruction 1 or 3, depending on the jump decision
846 * made at instruction 0.
848 * writer = instruction 0;
849 * 0 MOV TEMP[0], TEMP[1]
851 * 3 ADD TEMP[0], TEMP[0], none.1
853 * The Abort flag will be set on instruction 3, because in the first iteration
854 * of the loop it reads the value written by instruction 0 and in all other
855 * iterations it reads the value written by instruction 3.
857 * @param read_cb This function will be called for for every instruction that
858 * has been determined to be a reader of writer.
859 * @param write_cb This function will be called for every instruction after
863 struct radeon_compiler * c,
864 struct rc_instruction * writer,
865 struct rc_reader_data * data,
866 rc_read_src_fn read_normal_cb,
867 rc_pair_read_arg_fn read_pair_cb,
868 rc_read_write_mask_fn write_cb)
870 struct get_readers_callback_data d;
872 init_get_readers_callback_data(&d, data, c, read_normal_cb,
873 read_pair_cb, write_cb);
875 rc_for_all_writes_mask(writer, get_readers_for_single_write, &d);
878 void rc_get_readers_sub(
879 struct radeon_compiler * c,
880 struct rc_instruction * writer,
881 struct rc_pair_sub_instruction * sub_writer,
882 struct rc_reader_data * data,
883 rc_read_src_fn read_normal_cb,
884 rc_pair_read_arg_fn read_pair_cb,
885 rc_read_write_mask_fn write_cb)
887 struct get_readers_callback_data d;
889 init_get_readers_callback_data(&d, data, c, read_normal_cb,
890 read_pair_cb, write_cb);
892 if (sub_writer->WriteMask) {
893 get_readers_for_single_write(&d, writer, RC_FILE_TEMPORARY,
894 sub_writer->DestIndex, sub_writer->WriteMask);