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
;
143 unsigned int channels
= 0;
144 if (&fullinst
->U
.P
.RGB
== sub
)
146 else if (&fullinst
->U
.P
.Alpha
== sub
)
149 assert(channels
> 0);
150 src_type
= rc_source_type_swz(sub
->Arg
[i
].Swizzle
, channels
);
152 if (src_type
== RC_SOURCE_NONE
)
155 if (sub
->Arg
[i
].Source
== RC_PAIR_PRESUB_SRC
) {
156 unsigned int presub_type
;
157 unsigned int presub_src_count
;
158 struct rc_pair_instruction_source
* src_array
;
160 if (src_type
& RC_SOURCE_RGB
) {
161 presub_type
= fullinst
->
162 U
.P
.RGB
.Src
[RC_PAIR_PRESUB_SRC
].Index
;
163 src_array
= fullinst
->U
.P
.RGB
.Src
;
165 presub_type
= fullinst
->
166 U
.P
.Alpha
.Src
[RC_PAIR_PRESUB_SRC
].Index
;
167 src_array
= fullinst
->U
.P
.Alpha
.Src
;
170 = rc_presubtract_src_reg_count(presub_type
);
171 for(j
= 0; j
< presub_src_count
; j
++) {
172 cb(userdata
, fullinst
, &sub
->Arg
[i
],
176 struct rc_pair_instruction_source
* src
=
177 rc_pair_get_src(&fullinst
->U
.P
, &sub
->Arg
[i
]);
179 cb(userdata
, fullinst
, &sub
->Arg
[i
], src
);
185 /* This function calls the callback function (cb) for each source used by
188 void rc_for_all_reads_src(
189 struct rc_instruction
* inst
,
193 const struct rc_opcode_info
* opcode
=
194 rc_get_opcode_info(inst
->U
.I
.Opcode
);
196 /* This function only works with normal instructions. */
197 if (inst
->Type
!= RC_INSTRUCTION_NORMAL
) {
202 for(unsigned int src
= 0; src
< opcode
->NumSrcRegs
; ++src
) {
204 if (inst
->U
.I
.SrcReg
[src
].File
== RC_FILE_NONE
)
207 if (inst
->U
.I
.SrcReg
[src
].File
== RC_FILE_PRESUB
) {
209 unsigned int srcp_regs
= rc_presubtract_src_reg_count(
210 inst
->U
.I
.PreSub
.Opcode
);
211 for( i
= 0; i
< srcp_regs
; i
++) {
212 cb(userdata
, inst
, &inst
->U
.I
.PreSub
.SrcReg
[i
]);
215 cb(userdata
, inst
, &inst
->U
.I
.SrcReg
[src
]);
221 * This function calls the callback function (cb) for each arg of the RGB and
224 void rc_pair_for_all_reads_arg(
225 struct rc_instruction
* inst
,
226 rc_pair_read_arg_fn cb
,
229 /* This function only works with pair instructions. */
230 if (inst
->Type
!= RC_INSTRUCTION_PAIR
) {
235 pair_sub_for_all_args(inst
, &inst
->U
.P
.RGB
, cb
, userdata
);
236 pair_sub_for_all_args(inst
, &inst
->U
.P
.Alpha
, cb
, userdata
);
240 * Calls a callback function for all register reads.
242 * This is conservative, i.e. if the same register is referenced multiple times,
243 * the callback may also be called multiple times.
244 * Also, the writemask of the instruction is not taken into account.
246 void rc_for_all_reads_mask(struct rc_instruction
* inst
, rc_read_write_mask_fn cb
, void * userdata
)
248 if (inst
->Type
== RC_INSTRUCTION_NORMAL
) {
249 struct read_write_mask_data cb_data
;
250 cb_data
.UserData
= userdata
;
253 rc_for_all_reads_src(inst
, reads_normal_callback
, &cb_data
);
255 reads_pair(inst
, cb
, userdata
);
261 static void writes_normal(struct rc_instruction
* fullinst
, rc_read_write_mask_fn cb
, void * userdata
)
263 struct rc_sub_instruction
* inst
= &fullinst
->U
.I
;
264 const struct rc_opcode_info
* opcode
= rc_get_opcode_info(inst
->Opcode
);
266 if (opcode
->HasDstReg
&& inst
->DstReg
.WriteMask
)
267 cb(userdata
, fullinst
, inst
->DstReg
.File
, inst
->DstReg
.Index
, inst
->DstReg
.WriteMask
);
269 if (inst
->WriteALUResult
)
270 cb(userdata
, fullinst
, RC_FILE_SPECIAL
, RC_SPECIAL_ALU_RESULT
, RC_MASK_X
);
273 static void writes_pair(struct rc_instruction
* fullinst
, rc_read_write_mask_fn cb
, void * userdata
)
275 struct rc_pair_instruction
* inst
= &fullinst
->U
.P
;
277 if (inst
->RGB
.WriteMask
)
278 cb(userdata
, fullinst
, RC_FILE_TEMPORARY
, inst
->RGB
.DestIndex
, inst
->RGB
.WriteMask
);
280 if (inst
->Alpha
.WriteMask
)
281 cb(userdata
, fullinst
, RC_FILE_TEMPORARY
, inst
->Alpha
.DestIndex
, RC_MASK_W
);
283 if (inst
->WriteALUResult
)
284 cb(userdata
, fullinst
, RC_FILE_SPECIAL
, RC_SPECIAL_ALU_RESULT
, RC_MASK_X
);
288 * Calls a callback function for all register writes in the instruction,
289 * reporting writemasks to the callback function.
291 * \warning Does not report output registers for paired instructions!
293 void rc_for_all_writes_mask(struct rc_instruction
* inst
, rc_read_write_mask_fn cb
, void * userdata
)
295 if (inst
->Type
== RC_INSTRUCTION_NORMAL
) {
296 writes_normal(inst
, cb
, userdata
);
298 writes_pair(inst
, cb
, userdata
);
303 struct mask_to_chan_data
{
305 rc_read_write_chan_fn Fn
;
308 static void mask_to_chan_cb(void * data
, struct rc_instruction
* inst
,
309 rc_register_file file
, unsigned int index
, unsigned int mask
)
311 struct mask_to_chan_data
* d
= data
;
312 for(unsigned int chan
= 0; chan
< 4; ++chan
) {
313 if (GET_BIT(mask
, chan
))
314 d
->Fn(d
->UserData
, inst
, file
, index
, chan
);
319 * Calls a callback function for all sourced register channels.
321 * This is conservative, i.e. channels may be called multiple times,
322 * and the writemask of the instruction is not taken into account.
324 void rc_for_all_reads_chan(struct rc_instruction
* inst
, rc_read_write_chan_fn cb
, void * userdata
)
326 struct mask_to_chan_data d
;
327 d
.UserData
= userdata
;
329 rc_for_all_reads_mask(inst
, &mask_to_chan_cb
, &d
);
333 * Calls a callback function for all written register channels.
335 * \warning Does not report output registers for paired instructions!
337 void rc_for_all_writes_chan(struct rc_instruction
* inst
, rc_read_write_chan_fn cb
, void * userdata
)
339 struct mask_to_chan_data d
;
340 d
.UserData
= userdata
;
342 rc_for_all_writes_mask(inst
, &mask_to_chan_cb
, &d
);
345 static void remap_normal_instruction(struct rc_instruction
* fullinst
,
346 rc_remap_register_fn cb
, void * userdata
)
348 struct rc_sub_instruction
* inst
= &fullinst
->U
.I
;
349 const struct rc_opcode_info
* opcode
= rc_get_opcode_info(inst
->Opcode
);
351 if (opcode
->HasDstReg
) {
352 rc_register_file file
= inst
->DstReg
.File
;
353 unsigned int index
= inst
->DstReg
.Index
;
355 cb(userdata
, fullinst
, &file
, &index
);
357 inst
->DstReg
.File
= file
;
358 inst
->DstReg
.Index
= index
;
361 for(unsigned int src
= 0; src
< opcode
->NumSrcRegs
; ++src
) {
362 rc_register_file file
= inst
->SrcReg
[src
].File
;
363 unsigned int index
= inst
->SrcReg
[src
].Index
;
365 if (file
== RC_FILE_PRESUB
) {
367 unsigned int srcp_srcs
= rc_presubtract_src_reg_count(
368 inst
->PreSub
.Opcode
);
369 for(i
= 0; i
< srcp_srcs
; i
++) {
370 file
= inst
->PreSub
.SrcReg
[i
].File
;
371 index
= inst
->PreSub
.SrcReg
[i
].Index
;
372 cb(userdata
, fullinst
, &file
, &index
);
373 inst
->PreSub
.SrcReg
[i
].File
= file
;
374 inst
->PreSub
.SrcReg
[i
].Index
= index
;
379 cb(userdata
, fullinst
, &file
, &index
);
381 inst
->SrcReg
[src
].File
= file
;
382 inst
->SrcReg
[src
].Index
= index
;
387 static void remap_pair_instruction(struct rc_instruction
* fullinst
,
388 rc_remap_register_fn cb
, void * userdata
)
390 struct rc_pair_instruction
* inst
= &fullinst
->U
.P
;
392 if (inst
->RGB
.WriteMask
) {
393 rc_register_file file
= RC_FILE_TEMPORARY
;
394 unsigned int index
= inst
->RGB
.DestIndex
;
396 cb(userdata
, fullinst
, &file
, &index
);
398 inst
->RGB
.DestIndex
= index
;
401 if (inst
->Alpha
.WriteMask
) {
402 rc_register_file file
= RC_FILE_TEMPORARY
;
403 unsigned int index
= inst
->Alpha
.DestIndex
;
405 cb(userdata
, fullinst
, &file
, &index
);
407 inst
->Alpha
.DestIndex
= index
;
410 for(unsigned int src
= 0; src
< 3; ++src
) {
411 if (inst
->RGB
.Src
[src
].Used
) {
412 rc_register_file file
= inst
->RGB
.Src
[src
].File
;
413 unsigned int index
= inst
->RGB
.Src
[src
].Index
;
415 cb(userdata
, fullinst
, &file
, &index
);
417 inst
->RGB
.Src
[src
].File
= file
;
418 inst
->RGB
.Src
[src
].Index
= index
;
421 if (inst
->Alpha
.Src
[src
].Used
) {
422 rc_register_file file
= inst
->Alpha
.Src
[src
].File
;
423 unsigned int index
= inst
->Alpha
.Src
[src
].Index
;
425 cb(userdata
, fullinst
, &file
, &index
);
427 inst
->Alpha
.Src
[src
].File
= file
;
428 inst
->Alpha
.Src
[src
].Index
= index
;
435 * Remap all register accesses according to the given function.
436 * That is, call the function \p cb for each referenced register (both read and written)
437 * and update the given instruction \p inst accordingly
438 * if it modifies its \ref pfile and \ref pindex contents.
440 void rc_remap_registers(struct rc_instruction
* inst
, rc_remap_register_fn cb
, void * userdata
)
442 if (inst
->Type
== RC_INSTRUCTION_NORMAL
)
443 remap_normal_instruction(inst
, cb
, userdata
);
445 remap_pair_instruction(inst
, cb
, userdata
);
449 * @return RC_OPCODE_NOOP if inst is not a flow control instruction.
450 * @return The opcode of inst if it is a flow control instruction.
452 static rc_opcode
get_flow_control_inst(struct rc_instruction
* inst
)
454 const struct rc_opcode_info
* info
;
455 if (inst
->Type
== RC_INSTRUCTION_NORMAL
) {
456 info
= rc_get_opcode_info(inst
->U
.I
.Opcode
);
458 info
= rc_get_opcode_info(inst
->U
.P
.RGB
.Opcode
);
459 /*A flow control instruction shouldn't have an alpha
461 assert(!info
->IsFlowControl
||
462 inst
->U
.P
.Alpha
.Opcode
== RC_OPCODE_NOP
);
465 if (info
->IsFlowControl
)
468 return RC_OPCODE_NOP
;
472 struct branch_write_mask
{
473 unsigned int IfWriteMask
:4;
474 unsigned int ElseWriteMask
:4;
475 unsigned int HasElse
:1;
478 union get_readers_read_cb
{
480 rc_pair_read_arg_fn P
;
483 struct get_readers_callback_data
{
484 struct radeon_compiler
* C
;
485 struct rc_reader_data
* ReaderData
;
486 rc_read_src_fn ReadNormalCB
;
487 rc_pair_read_arg_fn ReadPairCB
;
488 rc_read_write_mask_fn WriteCB
;
489 rc_register_file DstFile
;
490 unsigned int DstIndex
;
491 unsigned int DstMask
;
492 unsigned int AliveWriteMask
;
493 /* For convenience, this is indexed starting at 1 */
494 struct branch_write_mask BranchMasks
[R500_PFS_MAX_BRANCH_DEPTH_FULL
+ 1];
497 static void add_reader(
498 struct memory_pool
* pool
,
499 struct rc_reader_data
* data
,
500 struct rc_instruction
* inst
,
504 struct rc_reader
* new;
505 memory_pool_array_reserve(pool
, struct rc_reader
, data
->Readers
,
506 data
->ReaderCount
, data
->ReadersReserved
, 1);
507 new = &data
->Readers
[data
->ReaderCount
++];
509 new->WriteMask
= mask
;
510 if (inst
->Type
== RC_INSTRUCTION_NORMAL
) {
511 new->U
.Src
= arg_or_src
;
513 new->U
.Arg
= arg_or_src
;
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 /* XXX The behavior in this case should be configurable. */
547 if ((read_mask
& cb_data
->AliveWriteMask
) != read_mask
) {
548 cb_data
->ReaderData
->Abort
= 1;
555 static void get_readers_pair_read_callback(
557 struct rc_instruction
* inst
,
558 struct rc_pair_instruction_arg
* arg
,
559 struct rc_pair_instruction_source
* src
)
561 unsigned int shared_mask
;
562 struct get_readers_callback_data
* d
= userdata
;
564 shared_mask
= get_readers_read_callback(d
,
565 0 /*Pair Instructions don't use RelAddr*/,
566 src
->File
, src
->Index
, arg
->Swizzle
);
568 if (shared_mask
== RC_MASK_NONE
)
572 d
->ReadPairCB(d
->ReaderData
, inst
, arg
, src
);
574 if (d
->ReaderData
->Abort
)
577 add_reader(&d
->C
->Pool
, d
->ReaderData
, inst
, shared_mask
, arg
);
581 * This function is used by rc_get_readers_normal() to determine whether inst
582 * is a reader of userdata->ReaderData->Writer
584 static void get_readers_normal_read_callback(
586 struct rc_instruction
* inst
,
587 struct rc_src_register
* src
)
589 struct get_readers_callback_data
* d
= userdata
;
590 unsigned int shared_mask
;
592 shared_mask
= get_readers_read_callback(d
,
593 src
->RelAddr
, src
->File
, src
->Index
, src
->Swizzle
);
595 if (shared_mask
== RC_MASK_NONE
)
597 /* The callback function could potentially clear d->ReaderData->Abort,
598 * so we need to call it before we return. */
600 d
->ReadNormalCB(d
->ReaderData
, inst
, src
);
602 if (d
->ReaderData
->Abort
)
605 add_reader(&d
->C
->Pool
, d
->ReaderData
, inst
, shared_mask
, src
);
609 * This function is used by rc_get_readers_normal() to determine when
610 * userdata->ReaderData->Writer is dead (i. e. All compontents of its
611 * destination register have been overwritten by other instructions).
613 static void get_readers_write_callback(
615 struct rc_instruction
* inst
,
616 rc_register_file file
,
620 struct get_readers_callback_data
* d
= userdata
;
622 if (index
== d
->DstIndex
&& file
== d
->DstFile
) {
623 unsigned int shared_mask
= mask
& d
->DstMask
;
624 d
->ReaderData
->AbortOnRead
&= ~shared_mask
;
625 d
->AliveWriteMask
&= ~shared_mask
;
629 d
->WriteCB(d
->ReaderData
, inst
, file
, index
, mask
);
632 static void get_readers_for_single_write(
634 struct rc_instruction
* writer
,
635 rc_register_file dst_file
,
636 unsigned int dst_index
,
637 unsigned int dst_mask
)
639 struct rc_instruction
* tmp
;
640 unsigned int branch_depth
= 0;
641 struct get_readers_callback_data
* d
= userdata
;
643 d
->ReaderData
->Writer
= writer
;
644 d
->ReaderData
->AbortOnRead
= 0;
645 d
->ReaderData
->InElse
= 0;
646 d
->DstFile
= dst_file
;
647 d
->DstIndex
= dst_index
;
648 d
->DstMask
= dst_mask
;
649 d
->AliveWriteMask
= dst_mask
;
650 memset(d
->BranchMasks
, 0, sizeof(d
->BranchMasks
));
655 for(tmp
= writer
->Next
; tmp
!= &d
->C
->Program
.Instructions
;
657 rc_opcode opcode
= get_flow_control_inst(tmp
);
659 case RC_OPCODE_BGNLOOP
:
660 /* XXX We can do better when we see a BGNLOOP if we
661 * add a flag called AbortOnWrite to struct
662 * rc_reader_data and leave it set until the next
664 case RC_OPCODE_ENDLOOP
:
665 /* XXX We can do better when we see an ENDLOOP by
666 * searching backwards from writer and looking for
667 * readers of writer's destination index. If we find a
668 * reader before we get to the BGNLOOP, we must abort
669 * unless there is another writer between that reader
670 * and the BGNLOOP. */
673 d
->ReaderData
->Abort
= 1;
677 if (branch_depth
> R500_PFS_MAX_BRANCH_DEPTH_FULL
) {
678 d
->ReaderData
->Abort
= 1;
681 d
->BranchMasks
[branch_depth
].IfWriteMask
=
685 if (branch_depth
== 0) {
686 d
->ReaderData
->InElse
= 1;
688 unsigned int temp_mask
= d
->AliveWriteMask
;
690 d
->BranchMasks
[branch_depth
].IfWriteMask
;
691 d
->BranchMasks
[branch_depth
].ElseWriteMask
=
693 d
->BranchMasks
[branch_depth
].HasElse
= 1;
696 case RC_OPCODE_ENDIF
:
697 if (branch_depth
== 0) {
698 d
->ReaderData
->AbortOnRead
= d
->AliveWriteMask
;
699 d
->ReaderData
->InElse
= 0;
702 struct branch_write_mask
* masks
=
703 &d
->BranchMasks
[branch_depth
];
705 if (masks
->HasElse
) {
706 d
->ReaderData
->AbortOnRead
|=
708 & ~masks
->ElseWriteMask
;
709 d
->AliveWriteMask
= masks
->IfWriteMask
710 ^ ((masks
->IfWriteMask
^
711 masks
->ElseWriteMask
)
712 & (masks
->IfWriteMask
713 ^ d
->AliveWriteMask
));
715 d
->ReaderData
->AbortOnRead
|=
717 & ~d
->AliveWriteMask
;
718 d
->AliveWriteMask
= masks
->IfWriteMask
;
722 sizeof(struct branch_write_mask
));
730 if (d
->ReaderData
->InElse
)
733 if (tmp
->Type
== RC_INSTRUCTION_NORMAL
) {
734 rc_for_all_reads_src(tmp
,
735 get_readers_normal_read_callback
, d
);
737 rc_pair_for_all_reads_arg(tmp
,
738 get_readers_pair_read_callback
, d
);
740 rc_for_all_writes_mask(tmp
, get_readers_write_callback
, d
);
742 if (d
->ReaderData
->Abort
)
745 if (branch_depth
== 0 && !d
->AliveWriteMask
)
751 * This function will create a list of readers via the rc_reader_data struct.
752 * This function will abort (set the flag data->Abort) and return if it
753 * encounters an instruction that reads from @param writer and also a different
754 * instruction. Here are some examples:
756 * writer = instruction 0;
757 * 0 MOV TEMP[0].xy, TEMP[1].xy
758 * 1 MOV TEMP[0].zw, TEMP[2].xy
759 * 2 MOV TEMP[3], TEMP[0]
760 * The Abort flag will be set on instruction 2, because it reads values written
761 * by instructions 0 and 1.
763 * writer = instruction 1;
765 * 1 MOV TEMP[1], TEMP[2]
767 * 3 MOV TEMP[1], TEMP[2]
769 * 5 MOV TEMP[3], TEMP[1]
770 * The Abort flag will be set on instruction 5, because it could read from the
771 * value written by either instruction 1 or 3, depending on the jump decision
772 * made at instruction 0.
774 * writer = instruction 0;
775 * 0 MOV TEMP[0], TEMP[1]
777 * 3 ADD TEMP[0], TEMP[0], none.1
779 * The Abort flag will be set on instruction 3, because in the first iteration
780 * of the loop it reads the value written by instruction 0 and in all other
781 * iterations it reads the value written by instruction 3.
783 * @param read_cb This function will be called for for every instruction that
784 * has been determined to be a reader of writer.
785 * @param write_cb This function will be called for every instruction after
789 struct radeon_compiler
* c
,
790 struct rc_instruction
* writer
,
791 struct rc_reader_data
* data
,
792 rc_read_src_fn read_normal_cb
,
793 rc_pair_read_arg_fn read_pair_cb
,
794 rc_read_write_mask_fn write_cb
)
796 struct get_readers_callback_data d
;
799 data
->ReaderCount
= 0;
800 data
->ReadersReserved
= 0;
801 data
->Readers
= NULL
;
805 d
.ReadNormalCB
= read_normal_cb
;
806 d
.ReadPairCB
= read_pair_cb
;
807 d
.WriteCB
= write_cb
;
809 rc_for_all_writes_mask(writer
, get_readers_for_single_write
, &d
);