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