1 /* 2 * Copyright (C) 2010 Marek Olk <maraeo (at) 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 <stdlib.h> 29 #include "radeon_remove_constants.h" 30 #include "radeon_dataflow.h" 31 32 struct mark_used_data { 33 unsigned char * const_used; 34 unsigned * has_rel_addr; 35 }; 36 37 static void remap_regs(void * userdata, struct rc_instruction * inst, 38 rc_register_file * pfile, unsigned int * pindex) 39 { 40 unsigned *inv_remap_table = userdata; 41 42 if (*pfile == RC_FILE_CONSTANT) { 43 *pindex = inv_remap_table[*pindex]; 44 } 45 } 46 47 static void mark_used(void * userdata, struct rc_instruction * inst, 48 struct rc_src_register * src) 49 { 50 struct mark_used_data * d = userdata; 51 52 if (src->File == RC_FILE_CONSTANT) { 53 if (src->RelAddr) { 54 *d->has_rel_addr = 1; 55 } else { 56 d->const_used[src->Index] = 1; 57 } 58 } 59 } 60 61 void rc_remove_unused_constants(struct radeon_compiler *c, void *user) 62 { 63 unsigned **out_remap_table = (unsigned**)user; 64 unsigned char *const_used; 65 unsigned *remap_table; 66 unsigned *inv_remap_table; 67 unsigned has_rel_addr = 0; 68 unsigned is_identity = 1; 69 unsigned are_externals_remapped = 0; 70 struct rc_constant *constants = c->Program.Constants.Constants; 71 struct mark_used_data d; 72 unsigned new_count; 73 74 if (!c->Program.Constants.Count) { 75 *out_remap_table = NULL; 76 return; 77 } 78 79 const_used = malloc(c->Program.Constants.Count); 80 memset(const_used, 0, c->Program.Constants.Count); 81 82 d.const_used = const_used; 83 d.has_rel_addr = &has_rel_addr; 84 85 /* Pass 1: Mark used constants. */ 86 for (struct rc_instruction *inst = c->Program.Instructions.Next; 87 inst != &c->Program.Instructions; inst = inst->Next) { 88 rc_for_all_reads_src(inst, mark_used, &d); 89 } 90 91 /* Pass 2: If there is relative addressing or dead constant elimination 92 * is disabled, mark all externals as used. */ 93 if (has_rel_addr || !c->remove_unused_constants) { 94 for (unsigned i = 0; i < c->Program.Constants.Count; i++) 95 if (constants[i].Type == RC_CONSTANT_EXTERNAL) 96 const_used[i] = 1; 97 } 98 99 /* Pass 3: Make the remapping table and remap constants. 100 * This pass removes unused constants simply by overwriting them by other constants. */ 101 remap_table = malloc(c->Program.Constants.Count * sizeof(unsigned)); 102 inv_remap_table = malloc(c->Program.Constants.Count * sizeof(unsigned)); 103 new_count = 0; 104 105 for (unsigned i = 0; i < c->Program.Constants.Count; i++) { 106 if (const_used[i]) { 107 remap_table[new_count] = i; 108 inv_remap_table[i] = new_count; 109 110 if (i != new_count) { 111 if (constants[i].Type == RC_CONSTANT_EXTERNAL) 112 are_externals_remapped = 1; 113 114 constants[new_count] = constants[i]; 115 is_identity = 0; 116 } 117 new_count++; 118 } 119 } 120 121 /* is_identity ==> new_count == old_count 122 * !is_identity ==> new_count < old_count */ 123 assert( is_identity || new_count < c->Program.Constants.Count); 124 assert(!((has_rel_addr || !c->remove_unused_constants) && are_externals_remapped)); 125 126 /* Pass 4: Redirect reads of all constants to their new locations. */ 127 if (!is_identity) { 128 for (struct rc_instruction *inst = c->Program.Instructions.Next; 129 inst != &c->Program.Instructions; inst = inst->Next) { 130 rc_remap_registers(inst, remap_regs, inv_remap_table); 131 } 132 } 133 134 /* Set the new constant count. Note that new_count may be less than 135 * Count even though the remapping function is identity. In that case, 136 * the constants have been removed at the end of the array. */ 137 c->Program.Constants.Count = new_count; 138 139 if (are_externals_remapped) { 140 *out_remap_table = remap_table; 141 } else { 142 *out_remap_table = NULL; 143 free(remap_table); 144 } 145 146 free(const_used); 147 free(inv_remap_table); 148 149 if (c->Debug & RC_DBG_LOG) 150 rc_constants_print(&c->Program.Constants); 151 } 152