• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 masked_negate;
58 
59 		mov->U.I.Opcode = RC_OPCODE_MOV;
60 		mov->U.I.DstReg.File = RC_FILE_TEMPORARY;
61 		mov->U.I.DstReg.Index = tempreg;
62 		mov->U.I.DstReg.WriteMask = split.Phase[phase];
63 		mov->U.I.SrcReg[0] = inst->U.I.SrcReg[src];
64 		mov->U.I.PreSub = inst->U.I.PreSub;
65 
66 		for(unsigned int chan = 0; chan < 4; ++chan) {
67 			if (!GET_BIT(split.Phase[phase], chan))
68 				SET_SWZ(mov->U.I.SrcReg[0].Swizzle, chan, RC_SWIZZLE_UNUSED);
69 		}
70 
71 		masked_negate = split.Phase[phase] & mov->U.I.SrcReg[0].Negate;
72 		if (masked_negate == 0)
73 			mov->U.I.SrcReg[0].Negate = 0;
74 		else if (masked_negate == split.Phase[phase])
75 			mov->U.I.SrcReg[0].Negate = RC_MASK_XYZW;
76 
77 	}
78 
79 	inst->U.I.SrcReg[src].File = RC_FILE_TEMPORARY;
80 	inst->U.I.SrcReg[src].Index = tempreg;
81 	inst->U.I.SrcReg[src].Swizzle = 0;
82 	inst->U.I.SrcReg[src].Negate = RC_MASK_NONE;
83 	inst->U.I.SrcReg[src].Abs = 0;
84 	for(unsigned int chan = 0; chan < 4; ++chan) {
85 		SET_SWZ(inst->U.I.SrcReg[src].Swizzle, chan,
86 				GET_BIT(usemask, chan) ? chan : RC_SWIZZLE_UNUSED);
87 	}
88 }
89 
90 /**
91  * This function will attempt to rewrite non-native swizzles that read from
92  * immediate registers by rearranging the immediates to allow the
93  * instruction to use native swizzles.
94  */
try_rewrite_constant(struct radeon_compiler * c,struct rc_src_register * reg)95 static unsigned try_rewrite_constant(struct radeon_compiler *c,
96 					struct rc_src_register *reg)
97 {
98 	unsigned new_swizzle, chan, swz0, swz1, swz2, swz3, found_swizzle, swz;
99 	unsigned all_inline = 0;
100 	bool w_inline_constant = false;
101 	float imms[4] = {0.0f, 0.0f, 0.0f, 0.0f};
102 
103 	if (!rc_src_reg_is_immediate(c, reg->File, reg->Index)) {
104 		/* The register does not contain immediates, but if all
105 		 * the swizzles are inline constants, we can still rewrite
106 		 * it. */
107 
108 		new_swizzle = RC_SWIZZLE_XYZW;
109 		for (chan = 0 ; chan < 4; chan++) {
110 			unsigned swz = GET_SWZ(reg->Swizzle, chan);
111 			if (swz <= RC_SWIZZLE_W) {
112 				return 0;
113 			}
114 			if (swz == RC_SWIZZLE_UNUSED) {
115 				SET_SWZ(new_swizzle, chan, RC_SWIZZLE_UNUSED);
116 			}
117 		}
118 		all_inline = 1;
119 	} else {
120 		new_swizzle = reg->Swizzle;
121 	}
122 
123 	swz = RC_SWIZZLE_UNUSED;
124 	found_swizzle = 1;
125 	/* Check if all channels have the same swizzle.  If they do we can skip
126 	 * the search for a native swizzle.  We only need to check the first
127 	 * three channels, because any swizzle is legal in the fourth channel.
128 	 */
129 	for (chan = 0; chan < 3; chan++) {
130 		unsigned chan_swz = GET_SWZ(reg->Swizzle, chan);
131 		if (chan_swz == RC_SWIZZLE_UNUSED) {
132 			continue;
133 		}
134 		if (swz == RC_SWIZZLE_UNUSED) {
135 			swz = chan_swz;
136 		} else if (swz != chan_swz) {
137 			found_swizzle = 0;
138 			break;
139 		}
140 	}
141 
142 	/* Find a legal swizzle */
143 
144 	/* This loop attempts to find a native swizzle where all the
145 	 * channels are different. */
146 	while (!found_swizzle && !all_inline) {
147 		swz0 = GET_SWZ(new_swizzle, 0);
148 		swz1 = GET_SWZ(new_swizzle, 1);
149 		swz2 = GET_SWZ(new_swizzle, 2);
150 
151 		/* Swizzle .W. is never legal. */
152 		if (swz1 == RC_SWIZZLE_W ||
153 			swz1 == RC_SWIZZLE_UNUSED ||
154 			swz1 == RC_SWIZZLE_ZERO ||
155 			swz1 == RC_SWIZZLE_HALF ||
156 			swz1 == RC_SWIZZLE_ONE) {
157 			/* We chose Z, because there are two non-repeating
158 			 * swizzle combinations of the form .Z. There are
159 			 * only one combination each for .X. and .Y. */
160 			SET_SWZ(new_swizzle, 1, RC_SWIZZLE_Z);
161 			continue;
162 		}
163 
164 		if (swz2 == RC_SWIZZLE_UNUSED) {
165 			/* We choose Y, because there are two non-repeating
166 			 * swizzle combinations of the form ..Y */
167 			SET_SWZ(new_swizzle, 2, RC_SWIZZLE_Y);
168 			continue;
169 		}
170 
171 		switch (swz0) {
172 		/* X.. */
173 		case RC_SWIZZLE_X:
174 			/* Legal swizzles that start with X: XYZ, XXX */
175 			switch (swz1) {
176 			/* XX. */
177 			case RC_SWIZZLE_X:
178 				/*  The new swizzle will be:
179 				 *  ZXY (XX. => ZX. => ZXY) */
180 				SET_SWZ(new_swizzle, 0, RC_SWIZZLE_Z);
181 				break;
182 			/* XY. */
183 			case RC_SWIZZLE_Y:
184 				/* The new swizzle is XYZ */
185 				SET_SWZ(new_swizzle, 2, RC_SWIZZLE_Z);
186 				found_swizzle = 1;
187 				break;
188 			/* XZ. */
189 			case RC_SWIZZLE_Z:
190 				/* XZZ */
191 				if (swz2 == RC_SWIZZLE_Z) {
192 					/* The new swizzle is XYZ */
193 					SET_SWZ(new_swizzle, 1, RC_SWIZZLE_Y);
194 					found_swizzle = 1;
195 				} else { /* XZ[^Z] */
196 					/* The new swizzle will be:
197 					 * YZX (XZ. => YZ. => YZX) */
198 					SET_SWZ(new_swizzle, 0, RC_SWIZZLE_Y);
199 				}
200 				break;
201 			/* XW. Should have already been handled. */
202 			case RC_SWIZZLE_W:
203 				assert(0);
204 				break;
205 			}
206 			break;
207 		/* Y.. */
208 		case RC_SWIZZLE_Y:
209 			/* Legal swizzles that start with Y: YYY, YZX */
210 			switch (swz1) {
211 			/* YY. */
212 			case RC_SWIZZLE_Y:
213 				/* The new swizzle will be:
214 				 * XYZ (YY. => XY. => XYZ) */
215 				SET_SWZ(new_swizzle, 0, RC_SWIZZLE_X);
216 				break;
217 			/* YZ. */
218 			case RC_SWIZZLE_Z:
219 				/* The new swizzle is YZX */
220 				SET_SWZ(new_swizzle, 2, RC_SWIZZLE_X);
221 				found_swizzle = 1;
222 				break;
223 			/* YX. */
224 			case RC_SWIZZLE_X:
225 				/* YXX */
226 				if (swz2 == RC_SWIZZLE_X) {
227 					/*The new swizzle is YZX */
228 					SET_SWZ(new_swizzle, 1, RC_SWIZZLE_Z);
229 					found_swizzle = 1;
230 				} else { /* YX[^X] */
231 					/* The new swizzle will be:
232 					 * ZXY (YX. => ZX. -> ZXY) */
233 					SET_SWZ(new_swizzle, 0, RC_SWIZZLE_Z);
234 				}
235 				break;
236 			/* YW. Should have already been handled. */
237 			case RC_SWIZZLE_W:
238 				assert(0);
239 				break;
240 			}
241 			break;
242 		/* Z.. */
243 		case RC_SWIZZLE_Z:
244 			/* Legal swizzles that start with Z: ZZZ, ZXY */
245 			switch (swz1) {
246 			/* ZZ. */
247 			case RC_SWIZZLE_Z:
248 				/* The new swizzle will be:
249 				 * WZY (ZZ. => WZ. => WZY) */
250 				SET_SWZ(new_swizzle, 0, RC_SWIZZLE_W);
251 				break;
252 			/* ZX. */
253 			case RC_SWIZZLE_X:
254 				/* The new swizzle is ZXY */
255 				SET_SWZ(new_swizzle, 2, RC_SWIZZLE_Y);
256 				found_swizzle = 1;
257 				break;
258 			/* ZY. */
259 			case RC_SWIZZLE_Y:
260 				/* ZYY */
261 				if (swz2 == RC_SWIZZLE_Y) {
262 					/* The new swizzle is ZXY */
263 					SET_SWZ(new_swizzle, 1, RC_SWIZZLE_X);
264 					found_swizzle = 1;
265 				} else { /* ZY[^Y] */
266 					/* The new swizzle will be:
267 					 * XYZ (ZY. => XY. => XYZ) */
268 					SET_SWZ(new_swizzle, 0, RC_SWIZZLE_X);
269 				}
270 				break;
271 			/* ZW. Should have already been handled. */
272 			case RC_SWIZZLE_W:
273 				assert(0);
274 				break;
275 			}
276 			break;
277 
278 		/* W.. */
279 		case RC_SWIZZLE_W:
280 			/* Legal swizzles that start with X: WWW, WZY */
281 			switch (swz1) {
282 			/* WW. Should have already been handled. */
283 			case RC_SWIZZLE_W:
284 				assert(0);
285 				break;
286 			/* WZ. */
287 			case RC_SWIZZLE_Z:
288 				/* The new swizzle will be WZY */
289 				SET_SWZ(new_swizzle, 2, RC_SWIZZLE_Y);
290 				found_swizzle = 1;
291 				break;
292 			/* WX. */
293 			case RC_SWIZZLE_X:
294 			/* WY. */
295 			case RC_SWIZZLE_Y:
296 				/* W[XY]Y */
297 				if (swz2 == RC_SWIZZLE_Y) {
298 					/* The new swizzle will be WZY */
299 					SET_SWZ(new_swizzle, 1, RC_SWIZZLE_Z);
300 					found_swizzle = 1;
301 				} else { /* W[XY][^Y] */
302 					/* The new swizzle will be:
303 					 * ZXY (WX. => XX. => ZX. => ZXY) or
304 					 * XYZ (WY. => XY. => XYZ)
305 					 */
306 					SET_SWZ(new_swizzle, 0, RC_SWIZZLE_X);
307 				}
308 				break;
309 			}
310 			break;
311 		/* U.. 0.. 1.. H..*/
312 		case RC_SWIZZLE_UNUSED:
313 		case RC_SWIZZLE_ZERO:
314 		case RC_SWIZZLE_ONE:
315 		case RC_SWIZZLE_HALF:
316 			SET_SWZ(new_swizzle, 0, RC_SWIZZLE_X);
317 			break;
318 		}
319 	}
320 
321 	/* Handle the swizzle in the w channel. */
322 	swz3 = GET_SWZ(reg->Swizzle, 3);
323 
324 	/* We can skip this if the swizzle in channel w is an inline constant. */
325 	if (is_swizzle_inline_constant(swz3)) {
326 		w_inline_constant = true;
327 	} else {
328 		for (chan = 0; chan < 3; chan++) {
329 			unsigned old_swz = GET_SWZ(reg->Swizzle, chan);
330 			unsigned new_swz = GET_SWZ(new_swizzle, chan);
331 			/* If the swizzle in the w channel is the same as the
332 			 * swizzle in any other channels, we need to rewrite it.
333 			 * For example:
334 			 * reg->Swizzle == XWZW
335 			 * new_swizzle  == XYZX
336 			 * Since the swizzle in the y channel is being
337 			 * rewritten from W -> Y we need to change the swizzle
338 			 * in the w channel from W -> Y as well.
339 			 */
340 			if (old_swz == swz3) {
341 				SET_SWZ(new_swizzle, 3,
342 						GET_SWZ(new_swizzle, chan));
343 				break;
344 			}
345 
346 			/* The swizzle in channel w will be overwritten by one
347 			 * of the new swizzles. */
348 			if (new_swz == swz3) {
349 				/* Find an unused swizzle */
350 				unsigned i;
351 				unsigned used = 0;
352 				for (i = 0; i < 3; i++) {
353 					used |= 1 << GET_SWZ(new_swizzle, i);
354 				}
355 				for (i = 0; i < 4; i++) {
356 					if (used & (1 << i)) {
357 						continue;
358 					}
359 					SET_SWZ(new_swizzle, 3, i);
360 				}
361 			}
362 		}
363 	}
364 
365 	for (chan = 0; chan < 4; chan++) {
366 		unsigned old_swz = GET_SWZ(reg->Swizzle, chan);
367 		unsigned new_swz = GET_SWZ(new_swizzle, chan);
368 
369 		if (old_swz == RC_SWIZZLE_UNUSED) {
370 			continue;
371 		}
372 
373 		/* We don't need to change the swizzle in channel w if it is
374 		 * an inline constant.  These are always legal in the w channel.
375 		 *
376 		 * Swizzles with a value > RC_SWIZZLE_W are inline constants.
377 		 */
378 		if (chan == 3 && w_inline_constant) {
379 			continue;
380 		}
381 
382 		if (new_swz > RC_SWIZZLE_W) {
383 			rc_error(c, "Bad swizzle in try_rewrite_constant()");
384 			new_swz = RC_SWIZZLE_X;
385 		}
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 = w_inline_constant ? reg->Negate & (1 << 3) : 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