r300/compiler: Don't unroll loops with continue or break.
[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_chan_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 if (refmask)
50 cb(userdata, fullinst, inst->SrcReg[src].File, inst->SrcReg[src].Index, refmask);
51
52 if (refmask && inst->SrcReg[src].RelAddr)
53 cb(userdata, fullinst, RC_FILE_ADDRESS, 0, RC_MASK_X);
54 }
55 }
56
57 static void reads_pair(struct rc_instruction * fullinst, rc_read_write_mask_fn cb, void * userdata)
58 {
59 struct rc_pair_instruction * inst = &fullinst->U.P;
60 unsigned int refmasks[3] = { 0, 0, 0 };
61
62 if (inst->RGB.Opcode != RC_OPCODE_NOP) {
63 const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->RGB.Opcode);
64
65 for(unsigned int arg = 0; arg < opcode->NumSrcRegs; ++arg) {
66 for(unsigned int chan = 0; chan < 3; ++chan) {
67 unsigned int swz = GET_SWZ(inst->RGB.Arg[arg].Swizzle, chan);
68 if (swz < 4)
69 refmasks[inst->RGB.Arg[arg].Source] |= 1 << swz;
70 }
71 }
72 }
73
74 if (inst->Alpha.Opcode != RC_OPCODE_NOP) {
75 const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->Alpha.Opcode);
76
77 for(unsigned int arg = 0; arg < opcode->NumSrcRegs; ++arg) {
78 if (inst->Alpha.Arg[arg].Swizzle < 4)
79 refmasks[inst->Alpha.Arg[arg].Source] |= 1 << inst->Alpha.Arg[arg].Swizzle;
80 }
81 }
82
83 for(unsigned int src = 0; src < 3; ++src) {
84 if (inst->RGB.Src[src].Used && (refmasks[src] & RC_MASK_XYZ))
85 cb(userdata, fullinst, inst->RGB.Src[src].File, inst->RGB.Src[src].Index,
86 refmasks[src] & RC_MASK_XYZ);
87
88 if (inst->Alpha.Src[src].Used && (refmasks[src] & RC_MASK_W))
89 cb(userdata, fullinst, inst->Alpha.Src[src].File, inst->Alpha.Src[src].Index, RC_MASK_W);
90 }
91 }
92
93 /**
94 * Calls a callback function for all register reads.
95 *
96 * This is conservative, i.e. if the same register is referenced multiple times,
97 * the callback may also be called multiple times.
98 * Also, the writemask of the instruction is not taken into account.
99 */
100 void rc_for_all_reads_mask(struct rc_instruction * inst, rc_read_write_mask_fn cb, void * userdata)
101 {
102 if (inst->Type == RC_INSTRUCTION_NORMAL) {
103 reads_normal(inst, cb, userdata);
104 } else {
105 reads_pair(inst, cb, userdata);
106 }
107 }
108
109
110
111 static void writes_normal(struct rc_instruction * fullinst, rc_read_write_mask_fn cb, void * userdata)
112 {
113 struct rc_sub_instruction * inst = &fullinst->U.I;
114 const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->Opcode);
115
116 if (opcode->HasDstReg && inst->DstReg.WriteMask)
117 cb(userdata, fullinst, inst->DstReg.File, inst->DstReg.Index, inst->DstReg.WriteMask);
118
119 if (inst->WriteALUResult)
120 cb(userdata, fullinst, RC_FILE_SPECIAL, RC_SPECIAL_ALU_RESULT, RC_MASK_X);
121 }
122
123 static void writes_pair(struct rc_instruction * fullinst, rc_read_write_mask_fn cb, void * userdata)
124 {
125 struct rc_pair_instruction * inst = &fullinst->U.P;
126
127 if (inst->RGB.WriteMask)
128 cb(userdata, fullinst, RC_FILE_TEMPORARY, inst->RGB.DestIndex, inst->RGB.WriteMask);
129
130 if (inst->Alpha.WriteMask)
131 cb(userdata, fullinst, RC_FILE_TEMPORARY, inst->Alpha.DestIndex, RC_MASK_W);
132
133 if (inst->WriteALUResult)
134 cb(userdata, fullinst, RC_FILE_SPECIAL, RC_SPECIAL_ALU_RESULT, RC_MASK_X);
135 }
136
137 /**
138 * Calls a callback function for all register writes in the instruction,
139 * reporting writemasks to the callback function.
140 *
141 * \warning Does not report output registers for paired instructions!
142 */
143 void rc_for_all_writes_mask(struct rc_instruction * inst, rc_read_write_mask_fn cb, void * userdata)
144 {
145 if (inst->Type == RC_INSTRUCTION_NORMAL) {
146 writes_normal(inst, cb, userdata);
147 } else {
148 writes_pair(inst, cb, userdata);
149 }
150 }
151
152
153 struct mask_to_chan_data {
154 void * UserData;
155 rc_read_write_chan_fn Fn;
156 };
157
158 static void mask_to_chan_cb(void * data, struct rc_instruction * inst,
159 rc_register_file file, unsigned int index, unsigned int mask)
160 {
161 struct mask_to_chan_data * d = data;
162 for(unsigned int chan = 0; chan < 4; ++chan) {
163 if (GET_BIT(mask, chan))
164 d->Fn(d->UserData, inst, file, index, chan);
165 }
166 }
167
168 /**
169 * Calls a callback function for all sourced register channels.
170 *
171 * This is conservative, i.e. channels may be called multiple times,
172 * and the writemask of the instruction is not taken into account.
173 */
174 void rc_for_all_reads_chan(struct rc_instruction * inst, rc_read_write_chan_fn cb, void * userdata)
175 {
176 struct mask_to_chan_data d;
177 d.UserData = userdata;
178 d.Fn = cb;
179 rc_for_all_reads_mask(inst, &mask_to_chan_cb, &d);
180 }
181
182 /**
183 * Calls a callback function for all written register channels.
184 *
185 * \warning Does not report output registers for paired instructions!
186 */
187 void rc_for_all_writes_chan(struct rc_instruction * inst, rc_read_write_chan_fn cb, void * userdata)
188 {
189 struct mask_to_chan_data d;
190 d.UserData = userdata;
191 d.Fn = cb;
192 rc_for_all_writes_mask(inst, &mask_to_chan_cb, &d);
193 }
194
195 static void remap_normal_instruction(struct rc_instruction * fullinst,
196 rc_remap_register_fn cb, void * userdata)
197 {
198 struct rc_sub_instruction * inst = &fullinst->U.I;
199 const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->Opcode);
200
201 if (opcode->HasDstReg) {
202 rc_register_file file = inst->DstReg.File;
203 unsigned int index = inst->DstReg.Index;
204
205 cb(userdata, fullinst, &file, &index);
206
207 inst->DstReg.File = file;
208 inst->DstReg.Index = index;
209 }
210
211 for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src) {
212 rc_register_file file = inst->SrcReg[src].File;
213 unsigned int index = inst->SrcReg[src].Index;
214
215 cb(userdata, fullinst, &file, &index);
216
217 inst->SrcReg[src].File = file;
218 inst->SrcReg[src].Index = index;
219 }
220 }
221
222 static void remap_pair_instruction(struct rc_instruction * fullinst,
223 rc_remap_register_fn cb, void * userdata)
224 {
225 struct rc_pair_instruction * inst = &fullinst->U.P;
226
227 if (inst->RGB.WriteMask) {
228 rc_register_file file = RC_FILE_TEMPORARY;
229 unsigned int index = inst->RGB.DestIndex;
230
231 cb(userdata, fullinst, &file, &index);
232
233 inst->RGB.DestIndex = index;
234 }
235
236 if (inst->Alpha.WriteMask) {
237 rc_register_file file = RC_FILE_TEMPORARY;
238 unsigned int index = inst->Alpha.DestIndex;
239
240 cb(userdata, fullinst, &file, &index);
241
242 inst->Alpha.DestIndex = index;
243 }
244
245 for(unsigned int src = 0; src < 3; ++src) {
246 if (inst->RGB.Src[src].Used) {
247 rc_register_file file = inst->RGB.Src[src].File;
248 unsigned int index = inst->RGB.Src[src].Index;
249
250 cb(userdata, fullinst, &file, &index);
251
252 inst->RGB.Src[src].File = file;
253 inst->RGB.Src[src].Index = index;
254 }
255
256 if (inst->Alpha.Src[src].Used) {
257 rc_register_file file = inst->Alpha.Src[src].File;
258 unsigned int index = inst->Alpha.Src[src].Index;
259
260 cb(userdata, fullinst, &file, &index);
261
262 inst->Alpha.Src[src].File = file;
263 inst->Alpha.Src[src].Index = index;
264 }
265 }
266 }
267
268
269 /**
270 * Remap all register accesses according to the given function.
271 * That is, call the function \p cb for each referenced register (both read and written)
272 * and update the given instruction \p inst accordingly
273 * if it modifies its \ref pfile and \ref pindex contents.
274 */
275 void rc_remap_registers(struct rc_instruction * inst, rc_remap_register_fn cb, void * userdata)
276 {
277 if (inst->Type == RC_INSTRUCTION_NORMAL)
278 remap_normal_instruction(inst, cb, userdata);
279 else
280 remap_pair_instruction(inst, cb, userdata);
281 }