Merge remote branch 'origin/mesa_7_6_branch'
[mesa.git] / src / mesa / drivers / dri / r300 / compiler / radeon_dataflow.c
1 /*
2 * Copyright (C) 2009 Nicolai Haehnle.
3 *
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial
16 * portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
22 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 */
27
28 #include "radeon_dataflow.h"
29
30 #include "radeon_program.h"
31
32
33 static void reads_normal(struct rc_instruction * fullinst, rc_read_write_fn cb, void * userdata)
34 {
35 struct rc_sub_instruction * inst = &fullinst->U.I;
36 const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->Opcode);
37
38 for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src) {
39 unsigned int refmask = 0;
40
41 if (inst->SrcReg[src].File == RC_FILE_NONE)
42 return;
43
44 for(unsigned int chan = 0; chan < 4; ++chan)
45 refmask |= 1 << GET_SWZ(inst->SrcReg[src].Swizzle, chan);
46
47 refmask &= RC_MASK_XYZW;
48
49 for(unsigned int chan = 0; chan < 4; ++chan) {
50 if (GET_BIT(refmask, chan)) {
51 cb(userdata, fullinst, inst->SrcReg[src].File, inst->SrcReg[src].Index, chan);
52 }
53 }
54
55 if (refmask && inst->SrcReg[src].RelAddr)
56 cb(userdata, fullinst, RC_FILE_ADDRESS, 0, RC_MASK_X);
57 }
58 }
59
60 static void reads_pair(struct rc_instruction * fullinst, rc_read_write_fn cb, void * userdata)
61 {
62 struct rc_pair_instruction * inst = &fullinst->U.P;
63 unsigned int refmasks[3] = { 0, 0, 0 };
64
65 if (inst->RGB.Opcode != RC_OPCODE_NOP) {
66 const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->RGB.Opcode);
67
68 for(unsigned int arg = 0; arg < opcode->NumSrcRegs; ++arg) {
69 for(unsigned int chan = 0; chan < 3; ++chan) {
70 unsigned int swz = GET_SWZ(inst->RGB.Arg[arg].Swizzle, chan);
71 if (swz < 4)
72 refmasks[inst->RGB.Arg[arg].Source] |= 1 << swz;
73 }
74 }
75 }
76
77 if (inst->Alpha.Opcode != RC_OPCODE_NOP) {
78 const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->Alpha.Opcode);
79
80 for(unsigned int arg = 0; arg < opcode->NumSrcRegs; ++arg) {
81 if (inst->Alpha.Arg[arg].Swizzle < 4)
82 refmasks[inst->Alpha.Arg[arg].Source] |= 1 << inst->Alpha.Arg[arg].Swizzle;
83 }
84 }
85
86 for(unsigned int src = 0; src < 3; ++src) {
87 if (inst->RGB.Src[src].Used) {
88 for(unsigned int chan = 0; chan < 3; ++chan) {
89 if (GET_BIT(refmasks[src], chan))
90 cb(userdata, fullinst, inst->RGB.Src[src].File, inst->RGB.Src[src].Index, chan);
91 }
92 }
93
94 if (inst->Alpha.Src[src].Used) {
95 if (GET_BIT(refmasks[src], 3))
96 cb(userdata, fullinst, inst->Alpha.Src[src].File, inst->Alpha.Src[src].Index, 3);
97 }
98 }
99 }
100
101 /**
102 * Calls a callback function for all sourced register channels.
103 *
104 * This is conservative, i.e. channels may be called multiple times,
105 * and the writemask of the instruction is not taken into account.
106 */
107 void rc_for_all_reads(struct rc_instruction * inst, rc_read_write_fn cb, void * userdata)
108 {
109 if (inst->Type == RC_INSTRUCTION_NORMAL) {
110 reads_normal(inst, cb, userdata);
111 } else {
112 reads_pair(inst, cb, userdata);
113 }
114 }
115
116
117
118 static void writes_normal(struct rc_instruction * fullinst, rc_read_write_fn cb, void * userdata)
119 {
120 struct rc_sub_instruction * inst = &fullinst->U.I;
121 const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->Opcode);
122
123 if (opcode->HasDstReg) {
124 for(unsigned int chan = 0; chan < 4; ++chan) {
125 if (GET_BIT(inst->DstReg.WriteMask, chan))
126 cb(userdata, fullinst, inst->DstReg.File, inst->DstReg.Index, chan);
127 }
128 }
129
130 if (inst->WriteALUResult)
131 cb(userdata, fullinst, RC_FILE_SPECIAL, RC_SPECIAL_ALU_RESULT, 0);
132 }
133
134 static void writes_pair(struct rc_instruction * fullinst, rc_read_write_fn cb, void * userdata)
135 {
136 struct rc_pair_instruction * inst = &fullinst->U.P;
137
138 for(unsigned int chan = 0; chan < 3; ++chan) {
139 if (GET_BIT(inst->RGB.WriteMask, chan))
140 cb(userdata, fullinst, RC_FILE_TEMPORARY, inst->RGB.DestIndex, chan);
141 }
142
143 if (inst->Alpha.WriteMask)
144 cb(userdata, fullinst, RC_FILE_TEMPORARY, inst->Alpha.DestIndex, 3);
145
146 if (inst->WriteALUResult)
147 cb(userdata, fullinst, RC_FILE_SPECIAL, RC_SPECIAL_ALU_RESULT, 0);
148 }
149
150 /**
151 * Calls a callback function for all written register channels.
152 *
153 * \warning Does not report output registers for paired instructions!
154 */
155 void rc_for_all_writes(struct rc_instruction * inst, rc_read_write_fn cb, void * userdata)
156 {
157 if (inst->Type == RC_INSTRUCTION_NORMAL) {
158 writes_normal(inst, cb, userdata);
159 } else {
160 writes_pair(inst, cb, userdata);
161 }
162 }