1 /*
2 * Copyright (C) 2009 Nicolai Haehnle.
3 * Copyright 2012 Advanced Micro Devices, Inc.
4 *
5 * All Rights Reserved.
6 *
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:
14 *
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.
18 *
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.
26 *
27 * Authors:
28 * Nicolai Haehnle
29 * Tom Stellard <thomas.stellard@amd.com>
30 */
31
32 #include "radeon_dataflow.h"
33
34 #include "radeon_code.h"
35 #include "radeon_compiler.h"
36 #include "radeon_compiler_util.h"
37 #include "radeon_swizzle.h"
38
39
rewrite_source(struct radeon_compiler * c,struct rc_instruction * inst,unsigned src)40 static void rewrite_source(struct radeon_compiler * c,
41 struct rc_instruction * inst, unsigned src)
42 {
43 struct rc_swizzle_split split;
44 unsigned int tempreg = rc_find_free_temporary(c);
45 unsigned int usemask;
46
47 usemask = 0;
48 for(unsigned int chan = 0; chan < 4; ++chan) {
49 if (GET_SWZ(inst->U.I.SrcReg[src].Swizzle, chan) != RC_SWIZZLE_UNUSED)
50 usemask |= 1 << chan;
51 }
52
53 c->SwizzleCaps->Split(inst->U.I.SrcReg[src], usemask, &split);
54
55 for(unsigned int phase = 0; phase < split.NumPhases; ++phase) {
56 struct rc_instruction * mov = rc_insert_new_instruction(c, inst->Prev);
57 unsigned int phase_refmask;
58 unsigned int masked_negate;
59
60 mov->U.I.Opcode = RC_OPCODE_MOV;
61 mov->U.I.DstReg.File = RC_FILE_TEMPORARY;
62 mov->U.I.DstReg.Index = tempreg;
63 mov->U.I.DstReg.WriteMask = split.Phase[phase];
64 mov->U.I.SrcReg[0] = inst->U.I.SrcReg[src];
65 mov->U.I.PreSub = inst->U.I.PreSub;
66
67 phase_refmask = 0;
68 for(unsigned int chan = 0; chan < 4; ++chan) {
69 if (!GET_BIT(split.Phase[phase], chan))
70 SET_SWZ(mov->U.I.SrcReg[0].Swizzle, chan, RC_SWIZZLE_UNUSED);
71 else
72 phase_refmask |= 1 << GET_SWZ(mov->U.I.SrcReg[0].Swizzle, chan);
73 }
74
75 phase_refmask &= RC_MASK_XYZW;
76
77 masked_negate = split.Phase[phase] & mov->U.I.SrcReg[0].Negate;
78 if (masked_negate == 0)
79 mov->U.I.SrcReg[0].Negate = 0;
80 else if (masked_negate == split.Phase[phase])
81 mov->U.I.SrcReg[0].Negate = RC_MASK_XYZW;
82
83 }
84
85 inst->U.I.SrcReg[src].File = RC_FILE_TEMPORARY;
86 inst->U.I.SrcReg[src].Index = tempreg;
87 inst->U.I.SrcReg[src].Swizzle = 0;
88 inst->U.I.SrcReg[src].Negate = RC_MASK_NONE;
89 inst->U.I.SrcReg[src].Abs = 0;
90 for(unsigned int chan = 0; chan < 4; ++chan) {
91 SET_SWZ(inst->U.I.SrcReg[src].Swizzle, chan,
92 GET_BIT(usemask, chan) ? chan : RC_SWIZZLE_UNUSED);
93 }
94 }
95
96 /**
97 * This function will attempt to rewrite non-native swizzles that read from
98 * immediate registers by rearranging the immediates to allow the
99 * instruction to use native swizzles.
100 */
try_rewrite_constant(struct radeon_compiler * c,struct rc_src_register * reg)101 static unsigned try_rewrite_constant(struct radeon_compiler *c,
102 struct rc_src_register *reg)
103 {
104 unsigned new_swizzle, chan, swz0, swz1, swz2, swz3, found_swizzle, swz;
105 unsigned all_inline = 0;
106 float imms[4] = {0.0f, 0.0f, 0.0f, 0.0f};
107
108 if (!rc_src_reg_is_immediate(c, reg->File, reg->Index)) {
109 /* The register does not contain immediates, but if all
110 * the swizzles are inline constants, we can still rewrite
111 * it. */
112
113 new_swizzle = RC_SWIZZLE_XYZW;
114 for (chan = 0 ; chan < 4; chan++) {
115 unsigned swz = GET_SWZ(reg->Swizzle, chan);
116 if (swz <= RC_SWIZZLE_W) {
117 return 0;
118 }
119 if (swz == RC_SWIZZLE_UNUSED) {
120 SET_SWZ(new_swizzle, chan, RC_SWIZZLE_UNUSED);
121 }
122 }
123 all_inline = 1;
124 } else {
125 new_swizzle = reg->Swizzle;
126 }
127
128 swz = RC_SWIZZLE_UNUSED;
129 found_swizzle = 1;
130 /* Check if all channels have the same swizzle. If they do we can skip
131 * the search for a native swizzle. We only need to check the first
132 * three channels, because any swizzle is legal in the fourth channel.
133 */
134 for (chan = 0; chan < 3; chan++) {
135 unsigned chan_swz = GET_SWZ(reg->Swizzle, chan);
136 if (chan_swz == RC_SWIZZLE_UNUSED) {
137 continue;
138 }
139 if (swz == RC_SWIZZLE_UNUSED) {
140 swz = chan_swz;
141 } else if (swz != chan_swz) {
142 found_swizzle = 0;
143 break;
144 }
145 }
146
147 /* Find a legal swizzle */
148
149 /* This loop attempts to find a native swizzle where all the
150 * channels are different. */
151 while (!found_swizzle && !all_inline) {
152 swz0 = GET_SWZ(new_swizzle, 0);
153 swz1 = GET_SWZ(new_swizzle, 1);
154 swz2 = GET_SWZ(new_swizzle, 2);
155
156 /* Swizzle .W. is never legal. */
157 if (swz1 == RC_SWIZZLE_W ||
158 swz1 == RC_SWIZZLE_UNUSED ||
159 swz1 == RC_SWIZZLE_ZERO ||
160 swz1 == RC_SWIZZLE_HALF ||
161 swz1 == RC_SWIZZLE_ONE) {
162 /* We chose Z, because there are two non-repeating
163 * swizzle combinations of the form .Z. There are
164 * only one combination each for .X. and .Y. */
165 SET_SWZ(new_swizzle, 1, RC_SWIZZLE_Z);
166 continue;
167 }
168
169 if (swz2 == RC_SWIZZLE_UNUSED) {
170 /* We choose Y, because there are two non-repeating
171 * swizzle combinations of the form ..Y */
172 SET_SWZ(new_swizzle, 2, RC_SWIZZLE_Y);
173 continue;
174 }
175
176 switch (swz0) {
177 /* X.. */
178 case RC_SWIZZLE_X:
179 /* Legal swizzles that start with X: XYZ, XXX */
180 switch (swz1) {
181 /* XX. */
182 case RC_SWIZZLE_X:
183 /* The new swizzle will be:
184 * ZXY (XX. => ZX. => ZXY) */
185 SET_SWZ(new_swizzle, 0, RC_SWIZZLE_Z);
186 break;
187 /* XY. */
188 case RC_SWIZZLE_Y:
189 /* The new swizzle is XYZ */
190 SET_SWZ(new_swizzle, 2, RC_SWIZZLE_Z);
191 found_swizzle = 1;
192 break;
193 /* XZ. */
194 case RC_SWIZZLE_Z:
195 /* XZZ */
196 if (swz2 == RC_SWIZZLE_Z) {
197 /* The new swizzle is XYZ */
198 SET_SWZ(new_swizzle, 1, RC_SWIZZLE_Y);
199 found_swizzle = 1;
200 } else { /* XZ[^Z] */
201 /* The new swizzle will be:
202 * YZX (XZ. => YZ. => YZX) */
203 SET_SWZ(new_swizzle, 0, RC_SWIZZLE_Y);
204 }
205 break;
206 /* XW. Should have already been handled. */
207 case RC_SWIZZLE_W:
208 assert(0);
209 break;
210 }
211 break;
212 /* Y.. */
213 case RC_SWIZZLE_Y:
214 /* Legal swizzles that start with Y: YYY, YZX */
215 switch (swz1) {
216 /* YY. */
217 case RC_SWIZZLE_Y:
218 /* The new swizzle will be:
219 * XYZ (YY. => XY. => XYZ) */
220 SET_SWZ(new_swizzle, 0, RC_SWIZZLE_X);
221 break;
222 /* YZ. */
223 case RC_SWIZZLE_Z:
224 /* The new swizzle is YZX */
225 SET_SWZ(new_swizzle, 2, RC_SWIZZLE_X);
226 found_swizzle = 1;
227 break;
228 /* YX. */
229 case RC_SWIZZLE_X:
230 /* YXX */
231 if (swz2 == RC_SWIZZLE_X) {
232 /*The new swizzle is YZX */
233 SET_SWZ(new_swizzle, 1, RC_SWIZZLE_Z);
234 found_swizzle = 1;
235 } else { /* YX[^X] */
236 /* The new swizzle will be:
237 * ZXY (YX. => ZX. -> ZXY) */
238 SET_SWZ(new_swizzle, 0, RC_SWIZZLE_Z);
239 }
240 break;
241 /* YW. Should have already been handled. */
242 case RC_SWIZZLE_W:
243 assert(0);
244 break;
245 }
246 break;
247 /* Z.. */
248 case RC_SWIZZLE_Z:
249 /* Legal swizzles that start with Z: ZZZ, ZXY */
250 switch (swz1) {
251 /* ZZ. */
252 case RC_SWIZZLE_Z:
253 /* The new swizzle will be:
254 * WZY (ZZ. => WZ. => WZY) */
255 SET_SWZ(new_swizzle, 0, RC_SWIZZLE_W);
256 break;
257 /* ZX. */
258 case RC_SWIZZLE_X:
259 /* The new swizzle is ZXY */
260 SET_SWZ(new_swizzle, 2, RC_SWIZZLE_Y);
261 found_swizzle = 1;
262 break;
263 /* ZY. */
264 case RC_SWIZZLE_Y:
265 /* ZYY */
266 if (swz2 == RC_SWIZZLE_Y) {
267 /* The new swizzle is ZXY */
268 SET_SWZ(new_swizzle, 1, RC_SWIZZLE_X);
269 found_swizzle = 1;
270 } else { /* ZY[^Y] */
271 /* The new swizzle will be:
272 * XYZ (ZY. => XY. => XYZ) */
273 SET_SWZ(new_swizzle, 0, RC_SWIZZLE_X);
274 }
275 break;
276 /* ZW. Should have already been handled. */
277 case RC_SWIZZLE_W:
278 assert(0);
279 break;
280 }
281 break;
282
283 /* W.. */
284 case RC_SWIZZLE_W:
285 /* Legal swizzles that start with X: WWW, WZY */
286 switch (swz1) {
287 /* WW. Should have already been handled. */
288 case RC_SWIZZLE_W:
289 assert(0);
290 break;
291 /* WZ. */
292 case RC_SWIZZLE_Z:
293 /* The new swizzle will be WZY */
294 SET_SWZ(new_swizzle, 2, RC_SWIZZLE_Y);
295 found_swizzle = 1;
296 break;
297 /* WX. */
298 case RC_SWIZZLE_X:
299 /* WY. */
300 case RC_SWIZZLE_Y:
301 /* W[XY]Y */
302 if (swz2 == RC_SWIZZLE_Y) {
303 /* The new swizzle will be WZY */
304 SET_SWZ(new_swizzle, 1, RC_SWIZZLE_Z);
305 found_swizzle = 1;
306 } else { /* W[XY][^Y] */
307 /* The new swizzle will be:
308 * ZXY (WX. => XX. => ZX. => ZXY) or
309 * XYZ (WY. => XY. => XYZ)
310 */
311 SET_SWZ(new_swizzle, 0, RC_SWIZZLE_X);
312 }
313 break;
314 }
315 break;
316 /* U.. 0.. 1.. H..*/
317 case RC_SWIZZLE_UNUSED:
318 case RC_SWIZZLE_ZERO:
319 case RC_SWIZZLE_ONE:
320 case RC_SWIZZLE_HALF:
321 SET_SWZ(new_swizzle, 0, RC_SWIZZLE_X);
322 break;
323 }
324 }
325
326 /* Handle the swizzle in the w channel. */
327 swz3 = GET_SWZ(reg->Swizzle, 3);
328
329 /* We can skip this if the swizzle in channel w is an inline constant. */
330 if (swz3 <= RC_SWIZZLE_W) {
331 for (chan = 0; chan < 3; chan++) {
332 unsigned old_swz = GET_SWZ(reg->Swizzle, chan);
333 unsigned new_swz = GET_SWZ(new_swizzle, chan);
334 /* If the swizzle in the w channel is the same as the
335 * swizzle in any other channels, we need to rewrite it.
336 * For example:
337 * reg->Swizzle == XWZW
338 * new_swizzle == XYZX
339 * Since the swizzle in the y channel is being
340 * rewritten from W -> Y we need to change the swizzle
341 * in the w channel from W -> Y as well.
342 */
343 if (old_swz == swz3) {
344 SET_SWZ(new_swizzle, 3,
345 GET_SWZ(new_swizzle, chan));
346 break;
347 }
348
349 /* The swizzle in channel w will be overwritten by one
350 * of the new swizzles. */
351 if (new_swz == swz3) {
352 /* Find an unused swizzle */
353 unsigned i;
354 unsigned used = 0;
355 for (i = 0; i < 3; i++) {
356 used |= 1 << GET_SWZ(new_swizzle, i);
357 }
358 for (i = 0; i < 4; i++) {
359 if (used & (1 << i)) {
360 continue;
361 }
362 SET_SWZ(new_swizzle, 3, i);
363 }
364 }
365 }
366 }
367
368 for (chan = 0; chan < 4; chan++) {
369 unsigned old_swz = GET_SWZ(reg->Swizzle, chan);
370 unsigned new_swz = GET_SWZ(new_swizzle, chan);
371
372 if (old_swz == RC_SWIZZLE_UNUSED) {
373 continue;
374 }
375
376 /* We don't need to change the swizzle in channel w if it is
377 * an inline constant. These are always legal in the w channel.
378 *
379 * Swizzles with a value > RC_SWIZZLE_W are inline constants.
380 */
381 if (chan == 3 && old_swz > RC_SWIZZLE_W) {
382 continue;
383 }
384
385 assert(new_swz <= RC_SWIZZLE_W);
386
387 switch (old_swz) {
388 case RC_SWIZZLE_ZERO:
389 imms[new_swz] = 0.0f;
390 break;
391 case RC_SWIZZLE_HALF:
392 if (reg->Negate & (1 << chan)) {
393 imms[new_swz] = -0.5f;
394 } else {
395 imms[new_swz] = 0.5f;
396 }
397 break;
398 case RC_SWIZZLE_ONE:
399 if (reg->Negate & (1 << chan)) {
400 imms[new_swz] = -1.0f;
401 } else {
402 imms[new_swz] = 1.0f;
403 }
404 break;
405 default:
406 imms[new_swz] = rc_get_constant_value(c, reg->Index,
407 reg->Swizzle, reg->Negate, chan);
408 }
409 SET_SWZ(reg->Swizzle, chan, new_swz);
410 }
411 reg->Index = rc_constants_add_immediate_vec4(&c->Program.Constants,
412 imms);
413 /* We need to set the register file to CONSTANT in case we are
414 * converting a non-constant register with constant swizzles (e.g.
415 * ONE, ZERO, HALF).
416 */
417 reg->File = RC_FILE_CONSTANT;
418 reg->Negate = 0;
419 return 1;
420 }
421
rc_dataflow_swizzles(struct radeon_compiler * c,void * user)422 void rc_dataflow_swizzles(struct radeon_compiler * c, void *user)
423 {
424 struct rc_instruction * inst;
425
426 for(inst = c->Program.Instructions.Next;
427 inst != &c->Program.Instructions;
428 inst = inst->Next) {
429 const struct rc_opcode_info * opcode =
430 rc_get_opcode_info(inst->U.I.Opcode);
431 unsigned int src;
432
433 for(src = 0; src < opcode->NumSrcRegs; ++src) {
434 struct rc_src_register *reg = &inst->U.I.SrcReg[src];
435 if (c->SwizzleCaps->IsNative(inst->U.I.Opcode, *reg)) {
436 continue;
437 }
438 if (!c->is_r500 &&
439 c->Program.Constants.Count < R300_PFS_NUM_CONST_REGS &&
440 try_rewrite_constant(c, reg)) {
441 continue;
442 }
443 rewrite_source(c, inst, src);
444 }
445 }
446 if (c->Debug & RC_DBG_LOG)
447 rc_constants_print(&c->Program.Constants);
448 }
449