1/* 2 * Copyright (C) 2010 Marek Olšák <maraeo@gmail.com> 3 * 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining 7 * a copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sublicense, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial 16 * portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE 22 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 24 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 */ 27 28#include "radeon_remove_constants.h" 29#include "radeon_dataflow.h" 30 31struct mark_used_data { 32 unsigned char * const_used; 33 unsigned * has_rel_addr; 34}; 35 36static void remap_regs(void * userdata, struct rc_instruction * inst, 37 rc_register_file * pfile, unsigned int * pindex) 38{ 39 unsigned *inv_remap_table = userdata; 40 41 if (*pfile == RC_FILE_CONSTANT) { 42 *pindex = inv_remap_table[*pindex]; 43 } 44} 45 46static void mark_used(void * userdata, struct rc_instruction * inst, 47 struct rc_src_register * src) 48{ 49 struct mark_used_data * d = userdata; 50 51 if (src->File == RC_FILE_CONSTANT) { 52 if (src->RelAddr) { 53 *d->has_rel_addr = 1; 54 } else { 55 d->const_used[src->Index] = 1; 56 } 57 } 58} 59 60void rc_remove_unused_constants(struct radeon_compiler *c, void *user) 61{ 62 unsigned **out_remap_table = (unsigned**)user; 63 unsigned char *const_used; 64 unsigned *remap_table; 65 unsigned *inv_remap_table; 66 unsigned has_rel_addr = 0; 67 unsigned is_identity = 1; 68 unsigned are_externals_remapped = 0; 69 struct rc_constant *constants = c->Program.Constants.Constants; 70 struct mark_used_data d; 71 unsigned new_count; 72 73 if (!c->Program.Constants.Count) { 74 *out_remap_table = NULL; 75 return; 76 } 77 78 const_used = malloc(c->Program.Constants.Count); 79 memset(const_used, 0, c->Program.Constants.Count); 80 81 d.const_used = const_used; 82 d.has_rel_addr = &has_rel_addr; 83 84 /* Pass 1: Mark used constants. */ 85 for (struct rc_instruction *inst = c->Program.Instructions.Next; 86 inst != &c->Program.Instructions; inst = inst->Next) { 87 rc_for_all_reads_src(inst, mark_used, &d); 88 } 89 90 /* Pass 2: If there is relative addressing or dead constant elimination 91 * is disabled, mark all externals as used. */ 92 if (has_rel_addr || !c->remove_unused_constants) { 93 for (unsigned i = 0; i < c->Program.Constants.Count; i++) 94 if (constants[i].Type == RC_CONSTANT_EXTERNAL) 95 const_used[i] = 1; 96 } 97 98 /* Pass 3: Make the remapping table and remap constants. 99 * This pass removes unused constants simply by overwriting them by other constants. */ 100 remap_table = malloc(c->Program.Constants.Count * sizeof(unsigned)); 101 inv_remap_table = malloc(c->Program.Constants.Count * sizeof(unsigned)); 102 new_count = 0; 103 104 for (unsigned i = 0; i < c->Program.Constants.Count; i++) { 105 if (const_used[i]) { 106 remap_table[new_count] = i; 107 inv_remap_table[i] = new_count; 108 109 if (i != new_count) { 110 if (constants[i].Type == RC_CONSTANT_EXTERNAL) 111 are_externals_remapped = 1; 112 113 constants[new_count] = constants[i]; 114 is_identity = 0; 115 } 116 new_count++; 117 } 118 } 119 120 /* is_identity ==> new_count == old_count 121 * !is_identity ==> new_count < old_count */ 122 assert( is_identity || new_count < c->Program.Constants.Count); 123 assert(!((has_rel_addr || !c->remove_unused_constants) && are_externals_remapped)); 124 125 /* Pass 4: Redirect reads of all constants to their new locations. */ 126 if (!is_identity) { 127 for (struct rc_instruction *inst = c->Program.Instructions.Next; 128 inst != &c->Program.Instructions; inst = inst->Next) { 129 rc_remap_registers(inst, remap_regs, inv_remap_table); 130 } 131 } 132 133 /* Set the new constant count. Note that new_count may be less than 134 * Count even though the remapping function is identity. In that case, 135 * the constants have been removed at the end of the array. */ 136 c->Program.Constants.Count = new_count; 137 138 if (are_externals_remapped) { 139 *out_remap_table = remap_table; 140 } else { 141 *out_remap_table = NULL; 142 free(remap_table); 143 } 144 145 free(const_used); 146 free(inv_remap_table); 147 148 if (c->Debug & RC_DBG_LOG) 149 rc_constants_print(&c->Program.Constants); 150} 151