Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright (C) 2009 Nicolai Haehnle.
  3.  * Copyright 2012 Advanced Micro Devices, Inc.
  4.  *
  5.  * All Rights Reserved.
  6.  *
  7.  * Permission is hereby granted, free of charge, to any person obtaining
  8.  * a copy of this software and associated documentation files (the
  9.  * "Software"), to deal in the Software without restriction, including
  10.  * without limitation the rights to use, copy, modify, merge, publish,
  11.  * distribute, sublicense, and/or sell copies of the Software, and to
  12.  * permit persons to whom the Software is furnished to do so, subject to
  13.  * the following conditions:
  14.  *
  15.  * The above copyright notice and this permission notice (including the
  16.  * next paragraph) shall be included in all copies or substantial
  17.  * portions of the Software.
  18.  *
  19.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  20.  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  21.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  22.  * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
  23.  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  24.  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  25.  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  26.  *
  27.  * Authors:
  28.  * Nicolai Haehnle
  29.  * Tom Stellard <thomas.stellard@amd.com>
  30.  */
  31.  
  32. #include "radeon_dataflow.h"
  33.  
  34. #include "radeon_code.h"
  35. #include "radeon_compiler.h"
  36. #include "radeon_compiler_util.h"
  37. #include "radeon_swizzle.h"
  38.  
  39.  
  40. static void rewrite_source(struct radeon_compiler * c,
  41.                 struct rc_instruction * inst, unsigned src)
  42. {
  43.         struct rc_swizzle_split split;
  44.         unsigned int tempreg = rc_find_free_temporary(c);
  45.         unsigned int usemask;
  46.  
  47.         usemask = 0;
  48.         for(unsigned int chan = 0; chan < 4; ++chan) {
  49.                 if (GET_SWZ(inst->U.I.SrcReg[src].Swizzle, chan) != RC_SWIZZLE_UNUSED)
  50.                         usemask |= 1 << chan;
  51.         }
  52.  
  53.         c->SwizzleCaps->Split(inst->U.I.SrcReg[src], usemask, &split);
  54.  
  55.         for(unsigned int phase = 0; phase < split.NumPhases; ++phase) {
  56.                 struct rc_instruction * mov = rc_insert_new_instruction(c, inst->Prev);
  57.                 unsigned int phase_refmask;
  58.                 unsigned int masked_negate;
  59.  
  60.                 mov->U.I.Opcode = RC_OPCODE_MOV;
  61.                 mov->U.I.DstReg.File = RC_FILE_TEMPORARY;
  62.                 mov->U.I.DstReg.Index = tempreg;
  63.                 mov->U.I.DstReg.WriteMask = split.Phase[phase];
  64.                 mov->U.I.SrcReg[0] = inst->U.I.SrcReg[src];
  65.                 mov->U.I.PreSub = inst->U.I.PreSub;
  66.  
  67.                 phase_refmask = 0;
  68.                 for(unsigned int chan = 0; chan < 4; ++chan) {
  69.                         if (!GET_BIT(split.Phase[phase], chan))
  70.                                 SET_SWZ(mov->U.I.SrcReg[0].Swizzle, chan, RC_SWIZZLE_UNUSED);
  71.                         else
  72.                                 phase_refmask |= 1 << GET_SWZ(mov->U.I.SrcReg[0].Swizzle, chan);
  73.                 }
  74.  
  75.                 phase_refmask &= RC_MASK_XYZW;
  76.  
  77.                 masked_negate = split.Phase[phase] & mov->U.I.SrcReg[0].Negate;
  78.                 if (masked_negate == 0)
  79.                         mov->U.I.SrcReg[0].Negate = 0;
  80.                 else if (masked_negate == split.Phase[phase])
  81.                         mov->U.I.SrcReg[0].Negate = RC_MASK_XYZW;
  82.  
  83.         }
  84.  
  85.         inst->U.I.SrcReg[src].File = RC_FILE_TEMPORARY;
  86.         inst->U.I.SrcReg[src].Index = tempreg;
  87.         inst->U.I.SrcReg[src].Swizzle = 0;
  88.         inst->U.I.SrcReg[src].Negate = RC_MASK_NONE;
  89.         inst->U.I.SrcReg[src].Abs = 0;
  90.         for(unsigned int chan = 0; chan < 4; ++chan) {
  91.                 SET_SWZ(inst->U.I.SrcReg[src].Swizzle, chan,
  92.                                 GET_BIT(usemask, chan) ? chan : RC_SWIZZLE_UNUSED);
  93.         }
  94. }
  95.  
  96. /**
  97.  * This function will attempt to rewrite non-native swizzles that read from
  98.  * immediate registers by rearranging the immediates to allow the
  99.  * instruction to use native swizzles.
  100.  */
  101. static unsigned try_rewrite_constant(struct radeon_compiler *c,
  102.                                         struct rc_src_register *reg)
  103. {
  104.         unsigned new_swizzle, chan, swz0, swz1, swz2, swz3, found_swizzle, swz;
  105.         unsigned all_inline = 0;
  106.         float imms[4] = {0.0f, 0.0f, 0.0f, 0.0f};
  107.  
  108.         if (!rc_src_reg_is_immediate(c, reg->File, reg->Index)) {
  109.                 /* The register does not contain immediates, but if all
  110.                  * the swizzles are inline constants, we can still rewrite
  111.                  * it. */
  112.  
  113.                 new_swizzle = RC_SWIZZLE_XYZW;
  114.                 for (chan = 0 ; chan < 4; chan++) {
  115.                         unsigned swz = GET_SWZ(reg->Swizzle, chan);
  116.                         if (swz <= RC_SWIZZLE_W) {
  117.                                 return 0;
  118.                         }
  119.                         if (swz == RC_SWIZZLE_UNUSED) {
  120.                                 SET_SWZ(new_swizzle, chan, RC_SWIZZLE_UNUSED);
  121.                         }
  122.                 }
  123.                 all_inline = 1;
  124.         } else {
  125.                 new_swizzle = reg->Swizzle;
  126.         }
  127.  
  128.         swz = RC_SWIZZLE_UNUSED;
  129.         found_swizzle = 1;
  130.         /* Check if all channels have the same swizzle.  If they do we can skip
  131.          * the search for a native swizzle.  We only need to check the first
  132.          * three channels, because any swizzle is legal in the fourth channel.
  133.          */
  134.         for (chan = 0; chan < 3; chan++) {
  135.                 unsigned chan_swz = GET_SWZ(reg->Swizzle, chan);
  136.                 if (chan_swz == RC_SWIZZLE_UNUSED) {
  137.                         continue;
  138.                 }
  139.                 if (swz == RC_SWIZZLE_UNUSED) {
  140.                         swz = chan_swz;
  141.                 } else if (swz != chan_swz) {
  142.                         found_swizzle = 0;
  143.                         break;
  144.                 }
  145.         }
  146.  
  147.         /* Find a legal swizzle */
  148.  
  149.         /* This loop attempts to find a native swizzle where all the
  150.          * channels are different. */
  151.         while (!found_swizzle && !all_inline) {
  152.                 swz0 = GET_SWZ(new_swizzle, 0);
  153.                 swz1 = GET_SWZ(new_swizzle, 1);
  154.                 swz2 = GET_SWZ(new_swizzle, 2);
  155.  
  156.                 /* Swizzle .W. is never legal. */
  157.                 if (swz1 == RC_SWIZZLE_W ||
  158.                         swz1 == RC_SWIZZLE_UNUSED ||
  159.                         swz1 == RC_SWIZZLE_ZERO ||
  160.                         swz1 == RC_SWIZZLE_HALF ||
  161.                         swz1 == RC_SWIZZLE_ONE) {
  162.                         /* We chose Z, because there are two non-repeating
  163.                          * swizzle combinations of the form .Z. There are
  164.                          * only one combination each for .X. and .Y. */
  165.                         SET_SWZ(new_swizzle, 1, RC_SWIZZLE_Z);
  166.                         continue;
  167.                 }
  168.  
  169.                 if (swz2 == RC_SWIZZLE_UNUSED) {
  170.                         /* We choose Y, because there are two non-repeating
  171.                          * swizzle combinations of the form ..Y */
  172.                         SET_SWZ(new_swizzle, 2, RC_SWIZZLE_Y);
  173.                         continue;
  174.                 }
  175.  
  176.                 switch (swz0) {
  177.                 /* X.. */
  178.                 case RC_SWIZZLE_X:
  179.                         /* Legal swizzles that start with X: XYZ, XXX */
  180.                         switch (swz1) {
  181.                         /* XX. */
  182.                         case RC_SWIZZLE_X:
  183.                                 /*  The new swizzle will be:
  184.                                  *  ZXY (XX. => ZX. => ZXY) */
  185.                                 SET_SWZ(new_swizzle, 0, RC_SWIZZLE_Z);
  186.                                 break;
  187.                         /* XY. */
  188.                         case RC_SWIZZLE_Y:
  189.                                 /* The new swizzle is XYZ */
  190.                                 SET_SWZ(new_swizzle, 2, RC_SWIZZLE_Z);
  191.                                 found_swizzle = 1;
  192.                                 break;
  193.                         /* XZ. */
  194.                         case RC_SWIZZLE_Z:
  195.                                 /* XZZ */
  196.                                 if (swz2 == RC_SWIZZLE_Z) {
  197.                                         /* The new swizzle is XYZ */
  198.                                         SET_SWZ(new_swizzle, 1, RC_SWIZZLE_Y);
  199.                                         found_swizzle = 1;
  200.                                 } else { /* XZ[^Z] */
  201.                                         /* The new swizzle will be:
  202.                                          * YZX (XZ. => YZ. => YZX) */
  203.                                         SET_SWZ(new_swizzle, 0, RC_SWIZZLE_Y);
  204.                                 }
  205.                                 break;
  206.                         /* XW. Should have already been handled. */
  207.                         case RC_SWIZZLE_W:
  208.                                 assert(0);
  209.                                 break;
  210.                         }
  211.                         break;
  212.                 /* Y.. */
  213.                 case RC_SWIZZLE_Y:
  214.                         /* Legal swizzles that start with Y: YYY, YZX */
  215.                         switch (swz1) {
  216.                         /* YY. */
  217.                         case RC_SWIZZLE_Y:
  218.                                 /* The new swizzle will be:
  219.                                  * XYZ (YY. => XY. => XYZ) */
  220.                                 SET_SWZ(new_swizzle, 0, RC_SWIZZLE_X);
  221.                                 break;
  222.                         /* YZ. */
  223.                         case RC_SWIZZLE_Z:
  224.                                 /* The new swizzle is YZX */
  225.                                 SET_SWZ(new_swizzle, 2, RC_SWIZZLE_X);
  226.                                 found_swizzle = 1;
  227.                                 break;
  228.                         /* YX. */
  229.                         case RC_SWIZZLE_X:
  230.                                 /* YXX */
  231.                                 if (swz2 == RC_SWIZZLE_X) {
  232.                                         /*The new swizzle is YZX */
  233.                                         SET_SWZ(new_swizzle, 1, RC_SWIZZLE_Z);
  234.                                         found_swizzle = 1;
  235.                                 } else { /* YX[^X] */
  236.                                         /* The new swizzle will be:
  237.                                          * ZXY (YX. => ZX. -> ZXY) */
  238.                                         SET_SWZ(new_swizzle, 0, RC_SWIZZLE_Z);
  239.                                 }
  240.                                 break;
  241.                         /* YW. Should have already been handled. */
  242.                         case RC_SWIZZLE_W:
  243.                                 assert(0);
  244.                                 break;
  245.                         }
  246.                         break;
  247.                 /* Z.. */
  248.                 case RC_SWIZZLE_Z:
  249.                         /* Legal swizzles that start with Z: ZZZ, ZXY */
  250.                         switch (swz1) {
  251.                         /* ZZ. */
  252.                         case RC_SWIZZLE_Z:
  253.                                 /* The new swizzle will be:
  254.                                  * WZY (ZZ. => WZ. => WZY) */
  255.                                 SET_SWZ(new_swizzle, 0, RC_SWIZZLE_W);
  256.                                 break;
  257.                         /* ZX. */
  258.                         case RC_SWIZZLE_X:
  259.                                 /* The new swizzle is ZXY */
  260.                                 SET_SWZ(new_swizzle, 2, RC_SWIZZLE_Y);
  261.                                 found_swizzle = 1;
  262.                                 break;
  263.                         /* ZY. */
  264.                         case RC_SWIZZLE_Y:
  265.                                 /* ZYY */
  266.                                 if (swz2 == RC_SWIZZLE_Y) {
  267.                                         /* The new swizzle is ZXY */
  268.                                         SET_SWZ(new_swizzle, 1, RC_SWIZZLE_X);
  269.                                         found_swizzle = 1;
  270.                                 } else { /* ZY[^Y] */
  271.                                         /* The new swizzle will be:
  272.                                          * XYZ (ZY. => XY. => XYZ) */
  273.                                         SET_SWZ(new_swizzle, 0, RC_SWIZZLE_X);
  274.                                 }
  275.                                 break;
  276.                         /* ZW. Should have already been handled. */
  277.                         case RC_SWIZZLE_W:
  278.                                 assert(0);
  279.                                 break;
  280.                         }
  281.                         break;
  282.  
  283.                 /* W.. */
  284.                 case RC_SWIZZLE_W:
  285.                         /* Legal swizzles that start with X: WWW, WZY */
  286.                         switch (swz1) {
  287.                         /* WW. Should have already been handled. */
  288.                         case RC_SWIZZLE_W:
  289.                                 assert(0);
  290.                                 break;
  291.                         /* WZ. */
  292.                         case RC_SWIZZLE_Z:
  293.                                 /* The new swizzle will be WZY */
  294.                                 SET_SWZ(new_swizzle, 2, RC_SWIZZLE_Y);
  295.                                 found_swizzle = 1;
  296.                                 break;
  297.                         /* WX. */
  298.                         case RC_SWIZZLE_X:
  299.                         /* WY. */
  300.                         case RC_SWIZZLE_Y:
  301.                                 /* W[XY]Y */
  302.                                 if (swz2 == RC_SWIZZLE_Y) {
  303.                                         /* The new swizzle will be WZY */
  304.                                         SET_SWZ(new_swizzle, 1, RC_SWIZZLE_Z);
  305.                                         found_swizzle = 1;
  306.                                 } else { /* W[XY][^Y] */
  307.                                         /* The new swizzle will be:
  308.                                          * ZXY (WX. => XX. => ZX. => ZXY) or
  309.                                          * XYZ (WY. => XY. => XYZ)
  310.                                          */
  311.                                         SET_SWZ(new_swizzle, 0, RC_SWIZZLE_X);
  312.                                 }
  313.                                 break;
  314.                         }
  315.                         break;
  316.                 /* U.. 0.. 1.. H..*/
  317.                 case RC_SWIZZLE_UNUSED:
  318.                 case RC_SWIZZLE_ZERO:
  319.                 case RC_SWIZZLE_ONE:
  320.                 case RC_SWIZZLE_HALF:
  321.                         SET_SWZ(new_swizzle, 0, RC_SWIZZLE_X);
  322.                         break;
  323.                 }
  324.         }
  325.  
  326.         /* Handle the swizzle in the w channel. */
  327.         swz3 = GET_SWZ(reg->Swizzle, 3);
  328.  
  329.         /* We can skip this if the swizzle in channel w is an inline constant. */
  330.         if (swz3 <= RC_SWIZZLE_W) {
  331.                 for (chan = 0; chan < 3; chan++) {
  332.                         unsigned old_swz = GET_SWZ(reg->Swizzle, chan);
  333.                         unsigned new_swz = GET_SWZ(new_swizzle, chan);
  334.                         /* If the swizzle in the w channel is the same as the
  335.                          * swizzle in any other channels, we need to rewrite it.
  336.                          * For example:
  337.                          * reg->Swizzle == XWZW
  338.                          * new_swizzle  == XYZX
  339.                          * Since the swizzle in the y channel is being
  340.                          * rewritten from W -> Y we need to change the swizzle
  341.                          * in the w channel from W -> Y as well.
  342.                          */
  343.                         if (old_swz == swz3) {
  344.                                 SET_SWZ(new_swizzle, 3,
  345.                                                 GET_SWZ(new_swizzle, chan));
  346.                                 break;
  347.                         }
  348.  
  349.                         /* The swizzle in channel w will be overwritten by one
  350.                          * of the new swizzles. */
  351.                         if (new_swz == swz3) {
  352.                                 /* Find an unused swizzle */
  353.                                 unsigned i;
  354.                                 unsigned used = 0;
  355.                                 for (i = 0; i < 3; i++) {
  356.                                         used |= 1 << GET_SWZ(new_swizzle, i);
  357.                                 }
  358.                                 for (i = 0; i < 4; i++) {
  359.                                         if (used & (1 << i)) {
  360.                                                 continue;
  361.                                         }
  362.                                         SET_SWZ(new_swizzle, 3, i);
  363.                                 }
  364.                         }
  365.                 }
  366.         }
  367.  
  368.         for (chan = 0; chan < 4; chan++) {
  369.                 unsigned old_swz = GET_SWZ(reg->Swizzle, chan);
  370.                 unsigned new_swz = GET_SWZ(new_swizzle, chan);
  371.  
  372.                 if (old_swz == RC_SWIZZLE_UNUSED) {
  373.                         continue;
  374.                 }
  375.  
  376.                 /* We don't need to change the swizzle in channel w if it is
  377.                  * an inline constant.  These are always legal in the w channel.
  378.                  *
  379.                  * Swizzles with a value > RC_SWIZZLE_W are inline constants.
  380.                  */
  381.                 if (chan == 3 && old_swz > RC_SWIZZLE_W) {
  382.                         continue;
  383.                 }
  384.  
  385.                 assert(new_swz <= RC_SWIZZLE_W);
  386.  
  387.                 switch (old_swz) {
  388.                 case RC_SWIZZLE_ZERO:
  389.                         imms[new_swz] = 0.0f;
  390.                         break;
  391.                 case RC_SWIZZLE_HALF:
  392.                         if (reg->Negate & (1 << chan)) {
  393.                                 imms[new_swz] = -0.5f;
  394.                         } else {
  395.                                 imms[new_swz] = 0.5f;
  396.                         }
  397.                         break;
  398.                 case RC_SWIZZLE_ONE:
  399.                         if (reg->Negate & (1 << chan)) {
  400.                                 imms[new_swz] = -1.0f;
  401.                         } else {
  402.                                 imms[new_swz] = 1.0f;
  403.                         }
  404.                         break;
  405.                 default:
  406.                         imms[new_swz] = rc_get_constant_value(c, reg->Index,
  407.                                         reg->Swizzle, reg->Negate, chan);
  408.                 }
  409.                 SET_SWZ(reg->Swizzle, chan, new_swz);
  410.         }
  411.         reg->Index = rc_constants_add_immediate_vec4(&c->Program.Constants,
  412.                                                         imms);
  413.         /* We need to set the register file to CONSTANT in case we are
  414.          * converting a non-constant register with constant swizzles (e.g.
  415.          * ONE, ZERO, HALF).
  416.          */
  417.         reg->File = RC_FILE_CONSTANT;
  418.         reg->Negate = 0;
  419.         return 1;
  420. }
  421.  
  422. void rc_dataflow_swizzles(struct radeon_compiler * c, void *user)
  423. {
  424.         struct rc_instruction * inst;
  425.  
  426.         for(inst = c->Program.Instructions.Next;
  427.                                         inst != &c->Program.Instructions;
  428.                                         inst = inst->Next) {
  429.                 const struct rc_opcode_info * opcode =
  430.                                         rc_get_opcode_info(inst->U.I.Opcode);
  431.                 unsigned int src;
  432.  
  433.                 for(src = 0; src < opcode->NumSrcRegs; ++src) {
  434.                         struct rc_src_register *reg = &inst->U.I.SrcReg[src];
  435.                         if (c->SwizzleCaps->IsNative(inst->U.I.Opcode, *reg)) {
  436.                                 continue;
  437.                         }
  438.                         if (!c->is_r500 &&
  439.                             c->Program.Constants.Count < R300_PFS_NUM_CONST_REGS &&
  440.                             try_rewrite_constant(c, reg)) {
  441.                                 continue;
  442.                         }
  443.                         rewrite_source(c, inst, src);
  444.                 }
  445.         }
  446.         if (c->Debug & RC_DBG_LOG)
  447.                 rc_constants_print(&c->Program.Constants);
  448. }
  449.