1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright (c) 2019 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, sub license, 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 12bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 13bf215546Sopenharmony_ci * of the 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 NON-INFRINGEMENT. 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 21bf215546Sopenharmony_ci * DEALINGS IN THE SOFTWARE. 22bf215546Sopenharmony_ci * 23bf215546Sopenharmony_ci */ 24bf215546Sopenharmony_ci 25bf215546Sopenharmony_ci#include "gpir.h" 26bf215546Sopenharmony_ci 27bf215546Sopenharmony_ci/* Here we perform a few optimizations that can't currently be done in NIR: 28bf215546Sopenharmony_ci * 29bf215546Sopenharmony_ci * - Optimize the result of a conditional break/continue. In NIR something 30bf215546Sopenharmony_ci * like: 31bf215546Sopenharmony_ci * 32bf215546Sopenharmony_ci * loop { 33bf215546Sopenharmony_ci * ... 34bf215546Sopenharmony_ci * if (cond) 35bf215546Sopenharmony_ci * continue; 36bf215546Sopenharmony_ci * 37bf215546Sopenharmony_ci * would get lowered to: 38bf215546Sopenharmony_ci * 39bf215546Sopenharmony_ci * block_0: 40bf215546Sopenharmony_ci * ... 41bf215546Sopenharmony_ci * block_1: 42bf215546Sopenharmony_ci * branch_cond !cond block_3 43bf215546Sopenharmony_ci * block_2: 44bf215546Sopenharmony_ci * branch_uncond block_0 45bf215546Sopenharmony_ci * block_3: 46bf215546Sopenharmony_ci * ... 47bf215546Sopenharmony_ci * 48bf215546Sopenharmony_ci * We recognize the conditional branch skipping over the unconditional 49bf215546Sopenharmony_ci * branch, and turn it into: 50bf215546Sopenharmony_ci * 51bf215546Sopenharmony_ci * block_0: 52bf215546Sopenharmony_ci * ... 53bf215546Sopenharmony_ci * block_1: 54bf215546Sopenharmony_ci * branch_cond cond block_0 55bf215546Sopenharmony_ci * block_2: 56bf215546Sopenharmony_ci * block_3: 57bf215546Sopenharmony_ci * ... 58bf215546Sopenharmony_ci * 59bf215546Sopenharmony_ci * - Optimize away nots of comparisons as produced by lowering ifs to 60bf215546Sopenharmony_ci * branches, and nots of nots produced by the above optimization. 61bf215546Sopenharmony_ci * 62bf215546Sopenharmony_ci * - DCE 63bf215546Sopenharmony_ci */ 64bf215546Sopenharmony_ci 65bf215546Sopenharmony_cistatic void 66bf215546Sopenharmony_cioptimize_branches(gpir_compiler *comp) 67bf215546Sopenharmony_ci{ 68bf215546Sopenharmony_ci list_for_each_entry(gpir_block, block, &comp->block_list, list) { 69bf215546Sopenharmony_ci /* Look for a block with a single unconditional branch. */ 70bf215546Sopenharmony_ci if (!list_is_singular(&block->node_list)) 71bf215546Sopenharmony_ci continue; 72bf215546Sopenharmony_ci 73bf215546Sopenharmony_ci gpir_node *node = list_first_entry(&block->node_list, gpir_node, list); 74bf215546Sopenharmony_ci if (node->op != gpir_op_branch_uncond) 75bf215546Sopenharmony_ci continue; 76bf215546Sopenharmony_ci 77bf215546Sopenharmony_ci gpir_block *target = gpir_node_to_branch(node)->dest; 78bf215546Sopenharmony_ci 79bf215546Sopenharmony_ci /* Find the previous block */ 80bf215546Sopenharmony_ci if (block->list.prev == &comp->block_list) 81bf215546Sopenharmony_ci continue; 82bf215546Sopenharmony_ci 83bf215546Sopenharmony_ci gpir_block *prev_block = list_entry(block->list.prev, gpir_block, list); 84bf215546Sopenharmony_ci if (list_is_empty(&prev_block->node_list)) 85bf215546Sopenharmony_ci continue; 86bf215546Sopenharmony_ci 87bf215546Sopenharmony_ci /* Previous block must end with a conditional branch */ 88bf215546Sopenharmony_ci gpir_node *prev_block_last = 89bf215546Sopenharmony_ci list_last_entry(&prev_block->node_list, gpir_node, list); 90bf215546Sopenharmony_ci if (prev_block_last->op != gpir_op_branch_cond) 91bf215546Sopenharmony_ci continue; 92bf215546Sopenharmony_ci 93bf215546Sopenharmony_ci /* That branch must branch to the block after this */ 94bf215546Sopenharmony_ci gpir_branch_node *prev_branch = gpir_node_to_branch(prev_block_last); 95bf215546Sopenharmony_ci gpir_block *prev_target = prev_branch->dest; 96bf215546Sopenharmony_ci 97bf215546Sopenharmony_ci if (&prev_target->list != block->list.next) 98bf215546Sopenharmony_ci continue; 99bf215546Sopenharmony_ci 100bf215546Sopenharmony_ci /* Hooray! Invert the conditional branch and change the target */ 101bf215546Sopenharmony_ci gpir_alu_node *cond = gpir_node_create(prev_block, gpir_op_not); 102bf215546Sopenharmony_ci cond->children[0] = prev_branch->cond; 103bf215546Sopenharmony_ci cond->num_child = 1; 104bf215546Sopenharmony_ci gpir_node_add_dep(&cond->node, cond->children[0], GPIR_DEP_INPUT); 105bf215546Sopenharmony_ci list_addtail(&cond->node.list, &prev_block_last->list); 106bf215546Sopenharmony_ci gpir_node_insert_child(prev_block_last, prev_branch->cond, &cond->node); 107bf215546Sopenharmony_ci prev_branch->dest = target; 108bf215546Sopenharmony_ci prev_block->successors[1] = target; 109bf215546Sopenharmony_ci 110bf215546Sopenharmony_ci /* Delete the branch */ 111bf215546Sopenharmony_ci list_del(&node->list); 112bf215546Sopenharmony_ci block->successors[0] = list_entry(block->list.next, gpir_block, list); 113bf215546Sopenharmony_ci } 114bf215546Sopenharmony_ci} 115bf215546Sopenharmony_ci 116bf215546Sopenharmony_cistatic void 117bf215546Sopenharmony_cioptimize_not(gpir_compiler *comp) 118bf215546Sopenharmony_ci{ 119bf215546Sopenharmony_ci list_for_each_entry(gpir_block, block, &comp->block_list, list) { 120bf215546Sopenharmony_ci list_for_each_entry_rev(gpir_node, node, &block->node_list, list) { 121bf215546Sopenharmony_ci if (node->op != gpir_op_not) 122bf215546Sopenharmony_ci continue; 123bf215546Sopenharmony_ci 124bf215546Sopenharmony_ci gpir_alu_node *alu = gpir_node_to_alu(node); 125bf215546Sopenharmony_ci 126bf215546Sopenharmony_ci gpir_node *replace = NULL; 127bf215546Sopenharmony_ci if (alu->children[0]->op == gpir_op_not) { 128bf215546Sopenharmony_ci /* (not (not a)) -> a */ 129bf215546Sopenharmony_ci gpir_alu_node *child = gpir_node_to_alu(alu->children[0]); 130bf215546Sopenharmony_ci replace = child->children[0]; 131bf215546Sopenharmony_ci } else if (alu->children[0]->op == gpir_op_ge || 132bf215546Sopenharmony_ci alu->children[0]->op == gpir_op_lt) { 133bf215546Sopenharmony_ci /* (not (ge a, b)) -> (lt a, b) and 134bf215546Sopenharmony_ci * (not (lt a, b)) -> (ge a, b) 135bf215546Sopenharmony_ci */ 136bf215546Sopenharmony_ci gpir_alu_node *child = gpir_node_to_alu(alu->children[0]); 137bf215546Sopenharmony_ci gpir_op op = alu->children[0]->op == gpir_op_ge ? 138bf215546Sopenharmony_ci gpir_op_lt : gpir_op_ge; 139bf215546Sopenharmony_ci gpir_alu_node *new = gpir_node_create(block, op); 140bf215546Sopenharmony_ci new->children[0] = child->children[0]; 141bf215546Sopenharmony_ci new->children[1] = child->children[1]; 142bf215546Sopenharmony_ci new->num_child = 2; 143bf215546Sopenharmony_ci gpir_node_add_dep(&new->node, new->children[0], GPIR_DEP_INPUT); 144bf215546Sopenharmony_ci gpir_node_add_dep(&new->node, new->children[1], GPIR_DEP_INPUT); 145bf215546Sopenharmony_ci list_addtail(&new->node.list, &alu->children[0]->list); 146bf215546Sopenharmony_ci replace = &new->node; 147bf215546Sopenharmony_ci } 148bf215546Sopenharmony_ci 149bf215546Sopenharmony_ci if (replace) { 150bf215546Sopenharmony_ci gpir_node_replace_succ(replace, node); 151bf215546Sopenharmony_ci } 152bf215546Sopenharmony_ci } 153bf215546Sopenharmony_ci } 154bf215546Sopenharmony_ci} 155bf215546Sopenharmony_ci 156bf215546Sopenharmony_ci/* Does what it says. In addition to removing unused nodes from the not 157bf215546Sopenharmony_ci * optimization above, we need this to remove unused load_const nodes which 158bf215546Sopenharmony_ci * were created from store_output intrinsics in NIR, since we ignore the 159bf215546Sopenharmony_ci * offset. 160bf215546Sopenharmony_ci */ 161bf215546Sopenharmony_ci 162bf215546Sopenharmony_cistatic void 163bf215546Sopenharmony_cidead_code_eliminate(gpir_compiler *comp) 164bf215546Sopenharmony_ci{ 165bf215546Sopenharmony_ci list_for_each_entry(gpir_block, block, &comp->block_list, list) { 166bf215546Sopenharmony_ci list_for_each_entry_safe_rev(gpir_node, node, &block->node_list, list) { 167bf215546Sopenharmony_ci if (node->type != gpir_node_type_store && 168bf215546Sopenharmony_ci node->type != gpir_node_type_branch && 169bf215546Sopenharmony_ci list_is_empty(&node->succ_list)) { 170bf215546Sopenharmony_ci gpir_node_delete(node); 171bf215546Sopenharmony_ci } 172bf215546Sopenharmony_ci } 173bf215546Sopenharmony_ci } 174bf215546Sopenharmony_ci 175bf215546Sopenharmony_ci /* Kill all the writes to regs that are never read. All the known 176bf215546Sopenharmony_ci * instances of these are coming from the cycle-breaking register 177bf215546Sopenharmony_ci * created in out-of-SSA. See resolve_parallel_copy() in nir_from_ssa.c 178bf215546Sopenharmony_ci * Since we kill redundant movs when we translate nir into gpir, it 179bf215546Sopenharmony_ci * results in this reg being written, but never read. 180bf215546Sopenharmony_ci */ 181bf215546Sopenharmony_ci BITSET_WORD *regs = rzalloc_array(comp, BITSET_WORD, comp->cur_reg); 182bf215546Sopenharmony_ci list_for_each_entry(gpir_block, block, &comp->block_list, list) { 183bf215546Sopenharmony_ci list_for_each_entry(gpir_node, node, &block->node_list, list) { 184bf215546Sopenharmony_ci if (node->op != gpir_op_load_reg) 185bf215546Sopenharmony_ci continue; 186bf215546Sopenharmony_ci gpir_load_node *load = gpir_node_to_load(node); 187bf215546Sopenharmony_ci BITSET_SET(regs, load->reg->index); 188bf215546Sopenharmony_ci } 189bf215546Sopenharmony_ci } 190bf215546Sopenharmony_ci 191bf215546Sopenharmony_ci list_for_each_entry(gpir_block, block, &comp->block_list, list) { 192bf215546Sopenharmony_ci list_for_each_entry_safe(gpir_node, node, &block->node_list, list) { 193bf215546Sopenharmony_ci if (node->op != gpir_op_store_reg) 194bf215546Sopenharmony_ci continue; 195bf215546Sopenharmony_ci gpir_store_node *store = gpir_node_to_store(node); 196bf215546Sopenharmony_ci if (!BITSET_TEST(regs, store->reg->index)) 197bf215546Sopenharmony_ci gpir_node_delete(node); 198bf215546Sopenharmony_ci } 199bf215546Sopenharmony_ci } 200bf215546Sopenharmony_ci 201bf215546Sopenharmony_ci ralloc_free(regs); 202bf215546Sopenharmony_ci} 203bf215546Sopenharmony_ci 204bf215546Sopenharmony_cibool 205bf215546Sopenharmony_cigpir_optimize(gpir_compiler *comp) 206bf215546Sopenharmony_ci{ 207bf215546Sopenharmony_ci optimize_branches(comp); 208bf215546Sopenharmony_ci optimize_not(comp); 209bf215546Sopenharmony_ci dead_code_eliminate(comp); 210bf215546Sopenharmony_ci 211bf215546Sopenharmony_ci gpir_debug("after optimization\n"); 212bf215546Sopenharmony_ci gpir_node_print_prog_seq(comp); 213bf215546Sopenharmony_ci 214bf215546Sopenharmony_ci return true; 215bf215546Sopenharmony_ci} 216bf215546Sopenharmony_ci 217