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.
This commit is contained in:
Francisco Jerez 2012-04-06 19:08:27 +02:00 committed by Christoph Bumiller
parent 9bb36d54a2
commit a3dd45e1c2
2 changed files with 87 additions and 0 deletions

View 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;

View 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;
}