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 */
38unsigned 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
51rc_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 */
67unsigned 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
76unsigned 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
89unsigned 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 */
104rc_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. */
116unsigned 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
127static 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 */
148unsigned 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
164static 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 */
189void 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
209static 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 */
222void 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 */
261unsigned 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 */
288struct 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
306void 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
312unsigned 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 */
330unsigned 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
348unsigned 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
361struct src_select {
362	rc_register_file File;
363	int Index;
364	unsigned int SrcType;
365};
366
367struct 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
374static 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 */
392static 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
411unsigned 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
507struct max_data {
508	unsigned int Max;
509	unsigned int HasFileType;
510	rc_register_file File;
511};
512
513static 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 */
531int 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
553static 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 */
583unsigned 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 */
614rc_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 */
637struct 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 */
659struct 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 */
681unsigned 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 */
705unsigned 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 */
717float 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 */
742unsigned 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