• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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