1/* 2 * Copyright © 2014 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 * Authors: 24 * Connor Abbott (cwabbott0@gmail.com) 25 * 26 */ 27 28#include "nir.h" 29#include "nir_builder.h" 30 31/** 32 * SSA-based copy propagation 33 */ 34 35static bool 36is_swizzleless_move(nir_alu_instr *instr) 37{ 38 unsigned num_comp = instr->dest.dest.ssa.num_components; 39 40 if (instr->src[0].src.ssa->num_components != num_comp) 41 return false; 42 43 if (instr->op == nir_op_mov) { 44 for (unsigned i = 0; i < num_comp; i++) { 45 if (instr->src[0].swizzle[i] != i) 46 return false; 47 } 48 } else { 49 for (unsigned i = 0; i < num_comp; i++) { 50 if (instr->src[i].swizzle[0] != i || 51 instr->src[i].src.ssa != instr->src[0].src.ssa) 52 return false; 53 } 54 } 55 56 return true; 57} 58 59static bool 60rewrite_to_vec(nir_function_impl *impl, nir_alu_instr *mov, nir_alu_instr *vec) 61{ 62 if (mov->op != nir_op_mov) 63 return false; 64 65 nir_builder b; 66 nir_builder_init(&b, impl); 67 b.cursor = nir_after_instr(&mov->instr); 68 69 unsigned num_comp = mov->dest.dest.ssa.num_components; 70 nir_alu_instr *new_vec = nir_alu_instr_create(b.shader, nir_op_vec(num_comp)); 71 for (unsigned i = 0; i < num_comp; i++) 72 new_vec->src[i] = vec->src[mov->src[0].swizzle[i]]; 73 74 nir_ssa_def *new = nir_builder_alu_instr_finish_and_insert(&b, new_vec); 75 nir_ssa_def_rewrite_uses(&mov->dest.dest.ssa, new); 76 77 /* If we remove "mov" and it's the next instruction in the 78 * nir_foreach_instr_safe() loop, then we would end copy-propagation early. */ 79 80 return true; 81} 82 83static bool 84copy_propagate_alu(nir_function_impl *impl, nir_alu_src *src, nir_alu_instr *copy) 85{ 86 nir_ssa_def *def = NULL; 87 nir_alu_instr *user = nir_instr_as_alu(src->src.parent_instr); 88 unsigned src_idx = src - user->src; 89 assert(src_idx < nir_op_infos[user->op].num_inputs); 90 unsigned num_comp = nir_ssa_alu_instr_src_components(user, src_idx); 91 92 if (copy->op == nir_op_mov) { 93 def = copy->src[0].src.ssa; 94 95 for (unsigned i = 0; i < num_comp; i++) 96 src->swizzle[i] = copy->src[0].swizzle[src->swizzle[i]]; 97 } else { 98 def = copy->src[src->swizzle[0]].src.ssa; 99 100 for (unsigned i = 1; i < num_comp; i++) { 101 if (copy->src[src->swizzle[i]].src.ssa != def) 102 return rewrite_to_vec(impl, user, copy); 103 } 104 105 for (unsigned i = 0; i < num_comp; i++) 106 src->swizzle[i] = copy->src[src->swizzle[i]].swizzle[0]; 107 } 108 109 nir_instr_rewrite_src_ssa(src->src.parent_instr, &src->src, def); 110 111 return true; 112} 113 114static bool 115copy_propagate(nir_src *src, nir_alu_instr *copy) 116{ 117 if (!is_swizzleless_move(copy)) 118 return false; 119 120 nir_instr_rewrite_src_ssa(src->parent_instr, src, copy->src[0].src.ssa); 121 122 return true; 123} 124 125static bool 126copy_propagate_if(nir_src *src, nir_alu_instr *copy) 127{ 128 if (!is_swizzleless_move(copy)) 129 return false; 130 131 nir_if_rewrite_condition_ssa(src->parent_if, src, copy->src[0].src.ssa); 132 133 return true; 134} 135 136static bool 137copy_prop_instr(nir_function_impl *impl, nir_instr *instr) 138{ 139 if (instr->type != nir_instr_type_alu) 140 return false; 141 142 nir_alu_instr *mov = nir_instr_as_alu(instr); 143 144 if (!nir_alu_instr_is_copy(mov)) 145 return false; 146 147 bool progress = false; 148 149 nir_foreach_use_safe(src, &mov->dest.dest.ssa) { 150 if (src->parent_instr->type == nir_instr_type_alu) 151 progress |= copy_propagate_alu(impl, container_of(src, nir_alu_src, src), mov); 152 else 153 progress |= copy_propagate(src, mov); 154 } 155 156 nir_foreach_if_use_safe(src, &mov->dest.dest.ssa) 157 progress |= copy_propagate_if(src, mov); 158 159 if (progress && nir_ssa_def_is_unused(&mov->dest.dest.ssa)) 160 nir_instr_remove(&mov->instr); 161 162 return progress; 163} 164 165bool 166nir_copy_prop_impl(nir_function_impl *impl) 167{ 168 bool progress = false; 169 170 nir_foreach_block(block, impl) { 171 nir_foreach_instr_safe(instr, block) { 172 progress |= copy_prop_instr(impl, instr); 173 } 174 } 175 176 if (progress) { 177 nir_metadata_preserve(impl, nir_metadata_block_index | 178 nir_metadata_dominance); 179 } else { 180 nir_metadata_preserve(impl, nir_metadata_all); 181 } 182 183 return progress; 184} 185 186bool 187nir_copy_prop(nir_shader *shader) 188{ 189 bool progress = false; 190 191 nir_foreach_function(function, shader) { 192 if (function->impl && nir_copy_prop_impl(function->impl)) 193 progress = true; 194 } 195 196 return progress; 197} 198