freedreno/ir3: maintain predecessors/successors
authorRob Clark <robdclark@chromium.org>
Sat, 29 Jun 2019 11:52:47 +0000 (04:52 -0700)
committerEric Anholt <eric@anholt.net>
Wed, 28 Aug 2019 22:25:25 +0000 (15:25 -0700)
While resolving jumps to skip intermediate jumps from the structured
CFG, maintain the successors and predecessors correctly.

Signed-off-by: Rob Clark <robdclark@chromium.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
src/freedreno/ir3/ir3_legalize.c

index e46d1214d605962f488f0ec16b0634c499b54358..2fb7f9de6f185a18780691234edcd71e5f7aeb40 100644 (file)
@@ -400,6 +400,47 @@ resolve_dest_block(struct ir3_block *block)
        return block;
 }
 
+static void
+remove_unused_block(struct ir3_block *old_target)
+{
+       list_delinit(&old_target->node);
+
+       /* cleanup dangling predecessors: */
+       for (unsigned i = 0; i < ARRAY_SIZE(old_target->successors); i++) {
+               if (old_target->successors[i]) {
+                       struct ir3_block *succ = old_target->successors[i];
+                       _mesa_set_remove_key(succ->predecessors, old_target);
+               }
+       }
+}
+
+static void
+retarget_jump(struct ir3_instruction *instr, struct ir3_block *new_target)
+{
+       struct ir3_block *old_target = instr->cat0.target;
+       struct ir3_block *cur_block = instr->block;
+
+       /* update current blocks successors to reflect the retargetting: */
+       if (cur_block->successors[0] == old_target) {
+               cur_block->successors[0] = new_target;
+       } else {
+               debug_assert(cur_block->successors[1] == old_target);
+               cur_block->successors[1] = new_target;
+       }
+
+       /* update new target's predecessors: */
+       _mesa_set_add(new_target->predecessors, cur_block);
+
+       /* and remove old_target's predecessor: */
+       debug_assert(_mesa_set_search(old_target->predecessors, cur_block));
+       _mesa_set_remove_key(old_target->predecessors, cur_block);
+
+       if (old_target->predecessors->entries == 0)
+               remove_unused_block(old_target);
+
+       instr->cat0.target = new_target;
+}
+
 static bool
 resolve_jump(struct ir3_instruction *instr)
 {
@@ -408,8 +449,7 @@ resolve_jump(struct ir3_instruction *instr)
        struct ir3_instruction *target;
 
        if (tblock != instr->cat0.target) {
-               list_delinit(&instr->cat0.target->node);
-               instr->cat0.target = tblock;
+               retarget_jump(instr, tblock);
                return true;
        }