nv50/ir/opt: Fix tryPropagateBranch for BBs with several exit branches.
authorFrancisco Jerez <currojerez@riseup.net>
Wed, 6 Feb 2013 13:12:44 +0000 (14:12 +0100)
committerChristoph Bumiller <e0425955@student.tuwien.ac.at>
Tue, 12 Mar 2013 11:55:33 +0000 (12:55 +0100)
Comments and "if (bf->cfg.incidentCount() == 1)" condition added
by Christoph Bumiller.

src/gallium/drivers/nv50/codegen/nv50_ir_peephole.cpp

index 6f34b1a..05997b6 100644 (file)
@@ -1885,42 +1885,46 @@ FlatteningPass::mayPredicate(const Instruction *insn, const Value *pred) const
    return true;
 }
 
-// If we conditionally skip over or to a branch instruction, replace it.
+// If we jump to BRA/RET/EXIT, replace the jump with it.
 // NOTE: We do not update the CFG anymore here !
+//
+// TODO: Handle cases where we skip over a branch (maybe do that elsewhere ?):
+//  BB:0
+//   @p0 bra BB:2 -> @!p0 bra BB:3 iff (!) BB:2 immediately adjoins BB:1
+//  BB1:
+//   bra BB:3
+//  BB2:
+//   ...
+//  BB3:
+//   ...
 void
 FlatteningPass::tryPropagateBranch(BasicBlock *bb)
 {
-   BasicBlock *bf = NULL;
-   unsigned int i;
+   for (Instruction *i = bb->getExit(); i && i->op == OP_BRA; i = i->prev) {
+      BasicBlock *bf = i->asFlow()->target.bb;
 
-   if (bb->cfg.outgoingCount() != 2)
-      return;
-   if (!bb->getExit() || bb->getExit()->op != OP_BRA)
-      return;
-   Graph::EdgeIterator ei = bb->cfg.outgoing();
+      if (bf->getInsnCount() != 1)
+         continue;
 
-   for (i = 0; !ei.end(); ++i, ei.next()) {
-      bf = BasicBlock::get(ei.getNode());
-      if (bf->getInsnCount() == 1)
-         break;
-   }
-   if (ei.end() || !bf->getExit())
-      return;
-   FlowInstruction *bra = bb->getExit()->asFlow();
-   FlowInstruction *rep = bf->getExit()->asFlow();
+      FlowInstruction *bra = i->asFlow();
+      FlowInstruction *rep = bf->getExit()->asFlow();
 
-   if (rep->getPredicate())
-      return;
-   if (rep->op != OP_BRA &&
-       rep->op != OP_JOIN &&
-       rep->op != OP_EXIT)
-      return;
+      if (!rep || rep->getPredicate())
+         continue;
+      if (rep->op != OP_BRA &&
+          rep->op != OP_JOIN &&
+          rep->op != OP_EXIT)
+         continue;
 
-   bra->op = rep->op;
-   bra->target.bb = rep->target.bb;
-   if (i) // 2nd out block means branch not taken
-      bra->cc = inverseCondCode(bra->cc);
-   bf->remove(rep);
+      // TODO: If there are multiple branches to @rep, only the first would
+      // be replaced, so only remove them after this pass is done ?
+      // Also, need to check all incident blocks for fall-through exits and
+      // add the branch there.
+      bra->op = rep->op;
+      bra->target.bb = rep->target.bb;
+      if (bf->cfg.incidentCount() == 1)
+         bf->remove(rep);
+   }
 }
 
 bool