Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  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.  */
  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.  
  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.  */
  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.  
  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.  
  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.  */
  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. */
  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.  
  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.  */
  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.  
  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.  */
  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.  
  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.  */
  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.  */
  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.  */
  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.  
  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.  
  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.  */
  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.  
  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.  
  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.  */
  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.  
  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.  
  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.  */
  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.  
  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.  */
  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.  */
  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.  */
  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.  */
  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.  */
  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.  */
  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.  */
  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.  */
  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.