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