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 if (src_type
& RC_SOURCE_RGB
) {
155 presub_type
= fullinst
->
156 U
.P
.RGB
.Src
[RC_PAIR_PRESUB_SRC
].Index
;
157 src_array
= fullinst
->U
.P
.RGB
.Src
;
159 presub_type
= fullinst
->
160 U
.P
.Alpha
.Src
[RC_PAIR_PRESUB_SRC
].Index
;
161 src_array
= fullinst
->U
.P
.Alpha
.Src
;
164 = rc_presubtract_src_reg_count(presub_type
);
165 for(j
= 0; j
< presub_src_count
; j
++) {
166 cb(userdata
, fullinst
, &sub
->Arg
[i
],
170 struct rc_pair_instruction_source
* src
=
171 rc_pair_get_src(&fullinst
->U
.P
, &sub
->Arg
[i
]);
173 cb(userdata
, fullinst
, &sub
->Arg
[i
], src
);
179 /* This function calls the callback function (cb) for each source used by
182 void rc_for_all_reads_src(
183 struct rc_instruction
* inst
,
187 const struct rc_opcode_info
* opcode
=
188 rc_get_opcode_info(inst
->U
.I
.Opcode
);
190 /* This function only works with normal instructions. */
191 if (inst
->Type
!= RC_INSTRUCTION_NORMAL
) {
196 for(unsigned int src
= 0; src
< opcode
->NumSrcRegs
; ++src
) {
198 if (inst
->U
.I
.SrcReg
[src
].File
== RC_FILE_NONE
)
201 if (inst
->U
.I
.SrcReg
[src
].File
== RC_FILE_PRESUB
) {
203 unsigned int srcp_regs
= rc_presubtract_src_reg_count(
204 inst
->U
.I
.PreSub
.Opcode
);
205 for( i
= 0; i
< srcp_regs
; i
++) {
206 cb(userdata
, inst
, &inst
->U
.I
.PreSub
.SrcReg
[i
]);
209 cb(userdata
, inst
, &inst
->U
.I
.SrcReg
[src
]);
215 * This function calls the callback function (cb) for each arg of the RGB and
218 void rc_pair_for_all_reads_arg(
219 struct rc_instruction
* inst
,
220 rc_pair_read_arg_fn cb
,
223 /* This function only works with pair instructions. */
224 if (inst
->Type
!= RC_INSTRUCTION_PAIR
) {
229 pair_sub_for_all_args(inst
, &inst
->U
.P
.RGB
, cb
, userdata
);
230 pair_sub_for_all_args(inst
, &inst
->U
.P
.Alpha
, cb
, userdata
);
234 * Calls a callback function for all register reads.
236 * This is conservative, i.e. if the same register is referenced multiple times,
237 * the callback may also be called multiple times.
238 * Also, the writemask of the instruction is not taken into account.
240 void rc_for_all_reads_mask(struct rc_instruction
* inst
, rc_read_write_mask_fn cb
, void * userdata
)
242 if (inst
->Type
== RC_INSTRUCTION_NORMAL
) {
243 struct read_write_mask_data cb_data
;
244 cb_data
.UserData
= userdata
;
247 rc_for_all_reads_src(inst
, reads_normal_callback
, &cb_data
);
249 reads_pair(inst
, cb
, userdata
);
255 static void writes_normal(struct rc_instruction
* fullinst
, rc_read_write_mask_fn cb
, void * userdata
)
257 struct rc_sub_instruction
* inst
= &fullinst
->U
.I
;
258 const struct rc_opcode_info
* opcode
= rc_get_opcode_info(inst
->Opcode
);
260 if (opcode
->HasDstReg
&& inst
->DstReg
.WriteMask
)
261 cb(userdata
, fullinst
, inst
->DstReg
.File
, inst
->DstReg
.Index
, inst
->DstReg
.WriteMask
);
263 if (inst
->WriteALUResult
)
264 cb(userdata
, fullinst
, RC_FILE_SPECIAL
, RC_SPECIAL_ALU_RESULT
, RC_MASK_X
);
267 static void writes_pair(struct rc_instruction
* fullinst
, rc_read_write_mask_fn cb
, void * userdata
)
269 struct rc_pair_instruction
* inst
= &fullinst
->U
.P
;
271 if (inst
->RGB
.WriteMask
)
272 cb(userdata
, fullinst
, RC_FILE_TEMPORARY
, inst
->RGB
.DestIndex
, inst
->RGB
.WriteMask
);
274 if (inst
->Alpha
.WriteMask
)
275 cb(userdata
, fullinst
, RC_FILE_TEMPORARY
, inst
->Alpha
.DestIndex
, RC_MASK_W
);
277 if (inst
->WriteALUResult
)
278 cb(userdata
, fullinst
, RC_FILE_SPECIAL
, RC_SPECIAL_ALU_RESULT
, RC_MASK_X
);
282 * Calls a callback function for all register writes in the instruction,
283 * reporting writemasks to the callback function.
285 * \warning Does not report output registers for paired instructions!
287 void rc_for_all_writes_mask(struct rc_instruction
* inst
, rc_read_write_mask_fn cb
, void * userdata
)
289 if (inst
->Type
== RC_INSTRUCTION_NORMAL
) {
290 writes_normal(inst
, cb
, userdata
);
292 writes_pair(inst
, cb
, userdata
);
297 struct mask_to_chan_data
{
299 rc_read_write_chan_fn Fn
;
302 static void mask_to_chan_cb(void * data
, struct rc_instruction
* inst
,
303 rc_register_file file
, unsigned int index
, unsigned int mask
)
305 struct mask_to_chan_data
* d
= data
;
306 for(unsigned int chan
= 0; chan
< 4; ++chan
) {
307 if (GET_BIT(mask
, chan
))
308 d
->Fn(d
->UserData
, inst
, file
, index
, chan
);
313 * Calls a callback function for all sourced register channels.
315 * This is conservative, i.e. channels may be called multiple times,
316 * and the writemask of the instruction is not taken into account.
318 void rc_for_all_reads_chan(struct rc_instruction
* inst
, rc_read_write_chan_fn cb
, void * userdata
)
320 struct mask_to_chan_data d
;
321 d
.UserData
= userdata
;
323 rc_for_all_reads_mask(inst
, &mask_to_chan_cb
, &d
);
327 * Calls a callback function for all written register channels.
329 * \warning Does not report output registers for paired instructions!
331 void rc_for_all_writes_chan(struct rc_instruction
* inst
, rc_read_write_chan_fn cb
, void * userdata
)
333 struct mask_to_chan_data d
;
334 d
.UserData
= userdata
;
336 rc_for_all_writes_mask(inst
, &mask_to_chan_cb
, &d
);
339 static void remap_normal_instruction(struct rc_instruction
* fullinst
,
340 rc_remap_register_fn cb
, void * userdata
)
342 struct rc_sub_instruction
* inst
= &fullinst
->U
.I
;
343 const struct rc_opcode_info
* opcode
= rc_get_opcode_info(inst
->Opcode
);
344 unsigned int remapped_presub
= 0;
346 if (opcode
->HasDstReg
) {
347 rc_register_file file
= inst
->DstReg
.File
;
348 unsigned int index
= inst
->DstReg
.Index
;
350 cb(userdata
, fullinst
, &file
, &index
);
352 inst
->DstReg
.File
= file
;
353 inst
->DstReg
.Index
= index
;
356 for(unsigned int src
= 0; src
< opcode
->NumSrcRegs
; ++src
) {
357 rc_register_file file
= inst
->SrcReg
[src
].File
;
358 unsigned int index
= inst
->SrcReg
[src
].Index
;
360 if (file
== RC_FILE_PRESUB
) {
362 unsigned int srcp_srcs
= rc_presubtract_src_reg_count(
363 inst
->PreSub
.Opcode
);
364 /* Make sure we only remap presubtract sources once in
365 * case more than one source register reads the
366 * presubtract result. */
370 for(i
= 0; i
< srcp_srcs
; i
++) {
371 file
= inst
->PreSub
.SrcReg
[i
].File
;
372 index
= inst
->PreSub
.SrcReg
[i
].Index
;
373 cb(userdata
, fullinst
, &file
, &index
);
374 inst
->PreSub
.SrcReg
[i
].File
= file
;
375 inst
->PreSub
.SrcReg
[i
].Index
= index
;
380 cb(userdata
, fullinst
, &file
, &index
);
382 inst
->SrcReg
[src
].File
= file
;
383 inst
->SrcReg
[src
].Index
= index
;
388 static void remap_pair_instruction(struct rc_instruction
* fullinst
,
389 rc_remap_register_fn cb
, void * userdata
)
391 struct rc_pair_instruction
* inst
= &fullinst
->U
.P
;
393 if (inst
->RGB
.WriteMask
) {
394 rc_register_file file
= RC_FILE_TEMPORARY
;
395 unsigned int index
= inst
->RGB
.DestIndex
;
397 cb(userdata
, fullinst
, &file
, &index
);
399 inst
->RGB
.DestIndex
= index
;
402 if (inst
->Alpha
.WriteMask
) {
403 rc_register_file file
= RC_FILE_TEMPORARY
;
404 unsigned int index
= inst
->Alpha
.DestIndex
;
406 cb(userdata
, fullinst
, &file
, &index
);
408 inst
->Alpha
.DestIndex
= index
;
411 for(unsigned int src
= 0; src
< 3; ++src
) {
412 if (inst
->RGB
.Src
[src
].Used
) {
413 rc_register_file file
= inst
->RGB
.Src
[src
].File
;
414 unsigned int index
= inst
->RGB
.Src
[src
].Index
;
416 cb(userdata
, fullinst
, &file
, &index
);
418 inst
->RGB
.Src
[src
].File
= file
;
419 inst
->RGB
.Src
[src
].Index
= index
;
422 if (inst
->Alpha
.Src
[src
].Used
) {
423 rc_register_file file
= inst
->Alpha
.Src
[src
].File
;
424 unsigned int index
= inst
->Alpha
.Src
[src
].Index
;
426 cb(userdata
, fullinst
, &file
, &index
);
428 inst
->Alpha
.Src
[src
].File
= file
;
429 inst
->Alpha
.Src
[src
].Index
= index
;
436 * Remap all register accesses according to the given function.
437 * That is, call the function \p cb for each referenced register (both read and written)
438 * and update the given instruction \p inst accordingly
439 * if it modifies its \ref pfile and \ref pindex contents.
441 void rc_remap_registers(struct rc_instruction
* inst
, rc_remap_register_fn cb
, void * userdata
)
443 if (inst
->Type
== RC_INSTRUCTION_NORMAL
)
444 remap_normal_instruction(inst
, cb
, userdata
);
446 remap_pair_instruction(inst
, cb
, userdata
);
450 * @return RC_OPCODE_NOOP if inst is not a flow control instruction.
451 * @return The opcode of inst if it is a flow control instruction.
453 static rc_opcode
get_flow_control_inst(struct rc_instruction
* inst
)
455 const struct rc_opcode_info
* info
;
456 if (inst
->Type
== RC_INSTRUCTION_NORMAL
) {
457 info
= rc_get_opcode_info(inst
->U
.I
.Opcode
);
459 info
= rc_get_opcode_info(inst
->U
.P
.RGB
.Opcode
);
460 /*A flow control instruction shouldn't have an alpha
462 assert(!info
->IsFlowControl
||
463 inst
->U
.P
.Alpha
.Opcode
== RC_OPCODE_NOP
);
466 if (info
->IsFlowControl
)
469 return RC_OPCODE_NOP
;
473 struct branch_write_mask
{
474 unsigned int IfWriteMask
:4;
475 unsigned int ElseWriteMask
:4;
476 unsigned int HasElse
:1;
479 union get_readers_read_cb
{
481 rc_pair_read_arg_fn P
;
484 struct get_readers_callback_data
{
485 struct radeon_compiler
* C
;
486 struct rc_reader_data
* ReaderData
;
487 rc_read_src_fn ReadNormalCB
;
488 rc_pair_read_arg_fn ReadPairCB
;
489 rc_read_write_mask_fn WriteCB
;
490 rc_register_file DstFile
;
491 unsigned int DstIndex
;
492 unsigned int DstMask
;
493 unsigned int AliveWriteMask
;
494 /* For convenience, this is indexed starting at 1 */
495 struct branch_write_mask BranchMasks
[R500_PFS_MAX_BRANCH_DEPTH_FULL
+ 1];
498 static void add_reader(
499 struct memory_pool
* pool
,
500 struct rc_reader_data
* data
,
501 struct rc_instruction
* inst
,
505 struct rc_reader
* new;
506 memory_pool_array_reserve(pool
, struct rc_reader
, data
->Readers
,
507 data
->ReaderCount
, data
->ReadersReserved
, 1);
508 new = &data
->Readers
[data
->ReaderCount
++];
510 new->WriteMask
= mask
;
511 if (inst
->Type
== RC_INSTRUCTION_NORMAL
) {
512 new->U
.Src
= arg_or_src
;
514 new->U
.Arg
= arg_or_src
;
518 static unsigned int get_readers_read_callback(
519 struct get_readers_callback_data
* cb_data
,
520 unsigned int has_rel_addr
,
521 rc_register_file file
,
523 unsigned int swizzle
)
525 unsigned int shared_mask
, read_mask
;
528 cb_data
->ReaderData
->Abort
= 1;
532 shared_mask
= rc_src_reads_dst_mask(file
, index
, swizzle
,
533 cb_data
->DstFile
, cb_data
->DstIndex
, cb_data
->AliveWriteMask
);
535 if (shared_mask
== RC_MASK_NONE
)
538 /* If we make it this far, it means that this source reads from the
539 * same register written to by d->ReaderData->Writer. */
541 read_mask
= rc_swizzle_to_writemask(swizzle
);
542 if (cb_data
->ReaderData
->AbortOnRead
& read_mask
) {
543 cb_data
->ReaderData
->Abort
= 1;
547 /* XXX The behavior in this case should be configurable. */
548 if ((read_mask
& cb_data
->AliveWriteMask
) != read_mask
) {
549 cb_data
->ReaderData
->Abort
= 1;
556 static void get_readers_pair_read_callback(
558 struct rc_instruction
* inst
,
559 struct rc_pair_instruction_arg
* arg
,
560 struct rc_pair_instruction_source
* src
)
562 unsigned int shared_mask
;
563 struct get_readers_callback_data
* d
= userdata
;
565 shared_mask
= get_readers_read_callback(d
,
566 0 /*Pair Instructions don't use RelAddr*/,
567 src
->File
, src
->Index
, arg
->Swizzle
);
569 if (shared_mask
== RC_MASK_NONE
)
573 d
->ReadPairCB(d
->ReaderData
, inst
, arg
, src
);
575 if (d
->ReaderData
->Abort
)
578 add_reader(&d
->C
->Pool
, d
->ReaderData
, inst
, shared_mask
, arg
);
582 * This function is used by rc_get_readers_normal() to determine whether inst
583 * is a reader of userdata->ReaderData->Writer
585 static void get_readers_normal_read_callback(
587 struct rc_instruction
* inst
,
588 struct rc_src_register
* src
)
590 struct get_readers_callback_data
* d
= userdata
;
591 unsigned int shared_mask
;
593 shared_mask
= get_readers_read_callback(d
,
594 src
->RelAddr
, src
->File
, src
->Index
, src
->Swizzle
);
596 if (shared_mask
== RC_MASK_NONE
)
598 /* The callback function could potentially clear d->ReaderData->Abort,
599 * so we need to call it before we return. */
601 d
->ReadNormalCB(d
->ReaderData
, inst
, src
);
603 if (d
->ReaderData
->Abort
)
606 add_reader(&d
->C
->Pool
, d
->ReaderData
, inst
, shared_mask
, src
);
610 * This function is used by rc_get_readers_normal() to determine when
611 * userdata->ReaderData->Writer is dead (i. e. All compontents of its
612 * destination register have been overwritten by other instructions).
614 static void get_readers_write_callback(
616 struct rc_instruction
* inst
,
617 rc_register_file file
,
621 struct get_readers_callback_data
* d
= userdata
;
623 if (index
== d
->DstIndex
&& file
== d
->DstFile
) {
624 unsigned int shared_mask
= mask
& d
->DstMask
;
625 d
->ReaderData
->AbortOnRead
&= ~shared_mask
;
626 d
->AliveWriteMask
&= ~shared_mask
;
630 d
->WriteCB(d
->ReaderData
, inst
, file
, index
, mask
);
633 static void get_readers_for_single_write(
635 struct rc_instruction
* writer
,
636 rc_register_file dst_file
,
637 unsigned int dst_index
,
638 unsigned int dst_mask
)
640 struct rc_instruction
* tmp
;
641 unsigned int branch_depth
= 0;
642 struct get_readers_callback_data
* d
= userdata
;
644 d
->ReaderData
->Writer
= writer
;
645 d
->ReaderData
->AbortOnRead
= 0;
646 d
->ReaderData
->InElse
= 0;
647 d
->DstFile
= dst_file
;
648 d
->DstIndex
= dst_index
;
649 d
->DstMask
= dst_mask
;
650 d
->AliveWriteMask
= dst_mask
;
651 memset(d
->BranchMasks
, 0, sizeof(d
->BranchMasks
));
656 for(tmp
= writer
->Next
; tmp
!= &d
->C
->Program
.Instructions
;
658 rc_opcode opcode
= get_flow_control_inst(tmp
);
660 case RC_OPCODE_BGNLOOP
:
661 /* XXX We can do better when we see a BGNLOOP if we
662 * add a flag called AbortOnWrite to struct
663 * rc_reader_data and leave it set until the next
665 case RC_OPCODE_ENDLOOP
:
666 /* XXX We can do better when we see an ENDLOOP by
667 * searching backwards from writer and looking for
668 * readers of writer's destination index. If we find a
669 * reader before we get to the BGNLOOP, we must abort
670 * unless there is another writer between that reader
671 * and the BGNLOOP. */
674 d
->ReaderData
->Abort
= 1;
678 if (branch_depth
> R500_PFS_MAX_BRANCH_DEPTH_FULL
) {
679 d
->ReaderData
->Abort
= 1;
682 d
->BranchMasks
[branch_depth
].IfWriteMask
=
686 if (branch_depth
== 0) {
687 d
->ReaderData
->InElse
= 1;
689 unsigned int temp_mask
= d
->AliveWriteMask
;
691 d
->BranchMasks
[branch_depth
].IfWriteMask
;
692 d
->BranchMasks
[branch_depth
].ElseWriteMask
=
694 d
->BranchMasks
[branch_depth
].HasElse
= 1;
697 case RC_OPCODE_ENDIF
:
698 if (branch_depth
== 0) {
699 d
->ReaderData
->AbortOnRead
= d
->AliveWriteMask
;
700 d
->ReaderData
->InElse
= 0;
703 struct branch_write_mask
* masks
=
704 &d
->BranchMasks
[branch_depth
];
706 if (masks
->HasElse
) {
707 d
->ReaderData
->AbortOnRead
|=
709 & ~masks
->ElseWriteMask
;
710 d
->AliveWriteMask
= masks
->IfWriteMask
711 ^ ((masks
->IfWriteMask
^
712 masks
->ElseWriteMask
)
713 & (masks
->IfWriteMask
714 ^ d
->AliveWriteMask
));
716 d
->ReaderData
->AbortOnRead
|=
718 & ~d
->AliveWriteMask
;
719 d
->AliveWriteMask
= masks
->IfWriteMask
;
723 sizeof(struct branch_write_mask
));
731 if (d
->ReaderData
->InElse
)
734 if (tmp
->Type
== RC_INSTRUCTION_NORMAL
) {
735 rc_for_all_reads_src(tmp
,
736 get_readers_normal_read_callback
, d
);
738 rc_pair_for_all_reads_arg(tmp
,
739 get_readers_pair_read_callback
, d
);
741 rc_for_all_writes_mask(tmp
, get_readers_write_callback
, d
);
743 if (d
->ReaderData
->Abort
)
746 if (branch_depth
== 0 && !d
->AliveWriteMask
)
752 * This function will create a list of readers via the rc_reader_data struct.
753 * This function will abort (set the flag data->Abort) and return if it
754 * encounters an instruction that reads from @param writer and also a different
755 * instruction. Here are some examples:
757 * writer = instruction 0;
758 * 0 MOV TEMP[0].xy, TEMP[1].xy
759 * 1 MOV TEMP[0].zw, TEMP[2].xy
760 * 2 MOV TEMP[3], TEMP[0]
761 * The Abort flag will be set on instruction 2, because it reads values written
762 * by instructions 0 and 1.
764 * writer = instruction 1;
766 * 1 MOV TEMP[1], TEMP[2]
768 * 3 MOV TEMP[1], TEMP[2]
770 * 5 MOV TEMP[3], TEMP[1]
771 * The Abort flag will be set on instruction 5, because it could read from the
772 * value written by either instruction 1 or 3, depending on the jump decision
773 * made at instruction 0.
775 * writer = instruction 0;
776 * 0 MOV TEMP[0], TEMP[1]
778 * 3 ADD TEMP[0], TEMP[0], none.1
780 * The Abort flag will be set on instruction 3, because in the first iteration
781 * of the loop it reads the value written by instruction 0 and in all other
782 * iterations it reads the value written by instruction 3.
784 * @param read_cb This function will be called for for every instruction that
785 * has been determined to be a reader of writer.
786 * @param write_cb This function will be called for every instruction after
790 struct radeon_compiler
* c
,
791 struct rc_instruction
* writer
,
792 struct rc_reader_data
* data
,
793 rc_read_src_fn read_normal_cb
,
794 rc_pair_read_arg_fn read_pair_cb
,
795 rc_read_write_mask_fn write_cb
)
797 struct get_readers_callback_data d
;
800 data
->ReaderCount
= 0;
801 data
->ReadersReserved
= 0;
802 data
->Readers
= NULL
;
806 d
.ReadNormalCB
= read_normal_cb
;
807 d
.ReadPairCB
= read_pair_cb
;
808 d
.WriteCB
= write_cb
;
810 rc_for_all_writes_mask(writer
, get_readers_for_single_write
, &d
);