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