diff --git a/src/gallium/drivers/nouveau/codegen/nv50_ir_ra.cpp b/src/gallium/drivers/nouveau/codegen/nv50_ir_ra.cpp index 898653c..1bb5194 100644 --- a/src/gallium/drivers/nouveau/codegen/nv50_ir_ra.cpp +++ b/src/gallium/drivers/nouveau/codegen/nv50_ir_ra.cpp @@ -25,8 +25,21 @@ #include #include +#include #include +namespace std { +namespace tr1 { +template +struct hash > { +public: + size_t operator()(std::pair val) const { + return hash()(val.first) * 31 + hash()(val.second); + } +}; +} +} + namespace nv50_ir { #define MAX_REGISTER_FILE_SIZE 256 @@ -359,14 +372,25 @@ RegAlloc::PhiMovesPass::visit(BasicBlock *bb) { Instruction *phi, *mov; BasicBlock *pb, *pn; + int j; std::stack stack; - for (Graph::EdgeIterator ei = bb->cfg.incident(); !ei.end(); ei.next()) { + // We're about to, potentially, reorder the inbound edges. This means that + // we need to hold on to the (phi, bb) -> src mapping, so that we can + // later insert the movs. + typedef std::tr1::unordered_map< + std::pair, Value *> PhiMap; + PhiMap phis; + + j = 0; + for (Graph::EdgeIterator ei = bb->cfg.incident(); !ei.end(); ei.next(), ++j) { pb = BasicBlock::get(ei.getNode()); assert(pb); if (needNewElseBlock(bb, pb)) stack.push(pb); + for (phi = bb->getPhi(); phi && phi->op == OP_PHI; phi = phi->next) + phis.insert(std::make_pair(std::make_pair(phi, pb), phi->getSrc(j))); } while (!stack.empty()) { pb = stack.top(); @@ -380,10 +404,17 @@ RegAlloc::PhiMovesPass::visit(BasicBlock *bb) assert(pb->getExit()->op != OP_CALL); if (pb->getExit()->asFlow()->target.bb == bb) pb->getExit()->asFlow()->target.bb = pn; + + for (phi = bb->getPhi(); phi && phi->op == OP_PHI; phi = phi->next) { + PhiMap::iterator it = phis.find(std::make_pair(phi, pb)); + assert(it != phis.end()); + phis.insert(std::make_pair(std::make_pair(phi, pn), it->second)); + phis.erase(it); + } } // insert MOVs (phi->src(j) should stem from j-th in-BB) - int j = 0; + j = 0; for (Graph::EdgeIterator ei = bb->cfg.incident(); !ei.end(); ei.next()) { pb = BasicBlock::get(ei.getNode()); if (!pb->isTerminated()) @@ -393,7 +424,9 @@ RegAlloc::PhiMovesPass::visit(BasicBlock *bb) LValue *tmp = new_LValue(func, phi->getDef(0)->asLValue()); mov = new_Instruction(func, OP_MOV, typeOfSize(tmp->reg.size)); - mov->setSrc(0, phi->getSrc(j)); + PhiMap::const_iterator it = phis.find(std::make_pair(phi, pb)); + assert(it != phis.end()); + mov->setSrc(0, it->second); mov->setDef(0, tmp); phi->setSrc(j, tmp);