1 /* 2 * Copyright 2011 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23 24 /** 25 * @file brw_vec4_copy_propagation.cpp 26 * 27 * Implements tracking of values copied between registers, and 28 * optimizations based on that: copy propagation and constant 29 * propagation. 30 */ 31 32 #include "brw_vec4.h" 33 extern "C" { 34 #include "main/macros.h" 35 } 36 37 namespace brw { 38 39 static bool 40 is_direct_copy(vec4_instruction *inst) 41 { 42 return (inst->opcode == BRW_OPCODE_MOV && 43 !inst->predicate && 44 inst->dst.file == GRF && 45 !inst->saturate && 46 !inst->dst.reladdr && 47 !inst->src[0].reladdr && 48 inst->dst.type == inst->src[0].type); 49 } 50 51 static bool 52 is_dominated_by_previous_instruction(vec4_instruction *inst) 53 { 54 return (inst->opcode != BRW_OPCODE_DO && 55 inst->opcode != BRW_OPCODE_WHILE && 56 inst->opcode != BRW_OPCODE_ELSE && 57 inst->opcode != BRW_OPCODE_ENDIF); 58 } 59 60 static bool 61 try_constant_propagation(vec4_instruction *inst, int arg, src_reg *values[4]) 62 { 63 /* For constant propagation, we only handle the same constant 64 * across all 4 channels. Some day, we should handle the 8-bit 65 * float vector format, which would let us constant propagate 66 * vectors better. 67 */ 68 src_reg value = *values[0]; 69 for (int i = 1; i < 4; i++) { 70 if (!value.equals(values[i])) 71 return false; 72 } 73 74 if (value.file != IMM) 75 return false; 76 77 if (inst->src[arg].abs) { 78 if (value.type == BRW_REGISTER_TYPE_F) { 79 value.imm.f = fabs(value.imm.f); 80 } else if (value.type == BRW_REGISTER_TYPE_D) { 81 if (value.imm.i < 0) 82 value.imm.i = -value.imm.i; 83 } 84 } 85 86 if (inst->src[arg].negate) { 87 if (value.type == BRW_REGISTER_TYPE_F) 88 value.imm.f = -value.imm.f; 89 else 90 value.imm.u = -value.imm.u; 91 } 92 93 switch (inst->opcode) { 94 case BRW_OPCODE_MOV: 95 inst->src[arg] = value; 96 return true; 97 98 case BRW_OPCODE_MUL: 99 case BRW_OPCODE_ADD: 100 if (arg == 1) { 101 inst->src[arg] = value; 102 return true; 103 } else if (arg == 0 && inst->src[1].file != IMM) { 104 /* Fit this constant in by commuting the operands. Exception: we 105 * can't do this for 32-bit integer MUL because it's asymmetric. 106 */ 107 if (inst->opcode == BRW_OPCODE_MUL && 108 (inst->src[1].type == BRW_REGISTER_TYPE_D || 109 inst->src[1].type == BRW_REGISTER_TYPE_UD)) 110 break; 111 inst->src[0] = inst->src[1]; 112 inst->src[1] = value; 113 return true; 114 } 115 break; 116 117 case BRW_OPCODE_CMP: 118 if (arg == 1) { 119 inst->src[arg] = value; 120 return true; 121 } else if (arg == 0 && inst->src[1].file != IMM) { 122 uint32_t new_cmod; 123 124 new_cmod = brw_swap_cmod(inst->conditional_mod); 125 if (new_cmod != ~0u) { 126 /* Fit this constant in by swapping the operands and 127 * flipping the test. 128 */ 129 inst->src[0] = inst->src[1]; 130 inst->src[1] = value; 131 inst->conditional_mod = new_cmod; 132 return true; 133 } 134 } 135 break; 136 137 case BRW_OPCODE_SEL: 138 if (arg == 1) { 139 inst->src[arg] = value; 140 return true; 141 } else if (arg == 0 && inst->src[1].file != IMM) { 142 inst->src[0] = inst->src[1]; 143 inst->src[1] = value; 144 145 /* If this was predicated, flipping operands means 146 * we also need to flip the predicate. 147 */ 148 if (inst->conditional_mod == BRW_CONDITIONAL_NONE) { 149 inst->predicate_inverse = !inst->predicate_inverse; 150 } 151 return true; 152 } 153 break; 154 155 default: 156 break; 157 } 158 159 return false; 160 } 161 162 static bool 163 try_copy_propagation(struct intel_context *intel, 164 vec4_instruction *inst, int arg, src_reg *values[4]) 165 { 166 /* For constant propagation, we only handle the same constant 167 * across all 4 channels. Some day, we should handle the 8-bit 168 * float vector format, which would let us constant propagate 169 * vectors better. 170 */ 171 src_reg value = *values[0]; 172 for (int i = 1; i < 4; i++) { 173 /* This is equals() except we don't care about the swizzle. */ 174 if (value.file != values[i]->file || 175 value.reg != values[i]->reg || 176 value.reg_offset != values[i]->reg_offset || 177 value.type != values[i]->type || 178 value.negate != values[i]->negate || 179 value.abs != values[i]->abs) { 180 return false; 181 } 182 } 183 184 /* Compute the swizzle of the original register by swizzling the 185 * component loaded from each value according to the swizzle of 186 * operand we're going to change. 187 */ 188 int s[4]; 189 for (int i = 0; i < 4; i++) { 190 s[i] = BRW_GET_SWZ(values[i]->swizzle, 191 BRW_GET_SWZ(inst->src[arg].swizzle, i)); 192 } 193 value.swizzle = BRW_SWIZZLE4(s[0], s[1], s[2], s[3]); 194 195 if (value.file != UNIFORM && 196 value.file != GRF && 197 value.file != ATTR) 198 return false; 199 200 if (inst->src[arg].abs) { 201 value.negate = false; 202 value.abs = true; 203 } 204 if (inst->src[arg].negate) 205 value.negate = !value.negate; 206 207 /* FINISHME: We can't copy-propagate things that aren't normal 208 * vec8s into gen6 math instructions, because of the weird src 209 * handling for those instructions. Just ignore them for now. 210 */ 211 if (intel->gen >= 6 && inst->is_math()) 212 return false; 213 214 /* We can't copy-propagate a UD negation into a condmod 215 * instruction, because the condmod ends up looking at the 33-bit 216 * signed accumulator value instead of the 32-bit value we wanted 217 */ 218 if (inst->conditional_mod && 219 value.negate && 220 value.type == BRW_REGISTER_TYPE_UD) 221 return false; 222 223 /* Don't report progress if this is a noop. */ 224 if (value.equals(&inst->src[arg])) 225 return false; 226 227 value.type = inst->src[arg].type; 228 inst->src[arg] = value; 229 return true; 230 } 231 232 bool 233 vec4_visitor::opt_copy_propagation() 234 { 235 bool progress = false; 236 src_reg *cur_value[virtual_grf_reg_count][4]; 237 238 memset(&cur_value, 0, sizeof(cur_value)); 239 240 foreach_list(node, &this->instructions) { 241 vec4_instruction *inst = (vec4_instruction *)node; 242 243 /* This pass only works on basic blocks. If there's flow 244 * control, throw out all our information and start from 245 * scratch. 246 * 247 * This should really be fixed by using a structure like in 248 * src/glsl/opt_copy_propagation.cpp to track available copies. 249 */ 250 if (!is_dominated_by_previous_instruction(inst)) { 251 memset(cur_value, 0, sizeof(cur_value)); 252 continue; 253 } 254 255 /* For each source arg, see if each component comes from a copy 256 * from the same type file (IMM, GRF, UNIFORM), and try 257 * optimizing out access to the copy result 258 */ 259 for (int i = 2; i >= 0; i--) { 260 /* Copied values end up in GRFs, and we don't track reladdr 261 * accesses. 262 */ 263 if (inst->src[i].file != GRF || 264 inst->src[i].reladdr) 265 continue; 266 267 int reg = (virtual_grf_reg_map[inst->src[i].reg] + 268 inst->src[i].reg_offset); 269 270 /* Find the regs that each swizzle component came from. 271 */ 272 src_reg *values[4]; 273 int c; 274 for (c = 0; c < 4; c++) { 275 values[c] = cur_value[reg][BRW_GET_SWZ(inst->src[i].swizzle, c)]; 276 277 /* If there's no available copy for this channel, bail. 278 * We could be more aggressive here -- some channels might 279 * not get used based on the destination writemask. 280 */ 281 if (!values[c]) 282 break; 283 284 /* We'll only be able to copy propagate if the sources are 285 * all from the same file -- there's no ability to swizzle 286 * 0 or 1 constants in with source registers like in i915. 287 */ 288 if (c > 0 && values[c - 1]->file != values[c]->file) 289 break; 290 } 291 292 if (c != 4) 293 continue; 294 295 if (try_constant_propagation(inst, i, values) || 296 try_copy_propagation(intel, inst, i, values)) 297 progress = true; 298 } 299 300 /* Track available source registers. */ 301 if (inst->dst.file == GRF) { 302 const int reg = 303 virtual_grf_reg_map[inst->dst.reg] + inst->dst.reg_offset; 304 305 /* Update our destination's current channel values. For a direct copy, 306 * the value is the newly propagated source. Otherwise, we don't know 307 * the new value, so clear it. 308 */ 309 bool direct_copy = is_direct_copy(inst); 310 for (int i = 0; i < 4; i++) { 311 if (inst->dst.writemask & (1 << i)) { 312 cur_value[reg][i] = direct_copy ? &inst->src[0] : NULL; 313 } 314 } 315 316 /* Clear the records for any registers whose current value came from 317 * our destination's updated channels, as the two are no longer equal. 318 */ 319 if (inst->dst.reladdr) 320 memset(cur_value, 0, sizeof(cur_value)); 321 else { 322 for (int i = 0; i < virtual_grf_reg_count; i++) { 323 for (int j = 0; j < 4; j++) { 324 if (inst->dst.writemask & (1 << j) && 325 cur_value[i][j] && 326 cur_value[i][j]->file == GRF && 327 cur_value[i][j]->reg == inst->dst.reg && 328 cur_value[i][j]->reg_offset == inst->dst.reg_offset) { 329 cur_value[i][j] = NULL; 330 } 331 } 332 } 333 } 334 } 335 } 336 337 if (progress) 338 live_intervals_valid = false; 339 340 return progress; 341 } 342 343 } /* namespace brw */ 344