Path: blob/21.2-virgl/src/gallium/drivers/nouveau/codegen/nv50_ir_ssa.cpp
4574 views
/*1* Copyright 2011 Christoph Bumiller2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice shall be included in11* all copies or substantial portions of the Software.12*13* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR14* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,15* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL16* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR17* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,18* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR19* OTHER DEALINGS IN THE SOFTWARE.20*/2122#include "codegen/nv50_ir.h"23#include "codegen/nv50_ir_target.h"2425namespace nv50_ir {2627// Converts nv50 IR generated from TGSI to SSA form.2829// DominatorTree implements an algorithm for finding immediate dominators,30// as described by T. Lengauer & R. Tarjan.31class DominatorTree : public Graph32{33public:34DominatorTree(Graph *cfg);35~DominatorTree() { }3637bool dominates(BasicBlock *, BasicBlock *);3839void findDominanceFrontiers();4041private:42void build();43void buildDFS(Node *);4445void squash(int);46inline void link(int, int);47inline int eval(int);4849void debugPrint();5051Graph *cfg;5253Node **vert;54int *data;55const int count;5657#define SEMI(i) (data[(i) + 0 * count])58#define ANCESTOR(i) (data[(i) + 1 * count])59#define PARENT(i) (data[(i) + 2 * count])60#define LABEL(i) (data[(i) + 3 * count])61#define DOM(i) (data[(i) + 4 * count])62};6364void DominatorTree::debugPrint()65{66for (int i = 0; i < count; ++i) {67INFO("SEMI(%i) = %i\n", i, SEMI(i));68INFO("ANCESTOR(%i) = %i\n", i, ANCESTOR(i));69INFO("PARENT(%i) = %i\n", i, PARENT(i));70INFO("LABEL(%i) = %i\n", i, LABEL(i));71INFO("DOM(%i) = %i\n", i, DOM(i));72}73}7475DominatorTree::DominatorTree(Graph *cfgraph) : cfg(cfgraph),76count(cfg->getSize())77{78int i = 0;7980vert = new Node * [count];81data = new int[5 * count];8283for (IteratorRef it = cfg->iteratorDFS(true); !it->end(); it->next(), ++i) {84vert[i] = reinterpret_cast<Node *>(it->get());85vert[i]->tag = i;86LABEL(i) = i;87SEMI(i) = ANCESTOR(i) = -1;88}89assert(i == count);9091build();9293delete[] vert;94delete[] data;95}9697void DominatorTree::buildDFS(Graph::Node *node)98{99SEMI(node->tag) = node->tag;100101for (Graph::EdgeIterator ei = node->outgoing(); !ei.end(); ei.next()) {102if (SEMI(ei.getNode()->tag) < 0) {103buildDFS(ei.getNode());104PARENT(ei.getNode()->tag) = node->tag;105}106}107}108109void DominatorTree::squash(int v)110{111if (ANCESTOR(ANCESTOR(v)) >= 0) {112squash(ANCESTOR(v));113114if (SEMI(LABEL(ANCESTOR(v))) < SEMI(LABEL(v)))115LABEL(v) = LABEL(ANCESTOR(v));116ANCESTOR(v) = ANCESTOR(ANCESTOR(v));117}118}119120int DominatorTree::eval(int v)121{122if (ANCESTOR(v) < 0)123return v;124squash(v);125return LABEL(v);126}127128void DominatorTree::link(int v, int w)129{130ANCESTOR(w) = v;131}132133void DominatorTree::build()134{135DLList *bucket = new DLList[count];136Node *nv, *nw;137int p, u, v, w;138139buildDFS(cfg->getRoot());140141for (w = count - 1; w >= 1; --w) {142nw = vert[w];143assert(nw->tag == w);144for (Graph::EdgeIterator ei = nw->incident(); !ei.end(); ei.next()) {145nv = ei.getNode();146v = nv->tag;147u = eval(v);148if (SEMI(u) < SEMI(w))149SEMI(w) = SEMI(u);150}151p = PARENT(w);152bucket[SEMI(w)].insert(nw);153link(p, w);154155for (DLList::Iterator it = bucket[p].iterator(); !it.end(); it.erase()) {156v = reinterpret_cast<Node *>(it.get())->tag;157u = eval(v);158DOM(v) = (SEMI(u) < SEMI(v)) ? u : p;159}160}161for (w = 1; w < count; ++w) {162if (DOM(w) != SEMI(w))163DOM(w) = DOM(DOM(w));164}165DOM(0) = 0;166167insert(&BasicBlock::get(cfg->getRoot())->dom);168do {169p = 0;170for (v = 1; v < count; ++v) {171nw = &BasicBlock::get(vert[DOM(v)])->dom;172nv = &BasicBlock::get(vert[v])->dom;173if (nw->getGraph() && !nv->getGraph()) {174++p;175nw->attach(nv, Graph::Edge::TREE);176}177}178} while (p);179180delete[] bucket;181}182183#undef SEMI184#undef ANCESTOR185#undef PARENT186#undef LABEL187#undef DOM188189void DominatorTree::findDominanceFrontiers()190{191BasicBlock *bb;192193for (IteratorRef dtIt = iteratorDFS(false); !dtIt->end(); dtIt->next()) {194EdgeIterator succIt, chldIt;195196bb = BasicBlock::get(reinterpret_cast<Node *>(dtIt->get()));197bb->getDF().clear();198199for (succIt = bb->cfg.outgoing(); !succIt.end(); succIt.next()) {200BasicBlock *dfLocal = BasicBlock::get(succIt.getNode());201if (dfLocal->idom() != bb)202bb->getDF().insert(dfLocal);203}204205for (chldIt = bb->dom.outgoing(); !chldIt.end(); chldIt.next()) {206BasicBlock *cb = BasicBlock::get(chldIt.getNode());207208DLList::Iterator dfIt = cb->getDF().iterator();209for (; !dfIt.end(); dfIt.next()) {210BasicBlock *dfUp = BasicBlock::get(dfIt);211if (dfUp->idom() != bb)212bb->getDF().insert(dfUp);213}214}215}216}217218// liveIn(bb) = usedBeforeAssigned(bb) U (liveOut(bb) - assigned(bb))219void220Function::buildLiveSetsPreSSA(BasicBlock *bb, const int seq)221{222Function *f = bb->getFunction();223BitSet usedBeforeAssigned(allLValues.getSize(), true);224BitSet assigned(allLValues.getSize(), true);225226bb->liveSet.allocate(allLValues.getSize(), false);227228int n = 0;229for (Graph::EdgeIterator ei = bb->cfg.outgoing(); !ei.end(); ei.next()) {230BasicBlock *out = BasicBlock::get(ei.getNode());231if (out == bb)232continue;233if (out->cfg.visit(seq))234buildLiveSetsPreSSA(out, seq);235if (!n++)236bb->liveSet = out->liveSet;237else238bb->liveSet |= out->liveSet;239}240if (!n && !bb->liveSet.marker)241bb->liveSet.fill(0);242bb->liveSet.marker = true;243244for (Instruction *i = bb->getEntry(); i; i = i->next) {245for (int s = 0; i->srcExists(s); ++s)246if (i->getSrc(s)->asLValue() && !assigned.test(i->getSrc(s)->id))247usedBeforeAssigned.set(i->getSrc(s)->id);248for (int d = 0; i->defExists(d); ++d)249assigned.set(i->getDef(d)->id);250}251252if (bb == BasicBlock::get(f->cfgExit)) {253for (std::deque<ValueRef>::iterator it = f->outs.begin();254it != f->outs.end(); ++it) {255if (!assigned.test(it->get()->id))256usedBeforeAssigned.set(it->get()->id);257}258}259260bb->liveSet.andNot(assigned);261bb->liveSet |= usedBeforeAssigned;262}263264void265Function::buildDefSetsPreSSA(BasicBlock *bb, const int seq)266{267bb->defSet.allocate(allLValues.getSize(), !bb->liveSet.marker);268bb->liveSet.marker = true;269270for (Graph::EdgeIterator ei = bb->cfg.incident(); !ei.end(); ei.next()) {271BasicBlock *in = BasicBlock::get(ei.getNode());272273if (in->cfg.visit(seq))274buildDefSetsPreSSA(in, seq);275276bb->defSet |= in->defSet;277}278279for (Instruction *i = bb->getEntry(); i; i = i->next) {280for (int d = 0; i->defExists(d); ++d)281bb->defSet.set(i->getDef(d)->id);282}283}284285class RenamePass286{287public:288RenamePass(Function *);289~RenamePass();290291bool run();292void search(BasicBlock *);293294inline LValue *getStackTop(Value *);295296LValue *mkUndefined(Value *);297298private:299Stack *stack;300Function *func;301Program *prog;302};303304bool305Program::convertToSSA()306{307for (ArrayList::Iterator fi = allFuncs.iterator(); !fi.end(); fi.next()) {308Function *fn = reinterpret_cast<Function *>(fi.get());309if (!fn->convertToSSA())310return false;311}312return true;313}314315// XXX: add edge from entry to exit ?316317// Efficiently Computing Static Single Assignment Form and318// the Control Dependence Graph,319// R. Cytron, J. Ferrante, B. K. Rosen, M. N. Wegman, F. K. Zadeck320bool321Function::convertToSSA()322{323// 0. calculate live in variables (for pruned SSA)324buildLiveSets();325326// 1. create the dominator tree327domTree = new DominatorTree(&cfg);328reinterpret_cast<DominatorTree *>(domTree)->findDominanceFrontiers();329330// 2. insert PHI functions331DLList workList;332LValue *lval;333BasicBlock *bb;334int var;335int iterCount = 0;336int *hasAlready = new int[allBBlocks.getSize() * 2];337int *work = &hasAlready[allBBlocks.getSize()];338339memset(hasAlready, 0, allBBlocks.getSize() * 2 * sizeof(int));340341// for each variable342for (var = 0; var < allLValues.getSize(); ++var) {343if (!allLValues.get(var))344continue;345lval = reinterpret_cast<Value *>(allLValues.get(var))->asLValue();346if (!lval || lval->defs.empty())347continue;348++iterCount;349350// TODO: don't add phi functions for values that aren't used outside351// the BB they're defined in352353// gather blocks with assignments to lval in workList354for (Value::DefIterator d = lval->defs.begin();355d != lval->defs.end(); ++d) {356bb = ((*d)->getInsn() ? (*d)->getInsn()->bb : NULL);357if (!bb)358continue; // instruction likely been removed but not XXX deleted359360if (work[bb->getId()] == iterCount)361continue;362work[bb->getId()] = iterCount;363workList.insert(bb);364}365366// for each block in workList, insert a phi for lval in the block's367// dominance frontier (if we haven't already done so)368for (DLList::Iterator wI = workList.iterator(); !wI.end(); wI.erase()) {369bb = BasicBlock::get(wI);370371DLList::Iterator dfIter = bb->getDF().iterator();372for (; !dfIter.end(); dfIter.next()) {373Instruction *phi;374BasicBlock *dfBB = BasicBlock::get(dfIter);375376if (hasAlready[dfBB->getId()] >= iterCount)377continue;378hasAlready[dfBB->getId()] = iterCount;379380// pruned SSA: don't need a phi if the value is not live-in381if (!dfBB->liveSet.test(lval->id))382continue;383384phi = new_Instruction(this, OP_PHI, typeOfSize(lval->reg.size));385dfBB->insertTail(phi);386387phi->setDef(0, lval);388for (int s = 0; s < dfBB->cfg.incidentCount(); ++s)389phi->setSrc(s, lval);390391if (work[dfBB->getId()] < iterCount) {392work[dfBB->getId()] = iterCount;393wI.insert(dfBB);394}395}396}397}398delete[] hasAlready;399400RenamePass rename(this);401return rename.run();402}403404RenamePass::RenamePass(Function *fn) : func(fn), prog(fn->getProgram())405{406stack = new Stack[func->allLValues.getSize()];407}408409RenamePass::~RenamePass()410{411if (stack)412delete[] stack;413}414415LValue *416RenamePass::getStackTop(Value *val)417{418if (!stack[val->id].getSize())419return 0;420return reinterpret_cast<LValue *>(stack[val->id].peek().u.p);421}422423LValue *424RenamePass::mkUndefined(Value *val)425{426LValue *lval = val->asLValue();427assert(lval);428LValue *ud = new_LValue(func, lval);429Instruction *nop = new_Instruction(func, OP_NOP, typeOfSize(lval->reg.size));430nop->setDef(0, ud);431BasicBlock::get(func->cfg.getRoot())->insertHead(nop);432return ud;433}434435bool RenamePass::run()436{437if (!stack)438return false;439search(BasicBlock::get(func->domTree->getRoot()));440441return true;442}443444// Go through BBs in dominance order, create new values for each definition,445// and replace all sources with their current new values.446//447// NOTE: The values generated for function inputs/outputs have no connection448// to their corresponding outputs/inputs in other functions. Only allocation449// of physical registers will establish this connection.450//451void RenamePass::search(BasicBlock *bb)452{453LValue *lval, *ssa;454int d, s;455const Target *targ = prog->getTarget();456457// Put current definitions for function inputs values on the stack.458// They can be used before any redefinitions are pushed.459if (bb == BasicBlock::get(func->cfg.getRoot())) {460for (std::deque<ValueDef>::iterator it = func->ins.begin();461it != func->ins.end(); ++it) {462lval = it->get()->asLValue();463assert(lval);464465ssa = new_LValue(func, targ->nativeFile(lval->reg.file));466ssa->reg.size = lval->reg.size;467ssa->reg.data.id = lval->reg.data.id;468469it->setSSA(ssa);470stack[lval->id].push(ssa);471}472}473474for (Instruction *stmt = bb->getFirst(); stmt; stmt = stmt->next) {475// PHI sources get definitions from the passes through the incident BBs,476// so skip them here.477if (stmt->op != OP_PHI) {478for (s = 0; stmt->srcExists(s); ++s) {479lval = stmt->getSrc(s)->asLValue();480if (!lval)481continue;482// Values on the stack created in previously visited blocks, and483// function inputs, will be valid because they dominate this one.484lval = getStackTop(lval);485if (!lval)486lval = mkUndefined(stmt->getSrc(s));487stmt->setSrc(s, lval);488}489}490for (d = 0; stmt->defExists(d); ++d) {491lval = stmt->def(d).get()->asLValue();492assert(lval);493stmt->def(d).setSSA(494new_LValue(func, targ->nativeFile(lval->reg.file)));495stmt->def(d).get()->reg.size = lval->reg.size;496stmt->def(d).get()->reg.data.id = lval->reg.data.id;497stack[lval->id].push(stmt->def(d).get());498}499}500501// Update sources of PHI ops corresponding to this BB in outgoing BBs.502for (Graph::EdgeIterator ei = bb->cfg.outgoing(); !ei.end(); ei.next()) {503Instruction *phi;504int p = 0;505BasicBlock *sb = BasicBlock::get(ei.getNode());506507// which predecessor of sb is bb ?508for (Graph::EdgeIterator ei = sb->cfg.incident(); !ei.end(); ei.next()) {509if (ei.getNode() == &bb->cfg)510break;511++p;512}513assert(p < sb->cfg.incidentCount());514515for (phi = sb->getPhi(); phi && phi->op == OP_PHI; phi = phi->next) {516lval = getStackTop(phi->getSrc(p));517if (!lval)518lval = mkUndefined(phi->getSrc(p));519phi->setSrc(p, lval);520}521}522523// Visit the BBs we dominate.524for (Graph::EdgeIterator ei = bb->dom.outgoing(); !ei.end(); ei.next())525search(BasicBlock::get(ei.getNode()));526527// Update function outputs to the last definitions of their pre-SSA values.528// I hope they're unique, i.e. that we get PHIs for all of them ...529if (bb == BasicBlock::get(func->cfgExit)) {530for (std::deque<ValueRef>::iterator it = func->outs.begin();531it != func->outs.end(); ++it) {532lval = it->get()->asLValue();533if (!lval)534continue;535lval = getStackTop(lval);536if (!lval)537lval = mkUndefined(it->get());538it->set(lval);539}540}541542// Pop the values we created in this block from the stack because we will543// return to blocks that we do not dominate.544for (Instruction *stmt = bb->getFirst(); stmt; stmt = stmt->next) {545if (stmt->op == OP_NOP)546continue;547for (d = 0; stmt->defExists(d); ++d)548stack[stmt->def(d).preSSA()->id].pop();549}550}551552} // namespace nv50_ir553554555