182f1c0be1325130ab03d3bef629264618924b897Brian Paul/*
282f1c0be1325130ab03d3bef629264618924b897Brian Paul * Mesa 3-D graphics library
382f1c0be1325130ab03d3bef629264618924b897Brian Paul * Version:  7.5
482f1c0be1325130ab03d3bef629264618924b897Brian Paul *
582f1c0be1325130ab03d3bef629264618924b897Brian Paul * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
682f1c0be1325130ab03d3bef629264618924b897Brian Paul *
782f1c0be1325130ab03d3bef629264618924b897Brian Paul * Permission is hereby granted, free of charge, to any person obtaining a
882f1c0be1325130ab03d3bef629264618924b897Brian Paul * copy of this software and associated documentation files (the "Software"),
982f1c0be1325130ab03d3bef629264618924b897Brian Paul * to deal in the Software without restriction, including without limitation
1082f1c0be1325130ab03d3bef629264618924b897Brian Paul * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1182f1c0be1325130ab03d3bef629264618924b897Brian Paul * and/or sell copies of the Software, and to permit persons to whom the
1282f1c0be1325130ab03d3bef629264618924b897Brian Paul * Software is furnished to do so, subject to the following conditions:
1382f1c0be1325130ab03d3bef629264618924b897Brian Paul *
1482f1c0be1325130ab03d3bef629264618924b897Brian Paul * The above copyright notice and this permission notice shall be included
1582f1c0be1325130ab03d3bef629264618924b897Brian Paul * in all copies or substantial portions of the Software.
1682f1c0be1325130ab03d3bef629264618924b897Brian Paul *
1782f1c0be1325130ab03d3bef629264618924b897Brian Paul * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1882f1c0be1325130ab03d3bef629264618924b897Brian Paul * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1982f1c0be1325130ab03d3bef629264618924b897Brian Paul * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
2082f1c0be1325130ab03d3bef629264618924b897Brian Paul * VMWARE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
2182f1c0be1325130ab03d3bef629264618924b897Brian Paul * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2282f1c0be1325130ab03d3bef629264618924b897Brian Paul * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2382f1c0be1325130ab03d3bef629264618924b897Brian Paul */
2482f1c0be1325130ab03d3bef629264618924b897Brian Paul
2582f1c0be1325130ab03d3bef629264618924b897Brian Paul
2682f1c0be1325130ab03d3bef629264618924b897Brian Paul
2782f1c0be1325130ab03d3bef629264618924b897Brian Paul#include "main/glheader.h"
2882f1c0be1325130ab03d3bef629264618924b897Brian Paul#include "main/context.h"
2982f1c0be1325130ab03d3bef629264618924b897Brian Paul#include "main/macros.h"
3082f1c0be1325130ab03d3bef629264618924b897Brian Paul#include "program.h"
3182f1c0be1325130ab03d3bef629264618924b897Brian Paul#include "prog_instruction.h"
3282f1c0be1325130ab03d3bef629264618924b897Brian Paul#include "prog_optimize.h"
3382f1c0be1325130ab03d3bef629264618924b897Brian Paul#include "prog_print.h"
3482f1c0be1325130ab03d3bef629264618924b897Brian Paul
3582f1c0be1325130ab03d3bef629264618924b897Brian Paul
3612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul#define MAX_LOOP_NESTING 50
378bbdf6e7cdfc3265439761a06eea79627f4ee2faEric Anholt/* MAX_PROGRAM_TEMPS is a low number (256), and we want to be able to
388bbdf6e7cdfc3265439761a06eea79627f4ee2faEric Anholt * register allocate many temporary values into that small number of
398bbdf6e7cdfc3265439761a06eea79627f4ee2faEric Anholt * temps.  So allow large temporary indices coming into the register
408bbdf6e7cdfc3265439761a06eea79627f4ee2faEric Anholt * allocator.
418bbdf6e7cdfc3265439761a06eea79627f4ee2faEric Anholt */
428bbdf6e7cdfc3265439761a06eea79627f4ee2faEric Anholt#define REG_ALLOCATE_MAX_PROGRAM_TEMPS	((1 << INST_INDEX_BITS) - 1)
4312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
4482f1c0be1325130ab03d3bef629264618924b897Brian Paulstatic GLboolean dbg = GL_FALSE;
4582f1c0be1325130ab03d3bef629264618924b897Brian Paul
469021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia#define NO_MASK 0xf
479021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia
48e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul/**
49e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul * Returns the mask of channels (bitmask of WRITEMASK_X,Y,Z,W) which
50e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul * are read from the given src in this instruction, We also provide
51e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul * one optional masks which may mask other components in the dst
52e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul * register
536b0bcfafab7b380ee71da1a7754f4c09614811d6Eric Anholt */
546b0bcfafab7b380ee71da1a7754f4c09614811d6Eric Anholtstatic GLuint
55e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paulget_src_arg_mask(const struct prog_instruction *inst,
56e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul                 GLuint arg, GLuint dst_mask)
576b0bcfafab7b380ee71da1a7754f4c09614811d6Eric Anholt{
58e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul   GLuint read_mask, channel_mask;
59e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul   GLuint comp;
60e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul
619021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   ASSERT(arg < _mesa_num_inst_src_regs(inst->Opcode));
626b0bcfafab7b380ee71da1a7754f4c09614811d6Eric Anholt
639021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   /* Form the dst register, find the written channels */
649021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   if (inst->CondUpdate) {
659021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      channel_mask = WRITEMASK_XYZW;
669021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   }
679021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   else {
689021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      switch (inst->Opcode) {
699021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      case OPCODE_MOV:
709021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      case OPCODE_MIN:
719021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      case OPCODE_MAX:
729021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      case OPCODE_ABS:
739021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      case OPCODE_ADD:
749021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      case OPCODE_MAD:
759021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      case OPCODE_MUL:
769021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      case OPCODE_SUB:
77257cc48de2f4e472eb651a4c70042e5cb6b9fe0eTom Stellard      case OPCODE_CMP:
78257cc48de2f4e472eb651a4c70042e5cb6b9fe0eTom Stellard      case OPCODE_FLR:
79257cc48de2f4e472eb651a4c70042e5cb6b9fe0eTom Stellard      case OPCODE_FRC:
80257cc48de2f4e472eb651a4c70042e5cb6b9fe0eTom Stellard      case OPCODE_LRP:
81257cc48de2f4e472eb651a4c70042e5cb6b9fe0eTom Stellard      case OPCODE_SEQ:
82257cc48de2f4e472eb651a4c70042e5cb6b9fe0eTom Stellard      case OPCODE_SGE:
83257cc48de2f4e472eb651a4c70042e5cb6b9fe0eTom Stellard      case OPCODE_SGT:
84257cc48de2f4e472eb651a4c70042e5cb6b9fe0eTom Stellard      case OPCODE_SLE:
85257cc48de2f4e472eb651a4c70042e5cb6b9fe0eTom Stellard      case OPCODE_SLT:
86257cc48de2f4e472eb651a4c70042e5cb6b9fe0eTom Stellard      case OPCODE_SNE:
87257cc48de2f4e472eb651a4c70042e5cb6b9fe0eTom Stellard      case OPCODE_SSG:
889021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         channel_mask = inst->DstReg.WriteMask & dst_mask;
899021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         break;
909021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      case OPCODE_RCP:
919021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      case OPCODE_SIN:
929021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      case OPCODE_COS:
939021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      case OPCODE_RSQ:
949021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      case OPCODE_POW:
959021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      case OPCODE_EX2:
969021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      case OPCODE_LOG:
979021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         channel_mask = WRITEMASK_X;
989021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         break;
999021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      case OPCODE_DP2:
1009021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         channel_mask = WRITEMASK_XY;
1019021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         break;
1029021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      case OPCODE_DP3:
1039021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      case OPCODE_XPD:
1049021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         channel_mask = WRITEMASK_XYZ;
1059021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         break;
1069021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      default:
1079021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         channel_mask = WRITEMASK_XYZW;
1089021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         break;
1099021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      }
1109021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   }
1116b0bcfafab7b380ee71da1a7754f4c09614811d6Eric Anholt
1129021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   /* Now, given the src swizzle and the written channels, find which
1139021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia    * components are actually read
1149021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia    */
115e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul   read_mask = 0x0;
1169021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   for (comp = 0; comp < 4; ++comp) {
117e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul      const GLuint coord = GET_SWZ(inst->SrcReg[arg].Swizzle, comp);
1189021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      ASSERT(coord < 4);
1199021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      if (channel_mask & (1 << comp) && coord <= SWIZZLE_W)
1209021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         read_mask |= 1 << coord;
1216b0bcfafab7b380ee71da1a7754f4c09614811d6Eric Anholt   }
1229021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia
1239021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   return read_mask;
1249021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia}
1259021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia
126e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul
127e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul/**
128e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul * For a MOV instruction, compute a write mask when src register also has
129e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul * a mask
1309021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia */
1319021c56a5738815777f27c39b63637b5975270c6Benjamin Segoviastatic GLuint
132e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paulget_dst_mask_for_mov(const struct prog_instruction *mov, GLuint src_mask)
1339021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia{
134e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul   const GLuint mask = mov->DstReg.WriteMask;
135e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul   GLuint comp;
136e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul   GLuint updated_mask = 0x0;
137e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul
1389021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   ASSERT(mov->Opcode == OPCODE_MOV);
1399021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia
1409021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   for (comp = 0; comp < 4; ++comp) {
141e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul      GLuint src_comp;
1429021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      if ((mask & (1 << comp)) == 0)
1439021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         continue;
1449021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      src_comp = GET_SWZ(mov->SrcReg[0].Swizzle, comp);
1459021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      if ((src_mask & (1 << src_comp)) == 0)
1469021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         continue;
1479021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      updated_mask |= 1 << comp;
1489021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   }
1499021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia
1509021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   return updated_mask;
1519021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia}
1529021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia
153e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul
154e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul/**
155e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul * Ensure that the swizzle is regular.  That is, all of the swizzle
156e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul * terms are SWIZZLE_X,Y,Z,W and not SWIZZLE_ZERO or SWIZZLE_ONE.
157e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul */
158e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paulstatic GLboolean
159e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paulis_swizzle_regular(GLuint swz)
1609021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia{
1619021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   return GET_SWZ(swz,0) <= SWIZZLE_W &&
1629021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia          GET_SWZ(swz,1) <= SWIZZLE_W &&
1639021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia          GET_SWZ(swz,2) <= SWIZZLE_W &&
1649021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia          GET_SWZ(swz,3) <= SWIZZLE_W;
1656b0bcfafab7b380ee71da1a7754f4c09614811d6Eric Anholt}
1666b0bcfafab7b380ee71da1a7754f4c09614811d6Eric Anholt
167e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul
16882f1c0be1325130ab03d3bef629264618924b897Brian Paul/**
16982f1c0be1325130ab03d3bef629264618924b897Brian Paul * In 'prog' remove instruction[i] if removeFlags[i] == TRUE.
17082f1c0be1325130ab03d3bef629264618924b897Brian Paul * \return number of instructions removed
17182f1c0be1325130ab03d3bef629264618924b897Brian Paul */
17282f1c0be1325130ab03d3bef629264618924b897Brian Paulstatic GLuint
17382f1c0be1325130ab03d3bef629264618924b897Brian Paulremove_instructions(struct gl_program *prog, const GLboolean *removeFlags)
17482f1c0be1325130ab03d3bef629264618924b897Brian Paul{
17582f1c0be1325130ab03d3bef629264618924b897Brian Paul   GLint i, removeEnd = 0, removeCount = 0;
17682f1c0be1325130ab03d3bef629264618924b897Brian Paul   GLuint totalRemoved = 0;
17782f1c0be1325130ab03d3bef629264618924b897Brian Paul
17882f1c0be1325130ab03d3bef629264618924b897Brian Paul   /* go backward */
17982f1c0be1325130ab03d3bef629264618924b897Brian Paul   for (i = prog->NumInstructions - 1; i >= 0; i--) {
18082f1c0be1325130ab03d3bef629264618924b897Brian Paul      if (removeFlags[i]) {
18182f1c0be1325130ab03d3bef629264618924b897Brian Paul         totalRemoved++;
18282f1c0be1325130ab03d3bef629264618924b897Brian Paul         if (removeCount == 0) {
18382f1c0be1325130ab03d3bef629264618924b897Brian Paul            /* begin a run of instructions to remove */
18482f1c0be1325130ab03d3bef629264618924b897Brian Paul            removeEnd = i;
18582f1c0be1325130ab03d3bef629264618924b897Brian Paul            removeCount = 1;
18682f1c0be1325130ab03d3bef629264618924b897Brian Paul         }
18782f1c0be1325130ab03d3bef629264618924b897Brian Paul         else {
18882f1c0be1325130ab03d3bef629264618924b897Brian Paul            /* extend the run of instructions to remove */
18982f1c0be1325130ab03d3bef629264618924b897Brian Paul            removeCount++;
19082f1c0be1325130ab03d3bef629264618924b897Brian Paul         }
19182f1c0be1325130ab03d3bef629264618924b897Brian Paul      }
19282f1c0be1325130ab03d3bef629264618924b897Brian Paul      else {
19382f1c0be1325130ab03d3bef629264618924b897Brian Paul         /* don't remove this instruction, but check if the preceeding
19482f1c0be1325130ab03d3bef629264618924b897Brian Paul          * instructions are to be removed.
19582f1c0be1325130ab03d3bef629264618924b897Brian Paul          */
19682f1c0be1325130ab03d3bef629264618924b897Brian Paul         if (removeCount > 0) {
19782f1c0be1325130ab03d3bef629264618924b897Brian Paul            GLint removeStart = removeEnd - removeCount + 1;
19882f1c0be1325130ab03d3bef629264618924b897Brian Paul            _mesa_delete_instructions(prog, removeStart, removeCount);
19982f1c0be1325130ab03d3bef629264618924b897Brian Paul            removeStart = removeCount = 0; /* reset removal info */
20082f1c0be1325130ab03d3bef629264618924b897Brian Paul         }
20182f1c0be1325130ab03d3bef629264618924b897Brian Paul      }
20282f1c0be1325130ab03d3bef629264618924b897Brian Paul   }
203f3cacfe216fb58b913bbc23de49d696a33da69e1Eric Anholt   /* Finish removing if the first instruction was to be removed. */
204f3cacfe216fb58b913bbc23de49d696a33da69e1Eric Anholt   if (removeCount > 0) {
205f3cacfe216fb58b913bbc23de49d696a33da69e1Eric Anholt      GLint removeStart = removeEnd - removeCount + 1;
206f3cacfe216fb58b913bbc23de49d696a33da69e1Eric Anholt      _mesa_delete_instructions(prog, removeStart, removeCount);
207f3cacfe216fb58b913bbc23de49d696a33da69e1Eric Anholt   }
20882f1c0be1325130ab03d3bef629264618924b897Brian Paul   return totalRemoved;
20982f1c0be1325130ab03d3bef629264618924b897Brian Paul}
21082f1c0be1325130ab03d3bef629264618924b897Brian Paul
21182f1c0be1325130ab03d3bef629264618924b897Brian Paul
21282f1c0be1325130ab03d3bef629264618924b897Brian Paul/**
21312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul * Remap register indexes according to map.
21412256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul * \param prog  the program to search/replace
21512256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul * \param file  the type of register file to search/replace
21612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul * \param map  maps old register indexes to new indexes
21712256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul */
21812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paulstatic void
21912256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paulreplace_regs(struct gl_program *prog, gl_register_file file, const GLint map[])
22012256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul{
22112256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   GLuint i;
22212256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
22312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   for (i = 0; i < prog->NumInstructions; i++) {
22412256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      struct prog_instruction *inst = prog->Instructions + i;
22512256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode);
22612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      GLuint j;
22712256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      for (j = 0; j < numSrc; j++) {
22812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         if (inst->SrcReg[j].File == file) {
22912256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul            GLuint index = inst->SrcReg[j].Index;
23012256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul            ASSERT(map[index] >= 0);
23112256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul            inst->SrcReg[j].Index = map[index];
23212256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         }
23312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      }
23412256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      if (inst->DstReg.File == file) {
23512256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         const GLuint index = inst->DstReg.Index;
23612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         ASSERT(map[index] >= 0);
23712256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         inst->DstReg.Index = map[index];
23812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      }
23912256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   }
24012256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul}
24112256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
242e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul
24382f1c0be1325130ab03d3bef629264618924b897Brian Paul/**
24482f1c0be1325130ab03d3bef629264618924b897Brian Paul * Remove dead instructions from the given program.
24582f1c0be1325130ab03d3bef629264618924b897Brian Paul * This is very primitive for now.  Basically look for temp registers
24682f1c0be1325130ab03d3bef629264618924b897Brian Paul * that are written to but never read.  Remove any instructions that
24782f1c0be1325130ab03d3bef629264618924b897Brian Paul * write to such registers.  Be careful with condition code setters.
24882f1c0be1325130ab03d3bef629264618924b897Brian Paul */
2499021c56a5738815777f27c39b63637b5975270c6Benjamin Segoviastatic GLboolean
2509021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia_mesa_remove_dead_code_global(struct gl_program *prog)
25182f1c0be1325130ab03d3bef629264618924b897Brian Paul{
2528bbdf6e7cdfc3265439761a06eea79627f4ee2faEric Anholt   GLboolean tempRead[REG_ALLOCATE_MAX_PROGRAM_TEMPS][4];
25382f1c0be1325130ab03d3bef629264618924b897Brian Paul   GLboolean *removeInst; /* per-instruction removal flag */
254ee0a9e6e10060287747d9dd4afead3cbbb168e09Eric Anholt   GLuint i, rem = 0, comp;
25582f1c0be1325130ab03d3bef629264618924b897Brian Paul
25682f1c0be1325130ab03d3bef629264618924b897Brian Paul   memset(tempRead, 0, sizeof(tempRead));
25782f1c0be1325130ab03d3bef629264618924b897Brian Paul
25882f1c0be1325130ab03d3bef629264618924b897Brian Paul   if (dbg) {
259298be2b028263b2c343a707662c6fbfa18293cb2Kristian Høgsberg      printf("Optimize: Begin dead code removal\n");
26082f1c0be1325130ab03d3bef629264618924b897Brian Paul      /*_mesa_print_program(prog);*/
26182f1c0be1325130ab03d3bef629264618924b897Brian Paul   }
26282f1c0be1325130ab03d3bef629264618924b897Brian Paul
26382f1c0be1325130ab03d3bef629264618924b897Brian Paul   removeInst = (GLboolean *)
26432f2fd1c5d6088692551c80352b7d6fa35b0cd09Kristian Høgsberg      calloc(1, prog->NumInstructions * sizeof(GLboolean));
26582f1c0be1325130ab03d3bef629264618924b897Brian Paul
26682f1c0be1325130ab03d3bef629264618924b897Brian Paul   /* Determine which temps are read and written */
26782f1c0be1325130ab03d3bef629264618924b897Brian Paul   for (i = 0; i < prog->NumInstructions; i++) {
26882f1c0be1325130ab03d3bef629264618924b897Brian Paul      const struct prog_instruction *inst = prog->Instructions + i;
26982f1c0be1325130ab03d3bef629264618924b897Brian Paul      const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode);
27082f1c0be1325130ab03d3bef629264618924b897Brian Paul      GLuint j;
27182f1c0be1325130ab03d3bef629264618924b897Brian Paul
27282f1c0be1325130ab03d3bef629264618924b897Brian Paul      /* check src regs */
27382f1c0be1325130ab03d3bef629264618924b897Brian Paul      for (j = 0; j < numSrc; j++) {
27482f1c0be1325130ab03d3bef629264618924b897Brian Paul         if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) {
27582f1c0be1325130ab03d3bef629264618924b897Brian Paul            const GLuint index = inst->SrcReg[j].Index;
27618768393d19dedee7d4282e84905bb396dd30960brian            GLuint read_mask;
2778bbdf6e7cdfc3265439761a06eea79627f4ee2faEric Anholt            ASSERT(index < REG_ALLOCATE_MAX_PROGRAM_TEMPS);
2789021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia	    read_mask = get_src_arg_mask(inst, j, NO_MASK);
27982f1c0be1325130ab03d3bef629264618924b897Brian Paul
28082f1c0be1325130ab03d3bef629264618924b897Brian Paul            if (inst->SrcReg[j].RelAddr) {
28182f1c0be1325130ab03d3bef629264618924b897Brian Paul               if (dbg)
282298be2b028263b2c343a707662c6fbfa18293cb2Kristian Høgsberg                  printf("abort remove dead code (indirect temp)\n");
283ee0a9e6e10060287747d9dd4afead3cbbb168e09Eric Anholt               goto done;
28482f1c0be1325130ab03d3bef629264618924b897Brian Paul            }
28582f1c0be1325130ab03d3bef629264618924b897Brian Paul
286ee0a9e6e10060287747d9dd4afead3cbbb168e09Eric Anholt	    for (comp = 0; comp < 4; comp++) {
2879021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia	       const GLuint swz = GET_SWZ(inst->SrcReg[j].Swizzle, comp);
2889021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia	       ASSERT(swz < 4);
2899021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia               if ((read_mask & (1 << swz)) == 0)
2906b0bcfafab7b380ee71da1a7754f4c09614811d6Eric Anholt		  continue;
2919021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia               if (swz <= SWIZZLE_W)
2929021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia                  tempRead[index][swz] = GL_TRUE;
293ee0a9e6e10060287747d9dd4afead3cbbb168e09Eric Anholt	    }
29482f1c0be1325130ab03d3bef629264618924b897Brian Paul         }
29582f1c0be1325130ab03d3bef629264618924b897Brian Paul      }
29682f1c0be1325130ab03d3bef629264618924b897Brian Paul
29782f1c0be1325130ab03d3bef629264618924b897Brian Paul      /* check dst reg */
29882f1c0be1325130ab03d3bef629264618924b897Brian Paul      if (inst->DstReg.File == PROGRAM_TEMPORARY) {
29982f1c0be1325130ab03d3bef629264618924b897Brian Paul         const GLuint index = inst->DstReg.Index;
3008bbdf6e7cdfc3265439761a06eea79627f4ee2faEric Anholt         ASSERT(index < REG_ALLOCATE_MAX_PROGRAM_TEMPS);
30182f1c0be1325130ab03d3bef629264618924b897Brian Paul
30282f1c0be1325130ab03d3bef629264618924b897Brian Paul         if (inst->DstReg.RelAddr) {
30382f1c0be1325130ab03d3bef629264618924b897Brian Paul            if (dbg)
304298be2b028263b2c343a707662c6fbfa18293cb2Kristian Høgsberg               printf("abort remove dead code (indirect temp)\n");
305ee0a9e6e10060287747d9dd4afead3cbbb168e09Eric Anholt            goto done;
30682f1c0be1325130ab03d3bef629264618924b897Brian Paul         }
30782f1c0be1325130ab03d3bef629264618924b897Brian Paul
30882f1c0be1325130ab03d3bef629264618924b897Brian Paul         if (inst->CondUpdate) {
30982f1c0be1325130ab03d3bef629264618924b897Brian Paul            /* If we're writing to this register and setting condition
31082f1c0be1325130ab03d3bef629264618924b897Brian Paul             * codes we cannot remove the instruction.  Prevent removal
31182f1c0be1325130ab03d3bef629264618924b897Brian Paul             * by setting the 'read' flag.
31282f1c0be1325130ab03d3bef629264618924b897Brian Paul             */
313ee0a9e6e10060287747d9dd4afead3cbbb168e09Eric Anholt            tempRead[index][0] = GL_TRUE;
314ee0a9e6e10060287747d9dd4afead3cbbb168e09Eric Anholt            tempRead[index][1] = GL_TRUE;
315ee0a9e6e10060287747d9dd4afead3cbbb168e09Eric Anholt            tempRead[index][2] = GL_TRUE;
316ee0a9e6e10060287747d9dd4afead3cbbb168e09Eric Anholt            tempRead[index][3] = GL_TRUE;
31782f1c0be1325130ab03d3bef629264618924b897Brian Paul         }
31882f1c0be1325130ab03d3bef629264618924b897Brian Paul      }
31982f1c0be1325130ab03d3bef629264618924b897Brian Paul   }
32082f1c0be1325130ab03d3bef629264618924b897Brian Paul
32182f1c0be1325130ab03d3bef629264618924b897Brian Paul   /* find instructions that write to dead registers, flag for removal */
32282f1c0be1325130ab03d3bef629264618924b897Brian Paul   for (i = 0; i < prog->NumInstructions; i++) {
323ee0a9e6e10060287747d9dd4afead3cbbb168e09Eric Anholt      struct prog_instruction *inst = prog->Instructions + i;
324ee0a9e6e10060287747d9dd4afead3cbbb168e09Eric Anholt      const GLuint numDst = _mesa_num_inst_dst_regs(inst->Opcode);
325ee0a9e6e10060287747d9dd4afead3cbbb168e09Eric Anholt
326ee0a9e6e10060287747d9dd4afead3cbbb168e09Eric Anholt      if (numDst != 0 && inst->DstReg.File == PROGRAM_TEMPORARY) {
327ee0a9e6e10060287747d9dd4afead3cbbb168e09Eric Anholt         GLint chan, index = inst->DstReg.Index;
328ee0a9e6e10060287747d9dd4afead3cbbb168e09Eric Anholt
329ee0a9e6e10060287747d9dd4afead3cbbb168e09Eric Anholt	 for (chan = 0; chan < 4; chan++) {
330ee0a9e6e10060287747d9dd4afead3cbbb168e09Eric Anholt	    if (!tempRead[index][chan] &&
331ee0a9e6e10060287747d9dd4afead3cbbb168e09Eric Anholt		inst->DstReg.WriteMask & (1 << chan)) {
332ee0a9e6e10060287747d9dd4afead3cbbb168e09Eric Anholt	       if (dbg) {
333298be2b028263b2c343a707662c6fbfa18293cb2Kristian Høgsberg		  printf("Remove writemask on %u.%c\n", i,
334ee0a9e6e10060287747d9dd4afead3cbbb168e09Eric Anholt			       chan == 3 ? 'w' : 'x' + chan);
335ee0a9e6e10060287747d9dd4afead3cbbb168e09Eric Anholt	       }
336ee0a9e6e10060287747d9dd4afead3cbbb168e09Eric Anholt	       inst->DstReg.WriteMask &= ~(1 << chan);
337ee0a9e6e10060287747d9dd4afead3cbbb168e09Eric Anholt	       rem++;
338ee0a9e6e10060287747d9dd4afead3cbbb168e09Eric Anholt	    }
339ee0a9e6e10060287747d9dd4afead3cbbb168e09Eric Anholt	 }
340ee0a9e6e10060287747d9dd4afead3cbbb168e09Eric Anholt
341ee0a9e6e10060287747d9dd4afead3cbbb168e09Eric Anholt	 if (inst->DstReg.WriteMask == 0) {
342ee0a9e6e10060287747d9dd4afead3cbbb168e09Eric Anholt	    /* If we cleared all writes, the instruction can be removed. */
343ee0a9e6e10060287747d9dd4afead3cbbb168e09Eric Anholt	    if (dbg)
344298be2b028263b2c343a707662c6fbfa18293cb2Kristian Høgsberg	       printf("Remove instruction %u: \n", i);
345ee0a9e6e10060287747d9dd4afead3cbbb168e09Eric Anholt	    removeInst[i] = GL_TRUE;
346ee0a9e6e10060287747d9dd4afead3cbbb168e09Eric Anholt	 }
34782f1c0be1325130ab03d3bef629264618924b897Brian Paul      }
34882f1c0be1325130ab03d3bef629264618924b897Brian Paul   }
34982f1c0be1325130ab03d3bef629264618924b897Brian Paul
35082f1c0be1325130ab03d3bef629264618924b897Brian Paul   /* now remove the instructions which aren't needed */
35182f1c0be1325130ab03d3bef629264618924b897Brian Paul   rem = remove_instructions(prog, removeInst);
35282f1c0be1325130ab03d3bef629264618924b897Brian Paul
35382f1c0be1325130ab03d3bef629264618924b897Brian Paul   if (dbg) {
354298be2b028263b2c343a707662c6fbfa18293cb2Kristian Høgsberg      printf("Optimize: End dead code removal.\n");
355298be2b028263b2c343a707662c6fbfa18293cb2Kristian Høgsberg      printf("  %u channel writes removed\n", rem);
356298be2b028263b2c343a707662c6fbfa18293cb2Kristian Høgsberg      printf("  %u instructions removed\n", rem);
35782f1c0be1325130ab03d3bef629264618924b897Brian Paul      /*_mesa_print_program(prog);*/
35882f1c0be1325130ab03d3bef629264618924b897Brian Paul   }
359ee0a9e6e10060287747d9dd4afead3cbbb168e09Eric Anholt
360ee0a9e6e10060287747d9dd4afead3cbbb168e09Eric Anholtdone:
36132f2fd1c5d6088692551c80352b7d6fa35b0cd09Kristian Høgsberg   free(removeInst);
3629021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   return rem != 0;
36382f1c0be1325130ab03d3bef629264618924b897Brian Paul}
36482f1c0be1325130ab03d3bef629264618924b897Brian Paul
36582f1c0be1325130ab03d3bef629264618924b897Brian Paul
3669021c56a5738815777f27c39b63637b5975270c6Benjamin Segoviaenum inst_use
36782f1c0be1325130ab03d3bef629264618924b897Brian Paul{
36882f1c0be1325130ab03d3bef629264618924b897Brian Paul   READ,
36982f1c0be1325130ab03d3bef629264618924b897Brian Paul   WRITE,
37082f1c0be1325130ab03d3bef629264618924b897Brian Paul   FLOW,
37182f1c0be1325130ab03d3bef629264618924b897Brian Paul   END
37282f1c0be1325130ab03d3bef629264618924b897Brian Paul};
37382f1c0be1325130ab03d3bef629264618924b897Brian Paul
374e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul
37582f1c0be1325130ab03d3bef629264618924b897Brian Paul/**
3769021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia * Scan forward in program from 'start' for the next occurances of TEMP[index].
3779021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia * We look if an instruction reads the component given by the masks and if they
3789021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia * are overwritten.
37982f1c0be1325130ab03d3bef629264618924b897Brian Paul * Return READ, WRITE, FLOW or END to indicate the next usage or an indicator
38082f1c0be1325130ab03d3bef629264618924b897Brian Paul * that we can't look further.
38182f1c0be1325130ab03d3bef629264618924b897Brian Paul */
3829021c56a5738815777f27c39b63637b5975270c6Benjamin Segoviastatic enum inst_use
3839021c56a5738815777f27c39b63637b5975270c6Benjamin Segoviafind_next_use(const struct gl_program *prog,
3849021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia              GLuint start,
3859021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia              GLuint index,
3869021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia              GLuint mask)
38782f1c0be1325130ab03d3bef629264618924b897Brian Paul{
38882f1c0be1325130ab03d3bef629264618924b897Brian Paul   GLuint i;
38982f1c0be1325130ab03d3bef629264618924b897Brian Paul
39082f1c0be1325130ab03d3bef629264618924b897Brian Paul   for (i = start; i < prog->NumInstructions; i++) {
39182f1c0be1325130ab03d3bef629264618924b897Brian Paul      const struct prog_instruction *inst = prog->Instructions + i;
39282f1c0be1325130ab03d3bef629264618924b897Brian Paul      switch (inst->Opcode) {
39382f1c0be1325130ab03d3bef629264618924b897Brian Paul      case OPCODE_BGNLOOP:
39482f1c0be1325130ab03d3bef629264618924b897Brian Paul      case OPCODE_BGNSUB:
3959021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      case OPCODE_BRA:
3969021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      case OPCODE_CAL:
3979021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      case OPCODE_CONT:
3989021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      case OPCODE_IF:
3999021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      case OPCODE_ELSE:
4009021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      case OPCODE_ENDIF:
4019021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      case OPCODE_ENDLOOP:
40282f1c0be1325130ab03d3bef629264618924b897Brian Paul      case OPCODE_ENDSUB:
4039021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      case OPCODE_RET:
40482f1c0be1325130ab03d3bef629264618924b897Brian Paul         return FLOW;
4059021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      case OPCODE_END:
4069021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         return END;
40782f1c0be1325130ab03d3bef629264618924b897Brian Paul      default:
40882f1c0be1325130ab03d3bef629264618924b897Brian Paul         {
40982f1c0be1325130ab03d3bef629264618924b897Brian Paul            const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode);
41082f1c0be1325130ab03d3bef629264618924b897Brian Paul            GLuint j;
41182f1c0be1325130ab03d3bef629264618924b897Brian Paul            for (j = 0; j < numSrc; j++) {
4129021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia               if (inst->SrcReg[j].RelAddr ||
4139021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia                   (inst->SrcReg[j].File == PROGRAM_TEMPORARY &&
4149021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia                   inst->SrcReg[j].Index == index &&
4159021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia                   (get_src_arg_mask(inst,j,NO_MASK) & mask)))
41682f1c0be1325130ab03d3bef629264618924b897Brian Paul                  return READ;
41782f1c0be1325130ab03d3bef629264618924b897Brian Paul            }
4189021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia            if (_mesa_num_inst_dst_regs(inst->Opcode) == 1 &&
4199021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia                inst->DstReg.File == PROGRAM_TEMPORARY &&
4209021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia                inst->DstReg.Index == index) {
4219021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia               mask &= ~inst->DstReg.WriteMask;
4229021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia               if (mask == 0)
4239021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia                  return WRITE;
4249021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia            }
42582f1c0be1325130ab03d3bef629264618924b897Brian Paul         }
42682f1c0be1325130ab03d3bef629264618924b897Brian Paul      }
42782f1c0be1325130ab03d3bef629264618924b897Brian Paul   }
42882f1c0be1325130ab03d3bef629264618924b897Brian Paul   return END;
42982f1c0be1325130ab03d3bef629264618924b897Brian Paul}
43082f1c0be1325130ab03d3bef629264618924b897Brian Paul
431e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul
432e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul/**
433e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul * Is the given instruction opcode a flow-control opcode?
434e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul * XXX maybe move this into prog_instruction.[ch]
435e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul */
436e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paulstatic GLboolean
437e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul_mesa_is_flow_control_opcode(enum prog_opcode opcode)
438d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt{
439d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt   switch (opcode) {
440d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt   case OPCODE_BGNLOOP:
441d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt   case OPCODE_BGNSUB:
442d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt   case OPCODE_BRA:
443d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt   case OPCODE_CAL:
444d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt   case OPCODE_CONT:
445d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt   case OPCODE_IF:
446d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt   case OPCODE_ELSE:
447d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt   case OPCODE_END:
448d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt   case OPCODE_ENDIF:
449d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt   case OPCODE_ENDLOOP:
450d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt   case OPCODE_ENDSUB:
451d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt   case OPCODE_RET:
452d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt      return GL_TRUE;
453d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt   default:
454d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt      return GL_FALSE;
455d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt   }
456d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt}
45782f1c0be1325130ab03d3bef629264618924b897Brian Paul
458e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul
459e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul/**
460e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul * Test if the given instruction is a simple MOV (no conditional updating,
461e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul * not relative addressing, no negation/abs, etc).
462e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul */
4639021c56a5738815777f27c39b63637b5975270c6Benjamin Segoviastatic GLboolean
4649021c56a5738815777f27c39b63637b5975270c6Benjamin Segoviacan_downward_mov_be_modifed(const struct prog_instruction *mov)
4659021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia{
4669021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   return
4679021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      mov->Opcode == OPCODE_MOV &&
4689021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      mov->CondUpdate == GL_FALSE &&
4699021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      mov->SrcReg[0].RelAddr == 0 &&
4709021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      mov->SrcReg[0].Negate == 0 &&
4719021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      mov->SrcReg[0].Abs == 0 &&
4729021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      mov->SrcReg[0].HasIndex2 == 0 &&
4739021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      mov->SrcReg[0].RelAddr2 == 0 &&
4749021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      mov->DstReg.RelAddr == 0 &&
4756bd5f43f212962a054a41290b0f8e350dae2f40dEric Anholt      mov->DstReg.CondMask == COND_TR;
4769021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia}
4779021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia
478e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul
4799021c56a5738815777f27c39b63637b5975270c6Benjamin Segoviastatic GLboolean
4809021c56a5738815777f27c39b63637b5975270c6Benjamin Segoviacan_upward_mov_be_modifed(const struct prog_instruction *mov)
4819021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia{
4829021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   return
4839021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      can_downward_mov_be_modifed(mov) &&
4846bd5f43f212962a054a41290b0f8e350dae2f40dEric Anholt      mov->DstReg.File == PROGRAM_TEMPORARY &&
4856bd5f43f212962a054a41290b0f8e350dae2f40dEric Anholt      mov->SaturateMode == SATURATE_OFF;
4869021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia}
4879021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia
488e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul
48982f1c0be1325130ab03d3bef629264618924b897Brian Paul/**
490e4e312d493847e07ced026b93d2b588b8036ae02Eric Anholt * Try to remove use of extraneous MOV instructions, to free them up for dead
491e4e312d493847e07ced026b93d2b588b8036ae02Eric Anholt * code removal.
492e4e312d493847e07ced026b93d2b588b8036ae02Eric Anholt */
493e4e312d493847e07ced026b93d2b588b8036ae02Eric Anholtstatic void
494e4e312d493847e07ced026b93d2b588b8036ae02Eric Anholt_mesa_remove_extra_move_use(struct gl_program *prog)
495e4e312d493847e07ced026b93d2b588b8036ae02Eric Anholt{
496d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt   GLuint i, j;
497e4e312d493847e07ced026b93d2b588b8036ae02Eric Anholt
498e4e312d493847e07ced026b93d2b588b8036ae02Eric Anholt   if (dbg) {
499298be2b028263b2c343a707662c6fbfa18293cb2Kristian Høgsberg      printf("Optimize: Begin remove extra move use\n");
500e4e312d493847e07ced026b93d2b588b8036ae02Eric Anholt      _mesa_print_program(prog);
501e4e312d493847e07ced026b93d2b588b8036ae02Eric Anholt   }
502e4e312d493847e07ced026b93d2b588b8036ae02Eric Anholt
503e4e312d493847e07ced026b93d2b588b8036ae02Eric Anholt   /*
504e4e312d493847e07ced026b93d2b588b8036ae02Eric Anholt    * Look for sequences such as this:
505e4e312d493847e07ced026b93d2b588b8036ae02Eric Anholt    *    MOV tmpX, arg0;
506d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt    *    ...
507e4e312d493847e07ced026b93d2b588b8036ae02Eric Anholt    *    FOO tmpY, tmpX, arg1;
508e4e312d493847e07ced026b93d2b588b8036ae02Eric Anholt    * and convert into:
509e4e312d493847e07ced026b93d2b588b8036ae02Eric Anholt    *    MOV tmpX, arg0;
510d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt    *    ...
511e4e312d493847e07ced026b93d2b588b8036ae02Eric Anholt    *    FOO tmpY, arg0, arg1;
512e4e312d493847e07ced026b93d2b588b8036ae02Eric Anholt    */
513e4e312d493847e07ced026b93d2b588b8036ae02Eric Anholt
514c4e8918cd248189d43cdc8df9f9f0450040261c5Eric Anholt   for (i = 0; i + 1 < prog->NumInstructions; i++) {
515e4e312d493847e07ced026b93d2b588b8036ae02Eric Anholt      const struct prog_instruction *mov = prog->Instructions + i;
516e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul      GLuint dst_mask, src_mask;
5179021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      if (can_upward_mov_be_modifed(mov) == GL_FALSE)
5189021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         continue;
519e4e312d493847e07ced026b93d2b588b8036ae02Eric Anholt
5209021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      /* Scanning the code, we maintain the components which are still active in
5219021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia       * these two masks
5229021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia       */
5239021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      dst_mask = mov->DstReg.WriteMask;
5249021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      src_mask = get_src_arg_mask(mov, 0, NO_MASK);
525e4e312d493847e07ced026b93d2b588b8036ae02Eric Anholt
526d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt      /* Walk through remaining instructions until the or src reg gets
527d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt       * rewritten or we get into some flow-control, eliminating the use of
528d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt       * this MOV.
529d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt       */
530d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt      for (j = i + 1; j < prog->NumInstructions; j++) {
531d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt	 struct prog_instruction *inst2 = prog->Instructions + j;
5329021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         GLuint arg;
533d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt
534d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt	 if (_mesa_is_flow_control_opcode(inst2->Opcode))
535d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt	     break;
536d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt
537d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt	 /* First rewrite this instruction's args if appropriate. */
538d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt	 for (arg = 0; arg < _mesa_num_inst_src_regs(inst2->Opcode); arg++) {
539e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul	    GLuint comp, read_mask;
540d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt
541d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt	    if (inst2->SrcReg[arg].File != mov->DstReg.File ||
542d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt		inst2->SrcReg[arg].Index != mov->DstReg.Index ||
543d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt		inst2->SrcReg[arg].RelAddr ||
544d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt		inst2->SrcReg[arg].Abs)
545d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt	       continue;
5469021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia            read_mask = get_src_arg_mask(inst2, arg, NO_MASK);
547d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt
5489021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia	    /* Adjust the swizzles of inst2 to point at MOV's source if ALL the
5499021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia             * components read still come from the mov instructions
5509021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia             */
551e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul            if (is_swizzle_regular(inst2->SrcReg[arg].Swizzle) &&
5529021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia               (read_mask & dst_mask) == read_mask) {
5539021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia               for (comp = 0; comp < 4; comp++) {
554e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul                  const GLuint inst2_swz =
555e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul                     GET_SWZ(inst2->SrcReg[arg].Swizzle, comp);
556e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul                  const GLuint s = GET_SWZ(mov->SrcReg[0].Swizzle, inst2_swz);
5579021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia                  inst2->SrcReg[arg].Swizzle &= ~(7 << (3 * comp));
5589021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia                  inst2->SrcReg[arg].Swizzle |= s << (3 * comp);
5599021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia                  inst2->SrcReg[arg].Negate ^= (((mov->SrcReg[0].Negate >>
5609021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia                                                  inst2_swz) & 0x1) << comp);
5619021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia               }
5629021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia               inst2->SrcReg[arg].File = mov->SrcReg[0].File;
5639021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia               inst2->SrcReg[arg].Index = mov->SrcReg[0].Index;
5649021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia            }
565e4e312d493847e07ced026b93d2b588b8036ae02Eric Anholt	 }
566d6690ce15fb8c7c6abf1bc0d847c1d2da2c33904Eric Anholt
5679021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia	 /* The source of MOV is written. This potentially deactivates some
5689021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia          * components from the src and dst of the MOV instruction
5699021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia          */
5709021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia	 if (inst2->DstReg.File == mov->DstReg.File &&
5719021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia	     (inst2->DstReg.RelAddr ||
5729021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia	      inst2->DstReg.Index == mov->DstReg.Index)) {
5739021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia            dst_mask &= ~inst2->DstReg.WriteMask;
5749021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia            src_mask = get_src_arg_mask(mov, 0, dst_mask);
5759021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         }
5769021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia
5779021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         /* Idem when the destination of mov is written */
5789021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia	 if (inst2->DstReg.File == mov->SrcReg[0].File &&
5799021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia	     (inst2->DstReg.RelAddr ||
5809021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia	      inst2->DstReg.Index == mov->SrcReg[0].Index)) {
5819021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia            src_mask &= ~inst2->DstReg.WriteMask;
5829021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia            dst_mask &= get_dst_mask_for_mov(mov, src_mask);
5839021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         }
5849021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         if (dst_mask == 0)
5859021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia            break;
586e4e312d493847e07ced026b93d2b588b8036ae02Eric Anholt      }
587e4e312d493847e07ced026b93d2b588b8036ae02Eric Anholt   }
588e4e312d493847e07ced026b93d2b588b8036ae02Eric Anholt
589e4e312d493847e07ced026b93d2b588b8036ae02Eric Anholt   if (dbg) {
590298be2b028263b2c343a707662c6fbfa18293cb2Kristian Høgsberg      printf("Optimize: End remove extra move use.\n");
591e4e312d493847e07ced026b93d2b588b8036ae02Eric Anholt      /*_mesa_print_program(prog);*/
592e4e312d493847e07ced026b93d2b588b8036ae02Eric Anholt   }
593e4e312d493847e07ced026b93d2b588b8036ae02Eric Anholt}
594e4e312d493847e07ced026b93d2b588b8036ae02Eric Anholt
595e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul
596e4e312d493847e07ced026b93d2b588b8036ae02Eric Anholt/**
5979021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia * Complements dead_code_global. Try to remove code in block of code by
5989021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia * carefully monitoring the swizzles. Both functions should be merged into one
5999021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia * with a proper control flow graph
6009021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia */
6019021c56a5738815777f27c39b63637b5975270c6Benjamin Segoviastatic GLboolean
6029021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia_mesa_remove_dead_code_local(struct gl_program *prog)
6039021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia{
6049021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   GLboolean *removeInst;
6059021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   GLuint i, arg, rem = 0;
6069021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia
6079021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   removeInst = (GLboolean *)
6089021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      calloc(1, prog->NumInstructions * sizeof(GLboolean));
6099021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia
6109021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   for (i = 0; i < prog->NumInstructions; i++) {
6119021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      const struct prog_instruction *inst = prog->Instructions + i;
6129021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      const GLuint index = inst->DstReg.Index;
6139021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      const GLuint mask = inst->DstReg.WriteMask;
6149021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      enum inst_use use;
6159021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia
6169021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      /* We must deactivate the pass as soon as some indirection is used */
6179021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      if (inst->DstReg.RelAddr)
6189021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         goto done;
6199021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      for (arg = 0; arg < _mesa_num_inst_src_regs(inst->Opcode); arg++)
6209021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         if (inst->SrcReg[arg].RelAddr)
6219021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia            goto done;
6229021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia
6239021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      if (_mesa_is_flow_control_opcode(inst->Opcode) ||
6249021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia          _mesa_num_inst_dst_regs(inst->Opcode) == 0 ||
6259021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia          inst->DstReg.File != PROGRAM_TEMPORARY ||
6269021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia          inst->DstReg.RelAddr)
6279021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         continue;
6289021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia
6299021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      use = find_next_use(prog, i+1, index, mask);
6309021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      if (use == WRITE || use == END)
6319021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         removeInst[i] = GL_TRUE;
6329021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   }
6339021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia
6349021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   rem = remove_instructions(prog, removeInst);
6359021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia
6369021c56a5738815777f27c39b63637b5975270c6Benjamin Segoviadone:
6379021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   free(removeInst);
6389021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   return rem != 0;
6399021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia}
6409021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia
641e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul
6429021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia/**
6439021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia * Try to inject the destination of mov as the destination of inst and recompute
6449021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia * the swizzles operators for the sources of inst if required. Return GL_TRUE
6459021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia * of the substitution was possible, GL_FALSE otherwise
6469021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia */
6479021c56a5738815777f27c39b63637b5975270c6Benjamin Segoviastatic GLboolean
6489021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia_mesa_merge_mov_into_inst(struct prog_instruction *inst,
6499021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia                          const struct prog_instruction *mov)
6509021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia{
6519021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   /* Indirection table which associates destination and source components for
6529021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia    * the mov instruction
6539021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia    */
6549021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   const GLuint mask = get_src_arg_mask(mov, 0, NO_MASK);
6559021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia
6569021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   /* Some components are not written by inst. We cannot remove the mov */
6579021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   if (mask != (inst->DstReg.WriteMask & mask))
6589021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      return GL_FALSE;
6599021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia
6606bd5f43f212962a054a41290b0f8e350dae2f40dEric Anholt   inst->SaturateMode |= mov->SaturateMode;
6616bd5f43f212962a054a41290b0f8e350dae2f40dEric Anholt
6629021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   /* Depending on the instruction, we may need to recompute the swizzles.
6639021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia    * Also, some other instructions (like TEX) are not linear. We will only
6649021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia    * consider completely active sources and destinations
6659021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia    */
6669021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   switch (inst->Opcode) {
6679021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia
6689021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   /* Carstesian instructions: we compute the swizzle */
6699021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   case OPCODE_MOV:
6709021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   case OPCODE_MIN:
6719021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   case OPCODE_MAX:
6729021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   case OPCODE_ABS:
6739021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   case OPCODE_ADD:
6749021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   case OPCODE_MAD:
6759021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   case OPCODE_MUL:
6769021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   case OPCODE_SUB:
6779021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   {
678e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul      GLuint dst_to_src_comp[4] = {0,0,0,0};
679e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul      GLuint dst_comp, arg;
6809021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      for (dst_comp = 0; dst_comp < 4; ++dst_comp) {
6819021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         if (mov->DstReg.WriteMask & (1 << dst_comp)) {
682e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul            const GLuint src_comp = GET_SWZ(mov->SrcReg[0].Swizzle, dst_comp);
6839021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia            ASSERT(src_comp < 4);
6849021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia            dst_to_src_comp[dst_comp] = src_comp;
6859021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         }
6869021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      }
6879021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia
6889021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      /* Patch each source of the instruction */
6899021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      for (arg = 0; arg < _mesa_num_inst_src_regs(inst->Opcode); arg++) {
690e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul         const GLuint arg_swz = inst->SrcReg[arg].Swizzle;
6919021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         inst->SrcReg[arg].Swizzle = 0;
6929021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia
6939021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         /* Reset each active component of the swizzle */
6949021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         for (dst_comp = 0; dst_comp < 4; ++dst_comp) {
695e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul            GLuint src_comp, arg_comp;
6969021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia            if ((mov->DstReg.WriteMask & (1 << dst_comp)) == 0)
6979021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia               continue;
6989021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia            src_comp = dst_to_src_comp[dst_comp];
6999021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia            ASSERT(src_comp < 4);
7009021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia            arg_comp = GET_SWZ(arg_swz, src_comp);
7019021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia            ASSERT(arg_comp < 4);
7029021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia            inst->SrcReg[arg].Swizzle |= arg_comp << (3*dst_comp);
7039021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         }
7049021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      }
7059021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      inst->DstReg = mov->DstReg;
7069021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      return GL_TRUE;
7079021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   }
7089021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia
7099021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   /* Dot products and scalar instructions: we only change the destination */
7109021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   case OPCODE_RCP:
7119021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   case OPCODE_SIN:
7129021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   case OPCODE_COS:
7139021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   case OPCODE_RSQ:
7149021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   case OPCODE_POW:
7159021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   case OPCODE_EX2:
7169021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   case OPCODE_LOG:
7179021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   case OPCODE_DP2:
7189021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   case OPCODE_DP3:
7199021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   case OPCODE_DP4:
7209021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      inst->DstReg = mov->DstReg;
7219021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      return GL_TRUE;
7229021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia
7239021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   /* All other instructions require fully active components with no swizzle */
7249021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   default:
7259021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      if (mov->SrcReg[0].Swizzle != SWIZZLE_XYZW ||
7269021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia          inst->DstReg.WriteMask != WRITEMASK_XYZW)
7279021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         return GL_FALSE;
7289021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      inst->DstReg = mov->DstReg;
7299021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      return GL_TRUE;
7309021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   }
7319021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia}
7329021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia
733e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul
7349021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia/**
73582f1c0be1325130ab03d3bef629264618924b897Brian Paul * Try to remove extraneous MOV instructions from the given program.
73682f1c0be1325130ab03d3bef629264618924b897Brian Paul */
7379021c56a5738815777f27c39b63637b5975270c6Benjamin Segoviastatic GLboolean
73882f1c0be1325130ab03d3bef629264618924b897Brian Paul_mesa_remove_extra_moves(struct gl_program *prog)
73982f1c0be1325130ab03d3bef629264618924b897Brian Paul{
74082f1c0be1325130ab03d3bef629264618924b897Brian Paul   GLboolean *removeInst; /* per-instruction removal flag */
7419021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   GLuint i, rem = 0, nesting = 0;
74282f1c0be1325130ab03d3bef629264618924b897Brian Paul
74382f1c0be1325130ab03d3bef629264618924b897Brian Paul   if (dbg) {
744298be2b028263b2c343a707662c6fbfa18293cb2Kristian Høgsberg      printf("Optimize: Begin remove extra moves\n");
74582f1c0be1325130ab03d3bef629264618924b897Brian Paul      _mesa_print_program(prog);
74682f1c0be1325130ab03d3bef629264618924b897Brian Paul   }
74782f1c0be1325130ab03d3bef629264618924b897Brian Paul
74882f1c0be1325130ab03d3bef629264618924b897Brian Paul   removeInst = (GLboolean *)
74932f2fd1c5d6088692551c80352b7d6fa35b0cd09Kristian Høgsberg      calloc(1, prog->NumInstructions * sizeof(GLboolean));
75082f1c0be1325130ab03d3bef629264618924b897Brian Paul
75182f1c0be1325130ab03d3bef629264618924b897Brian Paul   /*
75282f1c0be1325130ab03d3bef629264618924b897Brian Paul    * Look for sequences such as this:
75382f1c0be1325130ab03d3bef629264618924b897Brian Paul    *    FOO tmpX, arg0, arg1;
75482f1c0be1325130ab03d3bef629264618924b897Brian Paul    *    MOV tmpY, tmpX;
75582f1c0be1325130ab03d3bef629264618924b897Brian Paul    * and convert into:
75682f1c0be1325130ab03d3bef629264618924b897Brian Paul    *    FOO tmpY, arg0, arg1;
75782f1c0be1325130ab03d3bef629264618924b897Brian Paul    */
75882f1c0be1325130ab03d3bef629264618924b897Brian Paul
75982f1c0be1325130ab03d3bef629264618924b897Brian Paul   for (i = 0; i < prog->NumInstructions; i++) {
7609021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      const struct prog_instruction *mov = prog->Instructions + i;
76182f1c0be1325130ab03d3bef629264618924b897Brian Paul
7629021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      switch (mov->Opcode) {
76382f1c0be1325130ab03d3bef629264618924b897Brian Paul      case OPCODE_BGNLOOP:
76482f1c0be1325130ab03d3bef629264618924b897Brian Paul      case OPCODE_BGNSUB:
7659021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      case OPCODE_IF:
7669021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         nesting++;
76782f1c0be1325130ab03d3bef629264618924b897Brian Paul         break;
7689021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      case OPCODE_ENDLOOP:
76982f1c0be1325130ab03d3bef629264618924b897Brian Paul      case OPCODE_ENDSUB:
7709021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      case OPCODE_ENDIF:
7719021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         nesting--;
77282f1c0be1325130ab03d3bef629264618924b897Brian Paul         break;
77382f1c0be1325130ab03d3bef629264618924b897Brian Paul      case OPCODE_MOV:
7745a38e70d59eb54aa375fb0f19c824bb74b71486dBenjamin Segovia         if (i > 0 &&
7755a38e70d59eb54aa375fb0f19c824bb74b71486dBenjamin Segovia             can_downward_mov_be_modifed(mov) &&
7765a38e70d59eb54aa375fb0f19c824bb74b71486dBenjamin Segovia             mov->SrcReg[0].File == PROGRAM_TEMPORARY &&
7775a38e70d59eb54aa375fb0f19c824bb74b71486dBenjamin Segovia             nesting == 0)
7785a38e70d59eb54aa375fb0f19c824bb74b71486dBenjamin Segovia         {
7799021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia
78082f1c0be1325130ab03d3bef629264618924b897Brian Paul            /* see if this MOV can be removed */
7819021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia            const GLuint id = mov->SrcReg[0].Index;
78282f1c0be1325130ab03d3bef629264618924b897Brian Paul            struct prog_instruction *prevInst;
78382f1c0be1325130ab03d3bef629264618924b897Brian Paul            GLuint prevI;
78482f1c0be1325130ab03d3bef629264618924b897Brian Paul
78582f1c0be1325130ab03d3bef629264618924b897Brian Paul            /* get pointer to previous instruction */
78682f1c0be1325130ab03d3bef629264618924b897Brian Paul            prevI = i - 1;
787324568f79d6e014900c981bd9a0e1dffedc326c8Roel Kluin            while (prevI > 0 && removeInst[prevI])
78882f1c0be1325130ab03d3bef629264618924b897Brian Paul               prevI--;
78982f1c0be1325130ab03d3bef629264618924b897Brian Paul            prevInst = prog->Instructions + prevI;
79082f1c0be1325130ab03d3bef629264618924b897Brian Paul
79182f1c0be1325130ab03d3bef629264618924b897Brian Paul            if (prevInst->DstReg.File == PROGRAM_TEMPORARY &&
7929021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia                prevInst->DstReg.Index == id &&
7939021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia                prevInst->DstReg.RelAddr == 0 &&
7949021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia                prevInst->DstReg.CondSrc == 0 &&
7959021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia                prevInst->DstReg.CondMask == COND_TR) {
79682f1c0be1325130ab03d3bef629264618924b897Brian Paul
7979021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia               const GLuint dst_mask = prevInst->DstReg.WriteMask;
7989021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia               enum inst_use next_use = find_next_use(prog, i+1, id, dst_mask);
79982f1c0be1325130ab03d3bef629264618924b897Brian Paul
80082f1c0be1325130ab03d3bef629264618924b897Brian Paul               if (next_use == WRITE || next_use == END) {
80182f1c0be1325130ab03d3bef629264618924b897Brian Paul                  /* OK, we can safely remove this MOV instruction.
80282f1c0be1325130ab03d3bef629264618924b897Brian Paul                   * Transform:
80382f1c0be1325130ab03d3bef629264618924b897Brian Paul                   *   prevI: FOO tempIndex, x, y;
80482f1c0be1325130ab03d3bef629264618924b897Brian Paul                   *       i: MOV z, tempIndex;
80582f1c0be1325130ab03d3bef629264618924b897Brian Paul                   * Into:
80682f1c0be1325130ab03d3bef629264618924b897Brian Paul                   *   prevI: FOO z, x, y;
80782f1c0be1325130ab03d3bef629264618924b897Brian Paul                   */
8089021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia                  if (_mesa_merge_mov_into_inst(prevInst, mov)) {
8099021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia                     removeInst[i] = GL_TRUE;
8109021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia                     if (dbg) {
8119021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia                        printf("Remove MOV at %u\n", i);
8129021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia                        printf("new prev inst %u: ", prevI);
8139021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia                        _mesa_print_instruction(prevInst);
8149021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia                     }
81582f1c0be1325130ab03d3bef629264618924b897Brian Paul                  }
81682f1c0be1325130ab03d3bef629264618924b897Brian Paul               }
81782f1c0be1325130ab03d3bef629264618924b897Brian Paul            }
81882f1c0be1325130ab03d3bef629264618924b897Brian Paul         }
81982f1c0be1325130ab03d3bef629264618924b897Brian Paul         break;
82082f1c0be1325130ab03d3bef629264618924b897Brian Paul      default:
82182f1c0be1325130ab03d3bef629264618924b897Brian Paul         ; /* nothing */
82282f1c0be1325130ab03d3bef629264618924b897Brian Paul      }
82382f1c0be1325130ab03d3bef629264618924b897Brian Paul   }
82482f1c0be1325130ab03d3bef629264618924b897Brian Paul
82582f1c0be1325130ab03d3bef629264618924b897Brian Paul   /* now remove the instructions which aren't needed */
82682f1c0be1325130ab03d3bef629264618924b897Brian Paul   rem = remove_instructions(prog, removeInst);
82782f1c0be1325130ab03d3bef629264618924b897Brian Paul
82832f2fd1c5d6088692551c80352b7d6fa35b0cd09Kristian Høgsberg   free(removeInst);
82905749542384abc4d4776bfe2a386b6396002e0dfBrian Paul
83082f1c0be1325130ab03d3bef629264618924b897Brian Paul   if (dbg) {
831298be2b028263b2c343a707662c6fbfa18293cb2Kristian Høgsberg      printf("Optimize: End remove extra moves.  %u instructions removed\n", rem);
83282f1c0be1325130ab03d3bef629264618924b897Brian Paul      /*_mesa_print_program(prog);*/
83382f1c0be1325130ab03d3bef629264618924b897Brian Paul   }
8349021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia
8359021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   return rem != 0;
83682f1c0be1325130ab03d3bef629264618924b897Brian Paul}
83782f1c0be1325130ab03d3bef629264618924b897Brian Paul
83882f1c0be1325130ab03d3bef629264618924b897Brian Paul
83912256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul/** A live register interval */
84012256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paulstruct interval
84112256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul{
84212256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   GLuint Reg;         /** The temporary register index */
84312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   GLuint Start, End;  /** Start/end instruction numbers */
84412256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul};
84512256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
84612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
84712256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul/** A list of register intervals */
84812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paulstruct interval_list
84912256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul{
85012256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   GLuint Num;
8518bbdf6e7cdfc3265439761a06eea79627f4ee2faEric Anholt   struct interval Intervals[REG_ALLOCATE_MAX_PROGRAM_TEMPS];
85212256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul};
85312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
85412256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
85512256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paulstatic void
85612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paulappend_interval(struct interval_list *list, const struct interval *inv)
85712256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul{
85812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   list->Intervals[list->Num++] = *inv;
85912256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul}
86012256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
86112256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
86212256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul/** Insert interval inv into list, sorted by interval end */
86312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paulstatic void
86412256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paulinsert_interval_by_end(struct interval_list *list, const struct interval *inv)
86512256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul{
86612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   /* XXX we could do a binary search insertion here since list is sorted */
86712256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   GLint i = list->Num - 1;
86812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   while (i >= 0 && list->Intervals[i].End > inv->End) {
86912256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      list->Intervals[i + 1] = list->Intervals[i];
87012256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      i--;
87112256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   }
87212256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   list->Intervals[i + 1] = *inv;
87312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   list->Num++;
87412256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
87512256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul#ifdef DEBUG
87612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   {
87712256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      GLuint i;
87812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      for (i = 0; i + 1 < list->Num; i++) {
87912256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         ASSERT(list->Intervals[i].End <= list->Intervals[i + 1].End);
88012256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      }
88112256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   }
88212256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul#endif
88312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul}
88412256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
88512256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
88612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul/** Remove the given interval from the interval list */
88712256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paulstatic void
88812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paulremove_interval(struct interval_list *list, const struct interval *inv)
88912256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul{
89012256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   /* XXX we could binary search since list is sorted */
89112256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   GLuint k;
89212256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   for (k = 0; k < list->Num; k++) {
89312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      if (list->Intervals[k].Reg == inv->Reg) {
89412256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         /* found, remove it */
89512256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         ASSERT(list->Intervals[k].Start == inv->Start);
89612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         ASSERT(list->Intervals[k].End == inv->End);
89712256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         while (k < list->Num - 1) {
89812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul            list->Intervals[k] = list->Intervals[k + 1];
89912256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul            k++;
90012256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         }
90112256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         list->Num--;
90212256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         return;
90312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      }
90412256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   }
90512256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul}
90612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
90712256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
90812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul/** called by qsort() */
90912256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paulstatic int
91012256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paulcompare_start(const void *a, const void *b)
91112256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul{
91212256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   const struct interval *ia = (const struct interval *) a;
91312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   const struct interval *ib = (const struct interval *) b;
91412256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   if (ia->Start < ib->Start)
91512256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      return -1;
91612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   else if (ia->Start > ib->Start)
91712256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      return +1;
91812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   else
91912256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      return 0;
92012256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul}
92112256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
922e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul
92312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul/** sort the interval list according to interval starts */
92412256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paulstatic void
92512256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paulsort_interval_list_by_start(struct interval_list *list)
92612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul{
92712256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   qsort(list->Intervals, list->Num, sizeof(struct interval), compare_start);
92812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul#ifdef DEBUG
92912256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   {
93012256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      GLuint i;
93112256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      for (i = 0; i + 1 < list->Num; i++) {
93212256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         ASSERT(list->Intervals[i].Start <= list->Intervals[i + 1].Start);
93312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      }
93412256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   }
93512256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul#endif
93612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul}
93712256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
93825cda5039df0da6c2c65f1cac1bfc750c0c16e82Eric Anholtstruct loop_info
93925cda5039df0da6c2c65f1cac1bfc750c0c16e82Eric Anholt{
94025cda5039df0da6c2c65f1cac1bfc750c0c16e82Eric Anholt   GLuint Start, End;  /**< Start, end instructions of loop */
94125cda5039df0da6c2c65f1cac1bfc750c0c16e82Eric Anholt};
94212256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
94312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul/**
94412256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul * Update the intermediate interval info for register 'index' and
94512256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul * instruction 'ic'.
94612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul */
94712256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paulstatic void
94825cda5039df0da6c2c65f1cac1bfc750c0c16e82Eric Anholtupdate_interval(GLint intBegin[], GLint intEnd[],
94925cda5039df0da6c2c65f1cac1bfc750c0c16e82Eric Anholt		struct loop_info *loopStack, GLuint loopStackDepth,
95025cda5039df0da6c2c65f1cac1bfc750c0c16e82Eric Anholt		GLuint index, GLuint ic)
95112256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul{
95225cda5039df0da6c2c65f1cac1bfc750c0c16e82Eric Anholt   int i;
95318dcbd358f1d4fd5e4a40fa26c6d3bf99485884eTom Stellard   GLuint begin = ic;
95418dcbd358f1d4fd5e4a40fa26c6d3bf99485884eTom Stellard   GLuint end = ic;
95525cda5039df0da6c2c65f1cac1bfc750c0c16e82Eric Anholt
95625cda5039df0da6c2c65f1cac1bfc750c0c16e82Eric Anholt   /* If the register is used in a loop, extend its lifetime through the end
95725cda5039df0da6c2c65f1cac1bfc750c0c16e82Eric Anholt    * of the outermost loop that doesn't contain its definition.
95825cda5039df0da6c2c65f1cac1bfc750c0c16e82Eric Anholt    */
95925cda5039df0da6c2c65f1cac1bfc750c0c16e82Eric Anholt   for (i = 0; i < loopStackDepth; i++) {
96025cda5039df0da6c2c65f1cac1bfc750c0c16e82Eric Anholt      if (intBegin[index] < loopStack[i].Start) {
96118dcbd358f1d4fd5e4a40fa26c6d3bf99485884eTom Stellard	 end = loopStack[i].End;
96225cda5039df0da6c2c65f1cac1bfc750c0c16e82Eric Anholt	 break;
96325cda5039df0da6c2c65f1cac1bfc750c0c16e82Eric Anholt      }
96425cda5039df0da6c2c65f1cac1bfc750c0c16e82Eric Anholt   }
96525cda5039df0da6c2c65f1cac1bfc750c0c16e82Eric Anholt
96618dcbd358f1d4fd5e4a40fa26c6d3bf99485884eTom Stellard   /* Variables that are live at the end of a loop will also be live at the
96718dcbd358f1d4fd5e4a40fa26c6d3bf99485884eTom Stellard    * beginning, so an instruction inside of a loop should have its live
96818dcbd358f1d4fd5e4a40fa26c6d3bf99485884eTom Stellard    * interval begin at the start of the outermost loop.
96918dcbd358f1d4fd5e4a40fa26c6d3bf99485884eTom Stellard    */
97018dcbd358f1d4fd5e4a40fa26c6d3bf99485884eTom Stellard   if (loopStackDepth > 0 && ic > loopStack[0].Start && ic < loopStack[0].End) {
97118dcbd358f1d4fd5e4a40fa26c6d3bf99485884eTom Stellard      begin = loopStack[0].Start;
97218dcbd358f1d4fd5e4a40fa26c6d3bf99485884eTom Stellard   }
97318dcbd358f1d4fd5e4a40fa26c6d3bf99485884eTom Stellard
9748bbdf6e7cdfc3265439761a06eea79627f4ee2faEric Anholt   ASSERT(index < REG_ALLOCATE_MAX_PROGRAM_TEMPS);
97512256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   if (intBegin[index] == -1) {
97612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      ASSERT(intEnd[index] == -1);
97718dcbd358f1d4fd5e4a40fa26c6d3bf99485884eTom Stellard      intBegin[index] = begin;
97818dcbd358f1d4fd5e4a40fa26c6d3bf99485884eTom Stellard      intEnd[index] = end;
97912256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   }
98012256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   else {
98118dcbd358f1d4fd5e4a40fa26c6d3bf99485884eTom Stellard      intEnd[index] = end;
98212256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   }
98312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul}
98412256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
98512256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
98612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul/**
9877da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul * Find first/last instruction that references each temporary register.
98812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul */
9897da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian PaulGLboolean
9907da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul_mesa_find_temp_intervals(const struct prog_instruction *instructions,
9917da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul                          GLuint numInstructions,
9928bbdf6e7cdfc3265439761a06eea79627f4ee2faEric Anholt                          GLint intBegin[REG_ALLOCATE_MAX_PROGRAM_TEMPS],
9938bbdf6e7cdfc3265439761a06eea79627f4ee2faEric Anholt                          GLint intEnd[REG_ALLOCATE_MAX_PROGRAM_TEMPS])
99412256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul{
99512256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   struct loop_info loopStack[MAX_LOOP_NESTING];
99612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   GLuint loopStackDepth = 0;
99712256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   GLuint i;
99812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
9998bbdf6e7cdfc3265439761a06eea79627f4ee2faEric Anholt   for (i = 0; i < REG_ALLOCATE_MAX_PROGRAM_TEMPS; i++){
100012256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      intBegin[i] = intEnd[i] = -1;
100112256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   }
100212256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
100312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   /* Scan instructions looking for temporary registers */
10047da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul   for (i = 0; i < numInstructions; i++) {
10057da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul      const struct prog_instruction *inst = instructions + i;
100612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      if (inst->Opcode == OPCODE_BGNLOOP) {
100712256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         loopStack[loopStackDepth].Start = i;
100812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         loopStack[loopStackDepth].End = inst->BranchTarget;
100912256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         loopStackDepth++;
101012256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      }
101112256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      else if (inst->Opcode == OPCODE_ENDLOOP) {
101212256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         loopStackDepth--;
101312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      }
101412256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      else if (inst->Opcode == OPCODE_CAL) {
101512256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         return GL_FALSE;
101612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      }
101712256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      else {
10187da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul         const GLuint numSrc = 3;/*_mesa_num_inst_src_regs(inst->Opcode);*/
101912256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         GLuint j;
102012256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         for (j = 0; j < numSrc; j++) {
102112256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul            if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) {
102212256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul               const GLuint index = inst->SrcReg[j].Index;
102312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul               if (inst->SrcReg[j].RelAddr)
102412256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul                  return GL_FALSE;
102525cda5039df0da6c2c65f1cac1bfc750c0c16e82Eric Anholt               update_interval(intBegin, intEnd, loopStack, loopStackDepth,
102625cda5039df0da6c2c65f1cac1bfc750c0c16e82Eric Anholt			       index, i);
102712256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul            }
102812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         }
102912256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         if (inst->DstReg.File == PROGRAM_TEMPORARY) {
103012256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul            const GLuint index = inst->DstReg.Index;
103112256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul            if (inst->DstReg.RelAddr)
103212256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul               return GL_FALSE;
103325cda5039df0da6c2c65f1cac1bfc750c0c16e82Eric Anholt            update_interval(intBegin, intEnd, loopStack, loopStackDepth,
103425cda5039df0da6c2c65f1cac1bfc750c0c16e82Eric Anholt			    index, i);
103512256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         }
103612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      }
103712256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   }
103812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
10397da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul   return GL_TRUE;
10407da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul}
10417da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul
10427da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul
10437da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul/**
10447da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul * Find the live intervals for each temporary register in the program.
10457da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul * For register R, the interval [A,B] indicates that R is referenced
10467da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul * from instruction A through instruction B.
10477da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul * Special consideration is needed for loops and subroutines.
10487da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul * \return GL_TRUE if success, GL_FALSE if we cannot proceed for some reason
10497da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul */
10507da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paulstatic GLboolean
10517da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paulfind_live_intervals(struct gl_program *prog,
10527da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul                    struct interval_list *liveIntervals)
10537da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul{
10548bbdf6e7cdfc3265439761a06eea79627f4ee2faEric Anholt   GLint intBegin[REG_ALLOCATE_MAX_PROGRAM_TEMPS];
10558bbdf6e7cdfc3265439761a06eea79627f4ee2faEric Anholt   GLint intEnd[REG_ALLOCATE_MAX_PROGRAM_TEMPS];
10567da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul   GLuint i;
10577da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul
10587da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul   /*
10597da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul    * Note: we'll return GL_FALSE below if we find relative indexing
10607da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul    * into the TEMP register file.  We can't handle that yet.
10617da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul    * We also give up on subroutines for now.
10627da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul    */
10637da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul
10647da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul   if (dbg) {
1065298be2b028263b2c343a707662c6fbfa18293cb2Kristian Høgsberg      printf("Optimize: Begin find intervals\n");
10667da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul   }
10677da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul
10687da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul   /* build intermediate arrays */
10697da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul   if (!_mesa_find_temp_intervals(prog->Instructions, prog->NumInstructions,
10707da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul                                  intBegin, intEnd))
10717da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul      return GL_FALSE;
10727da3f9403b235394a5c7e9456e34a0c9dad7dd15Brian Paul
107312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   /* Build live intervals list from intermediate arrays */
107412256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   liveIntervals->Num = 0;
10758bbdf6e7cdfc3265439761a06eea79627f4ee2faEric Anholt   for (i = 0; i < REG_ALLOCATE_MAX_PROGRAM_TEMPS; i++) {
107612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      if (intBegin[i] >= 0) {
107712256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         struct interval inv;
107812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         inv.Reg = i;
107912256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         inv.Start = intBegin[i];
108012256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         inv.End = intEnd[i];
108112256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         append_interval(liveIntervals, &inv);
108212256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      }
108312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   }
108412256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
108512256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   /* Sort the list according to interval starts */
108612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   sort_interval_list_by_start(liveIntervals);
108712256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
108812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   if (dbg) {
108912256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      /* print interval info */
109012256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      for (i = 0; i < liveIntervals->Num; i++) {
109112256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         const struct interval *inv = liveIntervals->Intervals + i;
1092298be2b028263b2c343a707662c6fbfa18293cb2Kristian Høgsberg         printf("Reg[%d] live [%d, %d]:",
109312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul                      inv->Reg, inv->Start, inv->End);
109412256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         if (1) {
109520fbb24b67dda0679774756e4b6d98c2c66c2c42Brian Paul            GLuint j;
109612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul            for (j = 0; j < inv->Start; j++)
1097298be2b028263b2c343a707662c6fbfa18293cb2Kristian Høgsberg               printf(" ");
109812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul            for (j = inv->Start; j <= inv->End; j++)
1099298be2b028263b2c343a707662c6fbfa18293cb2Kristian Høgsberg               printf("x");
110012256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         }
1101298be2b028263b2c343a707662c6fbfa18293cb2Kristian Høgsberg         printf("\n");
110212256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      }
110312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   }
110412256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
110512256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   return GL_TRUE;
110612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul}
110712256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
110812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
1109f4468384b6caf2aa5cfc7546c08f349af93d928eBrian Paul/** Scan the array of used register flags to find free entry */
1110f4468384b6caf2aa5cfc7546c08f349af93d928eBrian Paulstatic GLint
11118bbdf6e7cdfc3265439761a06eea79627f4ee2faEric Anholtalloc_register(GLboolean usedRegs[REG_ALLOCATE_MAX_PROGRAM_TEMPS])
111212256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul{
111312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   GLuint k;
11148bbdf6e7cdfc3265439761a06eea79627f4ee2faEric Anholt   for (k = 0; k < REG_ALLOCATE_MAX_PROGRAM_TEMPS; k++) {
111512256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      if (!usedRegs[k]) {
111612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         usedRegs[k] = GL_TRUE;
111712256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         return k;
111812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      }
111912256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   }
1120f4468384b6caf2aa5cfc7546c08f349af93d928eBrian Paul   return -1;
112112256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul}
112212256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
112312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
112412256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul/**
112512256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul * This function implements "Linear Scan Register Allocation" to reduce
112612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul * the number of temporary registers used by the program.
112712256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul *
112812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul * We compute the "live interval" for all temporary registers then
112912256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul * examine the overlap of the intervals to allocate new registers.
113012256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul * Basically, if two intervals do not overlap, they can use the same register.
113112256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul */
113212256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paulstatic void
113312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul_mesa_reallocate_registers(struct gl_program *prog)
113412256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul{
113512256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   struct interval_list liveIntervals;
11368bbdf6e7cdfc3265439761a06eea79627f4ee2faEric Anholt   GLint registerMap[REG_ALLOCATE_MAX_PROGRAM_TEMPS];
11378bbdf6e7cdfc3265439761a06eea79627f4ee2faEric Anholt   GLboolean usedRegs[REG_ALLOCATE_MAX_PROGRAM_TEMPS];
113812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   GLuint i;
1139f4468384b6caf2aa5cfc7546c08f349af93d928eBrian Paul   GLint maxTemp = -1;
114012256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
114112256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   if (dbg) {
1142298be2b028263b2c343a707662c6fbfa18293cb2Kristian Høgsberg      printf("Optimize: Begin live-interval register reallocation\n");
114312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      _mesa_print_program(prog);
114412256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   }
114512256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
11468bbdf6e7cdfc3265439761a06eea79627f4ee2faEric Anholt   for (i = 0; i < REG_ALLOCATE_MAX_PROGRAM_TEMPS; i++){
114712256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      registerMap[i] = -1;
114812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      usedRegs[i] = GL_FALSE;
114912256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   }
115012256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
115112256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   if (!find_live_intervals(prog, &liveIntervals)) {
115212256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      if (dbg)
1153298be2b028263b2c343a707662c6fbfa18293cb2Kristian Høgsberg         printf("Aborting register reallocation\n");
115412256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      return;
115512256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   }
115612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
115712256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   {
115812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      struct interval_list activeIntervals;
115912256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      activeIntervals.Num = 0;
116012256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
116112256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      /* loop over live intervals, allocating a new register for each */
116212256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      for (i = 0; i < liveIntervals.Num; i++) {
116312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         const struct interval *live = liveIntervals.Intervals + i;
116412256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
116512256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         if (dbg)
1166298be2b028263b2c343a707662c6fbfa18293cb2Kristian Høgsberg            printf("Consider register %u\n", live->Reg);
116712256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
116812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         /* Expire old intervals.  Intervals which have ended with respect
116912256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul          * to the live interval can have their remapped registers freed.
117012256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul          */
117112256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         {
117212256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul            GLint j;
117320fbb24b67dda0679774756e4b6d98c2c66c2c42Brian Paul            for (j = 0; j < (GLint) activeIntervals.Num; j++) {
117412256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul               const struct interval *inv = activeIntervals.Intervals + j;
117512256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul               if (inv->End >= live->Start) {
117612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul                  /* Stop now.  Since the activeInterval list is sorted
117712256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul                   * we know we don't have to go further.
117812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul                   */
117912256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul                  break;
118012256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul               }
118112256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul               else {
118212256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul                  /* Interval 'inv' has expired */
118312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul                  const GLint regNew = registerMap[inv->Reg];
118412256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul                  ASSERT(regNew >= 0);
118512256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
118612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul                  if (dbg)
1187298be2b028263b2c343a707662c6fbfa18293cb2Kristian Høgsberg                     printf("  expire interval for reg %u\n", inv->Reg);
118812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
118912256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul                  /* remove interval j from active list */
119012256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul                  remove_interval(&activeIntervals, inv);
119112256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul                  j--;  /* counter-act j++ in for-loop above */
119212256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
119312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul                  /* return register regNew to the free pool */
119412256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul                  if (dbg)
1195298be2b028263b2c343a707662c6fbfa18293cb2Kristian Høgsberg                     printf("  free reg %d\n", regNew);
119612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul                  ASSERT(usedRegs[regNew] == GL_TRUE);
119712256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul                  usedRegs[regNew] = GL_FALSE;
119812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul               }
119912256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul            }
120012256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         }
120112256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
120212256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         /* find a free register for this live interval */
120312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         {
1204f4468384b6caf2aa5cfc7546c08f349af93d928eBrian Paul            const GLint k = alloc_register(usedRegs);
1205f4468384b6caf2aa5cfc7546c08f349af93d928eBrian Paul            if (k < 0) {
120612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul               /* out of registers, give up */
120712256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul               return;
120812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul            }
120912256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul            registerMap[live->Reg] = k;
121012256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul            maxTemp = MAX2(maxTemp, k);
121112256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul            if (dbg)
1212298be2b028263b2c343a707662c6fbfa18293cb2Kristian Høgsberg               printf("  remap register %u -> %d\n", live->Reg, k);
121312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         }
121412256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
121512256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         /* Insert this live interval into the active list which is sorted
121612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul          * by increasing end points.
121712256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul          */
121812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul         insert_interval_by_end(&activeIntervals, live);
121912256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      }
122012256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   }
122112256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
122220fbb24b67dda0679774756e4b6d98c2c66c2c42Brian Paul   if (maxTemp + 1 < (GLint) liveIntervals.Num) {
122312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      /* OK, we've reduced the number of registers needed.
122412256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul       * Scan the program and replace all the old temporary register
122512256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul       * indexes with the new indexes.
122612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul       */
122712256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      replace_regs(prog, PROGRAM_TEMPORARY, registerMap);
122812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
122912256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      prog->NumTemporaries = maxTemp + 1;
123012256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   }
123112256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
123212256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   if (dbg) {
1233298be2b028263b2c343a707662c6fbfa18293cb2Kristian Høgsberg      printf("Optimize: End live-interval register reallocation\n");
1234298be2b028263b2c343a707662c6fbfa18293cb2Kristian Høgsberg      printf("Num temp regs before: %u  after: %u\n",
123512256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul                   liveIntervals.Num, maxTemp + 1);
123612256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      _mesa_print_program(prog);
123712256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul   }
123812256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul}
123912256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
1240e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul
12419021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia#if 0
12429021c56a5738815777f27c39b63637b5975270c6Benjamin Segoviastatic void
1243f9995b30756140724f41daf963fa06167912be7fKristian Høgsbergprint_it(struct gl_context *ctx, struct gl_program *program, const char *txt) {
12449021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   fprintf(stderr, "%s (%u inst):\n", txt, program->NumInstructions);
12459021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   _mesa_print_program(program);
12469021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   _mesa_print_program_parameters(ctx, program);
12479021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   fprintf(stderr, "\n\n");
12489021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia}
12499021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia#endif
125012256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul
125197535699ee610a2f66732609f966102150847d3cTom Stellard/**
125297535699ee610a2f66732609f966102150847d3cTom Stellard * This pass replaces CMP T0, T1 T2 T0 with MOV T0, T2 when the CMP
125397535699ee610a2f66732609f966102150847d3cTom Stellard * instruction is the first instruction to write to register T0.  The are
125497535699ee610a2f66732609f966102150847d3cTom Stellard * several lowering passes done in GLSL IR (e.g. branches and
125597535699ee610a2f66732609f966102150847d3cTom Stellard * relative addressing) that create a large number of conditional assignments
125697535699ee610a2f66732609f966102150847d3cTom Stellard * that ir_to_mesa converts to CMP instructions like the one mentioned above.
125797535699ee610a2f66732609f966102150847d3cTom Stellard *
125897535699ee610a2f66732609f966102150847d3cTom Stellard * Here is why this conversion is safe:
125997535699ee610a2f66732609f966102150847d3cTom Stellard * CMP T0, T1 T2 T0 can be expanded to:
126097535699ee610a2f66732609f966102150847d3cTom Stellard * if (T1 < 0.0)
126197535699ee610a2f66732609f966102150847d3cTom Stellard * 	MOV T0, T2;
126297535699ee610a2f66732609f966102150847d3cTom Stellard * else
126397535699ee610a2f66732609f966102150847d3cTom Stellard * 	MOV T0, T0;
126497535699ee610a2f66732609f966102150847d3cTom Stellard *
126597535699ee610a2f66732609f966102150847d3cTom Stellard * If (T1 < 0.0) evaluates to true then our replacement MOV T0, T2 is the same
126697535699ee610a2f66732609f966102150847d3cTom Stellard * as the original program.  If (T1 < 0.0) evaluates to false, executing
126797535699ee610a2f66732609f966102150847d3cTom Stellard * MOV T0, T0 will store a garbage value in T0 since T0 is uninitialized.
126897535699ee610a2f66732609f966102150847d3cTom Stellard * Therefore, it doesn't matter that we are replacing MOV T0, T0 with MOV T0, T2
126997535699ee610a2f66732609f966102150847d3cTom Stellard * because any instruction that was going to read from T0 after this was going
127097535699ee610a2f66732609f966102150847d3cTom Stellard * to read a garbage value anyway.
127197535699ee610a2f66732609f966102150847d3cTom Stellard */
127297535699ee610a2f66732609f966102150847d3cTom Stellardstatic void
127397535699ee610a2f66732609f966102150847d3cTom Stellard_mesa_simplify_cmp(struct gl_program * program)
127497535699ee610a2f66732609f966102150847d3cTom Stellard{
127597535699ee610a2f66732609f966102150847d3cTom Stellard   GLuint tempWrites[REG_ALLOCATE_MAX_PROGRAM_TEMPS];
127697535699ee610a2f66732609f966102150847d3cTom Stellard   GLuint outputWrites[MAX_PROGRAM_OUTPUTS];
127797535699ee610a2f66732609f966102150847d3cTom Stellard   GLuint i;
127897535699ee610a2f66732609f966102150847d3cTom Stellard
127997535699ee610a2f66732609f966102150847d3cTom Stellard   if (dbg) {
128097535699ee610a2f66732609f966102150847d3cTom Stellard      printf("Optimize: Begin reads without writes\n");
128197535699ee610a2f66732609f966102150847d3cTom Stellard      _mesa_print_program(program);
128297535699ee610a2f66732609f966102150847d3cTom Stellard   }
128397535699ee610a2f66732609f966102150847d3cTom Stellard
128497535699ee610a2f66732609f966102150847d3cTom Stellard   for (i = 0; i < REG_ALLOCATE_MAX_PROGRAM_TEMPS; i++) {
128597535699ee610a2f66732609f966102150847d3cTom Stellard      tempWrites[i] = 0;
128697535699ee610a2f66732609f966102150847d3cTom Stellard   }
128797535699ee610a2f66732609f966102150847d3cTom Stellard
128897535699ee610a2f66732609f966102150847d3cTom Stellard   for (i = 0; i < MAX_PROGRAM_OUTPUTS; i++) {
128997535699ee610a2f66732609f966102150847d3cTom Stellard      outputWrites[i] = 0;
129097535699ee610a2f66732609f966102150847d3cTom Stellard   }
129197535699ee610a2f66732609f966102150847d3cTom Stellard
129297535699ee610a2f66732609f966102150847d3cTom Stellard   for (i = 0; i < program->NumInstructions; i++) {
129397535699ee610a2f66732609f966102150847d3cTom Stellard      struct prog_instruction *inst = program->Instructions + i;
129497535699ee610a2f66732609f966102150847d3cTom Stellard      GLuint prevWriteMask;
129597535699ee610a2f66732609f966102150847d3cTom Stellard
129697535699ee610a2f66732609f966102150847d3cTom Stellard      /* Give up if we encounter relative addressing or flow control. */
129797535699ee610a2f66732609f966102150847d3cTom Stellard      if (_mesa_is_flow_control_opcode(inst->Opcode) || inst->DstReg.RelAddr) {
129897535699ee610a2f66732609f966102150847d3cTom Stellard         return;
129997535699ee610a2f66732609f966102150847d3cTom Stellard      }
130097535699ee610a2f66732609f966102150847d3cTom Stellard
130197535699ee610a2f66732609f966102150847d3cTom Stellard      if (inst->DstReg.File == PROGRAM_OUTPUT) {
130297535699ee610a2f66732609f966102150847d3cTom Stellard         assert(inst->DstReg.Index < MAX_PROGRAM_OUTPUTS);
130397535699ee610a2f66732609f966102150847d3cTom Stellard         prevWriteMask = outputWrites[inst->DstReg.Index];
130497535699ee610a2f66732609f966102150847d3cTom Stellard         outputWrites[inst->DstReg.Index] |= inst->DstReg.WriteMask;
130597535699ee610a2f66732609f966102150847d3cTom Stellard      } else if (inst->DstReg.File == PROGRAM_TEMPORARY) {
130697535699ee610a2f66732609f966102150847d3cTom Stellard         assert(inst->DstReg.Index < REG_ALLOCATE_MAX_PROGRAM_TEMPS);
130797535699ee610a2f66732609f966102150847d3cTom Stellard         prevWriteMask = tempWrites[inst->DstReg.Index];
130897535699ee610a2f66732609f966102150847d3cTom Stellard         tempWrites[inst->DstReg.Index] |= inst->DstReg.WriteMask;
1309dade65505bdf62da448479e316cc7f4f2da22417Marek Olšák      } else {
1310dade65505bdf62da448479e316cc7f4f2da22417Marek Olšák         /* No other register type can be a destination register. */
1311dade65505bdf62da448479e316cc7f4f2da22417Marek Olšák         continue;
131297535699ee610a2f66732609f966102150847d3cTom Stellard      }
131397535699ee610a2f66732609f966102150847d3cTom Stellard
131497535699ee610a2f66732609f966102150847d3cTom Stellard      /* For a CMP to be considered a conditional write, the destination
131597535699ee610a2f66732609f966102150847d3cTom Stellard       * register and source register two must be the same. */
131697535699ee610a2f66732609f966102150847d3cTom Stellard      if (inst->Opcode == OPCODE_CMP
131797535699ee610a2f66732609f966102150847d3cTom Stellard          && !(inst->DstReg.WriteMask & prevWriteMask)
131897535699ee610a2f66732609f966102150847d3cTom Stellard          && inst->SrcReg[2].File == inst->DstReg.File
131997535699ee610a2f66732609f966102150847d3cTom Stellard          && inst->SrcReg[2].Index == inst->DstReg.Index
132097535699ee610a2f66732609f966102150847d3cTom Stellard          && inst->DstReg.WriteMask == get_src_arg_mask(inst, 2, NO_MASK)) {
132197535699ee610a2f66732609f966102150847d3cTom Stellard
132297535699ee610a2f66732609f966102150847d3cTom Stellard         inst->Opcode = OPCODE_MOV;
132397535699ee610a2f66732609f966102150847d3cTom Stellard         inst->SrcReg[0] = inst->SrcReg[1];
1324fbeb68e880318808f90c779cd3f8b8c4160eecf8Ian Romanick
1325fbeb68e880318808f90c779cd3f8b8c4160eecf8Ian Romanick	 /* Unused operands are expected to have the file set to
1326fbeb68e880318808f90c779cd3f8b8c4160eecf8Ian Romanick	  * PROGRAM_UNDEFINED.  This is how _mesa_init_instructions initializes
1327fbeb68e880318808f90c779cd3f8b8c4160eecf8Ian Romanick	  * all of the sources.
1328fbeb68e880318808f90c779cd3f8b8c4160eecf8Ian Romanick	  */
1329fbeb68e880318808f90c779cd3f8b8c4160eecf8Ian Romanick	 inst->SrcReg[1].File = PROGRAM_UNDEFINED;
1330fbeb68e880318808f90c779cd3f8b8c4160eecf8Ian Romanick	 inst->SrcReg[1].Swizzle = SWIZZLE_NOOP;
1331fbeb68e880318808f90c779cd3f8b8c4160eecf8Ian Romanick	 inst->SrcReg[2].File = PROGRAM_UNDEFINED;
1332fbeb68e880318808f90c779cd3f8b8c4160eecf8Ian Romanick	 inst->SrcReg[2].Swizzle = SWIZZLE_NOOP;
133397535699ee610a2f66732609f966102150847d3cTom Stellard      }
133497535699ee610a2f66732609f966102150847d3cTom Stellard   }
133597535699ee610a2f66732609f966102150847d3cTom Stellard   if (dbg) {
133697535699ee610a2f66732609f966102150847d3cTom Stellard      printf("Optimize: End reads without writes\n");
133797535699ee610a2f66732609f966102150847d3cTom Stellard      _mesa_print_program(program);
133897535699ee610a2f66732609f966102150847d3cTom Stellard   }
133997535699ee610a2f66732609f966102150847d3cTom Stellard}
1340e8000ffeaf3a11a8173d0ffc3f3f6f4e800972d3Brian Paul
134182f1c0be1325130ab03d3bef629264618924b897Brian Paul/**
134282f1c0be1325130ab03d3bef629264618924b897Brian Paul * Apply optimizations to the given program to eliminate unnecessary
134382f1c0be1325130ab03d3bef629264618924b897Brian Paul * instructions, temp regs, etc.
134482f1c0be1325130ab03d3bef629264618924b897Brian Paul */
134582f1c0be1325130ab03d3bef629264618924b897Brian Paulvoid
1346f9995b30756140724f41daf963fa06167912be7fKristian Høgsberg_mesa_optimize_program(struct gl_context *ctx, struct gl_program *program)
134782f1c0be1325130ab03d3bef629264618924b897Brian Paul{
13489021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   GLboolean any_change;
13499021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia
135097535699ee610a2f66732609f966102150847d3cTom Stellard   _mesa_simplify_cmp(program);
13519021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   /* Stop when no modifications were output */
13529021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   do {
13539021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      any_change = GL_FALSE;
13549021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      _mesa_remove_extra_move_use(program);
13559021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      if (_mesa_remove_dead_code_global(program))
13569021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         any_change = GL_TRUE;
13579021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      if (_mesa_remove_extra_moves(program))
13589021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         any_change = GL_TRUE;
13599021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia      if (_mesa_remove_dead_code_local(program))
13609021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia         any_change = GL_TRUE;
136154c48a95e6e0573886433f94ac83293876ffe03dIan Romanick
136254c48a95e6e0573886433f94ac83293876ffe03dIan Romanick      any_change = _mesa_constant_fold(program) || any_change;
136312256fc2b2e0a54db24210a4b86f6fb5919d0fe8Brian Paul      _mesa_reallocate_registers(program);
13649021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia   } while (any_change);
136582f1c0be1325130ab03d3bef629264618924b897Brian Paul}
13669021c56a5738815777f27c39b63637b5975270c6Benjamin Segovia
1367