summaryrefslogtreecommitdiffstats
path: root/src/gallium
diff options
context:
space:
mode:
authorFrancisco Jerez <[email protected]>2013-02-06 14:12:44 +0100
committerChristoph Bumiller <[email protected]>2013-03-12 12:55:33 +0100
commit5959d4247a28761e3b91f547f85b9fe0df434eb9 (patch)
treeb123828e0d7c875a4436ec7d094300c9c7b059bc /src/gallium
parent572bf83ec073702a747fbfd0da97caca26372f8e (diff)
nv50/ir/opt: Fix tryPropagateBranch for BBs with several exit branches.
Comments and "if (bf->cfg.incidentCount() == 1)" condition added by Christoph Bumiller.
Diffstat (limited to 'src/gallium')
-rw-r--r--src/gallium/drivers/nv50/codegen/nv50_ir_peephole.cpp60
1 files changed, 32 insertions, 28 deletions
diff --git a/src/gallium/drivers/nv50/codegen/nv50_ir_peephole.cpp b/src/gallium/drivers/nv50/codegen/nv50_ir_peephole.cpp
index 6f34b1aeb3c..05997b6b568 100644
--- a/src/gallium/drivers/nv50/codegen/nv50_ir_peephole.cpp
+++ b/src/gallium/drivers/nv50/codegen/nv50_ir_peephole.cpp
@@ -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