17ec681f3Smrg/*
27ec681f3Smrg * Copyright (C) 2021 Valve Corporation
37ec681f3Smrg *
47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
57ec681f3Smrg * copy of this software and associated documentation files (the "Software"),
67ec681f3Smrg * to deal in the Software without restriction, including without limitation
77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the
97ec681f3Smrg * Software is furnished to do so, subject to the following conditions:
107ec681f3Smrg *
117ec681f3Smrg * The above copyright notice and this permission notice (including the next
127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the
137ec681f3Smrg * Software.
147ec681f3Smrg *
157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
187ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
197ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
207ec681f3Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
217ec681f3Smrg * SOFTWARE.
227ec681f3Smrg */
237ec681f3Smrg
247ec681f3Smrg#include "ir3.h"
257ec681f3Smrg
267ec681f3Smrg/* Sometimes we can get unreachable blocks from NIR. In particular this happens
277ec681f3Smrg * for blocks after an if where both sides end in a break/continue. These blocks
287ec681f3Smrg * are then reachable only via the physical CFG. This pass deletes these blocks
297ec681f3Smrg * and reroutes the physical edge past it.
307ec681f3Smrg */
317ec681f3Smrg
327ec681f3Smrgstatic void
337ec681f3Smrgdelete_block(struct ir3 *ir, struct ir3_block *block)
347ec681f3Smrg{
357ec681f3Smrg   struct ir3_instruction *end = NULL;
367ec681f3Smrg   foreach_instr (instr, &block->instr_list) {
377ec681f3Smrg      if (instr->opc == OPC_END) {
387ec681f3Smrg         end = instr;
397ec681f3Smrg         break;
407ec681f3Smrg      }
417ec681f3Smrg   }
427ec681f3Smrg
437ec681f3Smrg   /* The end block can be legitimately unreachable if the shader only exits via
447ec681f3Smrg    * discarding. ir3_legalize will then insert a branch to the end. Keep the
457ec681f3Smrg    * block around but delete all the other instructions and make the end not
467ec681f3Smrg    * take any sources, so that we don't have any dangling references to other
477ec681f3Smrg    * unreachable blocks.
487ec681f3Smrg    */
497ec681f3Smrg   if (end) {
507ec681f3Smrg      foreach_instr_safe (instr, &block->instr_list) {
517ec681f3Smrg         if (instr != end)
527ec681f3Smrg            list_delinit(&instr->node);
537ec681f3Smrg      }
547ec681f3Smrg      end->srcs_count = 0;
557ec681f3Smrg      return;
567ec681f3Smrg   }
577ec681f3Smrg
587ec681f3Smrg   for (unsigned i = 0; i < 2; i++) {
597ec681f3Smrg      struct ir3_block *succ = block->successors[i];
607ec681f3Smrg      if (!succ)
617ec681f3Smrg         continue;
627ec681f3Smrg
637ec681f3Smrg      unsigned pred_idx = ir3_block_get_pred_index(succ, block);
647ec681f3Smrg
657ec681f3Smrg      /* If this isn't the last predecessor, we swap it with the last before
667ec681f3Smrg       * removing it.
677ec681f3Smrg       */
687ec681f3Smrg      bool swap_pred = pred_idx != succ->predecessors_count - 1;
697ec681f3Smrg
707ec681f3Smrg      foreach_instr (phi, &succ->instr_list) {
717ec681f3Smrg         if (phi->opc != OPC_META_PHI)
727ec681f3Smrg            break;
737ec681f3Smrg
747ec681f3Smrg         if (swap_pred)
757ec681f3Smrg            phi->srcs[pred_idx] = phi->srcs[phi->srcs_count - 1];
767ec681f3Smrg         phi->srcs_count--;
777ec681f3Smrg      }
787ec681f3Smrg      if (swap_pred) {
797ec681f3Smrg         succ->predecessors[pred_idx] =
807ec681f3Smrg            succ->predecessors[succ->predecessors_count - 1];
817ec681f3Smrg      }
827ec681f3Smrg      succ->predecessors_count--;
837ec681f3Smrg   }
847ec681f3Smrg
857ec681f3Smrg   for (unsigned i = 0; i < 2; i++) {
867ec681f3Smrg      struct ir3_block *succ = block->physical_successors[i];
877ec681f3Smrg      if (!succ)
887ec681f3Smrg         continue;
897ec681f3Smrg
907ec681f3Smrg      ir3_block_remove_physical_predecessor(succ, block);
917ec681f3Smrg   }
927ec681f3Smrg
937ec681f3Smrg   if (block->physical_predecessors_count != 0) {
947ec681f3Smrg      /* There should be only one physical predecessor, for the fallthrough
957ec681f3Smrg       * edge.
967ec681f3Smrg       */
977ec681f3Smrg      assert(block->physical_predecessors_count == 1);
987ec681f3Smrg      struct ir3_block *pred = block->physical_predecessors[0];
997ec681f3Smrg      assert(block->node.next != &ir->block_list);
1007ec681f3Smrg      struct ir3_block *next = LIST_ENTRY(struct ir3_block, block->node.next, node);
1017ec681f3Smrg      if (pred->physical_successors[1] == block)
1027ec681f3Smrg         pred->physical_successors[1] = next;
1037ec681f3Smrg      else
1047ec681f3Smrg         pred->physical_successors[0] = next;
1057ec681f3Smrg      ir3_block_add_physical_predecessor(next, pred);
1067ec681f3Smrg   }
1077ec681f3Smrg}
1087ec681f3Smrg
1097ec681f3Smrgbool
1107ec681f3Smrgir3_remove_unreachable(struct ir3 *ir)
1117ec681f3Smrg{
1127ec681f3Smrg   bool progress = false;
1137ec681f3Smrg   foreach_block_safe (block, &ir->block_list) {
1147ec681f3Smrg      if (block != ir3_start_block(ir) && block->predecessors_count == 0) {
1157ec681f3Smrg         delete_block(ir, block);
1167ec681f3Smrg         list_del(&block->node);
1177ec681f3Smrg         progress = true;
1187ec681f3Smrg      }
1197ec681f3Smrg   }
1207ec681f3Smrg
1217ec681f3Smrg   return progress;
1227ec681f3Smrg}
123