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