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