1b8e80941Smrg/* 2b8e80941Smrg * Copyright © 2013 Intel Corporation 3b8e80941Smrg * 4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a 5b8e80941Smrg * copy of this software and associated documentation files (the "Software"), 6b8e80941Smrg * to deal in the Software without restriction, including without limitation 7b8e80941Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8b8e80941Smrg * and/or sell copies of the Software, and to permit persons to whom the 9b8e80941Smrg * Software is furnished to do so, subject to the following conditions: 10b8e80941Smrg * 11b8e80941Smrg * The above copyright notice and this permission notice (including the next 12b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the 13b8e80941Smrg * Software. 14b8e80941Smrg * 15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19b8e80941Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20b8e80941Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21b8e80941Smrg * IN THE SOFTWARE. 22b8e80941Smrg */ 23b8e80941Smrg 24b8e80941Smrg#include "brw_cfg.h" 25b8e80941Smrg 26b8e80941Smrgusing namespace brw; 27b8e80941Smrg 28b8e80941Smrg/** @file brw_predicated_break.cpp 29b8e80941Smrg * 30b8e80941Smrg * Loops are often structured as 31b8e80941Smrg * 32b8e80941Smrg * loop: 33b8e80941Smrg * CMP.f0 34b8e80941Smrg * (+f0) IF 35b8e80941Smrg * BREAK 36b8e80941Smrg * ENDIF 37b8e80941Smrg * ... 38b8e80941Smrg * WHILE loop 39b8e80941Smrg * 40b8e80941Smrg * This peephole pass removes the IF and ENDIF instructions and predicates the 41b8e80941Smrg * BREAK, dropping two instructions from the loop body. 42b8e80941Smrg * 43b8e80941Smrg * If the loop was a DO { ... } WHILE loop, it looks like 44b8e80941Smrg * 45b8e80941Smrg * loop: 46b8e80941Smrg * ... 47b8e80941Smrg * CMP.f0 48b8e80941Smrg * (+f0) IF 49b8e80941Smrg * BREAK 50b8e80941Smrg * ENDIF 51b8e80941Smrg * WHILE loop 52b8e80941Smrg * 53b8e80941Smrg * and we can remove the BREAK instruction and predicate the WHILE. 54b8e80941Smrg */ 55b8e80941Smrg 56b8e80941Smrgbool 57b8e80941Smrgopt_predicated_break(backend_shader *s) 58b8e80941Smrg{ 59b8e80941Smrg bool progress = false; 60b8e80941Smrg 61b8e80941Smrg foreach_block (block, s->cfg) { 62b8e80941Smrg if (block->start_ip != block->end_ip) 63b8e80941Smrg continue; 64b8e80941Smrg 65b8e80941Smrg /* BREAK and CONTINUE instructions, by definition, can only be found at 66b8e80941Smrg * the ends of basic blocks. 67b8e80941Smrg */ 68b8e80941Smrg backend_instruction *jump_inst = block->end(); 69b8e80941Smrg if (jump_inst->opcode != BRW_OPCODE_BREAK && 70b8e80941Smrg jump_inst->opcode != BRW_OPCODE_CONTINUE) 71b8e80941Smrg continue; 72b8e80941Smrg 73b8e80941Smrg backend_instruction *if_inst = block->prev()->end(); 74b8e80941Smrg if (if_inst->opcode != BRW_OPCODE_IF) 75b8e80941Smrg continue; 76b8e80941Smrg 77b8e80941Smrg backend_instruction *endif_inst = block->next()->start(); 78b8e80941Smrg if (endif_inst->opcode != BRW_OPCODE_ENDIF) 79b8e80941Smrg continue; 80b8e80941Smrg 81b8e80941Smrg bblock_t *jump_block = block; 82b8e80941Smrg bblock_t *if_block = jump_block->prev(); 83b8e80941Smrg bblock_t *endif_block = jump_block->next(); 84b8e80941Smrg 85b8e80941Smrg jump_inst->predicate = if_inst->predicate; 86b8e80941Smrg jump_inst->predicate_inverse = if_inst->predicate_inverse; 87b8e80941Smrg 88b8e80941Smrg bblock_t *earlier_block = if_block; 89b8e80941Smrg if (if_block->start_ip == if_block->end_ip) { 90b8e80941Smrg earlier_block = if_block->prev(); 91b8e80941Smrg } 92b8e80941Smrg 93b8e80941Smrg if_inst->remove(if_block); 94b8e80941Smrg 95b8e80941Smrg bblock_t *later_block = endif_block; 96b8e80941Smrg if (endif_block->start_ip == endif_block->end_ip) { 97b8e80941Smrg later_block = endif_block->next(); 98b8e80941Smrg } 99b8e80941Smrg endif_inst->remove(endif_block); 100b8e80941Smrg 101b8e80941Smrg if (!earlier_block->ends_with_control_flow()) { 102b8e80941Smrg earlier_block->children.make_empty(); 103b8e80941Smrg earlier_block->add_successor(s->cfg->mem_ctx, jump_block); 104b8e80941Smrg } 105b8e80941Smrg 106b8e80941Smrg if (!later_block->starts_with_control_flow()) { 107b8e80941Smrg later_block->parents.make_empty(); 108b8e80941Smrg } 109b8e80941Smrg jump_block->add_successor(s->cfg->mem_ctx, later_block); 110b8e80941Smrg 111b8e80941Smrg if (earlier_block->can_combine_with(jump_block)) { 112b8e80941Smrg earlier_block->combine_with(jump_block); 113b8e80941Smrg 114b8e80941Smrg block = earlier_block; 115b8e80941Smrg } 116b8e80941Smrg 117b8e80941Smrg /* Now look at the first instruction of the block following the BREAK. If 118b8e80941Smrg * it's a WHILE, we can delete the break, predicate the WHILE, and join 119b8e80941Smrg * the two basic blocks. 120b8e80941Smrg */ 121b8e80941Smrg bblock_t *while_block = earlier_block->next(); 122b8e80941Smrg backend_instruction *while_inst = while_block->start(); 123b8e80941Smrg 124b8e80941Smrg if (jump_inst->opcode == BRW_OPCODE_BREAK && 125b8e80941Smrg while_inst->opcode == BRW_OPCODE_WHILE && 126b8e80941Smrg while_inst->predicate == BRW_PREDICATE_NONE) { 127b8e80941Smrg jump_inst->remove(earlier_block); 128b8e80941Smrg while_inst->predicate = jump_inst->predicate; 129b8e80941Smrg while_inst->predicate_inverse = !jump_inst->predicate_inverse; 130b8e80941Smrg 131b8e80941Smrg assert(earlier_block->can_combine_with(while_block)); 132b8e80941Smrg earlier_block->combine_with(while_block); 133b8e80941Smrg } 134b8e80941Smrg 135b8e80941Smrg progress = true; 136b8e80941Smrg } 137b8e80941Smrg 138b8e80941Smrg if (progress) 139b8e80941Smrg s->invalidate_live_intervals(); 140b8e80941Smrg 141b8e80941Smrg return progress; 142b8e80941Smrg} 143