nv50/ir/ra: Use matching physical regs for function args in caller and callee.
authorFrancisco Jerez <currojerez@riseup.net>
Thu, 29 Mar 2012 21:23:53 +0000 (23:23 +0200)
committerChristoph Bumiller <e0425955@student.tuwien.ac.at>
Sat, 14 Apr 2012 19:54:02 +0000 (21:54 +0200)
src/gallium/drivers/nv50/codegen/nv50_ir_ra.cpp

index a91a088..a08ca31 100644 (file)
@@ -43,7 +43,7 @@ public:
 
    bool assign(Value **, int nr);
    void release(const Value *);
-   void occupy(const Value *);
+   bool occupy(const Value *);
 
    int getMaxAssigned(DataFile f) const { return fill[f]; }
 
@@ -148,22 +148,25 @@ RegisterSet::assign(Value **def, int nr)
    return true;
 }
 
-void
+bool
 RegisterSet::occupy(const Value *val)
 {
    int id = val->reg.data.id;
-   if (id < 0)
-      return;
    unsigned int f = val->reg.file;
 
    uint32_t m = (1 << (val->reg.size >> unit[f])) - 1;
 
+   if (id < 0 || bits[f][id / 32] & m << (id % 32))
+      return false;
+
    INFO_DBG(0, REG_ALLOC, "reg occupy: %u[%i] %x\n", f, id, m);
 
    bits[f][id / 32] |= m << (id % 32);
 
    if (fill[f] < id)
       fill[f] = id;
+
+   return true;
 }
 
 void
@@ -207,6 +210,11 @@ private:
       inline bool needNewElseBlock(BasicBlock *b, BasicBlock *p);
    };
 
+   class ArgumentMovesPass : public Pass {
+   private:
+      virtual bool visit(BasicBlock *);
+   };
+
    class BuildIntervalsPass : public Pass {
    private:
       virtual bool visit(BasicBlock *);
@@ -344,6 +352,70 @@ RegAlloc::PhiMovesPass::visit(BasicBlock *bb)
    return true;
 }
 
+bool
+RegAlloc::ArgumentMovesPass::visit(BasicBlock *bb)
+{
+   // Bind function call inputs/outputs to the same physical register
+   // the callee uses, inserting moves as appropriate for the case a
+   // conflict arises.
+   for (Instruction *i = bb->getEntry(); i; i = i->next) {
+      FlowInstruction *cal = i->asFlow();
+      if (!cal || cal->op != OP_CALL || cal->builtin)
+         continue;
+      RegisterSet clobberSet(prog->getTarget());
+
+      // Bind input values.
+      for (int s = 0; cal->srcExists(s); ++s) {
+         LValue *tmp = new_LValue(func, cal->getSrc(s)->asLValue());
+         tmp->reg.data.id = cal->target.fn->ins[s].rep()->reg.data.id;
+
+         Instruction *mov =
+            new_Instruction(func, OP_MOV, typeOfSize(tmp->reg.size));
+         mov->setDef(0, tmp);
+         mov->setSrc(0, cal->getSrc(s));
+         cal->setSrc(s, tmp);
+
+         bb->insertBefore(cal, mov);
+      }
+
+      // Bind output values.
+      for (int d = 0; cal->defExists(d); ++d) {
+         LValue *tmp = new_LValue(func, cal->getDef(d)->asLValue());
+         tmp->reg.data.id = cal->target.fn->outs[d].rep()->reg.data.id;
+
+         Instruction *mov =
+            new_Instruction(func, OP_MOV, typeOfSize(tmp->reg.size));
+         mov->setSrc(0, tmp);
+         mov->setDef(0, cal->getDef(d));
+         cal->setDef(d, tmp);
+
+         bb->insertAfter(cal, mov);
+         clobberSet.occupy(tmp);
+      }
+
+      // Bind clobbered values.
+      for (std::deque<Value *>::iterator it = cal->target.fn->clobbers.begin();
+           it != cal->target.fn->clobbers.end();
+           ++it) {
+         if (clobberSet.occupy(*it)) {
+            Value *tmp = new_LValue(func, (*it)->asLValue());
+            tmp->reg.data.id = (*it)->reg.data.id;
+            cal->setDef(cal->defCount(), tmp);
+         }
+      }
+   }
+
+   // Update the clobber set of the function.
+   if (BasicBlock::get(func->cfgExit) == bb) {
+      func->buildDefSets();
+      for (unsigned int i = 0; i < bb->defSet.getSize(); ++i)
+         if (bb->defSet.test(i))
+            func->clobbers.push_back(func->getLValue(i));
+   }
+
+   return true;
+}
+
 // Build the set of live-in variables of bb.
 bool
 RegAlloc::buildLiveSets(BasicBlock *bb)
@@ -737,7 +809,8 @@ bool
 RegAlloc::execFunc()
 {
    InsertConstraintsPass insertConstr;
-   PhiMovesPass insertMoves;
+   PhiMovesPass insertPhiMoves;
+   ArgumentMovesPass insertArgMoves;
    BuildIntervalsPass buildIntervals;
 
    unsigned int i;
@@ -747,7 +820,11 @@ RegAlloc::execFunc()
    if (!ret)
       goto out;
 
-   ret = insertMoves.run(func);
+   ret = insertPhiMoves.run(func);
+   if (!ret)
+      goto out;
+
+   ret = insertArgMoves.run(func, true);
    if (!ret)
       goto out;