nv50/ir/tgsi: Infer function inputs/outputs.
authorFrancisco Jerez <currojerez@riseup.net>
Fri, 6 Apr 2012 17:08:27 +0000 (19:08 +0200)
committerChristoph Bumiller <e0425955@student.tuwien.ac.at>
Sat, 14 Apr 2012 19:54:02 +0000 (21:54 +0200)
Edit: Don't do it for the main function of (graphics) shaders,
its inputs and outputs always go through TGSI_FILE_INPUT/OUTPUT.
This prevents all TEMPs from counting as live out and reduces
register pressure.

src/gallium/drivers/nv50/codegen/nv50_ir.h
src/gallium/drivers/nv50/codegen/nv50_ir_from_tgsi.cpp

index 0a8a074..b06d093 100644 (file)
@@ -947,6 +947,10 @@ public:
    bool convertToSSA();
 
 public:
+   std::deque<ValueDef> ins;
+   std::deque<ValueRef> outs;
+   std::deque<Value *> clobbers;
+
    Graph cfg;
    Graph::Node *cfgExit;
    Graph *domTree;
index f4199c3..81d5d55 100644 (file)
@@ -1055,6 +1055,27 @@ private:
 
    Value *buildDot(int dim);
 
+   class BindArgumentsPass : public Pass {
+   public:
+      BindArgumentsPass(Converter &conv) : conv(conv) { }
+
+   private:
+      Converter &conv;
+      Subroutine *sub;
+
+      template<typename T> inline void
+      updateCallArgs(Instruction *i, void (Instruction::*setArg)(int, Value *),
+                     T (Function::*proto));
+
+      template<typename T> inline void
+      updatePrototype(BitSet *set, void (Function::*updateSet)(),
+                      T (Function::*proto));
+
+   protected:
+      bool visit(Function *);
+      bool visit(BasicBlock *bb) { return false; }
+   };
+
 private:
    const struct tgsi::Source *code;
    const struct nv50_ir_prog_info *info;
@@ -2293,6 +2314,64 @@ Converter::~Converter()
 {
 }
 
+template<typename T> inline void
+Converter::BindArgumentsPass::updateCallArgs(
+   Instruction *i, void (Instruction::*setArg)(int, Value *),
+   T (Function::*proto))
+{
+   Function *g = i->asFlow()->target.fn;
+   Subroutine *subg = conv.getSubroutine(g);
+
+   for (unsigned a = 0; a < (g->*proto).size(); ++a) {
+      Value *v = (g->*proto)[a].get();
+      const Converter::Location &l = subg->values.l.find(v)->second;
+      Converter::DataArray *array = conv.getArrayForFile(l.array, l.arrayIdx);
+
+      (i->*setArg)(a, array->acquire(sub->values, l.i, l.c));
+   }
+}
+
+template<typename T> inline void
+Converter::BindArgumentsPass::updatePrototype(
+   BitSet *set, void (Function::*updateSet)(), T (Function::*proto))
+{
+   (func->*updateSet)();
+
+   for (unsigned i = 0; i < set->getSize(); ++i) {
+      Value *v = func->getLValue(i);
+
+      // only include values with a matching TGSI register
+      if (set->test(i) && sub->values.l.find(v) != sub->values.l.end())
+         (func->*proto).push_back(v);
+   }
+}
+
+bool
+Converter::BindArgumentsPass::visit(Function *f)
+{
+   sub = conv.getSubroutine(f);
+
+   for (ArrayList::Iterator bi = f->allBBlocks.iterator();
+        !bi.end(); bi.next()) {
+      for (Instruction *i = BasicBlock::get(bi)->getFirst();
+           i; i = i->next) {
+         if (i->op == OP_CALL && !i->asFlow()->builtin) {
+            updateCallArgs(i, &Instruction::setSrc, &Function::ins);
+            updateCallArgs(i, &Instruction::setDef, &Function::outs);
+         }
+      }
+   }
+
+   if (func == prog->main && prog->getType() != Program::TYPE_COMPUTE)
+      return true;
+   updatePrototype(&BasicBlock::get(f->cfg.getRoot())->liveSet,
+                   &Function::buildLiveSets, &Function::ins);
+   updatePrototype(&BasicBlock::get(f->cfgExit)->defSet,
+                   &Function::buildDefSets, &Function::outs);
+
+   return true;
+}
+
 bool
 Converter::run()
 {
@@ -2320,6 +2399,10 @@ Converter::run()
       if (!handleInstruction(&code->insns[ip]))
          return false;
    }
+
+   if (!BindArgumentsPass(*this).run(prog))
+      return false;
+
    return true;
 }