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
;
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
],
171 struct rc_pair_instruction_source
* src
=
172 rc_pair_get_src(&fullinst
->U
.P
, &sub
->Arg
[i
]);
174 cb(userdata
, fullinst
, &sub
->Arg
[i
], src
);
180 /* This function calls the callback function (cb) for each source used by
183 void rc_for_all_reads_src(
184 struct rc_instruction
* inst
,
188 const struct rc_opcode_info
* opcode
=
189 rc_get_opcode_info(inst
->U
.I
.Opcode
);
191 /* This function only works with normal instructions. */
192 if (inst
->Type
!= RC_INSTRUCTION_NORMAL
) {
197 for(unsigned int src
= 0; src
< opcode
->NumSrcRegs
; ++src
) {
199 if (inst
->U
.I
.SrcReg
[src
].File
== RC_FILE_NONE
)
202 if (inst
->U
.I
.SrcReg
[src
].File
== RC_FILE_PRESUB
) {
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
]);
210 cb(userdata
, inst
, &inst
->U
.I
.SrcReg
[src
]);
216 * This function calls the callback function (cb) for each arg of the RGB and
219 void rc_pair_for_all_reads_arg(
220 struct rc_instruction
* inst
,
221 rc_pair_read_arg_fn cb
,
224 /* This function only works with pair instructions. */
225 if (inst
->Type
!= RC_INSTRUCTION_PAIR
) {
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
);
235 * Calls a callback function for all register reads.
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.
241 void rc_for_all_reads_mask(struct rc_instruction
* inst
, rc_read_write_mask_fn cb
, void * userdata
)
243 if (inst
->Type
== RC_INSTRUCTION_NORMAL
) {
244 struct read_write_mask_data cb_data
;
245 cb_data
.UserData
= userdata
;
248 rc_for_all_reads_src(inst
, reads_normal_callback
, &cb_data
);
250 reads_pair(inst
, cb
, userdata
);
256 static void writes_normal(struct rc_instruction
* fullinst
, rc_read_write_mask_fn cb
, void * userdata
)
258 struct rc_sub_instruction
* inst
= &fullinst
->U
.I
;
259 const struct rc_opcode_info
* opcode
= rc_get_opcode_info(inst
->Opcode
);
261 if (opcode
->HasDstReg
&& inst
->DstReg
.WriteMask
)
262 cb(userdata
, fullinst
, inst
->DstReg
.File
, inst
->DstReg
.Index
, inst
->DstReg
.WriteMask
);
264 if (inst
->WriteALUResult
)
265 cb(userdata
, fullinst
, RC_FILE_SPECIAL
, RC_SPECIAL_ALU_RESULT
, RC_MASK_X
);
268 static void writes_pair(struct rc_instruction
* fullinst
, rc_read_write_mask_fn cb
, void * userdata
)
270 struct rc_pair_instruction
* inst
= &fullinst
->U
.P
;
272 if (inst
->RGB
.WriteMask
)
273 cb(userdata
, fullinst
, RC_FILE_TEMPORARY
, inst
->RGB
.DestIndex
, inst
->RGB
.WriteMask
);
275 if (inst
->Alpha
.WriteMask
)
276 cb(userdata
, fullinst
, RC_FILE_TEMPORARY
, inst
->Alpha
.DestIndex
, RC_MASK_W
);
278 if (inst
->WriteALUResult
)
279 cb(userdata
, fullinst
, RC_FILE_SPECIAL
, RC_SPECIAL_ALU_RESULT
, RC_MASK_X
);
283 * Calls a callback function for all register writes in the instruction,
284 * reporting writemasks to the callback function.
286 * \warning Does not report output registers for paired instructions!
288 void rc_for_all_writes_mask(struct rc_instruction
* inst
, rc_read_write_mask_fn cb
, void * userdata
)
290 if (inst
->Type
== RC_INSTRUCTION_NORMAL
) {
291 writes_normal(inst
, cb
, userdata
);
293 writes_pair(inst
, cb
, userdata
);
298 struct mask_to_chan_data
{
300 rc_read_write_chan_fn Fn
;
303 static void mask_to_chan_cb(void * data
, struct rc_instruction
* inst
,
304 rc_register_file file
, unsigned int index
, unsigned int mask
)
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
);
314 * Calls a callback function for all sourced register channels.
316 * This is conservative, i.e. channels may be called multiple times,
317 * and the writemask of the instruction is not taken into account.
319 void rc_for_all_reads_chan(struct rc_instruction
* inst
, rc_read_write_chan_fn cb
, void * userdata
)
321 struct mask_to_chan_data d
;
322 d
.UserData
= userdata
;
324 rc_for_all_reads_mask(inst
, &mask_to_chan_cb
, &d
);
328 * Calls a callback function for all written register channels.
330 * \warning Does not report output registers for paired instructions!
332 void rc_for_all_writes_chan(struct rc_instruction
* inst
, rc_read_write_chan_fn cb
, void * userdata
)
334 struct mask_to_chan_data d
;
335 d
.UserData
= userdata
;
337 rc_for_all_writes_mask(inst
, &mask_to_chan_cb
, &d
);
340 static void remap_normal_instruction(struct rc_instruction
* fullinst
,
341 rc_remap_register_fn cb
, void * userdata
)
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;
347 if (opcode
->HasDstReg
) {
348 rc_register_file file
= inst
->DstReg
.File
;
349 unsigned int index
= inst
->DstReg
.Index
;
351 cb(userdata
, fullinst
, &file
, &index
);
353 inst
->DstReg
.File
= file
;
354 inst
->DstReg
.Index
= index
;
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
;
361 if (file
== RC_FILE_PRESUB
) {
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. */
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
;
381 cb(userdata
, fullinst
, &file
, &index
);
383 inst
->SrcReg
[src
].File
= file
;
384 inst
->SrcReg
[src
].Index
= index
;
389 static void remap_pair_instruction(struct rc_instruction
* fullinst
,
390 rc_remap_register_fn cb
, void * userdata
)
392 struct rc_pair_instruction
* inst
= &fullinst
->U
.P
;
394 if (inst
->RGB
.WriteMask
) {
395 rc_register_file file
= RC_FILE_TEMPORARY
;
396 unsigned int index
= inst
->RGB
.DestIndex
;
398 cb(userdata
, fullinst
, &file
, &index
);
400 inst
->RGB
.DestIndex
= index
;
403 if (inst
->Alpha
.WriteMask
) {
404 rc_register_file file
= RC_FILE_TEMPORARY
;
405 unsigned int index
= inst
->Alpha
.DestIndex
;
407 cb(userdata
, fullinst
, &file
, &index
);
409 inst
->Alpha
.DestIndex
= index
;
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
;
417 cb(userdata
, fullinst
, &file
, &index
);
419 inst
->RGB
.Src
[src
].File
= file
;
420 inst
->RGB
.Src
[src
].Index
= index
;
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
;
427 cb(userdata
, fullinst
, &file
, &index
);
429 inst
->Alpha
.Src
[src
].File
= file
;
430 inst
->Alpha
.Src
[src
].Index
= index
;
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.
442 void rc_remap_registers(struct rc_instruction
* inst
, rc_remap_register_fn cb
, void * userdata
)
444 if (inst
->Type
== RC_INSTRUCTION_NORMAL
)
445 remap_normal_instruction(inst
, cb
, userdata
);
447 remap_pair_instruction(inst
, cb
, userdata
);
450 struct branch_write_mask
{
451 unsigned int IfWriteMask
:4;
452 unsigned int ElseWriteMask
:4;
453 unsigned int HasElse
:1;
456 union get_readers_read_cb
{
458 rc_pair_read_arg_fn P
;
461 struct 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];
475 static struct rc_reader
* add_reader(
476 struct memory_pool
* pool
,
477 struct rc_reader_data
* data
,
478 struct rc_instruction
* inst
,
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
++];
486 new->WriteMask
= mask
;
490 static void add_reader_normal(
491 struct memory_pool
* pool
,
492 struct rc_reader_data
* data
,
493 struct rc_instruction
* inst
,
495 struct rc_src_register
* src
)
497 struct rc_reader
* new = add_reader(pool
, data
, inst
, mask
);
502 static void add_reader_pair(
503 struct memory_pool
* pool
,
504 struct rc_reader_data
* data
,
505 struct rc_instruction
* inst
,
507 struct rc_pair_instruction_arg
* arg
,
508 struct rc_pair_instruction_source
* src
)
510 struct rc_reader
* new = add_reader(pool
, data
, inst
, mask
);
515 static 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
,
520 unsigned int swizzle
)
522 unsigned int shared_mask
, read_mask
;
525 cb_data
->ReaderData
->Abort
= 1;
529 shared_mask
= rc_src_reads_dst_mask(file
, index
, swizzle
,
530 cb_data
->DstFile
, cb_data
->DstIndex
, cb_data
->AliveWriteMask
);
532 if (shared_mask
== RC_MASK_NONE
)
535 /* If we make it this far, it means that this source reads from the
536 * same register written to by d->ReaderData->Writer. */
538 read_mask
= rc_swizzle_to_writemask(swizzle
);
539 if (cb_data
->ReaderData
->AbortOnRead
& read_mask
) {
540 cb_data
->ReaderData
->Abort
= 1;
544 if (cb_data
->ReaderData
->LoopDepth
> 0) {
545 cb_data
->ReaderData
->AbortOnWrite
|=
546 (read_mask
& cb_data
->AliveWriteMask
);
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;
558 static void get_readers_pair_read_callback(
560 struct rc_instruction
* inst
,
561 struct rc_pair_instruction_arg
* arg
,
562 struct rc_pair_instruction_source
* src
)
564 unsigned int shared_mask
;
565 struct get_readers_callback_data
* d
= userdata
;
567 shared_mask
= get_readers_read_callback(d
,
568 0 /*Pair Instructions don't use RelAddr*/,
569 src
->File
, src
->Index
, arg
->Swizzle
);
571 if (shared_mask
== RC_MASK_NONE
)
575 d
->ReadPairCB(d
->ReaderData
, inst
, arg
, src
);
577 if (d
->ReaderData
->ExitOnAbort
&& d
->ReaderData
->Abort
)
580 add_reader_pair(&d
->C
->Pool
, d
->ReaderData
, inst
, shared_mask
, arg
, src
);
584 * This function is used by rc_get_readers_normal() to determine whether inst
585 * is a reader of userdata->ReaderData->Writer
587 static void get_readers_normal_read_callback(
589 struct rc_instruction
* inst
,
590 struct rc_src_register
* src
)
592 struct get_readers_callback_data
* d
= userdata
;
593 unsigned int shared_mask
;
595 shared_mask
= get_readers_read_callback(d
,
596 src
->RelAddr
, src
->File
, src
->Index
, src
->Swizzle
);
598 if (shared_mask
== RC_MASK_NONE
)
600 /* The callback function could potentially clear d->ReaderData->Abort,
601 * so we need to call it before we return. */
603 d
->ReadNormalCB(d
->ReaderData
, inst
, src
);
605 if (d
->ReaderData
->ExitOnAbort
&& d
->ReaderData
->Abort
)
608 add_reader_normal(&d
->C
->Pool
, d
->ReaderData
, inst
, shared_mask
, src
);
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).
616 static void get_readers_write_callback(
618 struct rc_instruction
* inst
,
619 rc_register_file file
,
623 struct get_readers_callback_data
* d
= userdata
;
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;
635 d
->WriteCB(d
->ReaderData
, inst
, file
, index
, mask
);
638 static void push_branch_mask(
639 struct get_readers_callback_data
* d
,
640 unsigned int * branch_depth
)
643 if (*branch_depth
> R500_PFS_MAX_BRANCH_DEPTH_FULL
) {
644 d
->ReaderData
->Abort
= 1;
647 d
->BranchMasks
[*branch_depth
].IfWriteMask
=
651 static void pop_branch_mask(
652 struct get_readers_callback_data
* d
,
653 unsigned int * branch_depth
)
655 struct branch_write_mask
* masks
= &d
->BranchMasks
[*branch_depth
];
657 if (masks
->HasElse
) {
658 /* Abort on read for components that were written in the IF
660 d
->ReaderData
->AbortOnRead
|=
661 masks
->IfWriteMask
& ~masks
->ElseWriteMask
;
662 /* Abort on read for components that were written in the ELSE
664 d
->ReaderData
->AbortOnRead
|=
665 masks
->ElseWriteMask
& ~d
->AliveWriteMask
;
667 d
->AliveWriteMask
= masks
->IfWriteMask
668 ^ ((masks
->IfWriteMask
^ masks
->ElseWriteMask
)
669 & (masks
->IfWriteMask
^ d
->AliveWriteMask
));
671 d
->ReaderData
->AbortOnRead
|=
672 masks
->IfWriteMask
& ~d
->AliveWriteMask
;
673 d
->AliveWriteMask
= masks
->IfWriteMask
;
676 memset(masks
, 0, sizeof(struct branch_write_mask
));
680 static void get_readers_for_single_write(
682 struct rc_instruction
* writer
,
683 rc_register_file dst_file
,
684 unsigned int dst_index
,
685 unsigned int dst_mask
)
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
;
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
));
707 for(tmp
= writer
->Next
; tmp
!= &d
->C
->Program
.Instructions
;
709 rc_opcode opcode
= rc_get_flow_control_inst(tmp
);
711 case RC_OPCODE_BGNLOOP
:
712 d
->ReaderData
->LoopDepth
++;
713 push_branch_mask(d
, &branch_depth
);
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;
721 pop_branch_mask(d
, &branch_depth
);
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.
733 tmp
= rc_match_endloop(tmp
);
735 rc_error(d
->C
, "Failed to match endloop.\n");
736 d
->ReaderData
->Abort
= 1;
739 abort_on_read_at_endloop
= d
->ReaderData
->AbortOnRead
;
740 d
->ReaderData
->AbortOnRead
|= d
->AliveWriteMask
;
745 push_branch_mask(d
, &branch_depth
);
748 if (branch_depth
== 0) {
749 d
->ReaderData
->InElse
= 1;
751 unsigned int temp_mask
= d
->AliveWriteMask
;
753 d
->BranchMasks
[branch_depth
].IfWriteMask
;
754 d
->BranchMasks
[branch_depth
].ElseWriteMask
=
756 d
->BranchMasks
[branch_depth
].HasElse
= 1;
759 case RC_OPCODE_ENDIF
:
760 if (branch_depth
== 0) {
761 d
->ReaderData
->AbortOnRead
= d
->AliveWriteMask
;
762 d
->ReaderData
->InElse
= 0;
765 pop_branch_mask(d
, &branch_depth
);
772 if (d
->ReaderData
->InElse
)
775 if (tmp
->Type
== RC_INSTRUCTION_NORMAL
) {
776 rc_for_all_reads_src(tmp
,
777 get_readers_normal_read_callback
, d
);
779 rc_pair_for_all_reads_arg(tmp
,
780 get_readers_pair_read_callback
, d
);
783 /* This can happen when we jump from an ENDLOOP to BGNLOOP */
787 d
->ReaderData
->AbortOnRead
= abort_on_read_at_endloop
;
790 rc_for_all_writes_mask(tmp
, get_readers_write_callback
, d
);
792 if (d
->ReaderData
->ExitOnAbort
&& d
->ReaderData
->Abort
)
795 if (branch_depth
== 0 && !d
->AliveWriteMask
)
800 static 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
)
808 reader_data
->Abort
= 0;
809 reader_data
->ReaderCount
= 0;
810 reader_data
->ReadersReserved
= 0;
811 reader_data
->Readers
= NULL
;
814 d
->ReaderData
= reader_data
;
815 d
->ReadNormalCB
= read_normal_cb
;
816 d
->ReadPairCB
= read_pair_cb
;
817 d
->WriteCB
= write_cb
;
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:
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.
833 * writer = instruction 1;
835 * 1 MOV TEMP[1], TEMP[2]
837 * 3 MOV TEMP[1], TEMP[2]
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.
844 * writer = instruction 0;
845 * 0 MOV TEMP[0], TEMP[1]
847 * 3 ADD TEMP[0], TEMP[0], none.1
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.
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
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
)
866 struct get_readers_callback_data d
;
868 init_get_readers_callback_data(&d
, data
, c
, read_normal_cb
,
869 read_pair_cb
, write_cb
);
871 rc_for_all_writes_mask(writer
, get_readers_for_single_write
, &d
);
874 void 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
)
883 struct get_readers_callback_data d
;
885 init_get_readers_callback_data(&d
, data
, c
, read_normal_cb
,
886 read_pair_cb
, write_cb
);
888 if (sub_writer
->WriteMask
) {
889 get_readers_for_single_write(&d
, writer
, RC_FILE_TEMPORARY
,
890 sub_writer
->DestIndex
, sub_writer
->WriteMask
);