aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorFrancisco Jerez <[email protected]>2012-04-06 19:08:27 +0200
committerChristoph Bumiller <[email protected]>2012-04-14 21:54:02 +0200
commita3dd45e1c27e4e55dadb9467c2ea428f58083ac1 (patch)
tree252a9d1e039778d753f534418537aa0bc7964f7a /src
parent9bb36d54a2c69ebdc9d1c9c4c71945060de8c860 (diff)
nv50/ir/tgsi: Infer function inputs/outputs.
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.
Diffstat (limited to 'src')
-rw-r--r--src/gallium/drivers/nv50/codegen/nv50_ir.h4
-rw-r--r--src/gallium/drivers/nv50/codegen/nv50_ir_from_tgsi.cpp83
2 files changed, 87 insertions, 0 deletions
diff --git a/src/gallium/drivers/nv50/codegen/nv50_ir.h b/src/gallium/drivers/nv50/codegen/nv50_ir.h
index 0a8a0743eb4..b06d0938b62 100644
--- a/src/gallium/drivers/nv50/codegen/nv50_ir.h
+++ b/src/gallium/drivers/nv50/codegen/nv50_ir.h
@@ -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;
diff --git a/src/gallium/drivers/nv50/codegen/nv50_ir_from_tgsi.cpp b/src/gallium/drivers/nv50/codegen/nv50_ir_from_tgsi.cpp
index f4199c3a9b8..81d5d55f780 100644
--- a/src/gallium/drivers/nv50/codegen/nv50_ir_from_tgsi.cpp
+++ b/src/gallium/drivers/nv50/codegen/nv50_ir_from_tgsi.cpp
@@ -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;
}