1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2014 Intel Corporation 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_control_flow_private.h" 29bf215546Sopenharmony_ci 30bf215546Sopenharmony_ci/** 31bf215546Sopenharmony_ci * \name Control flow modification 32bf215546Sopenharmony_ci * 33bf215546Sopenharmony_ci * These functions modify the control flow tree while keeping the control flow 34bf215546Sopenharmony_ci * graph up-to-date. The invariants respected are: 35bf215546Sopenharmony_ci * 1. Each then statement, else statement, or loop body must have at least one 36bf215546Sopenharmony_ci * control flow node. 37bf215546Sopenharmony_ci * 2. Each if-statement and loop must have one basic block before it and one 38bf215546Sopenharmony_ci * after. 39bf215546Sopenharmony_ci * 3. Two basic blocks cannot be directly next to each other. 40bf215546Sopenharmony_ci * 4. If a basic block has a jump instruction, there must be only one and it 41bf215546Sopenharmony_ci * must be at the end of the block. 42bf215546Sopenharmony_ci * 43bf215546Sopenharmony_ci * The purpose of the second one is so that we have places to insert code during 44bf215546Sopenharmony_ci * GCM, as well as eliminating the possibility of critical edges. 45bf215546Sopenharmony_ci */ 46bf215546Sopenharmony_ci/*@{*/ 47bf215546Sopenharmony_ci 48bf215546Sopenharmony_cistatic inline void 49bf215546Sopenharmony_ciblock_add_pred(nir_block *block, nir_block *pred) 50bf215546Sopenharmony_ci{ 51bf215546Sopenharmony_ci _mesa_set_add(block->predecessors, pred); 52bf215546Sopenharmony_ci} 53bf215546Sopenharmony_ci 54bf215546Sopenharmony_cistatic inline void 55bf215546Sopenharmony_ciblock_remove_pred(nir_block *block, nir_block *pred) 56bf215546Sopenharmony_ci{ 57bf215546Sopenharmony_ci struct set_entry *entry = _mesa_set_search(block->predecessors, pred); 58bf215546Sopenharmony_ci 59bf215546Sopenharmony_ci assert(entry); 60bf215546Sopenharmony_ci 61bf215546Sopenharmony_ci _mesa_set_remove(block->predecessors, entry); 62bf215546Sopenharmony_ci} 63bf215546Sopenharmony_ci 64bf215546Sopenharmony_cistatic void 65bf215546Sopenharmony_cilink_blocks(nir_block *pred, nir_block *succ1, nir_block *succ2) 66bf215546Sopenharmony_ci{ 67bf215546Sopenharmony_ci pred->successors[0] = succ1; 68bf215546Sopenharmony_ci if (succ1 != NULL) 69bf215546Sopenharmony_ci block_add_pred(succ1, pred); 70bf215546Sopenharmony_ci 71bf215546Sopenharmony_ci pred->successors[1] = succ2; 72bf215546Sopenharmony_ci if (succ2 != NULL) 73bf215546Sopenharmony_ci block_add_pred(succ2, pred); 74bf215546Sopenharmony_ci} 75bf215546Sopenharmony_ci 76bf215546Sopenharmony_cistatic void 77bf215546Sopenharmony_ciunlink_blocks(nir_block *pred, nir_block *succ) 78bf215546Sopenharmony_ci{ 79bf215546Sopenharmony_ci if (pred->successors[0] == succ) { 80bf215546Sopenharmony_ci pred->successors[0] = pred->successors[1]; 81bf215546Sopenharmony_ci pred->successors[1] = NULL; 82bf215546Sopenharmony_ci } else { 83bf215546Sopenharmony_ci assert(pred->successors[1] == succ); 84bf215546Sopenharmony_ci pred->successors[1] = NULL; 85bf215546Sopenharmony_ci } 86bf215546Sopenharmony_ci 87bf215546Sopenharmony_ci block_remove_pred(succ, pred); 88bf215546Sopenharmony_ci} 89bf215546Sopenharmony_ci 90bf215546Sopenharmony_cistatic void 91bf215546Sopenharmony_ciunlink_block_successors(nir_block *block) 92bf215546Sopenharmony_ci{ 93bf215546Sopenharmony_ci if (block->successors[1] != NULL) 94bf215546Sopenharmony_ci unlink_blocks(block, block->successors[1]); 95bf215546Sopenharmony_ci if (block->successors[0] != NULL) 96bf215546Sopenharmony_ci unlink_blocks(block, block->successors[0]); 97bf215546Sopenharmony_ci} 98bf215546Sopenharmony_ci 99bf215546Sopenharmony_cistatic void 100bf215546Sopenharmony_cilink_non_block_to_block(nir_cf_node *node, nir_block *block) 101bf215546Sopenharmony_ci{ 102bf215546Sopenharmony_ci if (node->type == nir_cf_node_if) { 103bf215546Sopenharmony_ci /* 104bf215546Sopenharmony_ci * We're trying to link an if to a block after it; this just means linking 105bf215546Sopenharmony_ci * the last block of the then and else branches. 106bf215546Sopenharmony_ci */ 107bf215546Sopenharmony_ci 108bf215546Sopenharmony_ci nir_if *if_stmt = nir_cf_node_as_if(node); 109bf215546Sopenharmony_ci 110bf215546Sopenharmony_ci nir_block *last_then_block = nir_if_last_then_block(if_stmt); 111bf215546Sopenharmony_ci nir_block *last_else_block = nir_if_last_else_block(if_stmt); 112bf215546Sopenharmony_ci 113bf215546Sopenharmony_ci if (!nir_block_ends_in_jump(last_then_block)) { 114bf215546Sopenharmony_ci unlink_block_successors(last_then_block); 115bf215546Sopenharmony_ci link_blocks(last_then_block, block, NULL); 116bf215546Sopenharmony_ci } 117bf215546Sopenharmony_ci 118bf215546Sopenharmony_ci if (!nir_block_ends_in_jump(last_else_block)) { 119bf215546Sopenharmony_ci unlink_block_successors(last_else_block); 120bf215546Sopenharmony_ci link_blocks(last_else_block, block, NULL); 121bf215546Sopenharmony_ci } 122bf215546Sopenharmony_ci } else { 123bf215546Sopenharmony_ci assert(node->type == nir_cf_node_loop); 124bf215546Sopenharmony_ci } 125bf215546Sopenharmony_ci} 126bf215546Sopenharmony_ci 127bf215546Sopenharmony_cistatic void 128bf215546Sopenharmony_cilink_block_to_non_block(nir_block *block, nir_cf_node *node) 129bf215546Sopenharmony_ci{ 130bf215546Sopenharmony_ci if (node->type == nir_cf_node_if) { 131bf215546Sopenharmony_ci /* 132bf215546Sopenharmony_ci * We're trying to link a block to an if after it; this just means linking 133bf215546Sopenharmony_ci * the block to the first block of the then and else branches. 134bf215546Sopenharmony_ci */ 135bf215546Sopenharmony_ci 136bf215546Sopenharmony_ci nir_if *if_stmt = nir_cf_node_as_if(node); 137bf215546Sopenharmony_ci 138bf215546Sopenharmony_ci nir_block *first_then_block = nir_if_first_then_block(if_stmt); 139bf215546Sopenharmony_ci nir_block *first_else_block = nir_if_first_else_block(if_stmt); 140bf215546Sopenharmony_ci 141bf215546Sopenharmony_ci unlink_block_successors(block); 142bf215546Sopenharmony_ci link_blocks(block, first_then_block, first_else_block); 143bf215546Sopenharmony_ci } else if (node->type == nir_cf_node_loop) { 144bf215546Sopenharmony_ci /* 145bf215546Sopenharmony_ci * For similar reasons as the corresponding case in 146bf215546Sopenharmony_ci * link_non_block_to_block(), don't worry about if the loop header has 147bf215546Sopenharmony_ci * any predecessors that need to be unlinked. 148bf215546Sopenharmony_ci */ 149bf215546Sopenharmony_ci 150bf215546Sopenharmony_ci nir_loop *loop = nir_cf_node_as_loop(node); 151bf215546Sopenharmony_ci 152bf215546Sopenharmony_ci nir_block *loop_header_block = nir_loop_first_block(loop); 153bf215546Sopenharmony_ci 154bf215546Sopenharmony_ci unlink_block_successors(block); 155bf215546Sopenharmony_ci link_blocks(block, loop_header_block, NULL); 156bf215546Sopenharmony_ci } 157bf215546Sopenharmony_ci 158bf215546Sopenharmony_ci} 159bf215546Sopenharmony_ci 160bf215546Sopenharmony_ci/** 161bf215546Sopenharmony_ci * Replace a block's successor with a different one. 162bf215546Sopenharmony_ci */ 163bf215546Sopenharmony_cistatic void 164bf215546Sopenharmony_cireplace_successor(nir_block *block, nir_block *old_succ, nir_block *new_succ) 165bf215546Sopenharmony_ci{ 166bf215546Sopenharmony_ci if (block->successors[0] == old_succ) { 167bf215546Sopenharmony_ci block->successors[0] = new_succ; 168bf215546Sopenharmony_ci } else { 169bf215546Sopenharmony_ci assert(block->successors[1] == old_succ); 170bf215546Sopenharmony_ci block->successors[1] = new_succ; 171bf215546Sopenharmony_ci } 172bf215546Sopenharmony_ci 173bf215546Sopenharmony_ci block_remove_pred(old_succ, block); 174bf215546Sopenharmony_ci block_add_pred(new_succ, block); 175bf215546Sopenharmony_ci} 176bf215546Sopenharmony_ci 177bf215546Sopenharmony_ci/** 178bf215546Sopenharmony_ci * Takes a basic block and inserts a new empty basic block before it, making its 179bf215546Sopenharmony_ci * predecessors point to the new block. This essentially splits the block into 180bf215546Sopenharmony_ci * an empty header and a body so that another non-block CF node can be inserted 181bf215546Sopenharmony_ci * between the two. Note that this does *not* link the two basic blocks, so 182bf215546Sopenharmony_ci * some kind of cleanup *must* be performed after this call. 183bf215546Sopenharmony_ci */ 184bf215546Sopenharmony_ci 185bf215546Sopenharmony_cistatic nir_block * 186bf215546Sopenharmony_cisplit_block_beginning(nir_block *block) 187bf215546Sopenharmony_ci{ 188bf215546Sopenharmony_ci nir_block *new_block = nir_block_create(ralloc_parent(block)); 189bf215546Sopenharmony_ci new_block->cf_node.parent = block->cf_node.parent; 190bf215546Sopenharmony_ci exec_node_insert_node_before(&block->cf_node.node, &new_block->cf_node.node); 191bf215546Sopenharmony_ci 192bf215546Sopenharmony_ci set_foreach(block->predecessors, entry) { 193bf215546Sopenharmony_ci nir_block *pred = (nir_block *) entry->key; 194bf215546Sopenharmony_ci replace_successor(pred, block, new_block); 195bf215546Sopenharmony_ci } 196bf215546Sopenharmony_ci 197bf215546Sopenharmony_ci /* Any phi nodes must stay part of the new block, or else their 198bf215546Sopenharmony_ci * sources will be messed up. 199bf215546Sopenharmony_ci */ 200bf215546Sopenharmony_ci nir_foreach_instr_safe(instr, block) { 201bf215546Sopenharmony_ci if (instr->type != nir_instr_type_phi) 202bf215546Sopenharmony_ci break; 203bf215546Sopenharmony_ci 204bf215546Sopenharmony_ci exec_node_remove(&instr->node); 205bf215546Sopenharmony_ci instr->block = new_block; 206bf215546Sopenharmony_ci exec_list_push_tail(&new_block->instr_list, &instr->node); 207bf215546Sopenharmony_ci } 208bf215546Sopenharmony_ci 209bf215546Sopenharmony_ci return new_block; 210bf215546Sopenharmony_ci} 211bf215546Sopenharmony_ci 212bf215546Sopenharmony_cistatic void 213bf215546Sopenharmony_cirewrite_phi_preds(nir_block *block, nir_block *old_pred, nir_block *new_pred) 214bf215546Sopenharmony_ci{ 215bf215546Sopenharmony_ci nir_foreach_instr_safe(instr, block) { 216bf215546Sopenharmony_ci if (instr->type != nir_instr_type_phi) 217bf215546Sopenharmony_ci break; 218bf215546Sopenharmony_ci 219bf215546Sopenharmony_ci nir_phi_instr *phi = nir_instr_as_phi(instr); 220bf215546Sopenharmony_ci nir_foreach_phi_src(src, phi) { 221bf215546Sopenharmony_ci if (src->pred == old_pred) { 222bf215546Sopenharmony_ci src->pred = new_pred; 223bf215546Sopenharmony_ci break; 224bf215546Sopenharmony_ci } 225bf215546Sopenharmony_ci } 226bf215546Sopenharmony_ci } 227bf215546Sopenharmony_ci} 228bf215546Sopenharmony_ci 229bf215546Sopenharmony_civoid 230bf215546Sopenharmony_cinir_insert_phi_undef(nir_block *block, nir_block *pred) 231bf215546Sopenharmony_ci{ 232bf215546Sopenharmony_ci nir_function_impl *impl = nir_cf_node_get_function(&block->cf_node); 233bf215546Sopenharmony_ci nir_foreach_instr(instr, block) { 234bf215546Sopenharmony_ci if (instr->type != nir_instr_type_phi) 235bf215546Sopenharmony_ci break; 236bf215546Sopenharmony_ci 237bf215546Sopenharmony_ci nir_phi_instr *phi = nir_instr_as_phi(instr); 238bf215546Sopenharmony_ci nir_ssa_undef_instr *undef = 239bf215546Sopenharmony_ci nir_ssa_undef_instr_create(impl->function->shader, 240bf215546Sopenharmony_ci phi->dest.ssa.num_components, 241bf215546Sopenharmony_ci phi->dest.ssa.bit_size); 242bf215546Sopenharmony_ci nir_instr_insert_before_cf_list(&impl->body, &undef->instr); 243bf215546Sopenharmony_ci nir_phi_src *src = nir_phi_instr_add_src(phi, pred, nir_src_for_ssa(&undef->def)); 244bf215546Sopenharmony_ci list_addtail(&src->src.use_link, &undef->def.uses); 245bf215546Sopenharmony_ci } 246bf215546Sopenharmony_ci} 247bf215546Sopenharmony_ci 248bf215546Sopenharmony_ci/** 249bf215546Sopenharmony_ci * Moves the successors of source to the successors of dest, leaving both 250bf215546Sopenharmony_ci * successors of source NULL. 251bf215546Sopenharmony_ci */ 252bf215546Sopenharmony_ci 253bf215546Sopenharmony_cistatic void 254bf215546Sopenharmony_cimove_successors(nir_block *source, nir_block *dest) 255bf215546Sopenharmony_ci{ 256bf215546Sopenharmony_ci nir_block *succ1 = source->successors[0]; 257bf215546Sopenharmony_ci nir_block *succ2 = source->successors[1]; 258bf215546Sopenharmony_ci 259bf215546Sopenharmony_ci if (succ1) { 260bf215546Sopenharmony_ci unlink_blocks(source, succ1); 261bf215546Sopenharmony_ci rewrite_phi_preds(succ1, source, dest); 262bf215546Sopenharmony_ci } 263bf215546Sopenharmony_ci 264bf215546Sopenharmony_ci if (succ2) { 265bf215546Sopenharmony_ci unlink_blocks(source, succ2); 266bf215546Sopenharmony_ci rewrite_phi_preds(succ2, source, dest); 267bf215546Sopenharmony_ci } 268bf215546Sopenharmony_ci 269bf215546Sopenharmony_ci unlink_block_successors(dest); 270bf215546Sopenharmony_ci link_blocks(dest, succ1, succ2); 271bf215546Sopenharmony_ci} 272bf215546Sopenharmony_ci 273bf215546Sopenharmony_ci/* Given a basic block with no successors that has been inserted into the 274bf215546Sopenharmony_ci * control flow tree, gives it the successors it would normally have assuming 275bf215546Sopenharmony_ci * it doesn't end in a jump instruction. Also inserts phi sources with undefs 276bf215546Sopenharmony_ci * if necessary. 277bf215546Sopenharmony_ci */ 278bf215546Sopenharmony_cistatic void 279bf215546Sopenharmony_ciblock_add_normal_succs(nir_block *block) 280bf215546Sopenharmony_ci{ 281bf215546Sopenharmony_ci if (exec_node_is_tail_sentinel(block->cf_node.node.next)) { 282bf215546Sopenharmony_ci nir_cf_node *parent = block->cf_node.parent; 283bf215546Sopenharmony_ci if (parent->type == nir_cf_node_if) { 284bf215546Sopenharmony_ci nir_cf_node *next = nir_cf_node_next(parent); 285bf215546Sopenharmony_ci nir_block *next_block = nir_cf_node_as_block(next); 286bf215546Sopenharmony_ci 287bf215546Sopenharmony_ci link_blocks(block, next_block, NULL); 288bf215546Sopenharmony_ci } else if (parent->type == nir_cf_node_loop) { 289bf215546Sopenharmony_ci nir_loop *loop = nir_cf_node_as_loop(parent); 290bf215546Sopenharmony_ci 291bf215546Sopenharmony_ci nir_block *head_block = nir_loop_first_block(loop); 292bf215546Sopenharmony_ci 293bf215546Sopenharmony_ci link_blocks(block, head_block, NULL); 294bf215546Sopenharmony_ci nir_insert_phi_undef(head_block, block); 295bf215546Sopenharmony_ci } else { 296bf215546Sopenharmony_ci nir_function_impl *impl = nir_cf_node_as_function(parent); 297bf215546Sopenharmony_ci link_blocks(block, impl->end_block, NULL); 298bf215546Sopenharmony_ci } 299bf215546Sopenharmony_ci } else { 300bf215546Sopenharmony_ci nir_cf_node *next = nir_cf_node_next(&block->cf_node); 301bf215546Sopenharmony_ci if (next->type == nir_cf_node_if) { 302bf215546Sopenharmony_ci nir_if *next_if = nir_cf_node_as_if(next); 303bf215546Sopenharmony_ci 304bf215546Sopenharmony_ci nir_block *first_then_block = nir_if_first_then_block(next_if); 305bf215546Sopenharmony_ci nir_block *first_else_block = nir_if_first_else_block(next_if); 306bf215546Sopenharmony_ci 307bf215546Sopenharmony_ci link_blocks(block, first_then_block, first_else_block); 308bf215546Sopenharmony_ci } else if (next->type == nir_cf_node_loop) { 309bf215546Sopenharmony_ci nir_loop *next_loop = nir_cf_node_as_loop(next); 310bf215546Sopenharmony_ci 311bf215546Sopenharmony_ci nir_block *first_block = nir_loop_first_block(next_loop); 312bf215546Sopenharmony_ci 313bf215546Sopenharmony_ci link_blocks(block, first_block, NULL); 314bf215546Sopenharmony_ci nir_insert_phi_undef(first_block, block); 315bf215546Sopenharmony_ci } 316bf215546Sopenharmony_ci } 317bf215546Sopenharmony_ci} 318bf215546Sopenharmony_ci 319bf215546Sopenharmony_cistatic nir_block * 320bf215546Sopenharmony_cisplit_block_end(nir_block *block) 321bf215546Sopenharmony_ci{ 322bf215546Sopenharmony_ci nir_block *new_block = nir_block_create(ralloc_parent(block)); 323bf215546Sopenharmony_ci new_block->cf_node.parent = block->cf_node.parent; 324bf215546Sopenharmony_ci exec_node_insert_after(&block->cf_node.node, &new_block->cf_node.node); 325bf215546Sopenharmony_ci 326bf215546Sopenharmony_ci if (nir_block_ends_in_jump(block)) { 327bf215546Sopenharmony_ci /* Figure out what successor block would've had if it didn't have a jump 328bf215546Sopenharmony_ci * instruction, and make new_block have that successor. 329bf215546Sopenharmony_ci */ 330bf215546Sopenharmony_ci block_add_normal_succs(new_block); 331bf215546Sopenharmony_ci } else { 332bf215546Sopenharmony_ci move_successors(block, new_block); 333bf215546Sopenharmony_ci } 334bf215546Sopenharmony_ci 335bf215546Sopenharmony_ci return new_block; 336bf215546Sopenharmony_ci} 337bf215546Sopenharmony_ci 338bf215546Sopenharmony_cistatic nir_block * 339bf215546Sopenharmony_cisplit_block_before_instr(nir_instr *instr) 340bf215546Sopenharmony_ci{ 341bf215546Sopenharmony_ci assert(instr->type != nir_instr_type_phi); 342bf215546Sopenharmony_ci nir_block *new_block = split_block_beginning(instr->block); 343bf215546Sopenharmony_ci 344bf215546Sopenharmony_ci nir_foreach_instr_safe(cur_instr, instr->block) { 345bf215546Sopenharmony_ci if (cur_instr == instr) 346bf215546Sopenharmony_ci break; 347bf215546Sopenharmony_ci 348bf215546Sopenharmony_ci exec_node_remove(&cur_instr->node); 349bf215546Sopenharmony_ci cur_instr->block = new_block; 350bf215546Sopenharmony_ci exec_list_push_tail(&new_block->instr_list, &cur_instr->node); 351bf215546Sopenharmony_ci } 352bf215546Sopenharmony_ci 353bf215546Sopenharmony_ci return new_block; 354bf215546Sopenharmony_ci} 355bf215546Sopenharmony_ci 356bf215546Sopenharmony_ci/* Splits a basic block at the point specified by the cursor. The "before" and 357bf215546Sopenharmony_ci * "after" arguments are filled out with the blocks resulting from the split 358bf215546Sopenharmony_ci * if non-NULL. Note that the "beginning" of the block is actually interpreted 359bf215546Sopenharmony_ci * as before the first non-phi instruction, and it's illegal to split a block 360bf215546Sopenharmony_ci * before a phi instruction. 361bf215546Sopenharmony_ci */ 362bf215546Sopenharmony_ci 363bf215546Sopenharmony_cistatic void 364bf215546Sopenharmony_cisplit_block_cursor(nir_cursor cursor, 365bf215546Sopenharmony_ci nir_block **_before, nir_block **_after) 366bf215546Sopenharmony_ci{ 367bf215546Sopenharmony_ci nir_block *before, *after; 368bf215546Sopenharmony_ci switch (cursor.option) { 369bf215546Sopenharmony_ci case nir_cursor_before_block: 370bf215546Sopenharmony_ci after = cursor.block; 371bf215546Sopenharmony_ci before = split_block_beginning(cursor.block); 372bf215546Sopenharmony_ci break; 373bf215546Sopenharmony_ci 374bf215546Sopenharmony_ci case nir_cursor_after_block: 375bf215546Sopenharmony_ci before = cursor.block; 376bf215546Sopenharmony_ci after = split_block_end(cursor.block); 377bf215546Sopenharmony_ci break; 378bf215546Sopenharmony_ci 379bf215546Sopenharmony_ci case nir_cursor_before_instr: 380bf215546Sopenharmony_ci after = cursor.instr->block; 381bf215546Sopenharmony_ci before = split_block_before_instr(cursor.instr); 382bf215546Sopenharmony_ci break; 383bf215546Sopenharmony_ci 384bf215546Sopenharmony_ci case nir_cursor_after_instr: 385bf215546Sopenharmony_ci /* We lower this to split_block_before_instr() so that we can keep the 386bf215546Sopenharmony_ci * after-a-jump-instr case contained to split_block_end(). 387bf215546Sopenharmony_ci */ 388bf215546Sopenharmony_ci if (nir_instr_is_last(cursor.instr)) { 389bf215546Sopenharmony_ci before = cursor.instr->block; 390bf215546Sopenharmony_ci after = split_block_end(cursor.instr->block); 391bf215546Sopenharmony_ci } else { 392bf215546Sopenharmony_ci after = cursor.instr->block; 393bf215546Sopenharmony_ci before = split_block_before_instr(nir_instr_next(cursor.instr)); 394bf215546Sopenharmony_ci } 395bf215546Sopenharmony_ci break; 396bf215546Sopenharmony_ci 397bf215546Sopenharmony_ci default: 398bf215546Sopenharmony_ci unreachable("not reached"); 399bf215546Sopenharmony_ci } 400bf215546Sopenharmony_ci 401bf215546Sopenharmony_ci if (_before) 402bf215546Sopenharmony_ci *_before = before; 403bf215546Sopenharmony_ci if (_after) 404bf215546Sopenharmony_ci *_after = after; 405bf215546Sopenharmony_ci} 406bf215546Sopenharmony_ci 407bf215546Sopenharmony_ci/** 408bf215546Sopenharmony_ci * Inserts a non-basic block between two basic blocks and links them together. 409bf215546Sopenharmony_ci */ 410bf215546Sopenharmony_ci 411bf215546Sopenharmony_cistatic void 412bf215546Sopenharmony_ciinsert_non_block(nir_block *before, nir_cf_node *node, nir_block *after) 413bf215546Sopenharmony_ci{ 414bf215546Sopenharmony_ci node->parent = before->cf_node.parent; 415bf215546Sopenharmony_ci exec_node_insert_after(&before->cf_node.node, &node->node); 416bf215546Sopenharmony_ci if (!nir_block_ends_in_jump(before)) 417bf215546Sopenharmony_ci link_block_to_non_block(before, node); 418bf215546Sopenharmony_ci link_non_block_to_block(node, after); 419bf215546Sopenharmony_ci} 420bf215546Sopenharmony_ci 421bf215546Sopenharmony_ci/* walk up the control flow tree to find the innermost enclosed loop */ 422bf215546Sopenharmony_cistatic nir_loop * 423bf215546Sopenharmony_cinearest_loop(nir_cf_node *node) 424bf215546Sopenharmony_ci{ 425bf215546Sopenharmony_ci while (node->type != nir_cf_node_loop) { 426bf215546Sopenharmony_ci node = node->parent; 427bf215546Sopenharmony_ci } 428bf215546Sopenharmony_ci 429bf215546Sopenharmony_ci return nir_cf_node_as_loop(node); 430bf215546Sopenharmony_ci} 431bf215546Sopenharmony_ci 432bf215546Sopenharmony_cistatic void 433bf215546Sopenharmony_ciremove_phi_src(nir_block *block, nir_block *pred) 434bf215546Sopenharmony_ci{ 435bf215546Sopenharmony_ci nir_foreach_instr(instr, block) { 436bf215546Sopenharmony_ci if (instr->type != nir_instr_type_phi) 437bf215546Sopenharmony_ci break; 438bf215546Sopenharmony_ci 439bf215546Sopenharmony_ci nir_phi_instr *phi = nir_instr_as_phi(instr); 440bf215546Sopenharmony_ci nir_foreach_phi_src_safe(src, phi) { 441bf215546Sopenharmony_ci if (src->pred == pred) { 442bf215546Sopenharmony_ci list_del(&src->src.use_link); 443bf215546Sopenharmony_ci exec_node_remove(&src->node); 444bf215546Sopenharmony_ci free(src); 445bf215546Sopenharmony_ci } 446bf215546Sopenharmony_ci } 447bf215546Sopenharmony_ci } 448bf215546Sopenharmony_ci} 449bf215546Sopenharmony_ci 450bf215546Sopenharmony_ci/* 451bf215546Sopenharmony_ci * update the CFG after a jump instruction has been added to the end of a block 452bf215546Sopenharmony_ci */ 453bf215546Sopenharmony_ci 454bf215546Sopenharmony_civoid 455bf215546Sopenharmony_cinir_handle_add_jump(nir_block *block) 456bf215546Sopenharmony_ci{ 457bf215546Sopenharmony_ci nir_instr *instr = nir_block_last_instr(block); 458bf215546Sopenharmony_ci nir_jump_instr *jump_instr = nir_instr_as_jump(instr); 459bf215546Sopenharmony_ci 460bf215546Sopenharmony_ci if (block->successors[0]) 461bf215546Sopenharmony_ci remove_phi_src(block->successors[0], block); 462bf215546Sopenharmony_ci if (block->successors[1]) 463bf215546Sopenharmony_ci remove_phi_src(block->successors[1], block); 464bf215546Sopenharmony_ci unlink_block_successors(block); 465bf215546Sopenharmony_ci 466bf215546Sopenharmony_ci nir_function_impl *impl = nir_cf_node_get_function(&block->cf_node); 467bf215546Sopenharmony_ci nir_metadata_preserve(impl, nir_metadata_none); 468bf215546Sopenharmony_ci 469bf215546Sopenharmony_ci switch (jump_instr->type) { 470bf215546Sopenharmony_ci case nir_jump_return: 471bf215546Sopenharmony_ci case nir_jump_halt: 472bf215546Sopenharmony_ci link_blocks(block, impl->end_block, NULL); 473bf215546Sopenharmony_ci break; 474bf215546Sopenharmony_ci 475bf215546Sopenharmony_ci case nir_jump_break: { 476bf215546Sopenharmony_ci nir_loop *loop = nearest_loop(&block->cf_node); 477bf215546Sopenharmony_ci nir_cf_node *after = nir_cf_node_next(&loop->cf_node); 478bf215546Sopenharmony_ci nir_block *after_block = nir_cf_node_as_block(after); 479bf215546Sopenharmony_ci link_blocks(block, after_block, NULL); 480bf215546Sopenharmony_ci break; 481bf215546Sopenharmony_ci } 482bf215546Sopenharmony_ci 483bf215546Sopenharmony_ci case nir_jump_continue: { 484bf215546Sopenharmony_ci nir_loop *loop = nearest_loop(&block->cf_node); 485bf215546Sopenharmony_ci nir_block *first_block = nir_loop_first_block(loop); 486bf215546Sopenharmony_ci link_blocks(block, first_block, NULL); 487bf215546Sopenharmony_ci break; 488bf215546Sopenharmony_ci } 489bf215546Sopenharmony_ci 490bf215546Sopenharmony_ci case nir_jump_goto: 491bf215546Sopenharmony_ci link_blocks(block, jump_instr->target, NULL); 492bf215546Sopenharmony_ci break; 493bf215546Sopenharmony_ci 494bf215546Sopenharmony_ci case nir_jump_goto_if: 495bf215546Sopenharmony_ci link_blocks(block, jump_instr->else_target, jump_instr->target); 496bf215546Sopenharmony_ci break; 497bf215546Sopenharmony_ci 498bf215546Sopenharmony_ci default: 499bf215546Sopenharmony_ci unreachable("Invalid jump type"); 500bf215546Sopenharmony_ci } 501bf215546Sopenharmony_ci} 502bf215546Sopenharmony_ci 503bf215546Sopenharmony_ci/* Removes the successor of a block with a jump. Note that the jump to be 504bf215546Sopenharmony_ci * eliminated may be free-floating. 505bf215546Sopenharmony_ci */ 506bf215546Sopenharmony_ci 507bf215546Sopenharmony_cistatic void 508bf215546Sopenharmony_ciunlink_jump(nir_block *block, nir_jump_type type, bool add_normal_successors) 509bf215546Sopenharmony_ci{ 510bf215546Sopenharmony_ci if (block->successors[0]) 511bf215546Sopenharmony_ci remove_phi_src(block->successors[0], block); 512bf215546Sopenharmony_ci if (block->successors[1]) 513bf215546Sopenharmony_ci remove_phi_src(block->successors[1], block); 514bf215546Sopenharmony_ci 515bf215546Sopenharmony_ci unlink_block_successors(block); 516bf215546Sopenharmony_ci if (add_normal_successors) 517bf215546Sopenharmony_ci block_add_normal_succs(block); 518bf215546Sopenharmony_ci} 519bf215546Sopenharmony_ci 520bf215546Sopenharmony_civoid 521bf215546Sopenharmony_cinir_handle_remove_jump(nir_block *block, nir_jump_type type) 522bf215546Sopenharmony_ci{ 523bf215546Sopenharmony_ci unlink_jump(block, type, true); 524bf215546Sopenharmony_ci 525bf215546Sopenharmony_ci nir_function_impl *impl = nir_cf_node_get_function(&block->cf_node); 526bf215546Sopenharmony_ci nir_metadata_preserve(impl, nir_metadata_none); 527bf215546Sopenharmony_ci} 528bf215546Sopenharmony_ci 529bf215546Sopenharmony_cistatic void 530bf215546Sopenharmony_ciupdate_if_uses(nir_cf_node *node) 531bf215546Sopenharmony_ci{ 532bf215546Sopenharmony_ci if (node->type != nir_cf_node_if) 533bf215546Sopenharmony_ci return; 534bf215546Sopenharmony_ci 535bf215546Sopenharmony_ci nir_if *if_stmt = nir_cf_node_as_if(node); 536bf215546Sopenharmony_ci 537bf215546Sopenharmony_ci if_stmt->condition.parent_if = if_stmt; 538bf215546Sopenharmony_ci if (if_stmt->condition.is_ssa) { 539bf215546Sopenharmony_ci list_addtail(&if_stmt->condition.use_link, 540bf215546Sopenharmony_ci &if_stmt->condition.ssa->if_uses); 541bf215546Sopenharmony_ci } else { 542bf215546Sopenharmony_ci list_addtail(&if_stmt->condition.use_link, 543bf215546Sopenharmony_ci &if_stmt->condition.reg.reg->if_uses); 544bf215546Sopenharmony_ci } 545bf215546Sopenharmony_ci} 546bf215546Sopenharmony_ci 547bf215546Sopenharmony_ci/** 548bf215546Sopenharmony_ci * Stitch two basic blocks together into one. The aggregate must have the same 549bf215546Sopenharmony_ci * predecessors as the first and the same successors as the second. 550bf215546Sopenharmony_ci * 551bf215546Sopenharmony_ci * Returns a cursor pointing at the end of the before block (i.e.m between the 552bf215546Sopenharmony_ci * two blocks) once stiched together. 553bf215546Sopenharmony_ci */ 554bf215546Sopenharmony_ci 555bf215546Sopenharmony_cistatic nir_cursor 556bf215546Sopenharmony_cistitch_blocks(nir_block *before, nir_block *after) 557bf215546Sopenharmony_ci{ 558bf215546Sopenharmony_ci /* 559bf215546Sopenharmony_ci * We move after into before, so we have to deal with up to 2 successors vs. 560bf215546Sopenharmony_ci * possibly a large number of predecessors. 561bf215546Sopenharmony_ci * 562bf215546Sopenharmony_ci * TODO: special case when before is empty and after isn't? 563bf215546Sopenharmony_ci */ 564bf215546Sopenharmony_ci 565bf215546Sopenharmony_ci if (nir_block_ends_in_jump(before)) { 566bf215546Sopenharmony_ci assert(exec_list_is_empty(&after->instr_list)); 567bf215546Sopenharmony_ci if (after->successors[0]) 568bf215546Sopenharmony_ci remove_phi_src(after->successors[0], after); 569bf215546Sopenharmony_ci if (after->successors[1]) 570bf215546Sopenharmony_ci remove_phi_src(after->successors[1], after); 571bf215546Sopenharmony_ci unlink_block_successors(after); 572bf215546Sopenharmony_ci exec_node_remove(&after->cf_node.node); 573bf215546Sopenharmony_ci 574bf215546Sopenharmony_ci return nir_after_block(before); 575bf215546Sopenharmony_ci } else { 576bf215546Sopenharmony_ci nir_instr *last_before_instr = nir_block_last_instr(before); 577bf215546Sopenharmony_ci 578bf215546Sopenharmony_ci move_successors(after, before); 579bf215546Sopenharmony_ci 580bf215546Sopenharmony_ci foreach_list_typed(nir_instr, instr, node, &after->instr_list) { 581bf215546Sopenharmony_ci instr->block = before; 582bf215546Sopenharmony_ci } 583bf215546Sopenharmony_ci 584bf215546Sopenharmony_ci exec_list_append(&before->instr_list, &after->instr_list); 585bf215546Sopenharmony_ci exec_node_remove(&after->cf_node.node); 586bf215546Sopenharmony_ci 587bf215546Sopenharmony_ci return last_before_instr ? nir_after_instr(last_before_instr) : 588bf215546Sopenharmony_ci nir_before_block(before); 589bf215546Sopenharmony_ci } 590bf215546Sopenharmony_ci} 591bf215546Sopenharmony_ci 592bf215546Sopenharmony_civoid 593bf215546Sopenharmony_cinir_cf_node_insert(nir_cursor cursor, nir_cf_node *node) 594bf215546Sopenharmony_ci{ 595bf215546Sopenharmony_ci nir_block *before, *after; 596bf215546Sopenharmony_ci 597bf215546Sopenharmony_ci split_block_cursor(cursor, &before, &after); 598bf215546Sopenharmony_ci 599bf215546Sopenharmony_ci if (node->type == nir_cf_node_block) { 600bf215546Sopenharmony_ci nir_block *block = nir_cf_node_as_block(node); 601bf215546Sopenharmony_ci exec_node_insert_after(&before->cf_node.node, &block->cf_node.node); 602bf215546Sopenharmony_ci block->cf_node.parent = before->cf_node.parent; 603bf215546Sopenharmony_ci /* stitch_blocks() assumes that any block that ends with a jump has 604bf215546Sopenharmony_ci * already been setup with the correct successors, so we need to set 605bf215546Sopenharmony_ci * up jumps here as the block is being inserted. 606bf215546Sopenharmony_ci */ 607bf215546Sopenharmony_ci if (nir_block_ends_in_jump(block)) 608bf215546Sopenharmony_ci nir_handle_add_jump(block); 609bf215546Sopenharmony_ci 610bf215546Sopenharmony_ci stitch_blocks(block, after); 611bf215546Sopenharmony_ci stitch_blocks(before, block); 612bf215546Sopenharmony_ci } else { 613bf215546Sopenharmony_ci update_if_uses(node); 614bf215546Sopenharmony_ci insert_non_block(before, node, after); 615bf215546Sopenharmony_ci } 616bf215546Sopenharmony_ci} 617bf215546Sopenharmony_ci 618bf215546Sopenharmony_cistatic bool 619bf215546Sopenharmony_cireplace_ssa_def_uses(nir_ssa_def *def, void *void_impl) 620bf215546Sopenharmony_ci{ 621bf215546Sopenharmony_ci nir_function_impl *impl = void_impl; 622bf215546Sopenharmony_ci 623bf215546Sopenharmony_ci nir_ssa_undef_instr *undef = 624bf215546Sopenharmony_ci nir_ssa_undef_instr_create(impl->function->shader, 625bf215546Sopenharmony_ci def->num_components, 626bf215546Sopenharmony_ci def->bit_size); 627bf215546Sopenharmony_ci nir_instr_insert_before_cf_list(&impl->body, &undef->instr); 628bf215546Sopenharmony_ci nir_ssa_def_rewrite_uses(def, &undef->def); 629bf215546Sopenharmony_ci return true; 630bf215546Sopenharmony_ci} 631bf215546Sopenharmony_ci 632bf215546Sopenharmony_cistatic void 633bf215546Sopenharmony_cicleanup_cf_node(nir_cf_node *node, nir_function_impl *impl) 634bf215546Sopenharmony_ci{ 635bf215546Sopenharmony_ci switch (node->type) { 636bf215546Sopenharmony_ci case nir_cf_node_block: { 637bf215546Sopenharmony_ci nir_block *block = nir_cf_node_as_block(node); 638bf215546Sopenharmony_ci /* We need to walk the instructions and clean up defs/uses */ 639bf215546Sopenharmony_ci nir_foreach_instr_safe(instr, block) { 640bf215546Sopenharmony_ci if (instr->type == nir_instr_type_jump) { 641bf215546Sopenharmony_ci nir_jump_instr *jump = nir_instr_as_jump(instr); 642bf215546Sopenharmony_ci unlink_jump(block, jump->type, false); 643bf215546Sopenharmony_ci if (jump->type == nir_jump_goto_if) 644bf215546Sopenharmony_ci nir_instr_rewrite_src(instr, &jump->condition, NIR_SRC_INIT); 645bf215546Sopenharmony_ci } else { 646bf215546Sopenharmony_ci nir_foreach_ssa_def(instr, replace_ssa_def_uses, impl); 647bf215546Sopenharmony_ci nir_instr_remove(instr); 648bf215546Sopenharmony_ci } 649bf215546Sopenharmony_ci } 650bf215546Sopenharmony_ci break; 651bf215546Sopenharmony_ci } 652bf215546Sopenharmony_ci 653bf215546Sopenharmony_ci case nir_cf_node_if: { 654bf215546Sopenharmony_ci nir_if *if_stmt = nir_cf_node_as_if(node); 655bf215546Sopenharmony_ci foreach_list_typed(nir_cf_node, child, node, &if_stmt->then_list) 656bf215546Sopenharmony_ci cleanup_cf_node(child, impl); 657bf215546Sopenharmony_ci foreach_list_typed(nir_cf_node, child, node, &if_stmt->else_list) 658bf215546Sopenharmony_ci cleanup_cf_node(child, impl); 659bf215546Sopenharmony_ci 660bf215546Sopenharmony_ci list_del(&if_stmt->condition.use_link); 661bf215546Sopenharmony_ci break; 662bf215546Sopenharmony_ci } 663bf215546Sopenharmony_ci 664bf215546Sopenharmony_ci case nir_cf_node_loop: { 665bf215546Sopenharmony_ci nir_loop *loop = nir_cf_node_as_loop(node); 666bf215546Sopenharmony_ci foreach_list_typed(nir_cf_node, child, node, &loop->body) 667bf215546Sopenharmony_ci cleanup_cf_node(child, impl); 668bf215546Sopenharmony_ci break; 669bf215546Sopenharmony_ci } 670bf215546Sopenharmony_ci case nir_cf_node_function: { 671bf215546Sopenharmony_ci nir_function_impl *impl = nir_cf_node_as_function(node); 672bf215546Sopenharmony_ci foreach_list_typed(nir_cf_node, child, node, &impl->body) 673bf215546Sopenharmony_ci cleanup_cf_node(child, impl); 674bf215546Sopenharmony_ci break; 675bf215546Sopenharmony_ci } 676bf215546Sopenharmony_ci default: 677bf215546Sopenharmony_ci unreachable("Invalid CF node type"); 678bf215546Sopenharmony_ci } 679bf215546Sopenharmony_ci} 680bf215546Sopenharmony_ci 681bf215546Sopenharmony_ci/** 682bf215546Sopenharmony_ci * Extracts everything between two cursors. Returns the cursor which is 683bf215546Sopenharmony_ci * equivalent to the old begin/end curosors. 684bf215546Sopenharmony_ci */ 685bf215546Sopenharmony_cinir_cursor 686bf215546Sopenharmony_cinir_cf_extract(nir_cf_list *extracted, nir_cursor begin, nir_cursor end) 687bf215546Sopenharmony_ci{ 688bf215546Sopenharmony_ci nir_block *block_begin, *block_end, *block_before, *block_after; 689bf215546Sopenharmony_ci 690bf215546Sopenharmony_ci if (nir_cursors_equal(begin, end)) { 691bf215546Sopenharmony_ci exec_list_make_empty(&extracted->list); 692bf215546Sopenharmony_ci extracted->impl = NULL; /* we shouldn't need this */ 693bf215546Sopenharmony_ci return begin; 694bf215546Sopenharmony_ci } 695bf215546Sopenharmony_ci 696bf215546Sopenharmony_ci split_block_cursor(begin, &block_before, &block_begin); 697bf215546Sopenharmony_ci 698bf215546Sopenharmony_ci /* Splitting a block twice with two cursors created before either split is 699bf215546Sopenharmony_ci * tricky and there are a couple of places it can go wrong if both cursors 700bf215546Sopenharmony_ci * point to the same block. One is if the second cursor is an block-based 701bf215546Sopenharmony_ci * cursor and, thanks to the split above, it ends up pointing to the wrong 702bf215546Sopenharmony_ci * block. If it's a before_block cursor and it's in the same block as 703bf215546Sopenharmony_ci * begin, then begin must also be a before_block cursor and it should be 704bf215546Sopenharmony_ci * caught by the nir_cursors_equal check above and we won't get here. If 705bf215546Sopenharmony_ci * it's an after_block cursor, we need to re-adjust to ensure that it 706bf215546Sopenharmony_ci * points to the second one of the split blocks, regardless of which it is. 707bf215546Sopenharmony_ci */ 708bf215546Sopenharmony_ci if (end.option == nir_cursor_after_block && end.block == block_before) 709bf215546Sopenharmony_ci end.block = block_begin; 710bf215546Sopenharmony_ci 711bf215546Sopenharmony_ci split_block_cursor(end, &block_end, &block_after); 712bf215546Sopenharmony_ci 713bf215546Sopenharmony_ci /* The second place this can all go wrong is that it could be that the 714bf215546Sopenharmony_ci * second split places the original block after the new block in which case 715bf215546Sopenharmony_ci * the block_begin pointer that we saved off above is pointing to the block 716bf215546Sopenharmony_ci * at the end rather than the block in the middle like it's supposed to be. 717bf215546Sopenharmony_ci * In this case, we have to re-adjust begin_block to point to the middle 718bf215546Sopenharmony_ci * one. 719bf215546Sopenharmony_ci */ 720bf215546Sopenharmony_ci if (block_begin == block_after) 721bf215546Sopenharmony_ci block_begin = block_end; 722bf215546Sopenharmony_ci 723bf215546Sopenharmony_ci extracted->impl = nir_cf_node_get_function(&block_begin->cf_node); 724bf215546Sopenharmony_ci exec_list_make_empty(&extracted->list); 725bf215546Sopenharmony_ci 726bf215546Sopenharmony_ci /* Dominance and other block-related information is toast. */ 727bf215546Sopenharmony_ci nir_metadata_preserve(extracted->impl, nir_metadata_none); 728bf215546Sopenharmony_ci 729bf215546Sopenharmony_ci nir_cf_node *cf_node = &block_begin->cf_node; 730bf215546Sopenharmony_ci nir_cf_node *cf_node_end = &block_end->cf_node; 731bf215546Sopenharmony_ci while (true) { 732bf215546Sopenharmony_ci nir_cf_node *next = nir_cf_node_next(cf_node); 733bf215546Sopenharmony_ci 734bf215546Sopenharmony_ci exec_node_remove(&cf_node->node); 735bf215546Sopenharmony_ci cf_node->parent = NULL; 736bf215546Sopenharmony_ci exec_list_push_tail(&extracted->list, &cf_node->node); 737bf215546Sopenharmony_ci 738bf215546Sopenharmony_ci if (cf_node == cf_node_end) 739bf215546Sopenharmony_ci break; 740bf215546Sopenharmony_ci 741bf215546Sopenharmony_ci cf_node = next; 742bf215546Sopenharmony_ci } 743bf215546Sopenharmony_ci 744bf215546Sopenharmony_ci return stitch_blocks(block_before, block_after); 745bf215546Sopenharmony_ci} 746bf215546Sopenharmony_ci 747bf215546Sopenharmony_cistatic void 748bf215546Sopenharmony_cirelink_jump_halt_cf_node(nir_cf_node *node, nir_block *end_block) 749bf215546Sopenharmony_ci{ 750bf215546Sopenharmony_ci switch (node->type) { 751bf215546Sopenharmony_ci case nir_cf_node_block: { 752bf215546Sopenharmony_ci nir_block *block = nir_cf_node_as_block(node); 753bf215546Sopenharmony_ci nir_instr *last_instr = nir_block_last_instr(block); 754bf215546Sopenharmony_ci if (last_instr == NULL || last_instr->type != nir_instr_type_jump) 755bf215546Sopenharmony_ci break; 756bf215546Sopenharmony_ci 757bf215546Sopenharmony_ci nir_jump_instr *jump = nir_instr_as_jump(last_instr); 758bf215546Sopenharmony_ci /* We can't move a CF list from one function to another while we still 759bf215546Sopenharmony_ci * have returns. 760bf215546Sopenharmony_ci */ 761bf215546Sopenharmony_ci assert(jump->type != nir_jump_return); 762bf215546Sopenharmony_ci 763bf215546Sopenharmony_ci if (jump->type == nir_jump_halt) { 764bf215546Sopenharmony_ci unlink_block_successors(block); 765bf215546Sopenharmony_ci link_blocks(block, end_block, NULL); 766bf215546Sopenharmony_ci } 767bf215546Sopenharmony_ci break; 768bf215546Sopenharmony_ci } 769bf215546Sopenharmony_ci 770bf215546Sopenharmony_ci case nir_cf_node_if: { 771bf215546Sopenharmony_ci nir_if *if_stmt = nir_cf_node_as_if(node); 772bf215546Sopenharmony_ci foreach_list_typed(nir_cf_node, child, node, &if_stmt->then_list) 773bf215546Sopenharmony_ci relink_jump_halt_cf_node(child, end_block); 774bf215546Sopenharmony_ci foreach_list_typed(nir_cf_node, child, node, &if_stmt->else_list) 775bf215546Sopenharmony_ci relink_jump_halt_cf_node(child, end_block); 776bf215546Sopenharmony_ci break; 777bf215546Sopenharmony_ci } 778bf215546Sopenharmony_ci 779bf215546Sopenharmony_ci case nir_cf_node_loop: { 780bf215546Sopenharmony_ci nir_loop *loop = nir_cf_node_as_loop(node); 781bf215546Sopenharmony_ci foreach_list_typed(nir_cf_node, child, node, &loop->body) 782bf215546Sopenharmony_ci relink_jump_halt_cf_node(child, end_block); 783bf215546Sopenharmony_ci break; 784bf215546Sopenharmony_ci } 785bf215546Sopenharmony_ci 786bf215546Sopenharmony_ci case nir_cf_node_function: 787bf215546Sopenharmony_ci unreachable("Cannot insert a function in a function"); 788bf215546Sopenharmony_ci 789bf215546Sopenharmony_ci default: 790bf215546Sopenharmony_ci unreachable("Invalid CF node type"); 791bf215546Sopenharmony_ci } 792bf215546Sopenharmony_ci} 793bf215546Sopenharmony_ci 794bf215546Sopenharmony_ci/** 795bf215546Sopenharmony_ci * Inserts a list at a given cursor. Returns the cursor at the end of the 796bf215546Sopenharmony_ci * insertion (i.e., at the end of the instructions contained in cf_list). 797bf215546Sopenharmony_ci */ 798bf215546Sopenharmony_cinir_cursor 799bf215546Sopenharmony_cinir_cf_reinsert(nir_cf_list *cf_list, nir_cursor cursor) 800bf215546Sopenharmony_ci{ 801bf215546Sopenharmony_ci nir_block *before, *after; 802bf215546Sopenharmony_ci 803bf215546Sopenharmony_ci if (exec_list_is_empty(&cf_list->list)) 804bf215546Sopenharmony_ci return cursor; 805bf215546Sopenharmony_ci 806bf215546Sopenharmony_ci nir_function_impl *cursor_impl = 807bf215546Sopenharmony_ci nir_cf_node_get_function(&nir_cursor_current_block(cursor)->cf_node); 808bf215546Sopenharmony_ci if (cf_list->impl != cursor_impl) { 809bf215546Sopenharmony_ci foreach_list_typed(nir_cf_node, node, node, &cf_list->list) 810bf215546Sopenharmony_ci relink_jump_halt_cf_node(node, cursor_impl->end_block); 811bf215546Sopenharmony_ci } 812bf215546Sopenharmony_ci 813bf215546Sopenharmony_ci split_block_cursor(cursor, &before, &after); 814bf215546Sopenharmony_ci 815bf215546Sopenharmony_ci foreach_list_typed_safe(nir_cf_node, node, node, &cf_list->list) { 816bf215546Sopenharmony_ci exec_node_remove(&node->node); 817bf215546Sopenharmony_ci node->parent = before->cf_node.parent; 818bf215546Sopenharmony_ci exec_node_insert_node_before(&after->cf_node.node, &node->node); 819bf215546Sopenharmony_ci } 820bf215546Sopenharmony_ci 821bf215546Sopenharmony_ci stitch_blocks(before, 822bf215546Sopenharmony_ci nir_cf_node_as_block(nir_cf_node_next(&before->cf_node))); 823bf215546Sopenharmony_ci return stitch_blocks(nir_cf_node_as_block(nir_cf_node_prev(&after->cf_node)), 824bf215546Sopenharmony_ci after); 825bf215546Sopenharmony_ci} 826bf215546Sopenharmony_ci 827bf215546Sopenharmony_civoid 828bf215546Sopenharmony_cinir_cf_delete(nir_cf_list *cf_list) 829bf215546Sopenharmony_ci{ 830bf215546Sopenharmony_ci foreach_list_typed(nir_cf_node, node, node, &cf_list->list) { 831bf215546Sopenharmony_ci cleanup_cf_node(node, cf_list->impl); 832bf215546Sopenharmony_ci } 833bf215546Sopenharmony_ci} 834