1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2015 Connor Abbott 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21bf215546Sopenharmony_ci * IN THE SOFTWARE. 22bf215546Sopenharmony_ci * 23bf215546Sopenharmony_ci * Authors: 24bf215546Sopenharmony_ci * Connor Abbott (cwabbott0@gmail.com) 25bf215546Sopenharmony_ci * 26bf215546Sopenharmony_ci */ 27bf215546Sopenharmony_ci 28bf215546Sopenharmony_ci#include "nir.h" 29bf215546Sopenharmony_ci#include "nir_builder.h" 30bf215546Sopenharmony_ci 31bf215546Sopenharmony_cistatic nir_alu_instr * 32bf215546Sopenharmony_ciget_parent_mov(nir_ssa_def *ssa) 33bf215546Sopenharmony_ci{ 34bf215546Sopenharmony_ci if (ssa->parent_instr->type != nir_instr_type_alu) 35bf215546Sopenharmony_ci return NULL; 36bf215546Sopenharmony_ci 37bf215546Sopenharmony_ci nir_alu_instr *alu = nir_instr_as_alu(ssa->parent_instr); 38bf215546Sopenharmony_ci return (alu->op == nir_op_mov) ? alu : NULL; 39bf215546Sopenharmony_ci} 40bf215546Sopenharmony_ci 41bf215546Sopenharmony_cistatic bool 42bf215546Sopenharmony_cimatching_mov(nir_alu_instr *mov1, nir_ssa_def *ssa) 43bf215546Sopenharmony_ci{ 44bf215546Sopenharmony_ci if (!mov1) 45bf215546Sopenharmony_ci return false; 46bf215546Sopenharmony_ci 47bf215546Sopenharmony_ci nir_alu_instr *mov2 = get_parent_mov(ssa); 48bf215546Sopenharmony_ci return mov2 && nir_alu_srcs_equal(mov1, mov2, 0, 0); 49bf215546Sopenharmony_ci} 50bf215546Sopenharmony_ci 51bf215546Sopenharmony_ci/* 52bf215546Sopenharmony_ci * This is a pass for removing phi nodes that look like: 53bf215546Sopenharmony_ci * a = phi(b, b, b, ...) 54bf215546Sopenharmony_ci * 55bf215546Sopenharmony_ci * Note that we can't always ignore undef sources here, or else we may create a 56bf215546Sopenharmony_ci * situation where the definition of b isn't dominated by its uses. We're 57bf215546Sopenharmony_ci * allowed to do this since the definition of b must dominate all of the 58bf215546Sopenharmony_ci * phi node's predecessors, which means it must dominate the phi node as well 59bf215546Sopenharmony_ci * as all of the phi node's uses. In essence, the phi node acts as a copy 60bf215546Sopenharmony_ci * instruction. b can't be another phi node in the same block, since the only 61bf215546Sopenharmony_ci * time when phi nodes can source other phi nodes defined in the same block is 62bf215546Sopenharmony_ci * at the loop header, and in that case one of the sources of the phi has to 63bf215546Sopenharmony_ci * be from before the loop and that source can't be b. 64bf215546Sopenharmony_ci */ 65bf215546Sopenharmony_ci 66bf215546Sopenharmony_cistatic bool 67bf215546Sopenharmony_ciremove_phis_block(nir_block *block, nir_builder *b) 68bf215546Sopenharmony_ci{ 69bf215546Sopenharmony_ci bool progress = false; 70bf215546Sopenharmony_ci 71bf215546Sopenharmony_ci nir_foreach_instr_safe(instr, block) { 72bf215546Sopenharmony_ci if (instr->type != nir_instr_type_phi) 73bf215546Sopenharmony_ci break; 74bf215546Sopenharmony_ci 75bf215546Sopenharmony_ci nir_phi_instr *phi = nir_instr_as_phi(instr); 76bf215546Sopenharmony_ci 77bf215546Sopenharmony_ci nir_ssa_def *def = NULL; 78bf215546Sopenharmony_ci nir_alu_instr *mov = NULL; 79bf215546Sopenharmony_ci bool srcs_same = true; 80bf215546Sopenharmony_ci 81bf215546Sopenharmony_ci nir_foreach_phi_src(src, phi) { 82bf215546Sopenharmony_ci assert(src->src.is_ssa); 83bf215546Sopenharmony_ci 84bf215546Sopenharmony_ci /* For phi nodes at the beginning of loops, we may encounter some 85bf215546Sopenharmony_ci * sources from backedges that point back to the destination of the 86bf215546Sopenharmony_ci * same phi, i.e. something like: 87bf215546Sopenharmony_ci * 88bf215546Sopenharmony_ci * a = phi(a, b, ...) 89bf215546Sopenharmony_ci * 90bf215546Sopenharmony_ci * We can safely ignore these sources, since if all of the normal 91bf215546Sopenharmony_ci * sources point to the same definition, then that definition must 92bf215546Sopenharmony_ci * still dominate the phi node, and the phi will still always take 93bf215546Sopenharmony_ci * the value of that definition. 94bf215546Sopenharmony_ci */ 95bf215546Sopenharmony_ci if (src->src.ssa == &phi->dest.ssa) 96bf215546Sopenharmony_ci continue; 97bf215546Sopenharmony_ci 98bf215546Sopenharmony_ci if (def == NULL) { 99bf215546Sopenharmony_ci def = src->src.ssa; 100bf215546Sopenharmony_ci mov = get_parent_mov(def); 101bf215546Sopenharmony_ci } else if (nir_src_is_undef(src->src) && 102bf215546Sopenharmony_ci nir_block_dominates(def->parent_instr->block, src->pred)) { 103bf215546Sopenharmony_ci /* Ignore this undef source. */ 104bf215546Sopenharmony_ci } else { 105bf215546Sopenharmony_ci if (src->src.ssa != def && !matching_mov(mov, src->src.ssa)) { 106bf215546Sopenharmony_ci srcs_same = false; 107bf215546Sopenharmony_ci break; 108bf215546Sopenharmony_ci } 109bf215546Sopenharmony_ci } 110bf215546Sopenharmony_ci } 111bf215546Sopenharmony_ci 112bf215546Sopenharmony_ci if (!srcs_same) 113bf215546Sopenharmony_ci continue; 114bf215546Sopenharmony_ci 115bf215546Sopenharmony_ci if (!def) { 116bf215546Sopenharmony_ci /* In this case, the phi had no sources. So turn it into an undef. */ 117bf215546Sopenharmony_ci 118bf215546Sopenharmony_ci b->cursor = nir_after_phis(block); 119bf215546Sopenharmony_ci def = nir_ssa_undef(b, phi->dest.ssa.num_components, 120bf215546Sopenharmony_ci phi->dest.ssa.bit_size); 121bf215546Sopenharmony_ci } else if (mov) { 122bf215546Sopenharmony_ci /* If the sources were all movs from the same source with the same 123bf215546Sopenharmony_ci * swizzle, then we can't just pick a random move because it may not 124bf215546Sopenharmony_ci * dominate the phi node. Instead, we need to emit our own move after 125bf215546Sopenharmony_ci * the phi which uses the shared source, and rewrite uses of the phi 126bf215546Sopenharmony_ci * to use the move instead. This is ok, because while the movs may 127bf215546Sopenharmony_ci * not all dominate the phi node, their shared source does. 128bf215546Sopenharmony_ci */ 129bf215546Sopenharmony_ci 130bf215546Sopenharmony_ci b->cursor = nir_after_phis(block); 131bf215546Sopenharmony_ci def = nir_mov_alu(b, mov->src[0], def->num_components); 132bf215546Sopenharmony_ci } 133bf215546Sopenharmony_ci 134bf215546Sopenharmony_ci assert(phi->dest.is_ssa); 135bf215546Sopenharmony_ci nir_ssa_def_rewrite_uses(&phi->dest.ssa, def); 136bf215546Sopenharmony_ci nir_instr_remove(instr); 137bf215546Sopenharmony_ci 138bf215546Sopenharmony_ci progress = true; 139bf215546Sopenharmony_ci } 140bf215546Sopenharmony_ci 141bf215546Sopenharmony_ci return progress; 142bf215546Sopenharmony_ci} 143bf215546Sopenharmony_ci 144bf215546Sopenharmony_cibool 145bf215546Sopenharmony_cinir_opt_remove_phis_block(nir_block *block) 146bf215546Sopenharmony_ci{ 147bf215546Sopenharmony_ci nir_builder b; 148bf215546Sopenharmony_ci nir_builder_init(&b, nir_cf_node_get_function(&block->cf_node)); 149bf215546Sopenharmony_ci return remove_phis_block(block, &b); 150bf215546Sopenharmony_ci} 151bf215546Sopenharmony_ci 152bf215546Sopenharmony_cistatic bool 153bf215546Sopenharmony_cinir_opt_remove_phis_impl(nir_function_impl *impl) 154bf215546Sopenharmony_ci{ 155bf215546Sopenharmony_ci bool progress = false; 156bf215546Sopenharmony_ci nir_builder bld; 157bf215546Sopenharmony_ci nir_builder_init(&bld, impl); 158bf215546Sopenharmony_ci 159bf215546Sopenharmony_ci nir_metadata_require(impl, nir_metadata_dominance); 160bf215546Sopenharmony_ci 161bf215546Sopenharmony_ci nir_foreach_block(block, impl) { 162bf215546Sopenharmony_ci progress |= remove_phis_block(block, &bld); 163bf215546Sopenharmony_ci } 164bf215546Sopenharmony_ci 165bf215546Sopenharmony_ci if (progress) { 166bf215546Sopenharmony_ci nir_metadata_preserve(impl, nir_metadata_block_index | 167bf215546Sopenharmony_ci nir_metadata_dominance); 168bf215546Sopenharmony_ci } else { 169bf215546Sopenharmony_ci nir_metadata_preserve(impl, nir_metadata_all); 170bf215546Sopenharmony_ci } 171bf215546Sopenharmony_ci 172bf215546Sopenharmony_ci return progress; 173bf215546Sopenharmony_ci} 174bf215546Sopenharmony_ci 175bf215546Sopenharmony_cibool 176bf215546Sopenharmony_cinir_opt_remove_phis(nir_shader *shader) 177bf215546Sopenharmony_ci{ 178bf215546Sopenharmony_ci bool progress = false; 179bf215546Sopenharmony_ci 180bf215546Sopenharmony_ci nir_foreach_function(function, shader) 181bf215546Sopenharmony_ci if (function->impl) 182bf215546Sopenharmony_ci progress = nir_opt_remove_phis_impl(function->impl) || progress; 183bf215546Sopenharmony_ci 184bf215546Sopenharmony_ci return progress; 185bf215546Sopenharmony_ci} 186bf215546Sopenharmony_ci 187