• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "r300_fragprog_swizzle.h"
37 /**
38  */
rc_swizzle_to_writemask(unsigned int swz)39 unsigned int rc_swizzle_to_writemask(unsigned int swz)
40 {
41 	unsigned int mask = 0;
42 	unsigned int i;
43 
44 	for(i = 0; i < 4; i++) {
45 		mask |= 1 << GET_SWZ(swz, i);
46 	}
47 	mask &= RC_MASK_XYZW;
48 
49 	return mask;
50 }
51 
get_swz(unsigned int swz,rc_swizzle idx)52 rc_swizzle get_swz(unsigned int swz, rc_swizzle idx)
53 {
54 	if (idx & 0x4)
55 		return idx;
56 	return GET_SWZ(swz, idx);
57 }
58 
59 /**
60  * The purpose of this function is to standardize the number channels used by
61  * swizzles.  All swizzles regardless of what instruction they are a part of
62  * should have 4 channels initialized with values.
63  * @param channels The number of channels in initial_value that have a
64  * meaningful value.
65  * @return An initialized swizzle that has all of the unused channels set to
66  * RC_SWIZZLE_UNUSED.
67  */
rc_init_swizzle(unsigned int initial_value,unsigned int channels)68 unsigned int rc_init_swizzle(unsigned int initial_value, unsigned int channels)
69 {
70 	unsigned int i;
71 	for (i = channels; i < 4; i++) {
72 		SET_SWZ(initial_value, i, RC_SWIZZLE_UNUSED);
73 	}
74 	return initial_value;
75 }
76 
combine_swizzles4(unsigned int src,rc_swizzle swz_x,rc_swizzle swz_y,rc_swizzle swz_z,rc_swizzle swz_w)77 unsigned int combine_swizzles4(unsigned int src,
78 		rc_swizzle swz_x, rc_swizzle swz_y, rc_swizzle swz_z, rc_swizzle swz_w)
79 {
80 	unsigned int ret = 0;
81 
82 	ret |= get_swz(src, swz_x);
83 	ret |= get_swz(src, swz_y) << 3;
84 	ret |= get_swz(src, swz_z) << 6;
85 	ret |= get_swz(src, swz_w) << 9;
86 
87 	return ret;
88 }
89 
combine_swizzles(unsigned int src,unsigned int swz)90 unsigned int combine_swizzles(unsigned int src, unsigned int swz)
91 {
92 	unsigned int ret = 0;
93 
94 	ret |= get_swz(src, GET_SWZ(swz, RC_SWIZZLE_X));
95 	ret |= get_swz(src, GET_SWZ(swz, RC_SWIZZLE_Y)) << 3;
96 	ret |= get_swz(src, GET_SWZ(swz, RC_SWIZZLE_Z)) << 6;
97 	ret |= get_swz(src, GET_SWZ(swz, RC_SWIZZLE_W)) << 9;
98 
99 	return ret;
100 }
101 
102 /**
103  * @param mask Must be either RC_MASK_X, RC_MASK_Y, RC_MASK_Z, or RC_MASK_W
104  */
rc_mask_to_swizzle(unsigned int mask)105 rc_swizzle rc_mask_to_swizzle(unsigned int mask)
106 {
107 	switch (mask) {
108 	case RC_MASK_X: return RC_SWIZZLE_X;
109 	case RC_MASK_Y: return RC_SWIZZLE_Y;
110 	case RC_MASK_Z: return RC_SWIZZLE_Z;
111 	case RC_MASK_W: return RC_SWIZZLE_W;
112 	}
113 	return RC_SWIZZLE_UNUSED;
114 }
115 
116 /* Reorder mask bits according to swizzle. */
swizzle_mask(unsigned swizzle,unsigned mask)117 unsigned swizzle_mask(unsigned swizzle, unsigned mask)
118 {
119 	unsigned ret = 0;
120 	for (unsigned chan = 0; chan < 4; ++chan) {
121 		unsigned swz = GET_SWZ(swizzle, chan);
122 		if (swz < 4)
123 			ret |= GET_BIT(mask, swz) << chan;
124 	}
125 	return ret;
126 }
127 
srcs_need_rewrite(const struct rc_opcode_info * info)128 static unsigned int srcs_need_rewrite(const struct rc_opcode_info * info)
129 {
130 	if (info->HasTexture) {
131 		return 0;
132 	}
133 	switch (info->Opcode) {
134 		case RC_OPCODE_DP2:
135 		case RC_OPCODE_DP3:
136 		case RC_OPCODE_DP4:
137 		case RC_OPCODE_DDX:
138 		case RC_OPCODE_DDY:
139 			return 0;
140 		default:
141 			return 1;
142 	}
143 }
144 
145 /**
146  * This function moves the old swizzles to new channels using the values
147  * in the conversion swizzle. For example if the instruction writemask is
148  * changed from x to y, then conversion_swizzle should be y___ and this
149  * function will adjust the old argument swizzles (of the same instruction)
150  * to the new channels, so x___ will become _x__, etc...
151  *
152  * @param old_swizzle The swizzle to change
153  * @param conversion_swizzle Describes the conversion to perform on the swizzle
154  * @return A new swizzle
155  */
rc_adjust_channels(unsigned int old_swizzle,unsigned int conversion_swizzle)156 unsigned int rc_adjust_channels(
157 	unsigned int old_swizzle,
158 	unsigned int conversion_swizzle)
159 {
160 	unsigned int i;
161 	unsigned int new_swizzle = rc_init_swizzle(RC_SWIZZLE_UNUSED, 0);
162 	for (i = 0; i < 4; i++) {
163 		unsigned int new_chan = get_swz(conversion_swizzle, i);
164 		if (new_chan == RC_SWIZZLE_UNUSED) {
165 			continue;
166 		}
167 		SET_SWZ(new_swizzle, new_chan, GET_SWZ(old_swizzle, i));
168 	}
169 	return new_swizzle;
170 }
171 
rewrite_writemask(unsigned int old_mask,unsigned int conversion_swizzle)172 static unsigned int rewrite_writemask(
173 	unsigned int old_mask,
174 	unsigned int conversion_swizzle)
175 {
176 	unsigned int new_mask = 0;
177 	unsigned int i;
178 
179 	for (i = 0; i < 4; i++) {
180 		if (!GET_BIT(old_mask, i)
181 		   || GET_SWZ(conversion_swizzle, i) == RC_SWIZZLE_UNUSED) {
182 			continue;
183 		}
184 		new_mask |= (1 << GET_SWZ(conversion_swizzle, i));
185 	}
186 
187 	return new_mask;
188 }
189 
190 /**
191  * This function rewrites the writemask of sub and adjusts the swizzles
192  * of all its source registers based on the conversion_swizzle.
193  * conversion_swizzle represents a mapping of the old writemask to the
194  * new writemask.  For a detailed description of how conversion swizzles
195  * work see rc_rewrite_swizzle().
196  */
rc_pair_rewrite_writemask(struct rc_pair_sub_instruction * sub,unsigned int conversion_swizzle)197 void rc_pair_rewrite_writemask(
198 	struct rc_pair_sub_instruction * sub,
199 	unsigned int conversion_swizzle)
200 {
201 	const struct rc_opcode_info * info = rc_get_opcode_info(sub->Opcode);
202 	unsigned int i;
203 
204 	sub->WriteMask = rewrite_writemask(sub->WriteMask, conversion_swizzle);
205 
206 	if (!srcs_need_rewrite(info)) {
207 		return ;
208 	}
209 
210 	for (i = 0; i < info->NumSrcRegs; i++) {
211 		sub->Arg[i].Swizzle =
212 			rc_adjust_channels(sub->Arg[i].Swizzle,
213 						conversion_swizzle);
214 	}
215 }
216 
normal_rewrite_writemask_cb(void * userdata,struct rc_instruction * inst,struct rc_src_register * src)217 static void normal_rewrite_writemask_cb(
218 	void * userdata,
219 	struct rc_instruction * inst,
220 	struct rc_src_register * src)
221 {
222 	unsigned int * conversion_swizzle = (unsigned int *)userdata;
223 	src->Swizzle = rc_adjust_channels(src->Swizzle, *conversion_swizzle);
224 
225 	/* Per-channel negates are possible in vertex shaders,
226 	 * so we need to rewrite it properly as well. */
227 	unsigned int new_negate = 0;
228 	for (unsigned int i = 0; i < 4; i++) {
229 		unsigned int new_chan = get_swz(*conversion_swizzle, i);
230 
231 		if (new_chan == RC_SWIZZLE_UNUSED)
232 			continue;
233 
234 		if ((1 << i) & src->Negate)
235 			new_negate |= 1 << new_chan;
236 	}
237 	src->Negate = new_negate;
238 }
239 
240 /**
241  * This function is the same as rc_pair_rewrite_writemask() except it
242  * operates on normal instructions.
243  */
rc_normal_rewrite_writemask(struct rc_instruction * inst,unsigned int conversion_swizzle)244 void rc_normal_rewrite_writemask(
245 	struct rc_instruction * inst,
246 	unsigned int conversion_swizzle)
247 {
248 	struct rc_sub_instruction * sub = &inst->U.I;
249 	const struct rc_opcode_info * info = rc_get_opcode_info(sub->Opcode);
250 	sub->DstReg.WriteMask =
251 		rewrite_writemask(sub->DstReg.WriteMask, conversion_swizzle);
252 
253 	if (info->HasTexture) {
254 		unsigned int i;
255 		assert(sub->TexSwizzle == RC_SWIZZLE_XYZW);
256 		for (i = 0; i < 4; i++) {
257 			unsigned int swz = GET_SWZ(conversion_swizzle, i);
258 			if (swz > 3)
259 				continue;
260 			SET_SWZ(sub->TexSwizzle, swz, i);
261 		}
262 	}
263 
264 	if (!srcs_need_rewrite(info)) {
265 		return;
266 	}
267 
268 	rc_for_all_reads_src(inst, normal_rewrite_writemask_cb,
269 							&conversion_swizzle);
270 }
271 
272 /**
273  * This function replaces each value 'swz' in swizzle with the value of
274  * GET_SWZ(conversion_swizzle, swz).  So, if you want to change all the X's
275  * in swizzle to Y, then conversion_swizzle should be Y___ (0xff9).  If you want
276  * to change all the Y's in swizzle to X, then conversion_swizzle should be
277  * _X__ (0xfc7).  If you want to change the Y's to X and the X's to Y, then
278  * conversion swizzle should be YX__ (0xfc1).
279  * @param swizzle The swizzle to change
280  * @param conversion_swizzle Describes the conversion to perform on the swizzle
281  * @return A converted swizzle
282  */
rc_rewrite_swizzle(unsigned int swizzle,unsigned int conversion_swizzle)283 unsigned int rc_rewrite_swizzle(
284 	unsigned int swizzle,
285 	unsigned int conversion_swizzle)
286 {
287 	unsigned int chan;
288 	unsigned int out_swizzle = swizzle;
289 
290 	for (chan = 0; chan < 4; chan++) {
291 		unsigned int swz = GET_SWZ(swizzle, chan);
292 		unsigned int new_swz;
293 		if (swz > 3) {
294 			SET_SWZ(out_swizzle, chan, swz);
295 		} else {
296 			new_swz = GET_SWZ(conversion_swizzle, swz);
297 			if (new_swz != RC_SWIZZLE_UNUSED) {
298 				SET_SWZ(out_swizzle, chan, new_swz);
299 			} else {
300 				SET_SWZ(out_swizzle, chan, swz);
301 			}
302 		}
303 	}
304 	return out_swizzle;
305 }
306 
307 /**
308  * Left multiplication of a register with a swizzle
309  */
lmul_swizzle(unsigned int swizzle,struct rc_src_register srcreg)310 struct rc_src_register lmul_swizzle(unsigned int swizzle, struct rc_src_register srcreg)
311 {
312 	struct rc_src_register tmp = srcreg;
313 	int i;
314 	tmp.Swizzle = 0;
315 	tmp.Negate = 0;
316 	for(i = 0; i < 4; ++i) {
317 		rc_swizzle swz = GET_SWZ(swizzle, i);
318 		if (swz < 4) {
319 			tmp.Swizzle |= GET_SWZ(srcreg.Swizzle, swz) << (i*3);
320 			tmp.Negate |= GET_BIT(srcreg.Negate, swz) << i;
321 		} else {
322 			tmp.Swizzle |= swz << (i*3);
323 		}
324 	}
325 	return tmp;
326 }
327 
reset_srcreg(struct rc_src_register * reg)328 void reset_srcreg(struct rc_src_register* reg)
329 {
330 	memset(reg, 0, sizeof(struct rc_src_register));
331 	reg->Swizzle = RC_SWIZZLE_XYZW;
332 }
333 
rc_src_reads_dst_mask(rc_register_file src_file,unsigned int src_idx,unsigned int src_swz,rc_register_file dst_file,unsigned int dst_idx,unsigned int dst_mask)334 unsigned int rc_src_reads_dst_mask(
335 		rc_register_file src_file,
336 		unsigned int src_idx,
337 		unsigned int src_swz,
338 		rc_register_file dst_file,
339 		unsigned int dst_idx,
340 		unsigned int dst_mask)
341 {
342 	if (src_file != dst_file || src_idx != dst_idx) {
343 		return RC_MASK_NONE;
344 	}
345 	return dst_mask & rc_swizzle_to_writemask(src_swz);
346 }
347 
348 /**
349  * @return A bit mask specifying whether this swizzle will select from an RGB
350  * source, an Alpha source, or both.
351  */
rc_source_type_swz(unsigned int swizzle)352 unsigned int rc_source_type_swz(unsigned int swizzle)
353 {
354 	unsigned int chan;
355 	unsigned int swz = RC_SWIZZLE_UNUSED;
356 	unsigned int ret = RC_SOURCE_NONE;
357 
358 	for(chan = 0; chan < 4; chan++) {
359 		swz = GET_SWZ(swizzle, chan);
360 		if (swz == RC_SWIZZLE_W) {
361 			ret |= RC_SOURCE_ALPHA;
362 		} else if (swz == RC_SWIZZLE_X || swz == RC_SWIZZLE_Y
363 						|| swz == RC_SWIZZLE_Z) {
364 			ret |= RC_SOURCE_RGB;
365 		}
366 	}
367 	return ret;
368 }
369 
rc_source_type_mask(unsigned int mask)370 unsigned int rc_source_type_mask(unsigned int mask)
371 {
372 	unsigned int ret = RC_SOURCE_NONE;
373 
374 	if (mask & RC_MASK_XYZ)
375 		ret |= RC_SOURCE_RGB;
376 
377 	if (mask & RC_MASK_W)
378 		ret |= RC_SOURCE_ALPHA;
379 
380 	return ret;
381 }
382 
383 struct src_select {
384 	rc_register_file File;
385 	int Index;
386 	unsigned int SrcType;
387 	unsigned int Swizzle;
388 };
389 
390 struct can_use_presub_data {
391 	struct src_select Selects[5];
392 	unsigned int SelectCount;
393 	const struct rc_src_register * ReplaceReg;
394 	unsigned int ReplaceRemoved;
395 };
396 
can_use_presub_data_add_select(struct can_use_presub_data * data,rc_register_file file,unsigned int index,unsigned int swizzle)397 static void can_use_presub_data_add_select(
398 	struct can_use_presub_data * data,
399 	rc_register_file file,
400 	unsigned int index,
401 	unsigned int swizzle)
402 {
403 	struct src_select * select;
404 
405 	select = &data->Selects[data->SelectCount++];
406 	select->File = file;
407 	select->Index = index;
408 	select->SrcType = rc_source_type_swz(swizzle);
409 	select->Swizzle = swizzle;
410 }
411 
412 /**
413  * This callback function counts the number of sources in inst that are
414  * different from the sources in can_use_presub_data->RemoveSrcs.
415  */
can_use_presub_read_cb(void * userdata,struct rc_instruction * inst,struct rc_src_register * src)416 static void can_use_presub_read_cb(
417 	void * userdata,
418 	struct rc_instruction * inst,
419 	struct rc_src_register * src)
420 {
421 	struct can_use_presub_data * d = userdata;
422 
423 	if (!d->ReplaceRemoved && src == d->ReplaceReg) {
424 		d->ReplaceRemoved = 1;
425 		return;
426 	}
427 
428 	if (src->File == RC_FILE_NONE)
429 		return;
430 
431 	can_use_presub_data_add_select(d, src->File, src->Index,
432 					src->Swizzle);
433 }
434 
rc_inst_can_use_presub(struct radeon_compiler * c,struct rc_instruction * inst,rc_presubtract_op presub_op,unsigned int presub_writemask,const struct rc_src_register * replace_reg,const struct rc_src_register * presub_src0,const struct rc_src_register * presub_src1)435 unsigned int rc_inst_can_use_presub(
436 	struct radeon_compiler * c,
437 	struct rc_instruction * inst,
438 	rc_presubtract_op presub_op,
439 	unsigned int presub_writemask,
440 	const struct rc_src_register * replace_reg,
441 	const struct rc_src_register * presub_src0,
442 	const struct rc_src_register * presub_src1)
443 {
444 	struct can_use_presub_data d;
445 	unsigned int num_presub_srcs;
446 	unsigned int i;
447 	const struct rc_opcode_info * info =
448 					rc_get_opcode_info(inst->U.I.Opcode);
449 	int rgb_count = 0, alpha_count = 0;
450 	unsigned int src_type0, src_type1;
451 
452 	if (presub_op == RC_PRESUB_NONE) {
453 		return 1;
454 	}
455 
456 	if (info->HasTexture) {
457 		return 0;
458 	}
459 
460 	/* We can't allow constant swizzles from presubtract, because it is not possible
461 	 * to rewrite it to a native swizzle later. */
462 	if (!c->is_r500) {
463 		for (i = 0; i < 4; i++) {
464 			rc_swizzle swz = GET_SWZ(replace_reg->Swizzle, i);
465 			if (swz > RC_SWIZZLE_W && swz < RC_SWIZZLE_UNUSED)
466 				return 0;
467 		}
468 	}
469 
470 	/* We can't use more than one presubtract value in an
471 	 * instruction, unless the two prsubtract operations
472 	 * are the same and read from the same registers.
473 	 * XXX For now we will limit instructions to only one presubtract
474 	 * value.*/
475 	if (inst->U.I.PreSub.Opcode != RC_PRESUB_NONE) {
476 		return 0;
477 	}
478 
479 	memset(&d, 0, sizeof(d));
480 	d.ReplaceReg = replace_reg;
481 
482 	rc_for_all_reads_src(inst, can_use_presub_read_cb, &d);
483 
484 	num_presub_srcs = rc_presubtract_src_reg_count(presub_op);
485 
486 	src_type0 = rc_source_type_swz(presub_src0->Swizzle);
487 	can_use_presub_data_add_select(&d,
488 		presub_src0->File,
489 		presub_src0->Index,
490 		presub_src0->Swizzle);
491 
492 	if (num_presub_srcs > 1) {
493 		src_type1 = rc_source_type_swz(presub_src1->Swizzle);
494 		can_use_presub_data_add_select(&d,
495 			presub_src1->File,
496 			presub_src1->Index,
497 			presub_src1->Swizzle);
498 
499 		/* Even if both of the presub sources read from the same
500 		 * register, we still need to use 2 different source selects
501 		 * for them, so we need to increment the count to compensate.
502 		 */
503 		if (presub_src0->File == presub_src1->File
504 		    && presub_src0->Index == presub_src1->Index) {
505 			if (src_type0 & src_type1 & RC_SOURCE_RGB) {
506 				rgb_count++;
507 			}
508 			if (src_type0 & src_type1 & RC_SOURCE_ALPHA) {
509 				alpha_count++;
510 			}
511 		}
512 	}
513 
514 	/* Count the number of source selects for Alpha and RGB.  If we
515 	 * encounter two of the same source selects then we can ignore the
516 	 * first one. */
517 	for (i = 0; i < d.SelectCount; i++) {
518 		unsigned int j;
519 		unsigned int src_type = d.Selects[i].SrcType;
520 		for (j = i + 1; j < d.SelectCount; j++) {
521 			/* Even if the sources are the same now, they will not be the
522 			 * same later, if we have to rewrite some non-native swizzle. */
523 			if(!c->is_r500 && (
524 				!r300_swizzle_is_native_basic(d.Selects[i].Swizzle) ||
525 				!r300_swizzle_is_native_basic(d.Selects[j].Swizzle)))
526 				continue;
527 			if (d.Selects[i].File == d.Selects[j].File
528 			    && d.Selects[i].Index == d.Selects[j].Index) {
529 				src_type &= ~d.Selects[j].SrcType;
530 			}
531 		}
532 		if (src_type & RC_SOURCE_RGB) {
533 			rgb_count++;
534 		}
535 
536 		if (src_type & RC_SOURCE_ALPHA) {
537 			alpha_count++;
538 		}
539 	}
540 
541 	if (rgb_count > 3 || alpha_count > 3) {
542 		return 0;
543 	}
544 
545 	return 1;
546 }
547 
548 struct max_data {
549 	unsigned int Max;
550 	unsigned int HasFileType;
551 	rc_register_file File;
552 };
553 
max_callback(void * userdata,struct rc_instruction * inst,rc_register_file file,unsigned int index,unsigned int mask)554 static void max_callback(
555 	void * userdata,
556 	struct rc_instruction * inst,
557 	rc_register_file file,
558 	unsigned int index,
559 	unsigned int mask)
560 {
561 	struct max_data * d = (struct max_data*)userdata;
562 	if (file == d->File && (!d->HasFileType || index > d->Max)) {
563 		d->Max = index;
564 		d->HasFileType = 1;
565 	}
566 }
567 
568 /**
569  * @return The maximum index of the specified register file used by the
570  * program.
571  */
rc_get_max_index(struct radeon_compiler * c,rc_register_file file)572 int rc_get_max_index(
573 	struct radeon_compiler * c,
574 	rc_register_file file)
575 {
576 	struct max_data data;
577 	struct rc_instruction * inst;
578 	data.Max = 0;
579 	data.HasFileType = 0;
580 	data.File = file;
581 	for (inst = c->Program.Instructions.Next;
582 					inst != &c->Program.Instructions;
583 					inst = inst->Next) {
584 		rc_for_all_reads_mask(inst, max_callback, &data);
585 		rc_for_all_writes_mask(inst, max_callback, &data);
586 	}
587 	if (!data.HasFileType) {
588 		return -1;
589 	} else {
590 		return data.Max;
591 	}
592 }
593 
594 /**
595  * This function removes a source from a pair instructions.
596  * @param inst
597  * @param src_type RC_SOURCE_RGB, RC_SOURCE_ALPHA, or both bitwise or'd
598  * @param source The index of the source to remove
599 
600  */
rc_pair_remove_src(struct rc_instruction * inst,unsigned int src_type,unsigned int source)601 void rc_pair_remove_src(
602 	struct rc_instruction * inst,
603 	unsigned int src_type,
604 	unsigned int source)
605 {
606 	if (src_type & RC_SOURCE_RGB) {
607 		memset(&inst->U.P.RGB.Src[source], 0,
608 			sizeof(struct rc_pair_instruction_source));
609 	}
610 
611 	if (src_type & RC_SOURCE_ALPHA) {
612 		memset(&inst->U.P.Alpha.Src[source], 0,
613 			sizeof(struct rc_pair_instruction_source));
614 	}
615 }
616 
617 /**
618  * @return RC_OPCODE_NOOP if inst is not a flow control instruction.
619  * @return The opcode of inst if it is a flow control instruction.
620  */
rc_get_flow_control_inst(struct rc_instruction * inst)621 rc_opcode rc_get_flow_control_inst(struct rc_instruction * inst)
622 {
623 	const struct rc_opcode_info * info;
624 	if (inst->Type == RC_INSTRUCTION_NORMAL) {
625 		info = rc_get_opcode_info(inst->U.I.Opcode);
626 	} else {
627 		info = rc_get_opcode_info(inst->U.P.RGB.Opcode);
628 		/*A flow control instruction shouldn't have an alpha
629 		 * instruction.*/
630 		assert(!info->IsFlowControl ||
631 				inst->U.P.Alpha.Opcode == RC_OPCODE_NOP);
632 	}
633 
634 	if (info->IsFlowControl)
635 		return info->Opcode;
636 	else
637 		return RC_OPCODE_NOP;
638 
639 }
640 
641 /**
642  * @return The BGNLOOP instruction that starts the loop ended by endloop.
643  */
rc_match_endloop(struct rc_instruction * endloop)644 struct rc_instruction * rc_match_endloop(struct rc_instruction * endloop)
645 {
646 	unsigned int endloop_count = 0;
647 	struct rc_instruction * inst;
648 	for (inst = endloop->Prev; inst != endloop; inst = inst->Prev) {
649 		rc_opcode op = rc_get_flow_control_inst(inst);
650 		if (op == RC_OPCODE_ENDLOOP) {
651 			endloop_count++;
652 		} else if (op == RC_OPCODE_BGNLOOP) {
653 			if (endloop_count == 0) {
654 				return inst;
655 			} else {
656 				endloop_count--;
657 			}
658 		}
659 	}
660 	return NULL;
661 }
662 
663 /**
664  * @return The ENDLOOP instruction that ends the loop started by bgnloop.
665  */
rc_match_bgnloop(struct rc_instruction * bgnloop)666 struct rc_instruction * rc_match_bgnloop(struct rc_instruction * bgnloop)
667 {
668 	unsigned int bgnloop_count = 0;
669 	struct rc_instruction * inst;
670 	for (inst = bgnloop->Next; inst!=bgnloop; inst = inst->Next) {
671 		rc_opcode op = rc_get_flow_control_inst(inst);
672 		if (op == RC_OPCODE_BGNLOOP) {
673 			bgnloop_count++;
674 		} else if (op == RC_OPCODE_ENDLOOP) {
675 			if (bgnloop_count == 0) {
676 				return inst;
677 			} else {
678 				bgnloop_count--;
679 			}
680 		}
681 	}
682 	return NULL;
683 }
684 
685 /**
686  * @return A conversion swizzle for converting from old_mask->new_mask
687  */
rc_make_conversion_swizzle(unsigned int old_mask,unsigned int new_mask)688 unsigned int rc_make_conversion_swizzle(
689 	unsigned int old_mask,
690 	unsigned int new_mask)
691 {
692 	unsigned int conversion_swizzle = rc_init_swizzle(RC_SWIZZLE_UNUSED, 0);
693 	unsigned int old_idx;
694 	unsigned int new_idx = 0;
695 	for (old_idx = 0; old_idx < 4; old_idx++) {
696 		if (!GET_BIT(old_mask, old_idx))
697 			continue;
698 		for ( ; new_idx < 4; new_idx++) {
699 			if (GET_BIT(new_mask, new_idx)) {
700 				SET_SWZ(conversion_swizzle, old_idx, new_idx);
701 				new_idx++;
702 				break;
703 			}
704 		}
705 	}
706 	return conversion_swizzle;
707 }
708 
709 /**
710  * @return 1 if the register contains an immediate value, 0 otherwise.
711  */
rc_src_reg_is_immediate(struct radeon_compiler * c,unsigned int file,unsigned int index)712 unsigned int rc_src_reg_is_immediate(
713 	struct radeon_compiler * c,
714 	unsigned int file,
715 	unsigned int index)
716 {
717 	return file == RC_FILE_CONSTANT &&
718 	c->Program.Constants.Constants[index].Type == RC_CONSTANT_IMMEDIATE;
719 }
720 
721 /**
722  * @return The immediate value in the specified register.
723  */
rc_get_constant_value(struct radeon_compiler * c,unsigned int index,unsigned int swizzle,unsigned int negate,unsigned int chan)724 float rc_get_constant_value(
725 	struct radeon_compiler * c,
726 	unsigned int index,
727 	unsigned int swizzle,
728 	unsigned int negate,
729 	unsigned int chan)
730 {
731 	float base = 1.0f;
732 	int swz = GET_SWZ(swizzle, chan);
733 	if(swz >= 4 || index >= c->Program.Constants.Count ){
734 		rc_error(c, "get_constant_value: Can't find a value.\n");
735 		return 0.0f;
736 	}
737 	if(GET_BIT(negate, chan)){
738 		base = -1.0f;
739 	}
740 	return base *
741 		c->Program.Constants.Constants[index].u.Immediate[swz];
742 }
743 
744 /**
745  * This function returns the component value (RC_SWIZZLE_*) of the first used
746  * channel in the swizzle.  This is only useful for scalar instructions that are
747  * known to use only one channel of the swizzle.
748  */
rc_get_scalar_src_swz(unsigned int swizzle)749 unsigned int rc_get_scalar_src_swz(unsigned int swizzle)
750 {
751 	unsigned int swz, chan;
752 	for (chan = 0; chan < 4; chan++) {
753 		swz = GET_SWZ(swizzle, chan);
754 		if (swz != RC_SWIZZLE_UNUSED) {
755 			break;
756 		}
757 	}
758 	assert(swz != RC_SWIZZLE_UNUSED);
759 	return swz;
760 }
761 
rc_inst_has_three_diff_temp_srcs(struct rc_instruction * inst)762 bool rc_inst_has_three_diff_temp_srcs(struct rc_instruction *inst)
763 {
764 	return (inst->U.I.SrcReg[0].File == RC_FILE_TEMPORARY &&
765 		inst->U.I.SrcReg[1].File == RC_FILE_TEMPORARY &&
766 		inst->U.I.SrcReg[2].File == RC_FILE_TEMPORARY &&
767 		inst->U.I.SrcReg[0].Index != inst->U.I.SrcReg[1].Index &&
768 		inst->U.I.SrcReg[1].Index != inst->U.I.SrcReg[2].Index &&
769 		inst->U.I.SrcReg[0].Index != inst->U.I.SrcReg[2].Index);
770 }
771