r300/compiler: Standardize the number of bits used by swizzle fields
[mesa.git] / src / mesa / drivers / dri / r300 / compiler / radeon_compiler_util.c
1 /*
2 * Copyright 2010 Tom Stellard <tstellar@gmail.com>
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 /**
29 * \file
30 */
31
32 #include "radeon_compiler_util.h"
33
34 #include "radeon_compiler.h"
35 #include "radeon_dataflow.h"
36 /**
37 */
38 unsigned int rc_swizzle_to_writemask(unsigned int swz)
39 {
40 unsigned int mask = 0;
41 unsigned int i;
42
43 for(i = 0; i < 4; i++) {
44 mask |= 1 << GET_SWZ(swz, i);
45 }
46 mask &= RC_MASK_XYZW;
47
48 return mask;
49 }
50
51 rc_swizzle get_swz(unsigned int swz, rc_swizzle idx)
52 {
53 if (idx & 0x4)
54 return idx;
55 return GET_SWZ(swz, idx);
56 }
57
58 /**
59 * The purpose of this function is to standardize the number channels used by
60 * swizzles. All swizzles regardless of what instruction they are a part of
61 * should have 4 channels initialized with values.
62 * @param channels The number of channels in initial_value that have a
63 * meaningful value.
64 * @return An initialized swizzle that has all of the unused channels set to
65 * RC_SWIZZLE_UNUSED.
66 */
67 unsigned int rc_init_swizzle(unsigned int initial_value, unsigned int channels)
68 {
69 unsigned int i;
70 for (i = channels; i < 4; i++) {
71 SET_SWZ(initial_value, i, RC_SWIZZLE_UNUSED);
72 }
73 return initial_value;
74 }
75
76 unsigned int combine_swizzles4(unsigned int src,
77 rc_swizzle swz_x, rc_swizzle swz_y, rc_swizzle swz_z, rc_swizzle swz_w)
78 {
79 unsigned int ret = 0;
80
81 ret |= get_swz(src, swz_x);
82 ret |= get_swz(src, swz_y) << 3;
83 ret |= get_swz(src, swz_z) << 6;
84 ret |= get_swz(src, swz_w) << 9;
85
86 return ret;
87 }
88
89 unsigned int combine_swizzles(unsigned int src, unsigned int swz)
90 {
91 unsigned int ret = 0;
92
93 ret |= get_swz(src, GET_SWZ(swz, RC_SWIZZLE_X));
94 ret |= get_swz(src, GET_SWZ(swz, RC_SWIZZLE_Y)) << 3;
95 ret |= get_swz(src, GET_SWZ(swz, RC_SWIZZLE_Z)) << 6;
96 ret |= get_swz(src, GET_SWZ(swz, RC_SWIZZLE_W)) << 9;
97
98 return ret;
99 }
100
101 /**
102 * @param mask Must be either RC_MASK_X, RC_MASK_Y, RC_MASK_Z, or RC_MASK_W
103 */
104 rc_swizzle rc_mask_to_swizzle(unsigned int mask)
105 {
106 switch (mask) {
107 case RC_MASK_X: return RC_SWIZZLE_X;
108 case RC_MASK_Y: return RC_SWIZZLE_Y;
109 case RC_MASK_Z: return RC_SWIZZLE_Z;
110 case RC_MASK_W: return RC_SWIZZLE_W;
111 }
112 return RC_SWIZZLE_UNUSED;
113 }
114
115 /* Reorder mask bits according to swizzle. */
116 unsigned swizzle_mask(unsigned swizzle, unsigned mask)
117 {
118 unsigned ret = 0;
119 for (unsigned chan = 0; chan < 4; ++chan) {
120 unsigned swz = GET_SWZ(swizzle, chan);
121 if (swz < 4)
122 ret |= GET_BIT(mask, swz) << chan;
123 }
124 return ret;
125 }
126
127 /**
128 * Left multiplication of a register with a swizzle
129 */
130 struct rc_src_register lmul_swizzle(unsigned int swizzle, struct rc_src_register srcreg)
131 {
132 struct rc_src_register tmp = srcreg;
133 int i;
134 tmp.Swizzle = 0;
135 tmp.Negate = 0;
136 for(i = 0; i < 4; ++i) {
137 rc_swizzle swz = GET_SWZ(swizzle, i);
138 if (swz < 4) {
139 tmp.Swizzle |= GET_SWZ(srcreg.Swizzle, swz) << (i*3);
140 tmp.Negate |= GET_BIT(srcreg.Negate, swz) << i;
141 } else {
142 tmp.Swizzle |= swz << (i*3);
143 }
144 }
145 return tmp;
146 }
147
148 void reset_srcreg(struct rc_src_register* reg)
149 {
150 memset(reg, 0, sizeof(struct rc_src_register));
151 reg->Swizzle = RC_SWIZZLE_XYZW;
152 }
153
154 unsigned int rc_src_reads_dst_mask(
155 rc_register_file src_file,
156 unsigned int src_idx,
157 unsigned int src_swz,
158 rc_register_file dst_file,
159 unsigned int dst_idx,
160 unsigned int dst_mask)
161 {
162 if (src_file != dst_file || src_idx != dst_idx) {
163 return RC_MASK_NONE;
164 }
165 return dst_mask & rc_swizzle_to_writemask(src_swz);
166 }
167
168 /**
169 * @return A bit mask specifying whether this swizzle will select from an RGB
170 * source, an Alpha source, or both.
171 */
172 unsigned int rc_source_type_swz(unsigned int swizzle)
173 {
174 unsigned int chan;
175 unsigned int swz = RC_SWIZZLE_UNUSED;
176 unsigned int ret = RC_SOURCE_NONE;
177
178 for(chan = 0; chan < 4; chan++) {
179 swz = GET_SWZ(swizzle, chan);
180 if (swz == RC_SWIZZLE_W) {
181 ret |= RC_SOURCE_ALPHA;
182 } else if (swz == RC_SWIZZLE_X || swz == RC_SWIZZLE_Y
183 || swz == RC_SWIZZLE_Z) {
184 ret |= RC_SOURCE_RGB;
185 }
186 }
187 return ret;
188 }
189
190 unsigned int rc_source_type_mask(unsigned int mask)
191 {
192 unsigned int ret = RC_SOURCE_NONE;
193
194 if (mask & RC_MASK_XYZ)
195 ret |= RC_SOURCE_RGB;
196
197 if (mask & RC_MASK_W)
198 ret |= RC_SOURCE_ALPHA;
199
200 return ret;
201 }
202
203 struct can_use_presub_data {
204 struct rc_src_register RemoveSrcs[3];
205 unsigned int RGBCount;
206 unsigned int AlphaCount;
207 };
208
209 static void can_use_presub_read_cb(
210 void * userdata,
211 struct rc_instruction * inst,
212 rc_register_file file,
213 unsigned int index,
214 unsigned int mask)
215 {
216 struct can_use_presub_data * d = userdata;
217 unsigned int src_type = rc_source_type_mask(mask);
218 unsigned int i;
219
220 if (file == RC_FILE_NONE)
221 return;
222
223 for(i = 0; i < 3; i++) {
224 if (d->RemoveSrcs[i].File == file
225 && d->RemoveSrcs[i].Index == index) {
226 src_type &=
227 ~rc_source_type_swz(d->RemoveSrcs[i].Swizzle);
228 }
229 }
230
231 if (src_type & RC_SOURCE_RGB)
232 d->RGBCount++;
233
234 if (src_type & RC_SOURCE_ALPHA)
235 d->AlphaCount++;
236 }
237
238 unsigned int rc_inst_can_use_presub(
239 struct rc_instruction * inst,
240 rc_presubtract_op presub_op,
241 unsigned int presub_writemask,
242 struct rc_src_register replace_reg,
243 struct rc_src_register presub_src0,
244 struct rc_src_register presub_src1)
245 {
246 struct can_use_presub_data d;
247 unsigned int num_presub_srcs;
248 const struct rc_opcode_info * info =
249 rc_get_opcode_info(inst->U.I.Opcode);
250
251 if (presub_op == RC_PRESUB_NONE) {
252 return 1;
253 }
254
255 if (info->HasTexture) {
256 return 0;
257 }
258
259 /* We can't use more than one presubtract value in an
260 * instruction, unless the two prsubtract operations
261 * are the same and read from the same registers.
262 * XXX For now we will limit instructions to only one presubtract
263 * value.*/
264 if (inst->U.I.PreSub.Opcode != RC_PRESUB_NONE) {
265 return 0;
266 }
267
268 memset(&d, 0, sizeof(d));
269 d.RemoveSrcs[0] = replace_reg;
270 d.RemoveSrcs[1] = presub_src0;
271 d.RemoveSrcs[2] = presub_src1;
272
273 rc_for_all_reads_mask(inst, can_use_presub_read_cb, &d);
274
275 num_presub_srcs = rc_presubtract_src_reg_count(presub_op);
276
277 if (d.RGBCount + num_presub_srcs > 3 || d.AlphaCount + num_presub_srcs > 3) {
278 return 0;
279 }
280
281 return 1;
282 }
283