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