diff options
author | Francisco Jerez <[email protected]> | 2012-03-27 17:29:55 +0200 |
---|---|---|
committer | Christoph Bumiller <[email protected]> | 2012-04-14 21:54:02 +0200 |
commit | 9bb36d54a2c69ebdc9d1c9c4c71945060de8c860 (patch) | |
tree | 106b5884ddf5d3a630767195e0f27560aeadbece | |
parent | 56d40aa51b34b77791cc3a49d7e86473a7459b72 (diff) |
nv50/ir/tgsi: Replace the inlining logic with proper function calls.
5 files changed, 82 insertions, 68 deletions
diff --git a/src/gallium/drivers/nv50/codegen/nv50_ir.cpp b/src/gallium/drivers/nv50/codegen/nv50_ir.cpp index 698a1222263..314701bfb6a 100644 --- a/src/gallium/drivers/nv50/codegen/nv50_ir.cpp +++ b/src/gallium/drivers/nv50/codegen/nv50_ir.cpp @@ -919,11 +919,13 @@ CmpInstruction::clone(ClonePolicy<Function>& pol, Instruction *i) const return cmp; } -FlowInstruction::FlowInstruction(Function *fn, operation op, - BasicBlock *targ) +FlowInstruction::FlowInstruction(Function *fn, operation op, void *targ) : Instruction(fn, op, TYPE_NONE) { - target.bb = targ; + if (op == OP_CALL) + target.fn = reinterpret_cast<Function *>(targ); + else + target.bb = reinterpret_cast<BasicBlock *>(targ); if (op == OP_BRA || op == OP_CONT || op == OP_BREAK || diff --git a/src/gallium/drivers/nv50/codegen/nv50_ir.h b/src/gallium/drivers/nv50/codegen/nv50_ir.h index 93e3008cf0d..0a8a0743eb4 100644 --- a/src/gallium/drivers/nv50/codegen/nv50_ir.h +++ b/src/gallium/drivers/nv50/codegen/nv50_ir.h @@ -818,7 +818,7 @@ public: class FlowInstruction : public Instruction { public: - FlowInstruction(Function *, operation, BasicBlock *target); + FlowInstruction(Function *, operation, void *target); virtual FlowInstruction *clone(ClonePolicy<Function>&, Instruction * = NULL) const; diff --git a/src/gallium/drivers/nv50/codegen/nv50_ir_build_util.cpp b/src/gallium/drivers/nv50/codegen/nv50_ir_build_util.cpp index cb63854b043..dcae25bd508 100644 --- a/src/gallium/drivers/nv50/codegen/nv50_ir_build_util.cpp +++ b/src/gallium/drivers/nv50/codegen/nv50_ir_build_util.cpp @@ -282,7 +282,7 @@ BuildUtil::mkSelect(Value *pred, Value *dst, Value *trSrc, Value *flSrc) } FlowInstruction * -BuildUtil::mkFlow(operation op, BasicBlock *targ, CondCode cc, Value *pred) +BuildUtil::mkFlow(operation op, void *targ, CondCode cc, Value *pred) { FlowInstruction *insn = new_FlowInstruction(func, op, targ); diff --git a/src/gallium/drivers/nv50/codegen/nv50_ir_build_util.h b/src/gallium/drivers/nv50/codegen/nv50_ir_build_util.h index 69158861533..022a27f1748 100644 --- a/src/gallium/drivers/nv50/codegen/nv50_ir_build_util.h +++ b/src/gallium/drivers/nv50/codegen/nv50_ir_build_util.h @@ -76,8 +76,7 @@ public: Value **def, Value **src); Instruction *mkQuadop(uint8_t qop, Value *, uint8_t l, Value *, Value *); - FlowInstruction *mkFlow(operation, BasicBlock *target, - CondCode, Value *pred); + FlowInstruction *mkFlow(operation, void *target, CondCode, Value *pred); Instruction *mkSelect(Value *pred, Value *dst, Value *trSrc, Value *flSrc); 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 9f735bfb2e2..f4199c3a9b8 100644 --- a/src/gallium/drivers/nv50/codegen/nv50_ir_from_tgsi.cpp +++ b/src/gallium/drivers/nv50/codegen/nv50_ir_from_tgsi.cpp @@ -578,11 +578,6 @@ public: Source(struct nv50_ir_prog_info *); ~Source(); - struct Subroutine - { - unsigned pc; - }; - public: bool scanSource(); unsigned fileSize(unsigned file) const { return scan.file_max[file] + 1; } @@ -605,9 +600,6 @@ public: uint8_t *resourceTargets; // TGSI_TEXTURE_* unsigned resourceCount; - Subroutine *subroutines; - unsigned subroutineCount; - private: int inferSysValDirection(unsigned sn) const; bool scanDeclaration(const struct tgsi_full_declaration *); @@ -626,7 +618,6 @@ Source::Source(struct nv50_ir_prog_info *prog) : info(prog) tgsi_dump(tokens, 0); resourceTargets = NULL; - subroutines = NULL; mainTempsInLMem = FALSE; } @@ -643,14 +634,11 @@ Source::~Source() if (resourceTargets) delete[] resourceTargets; - if (subroutines) - delete[] subroutines; } bool Source::scanSource() { unsigned insnCount = 0; - unsigned subrCount = 0; struct tgsi_parse_context parse; tgsi_scan_shader(tokens, &scan); @@ -665,9 +653,6 @@ bool Source::scanSource() resourceCount = scan.file_max[TGSI_FILE_RESOURCE] + 1; resourceTargets = new uint8_t[resourceCount]; - subroutineCount = scan.opcode_count[TGSI_OPCODE_BGNSUB] + 1; - subroutines = new Subroutine[subroutineCount]; - info->immd.bufSize = 0; tempArrayCount = 0; immdArrayCount = 0; @@ -700,10 +685,7 @@ bool Source::scanSource() break; case TGSI_TOKEN_TYPE_INSTRUCTION: insns[insnCount++] = parse.FullToken.FullInstruction; - if (insns[insnCount - 1].Instruction.Opcode == TGSI_OPCODE_BGNSUB) - subroutines[++subrCount].pc = insnCount - 1; - else - scanInstruction(&parse.FullToken.FullInstruction); + scanInstruction(&parse.FullToken.FullInstruction); break; case TGSI_TOKEN_TYPE_PROPERTY: scanProperty(&parse.FullToken.FullProperty); @@ -1028,6 +1010,13 @@ public: bool run(); private: + struct Subroutine + { + Subroutine(Function *f) : f(f) { } + Function *f; + ValueMap values; + }; + Value *getVertexBase(int s); DataArray *getArrayForFile(unsigned file, int idx); Value *fetchSrc(int s, int c); @@ -1046,6 +1035,8 @@ private: bool handleInstruction(const struct tgsi_full_instruction *); void exportOutputs(); + inline Subroutine *getSubroutine(unsigned ip); + inline Subroutine *getSubroutine(Function *); inline bool isEndOfSubroutine(uint ip); void loadProjTexCoords(Value *dst[4], Value *src[4], unsigned int mask); @@ -1068,6 +1059,11 @@ private: const struct tgsi::Source *code; const struct nv50_ir_prog_info *info; + struct { + std::map<unsigned, Subroutine> map; + Subroutine *cur; + } sub; + uint ip; // instruction pointer tgsi::Instruction tgsi; @@ -1082,8 +1078,6 @@ private: std::vector<DataArray> lData; // TGSI_FILE_TEMPORARY_ARRAY std::vector<DataArray> iData; // TGSI_FILE_IMMEDIATE_ARRAY - ValueMap values; - Value *zero; Value *fragCoord[4]; Value *clipVtx[4]; @@ -1095,9 +1089,6 @@ private: Stack joinBBs; // fork BB, for inserting join ops on ENDIF Stack loopBBs; // loop headers Stack breakBBs; // end of / after loop - Stack entryBBs; // start of current (inlined) subroutine - Stack leaveBBs; // end of current (inlined) subroutine - Stack retIPs; // return instruction pointer }; Symbol * @@ -1310,7 +1301,8 @@ Converter::fetchSrc(tgsi::Instruction::SrcRegister src, int c, Value *ptr) assert(!ptr); return mkOp1v(OP_RDSV, TYPE_U32, getSSA(), srcToSym(src, c)); default: - return getArrayForFile(src.getFile(), idx2d)->load(values, idx, swz, ptr); + return getArrayForFile(src.getFile(), idx2d)->load( + sub.cur->values, idx, swz, ptr); } } @@ -1331,7 +1323,7 @@ Converter::acquireDst(int d, int c) (f == TGSI_FILE_OUTPUT && prog->getType() != Program::TYPE_FRAGMENT)) return getScratch(); - return getArrayForFile(f, idx2d)-> acquire(values, idx, c); + return getArrayForFile(f, idx2d)-> acquire(sub.cur->values, idx, c); } void @@ -1387,7 +1379,7 @@ Converter::storeDst(const tgsi::Instruction::DstRegister dst, int c, f == TGSI_FILE_PREDICATE || f == TGSI_FILE_ADDRESS || f == TGSI_FILE_OUTPUT) { - getArrayForFile(f, idx2d)->store(values, idx, c, ptr, val); + getArrayForFile(f, idx2d)->store(sub.cur->values, idx, c, ptr, val); } else { assert(!"invalid dst file"); } @@ -1654,6 +1646,30 @@ Converter::handleLIT(Value *dst0[4]) } } +Converter::Subroutine * +Converter::getSubroutine(unsigned ip) +{ + std::map<unsigned, Subroutine>::iterator it = sub.map.find(ip); + + if (it == sub.map.end()) + it = sub.map.insert(std::make_pair( + ip, Subroutine(new Function(prog, "SUB", ip)))).first; + + return &it->second; +} + +Converter::Subroutine * +Converter::getSubroutine(Function *f) +{ + unsigned ip = f->getLabel(); + std::map<unsigned, Subroutine>::iterator it = sub.map.find(ip); + + if (it == sub.map.end()) + it = sub.map.insert(std::make_pair(ip, Subroutine(f))).first; + + return &it->second; +} + bool Converter::isEndOfSubroutine(uint ip) { @@ -2107,56 +2123,54 @@ Converter::handleInstruction(const struct tgsi_full_instruction *insn) break; case TGSI_OPCODE_BGNSUB: { - if (!retIPs.getSize()) { - // end of main function - ip = code->scan.num_instructions - 2; // goto END - return true; - } - BasicBlock *entry = new BasicBlock(func); - BasicBlock *leave = new BasicBlock(func); - entryBBs.push(entry); - leaveBBs.push(leave); - bb->cfg.attach(&entry->cfg, Graph::Edge::TREE); + Subroutine *s = getSubroutine(ip); + BasicBlock *entry = new BasicBlock(s->f); + BasicBlock *leave = new BasicBlock(s->f); + + // multiple entrypoints possible, keep the graph connected + if (prog->getType() == Program::TYPE_COMPUTE) + prog->main->call.attach(&s->f->call, Graph::Edge::TREE); + + sub.cur = s; + s->f->setEntry(entry); + s->f->setExit(leave); setPosition(entry, true); - } return true; + } case TGSI_OPCODE_ENDSUB: { - BasicBlock *leave = reinterpret_cast<BasicBlock *>(leaveBBs.pop().u.p); - entryBBs.pop(); - bb->cfg.attach(&leave->cfg, Graph::Edge::TREE); - setPosition(leave, true); - ip = retIPs.pop().u.u; - } + sub.cur = getSubroutine(prog->main); + setPosition(BasicBlock::get(sub.cur->f->cfg.getRoot()), true); return true; + } case TGSI_OPCODE_CAL: - // we don't have function declarations, so inline everything - retIPs.push(ip); - ip = code->subroutines[tgsi.getLabel()].pc - 1; // +1 after return + { + Subroutine *s = getSubroutine(tgsi.getLabel()); + mkFlow(OP_CALL, s->f, CC_ALWAYS, NULL); + func->call.attach(&s->f->call, Graph::Edge::TREE); return true; + } case TGSI_OPCODE_RET: { if (bb->isTerminated()) return true; - BasicBlock *entry = reinterpret_cast<BasicBlock *>(entryBBs.peek().u.p); - BasicBlock *leave = reinterpret_cast<BasicBlock *>(leaveBBs.peek().u.p); + BasicBlock *leave = BasicBlock::get(func->cfgExit); + if (!isEndOfSubroutine(ip + 1)) { // insert a PRERET at the entry if this is an early return - FlowInstruction *preRet = new_FlowInstruction(func, OP_PRERET, leave); - preRet->fixed = 1; - entry->insertHead(preRet); + // (only needed for sharing code in the epilogue) + mkFlow(OP_PRERET, leave, CC_ALWAYS, NULL)->fixed = 1; bb->cfg.attach(&leave->cfg, Graph::Edge::CROSS); - } - // everything inlined so RET serves only to wrap up the stack - if (entry->getEntry() && entry->getEntry()->op == OP_PRERET) + } else { mkFlow(OP_RET, NULL, CC_ALWAYS, NULL)->fixed = 1; + bb->cfg.attach(&leave->cfg, Graph::Edge::TREE); + } } break; case TGSI_OPCODE_END: { // attach and generate epilogue code - BasicBlock *epilogue = reinterpret_cast<BasicBlock *>(leaveBBs.pop().u.p); - entryBBs.pop(); + BasicBlock *epilogue = BasicBlock::get(func->cfgExit); bb->cfg.attach(&epilogue->cfg, Graph::Edge::TREE); setPosition(epilogue, true); if (prog->getType() == Program::TYPE_FRAGMENT) @@ -2218,11 +2232,11 @@ Converter::exportOutputs() { for (unsigned int i = 0; i < info->numOutputs; ++i) { for (unsigned int c = 0; c < 4; ++c) { - if (!oData.exists(values, i, c)) + if (!oData.exists(sub.cur->values, i, c)) continue; Symbol *sym = mkSymbol(FILE_SHADER_OUTPUT, 0, TYPE_F32, info->out[i].slot[c] * 4); - Value *val = oData.load(values, i, c, NULL); + Value *val = oData.load(sub.cur->values, i, c, NULL); if (val) mkStore(OP_EXPORT, TYPE_F32, sym, NULL, val); } @@ -2289,8 +2303,7 @@ Converter::run() prog->main->setExit(leave); setPosition(entry, true); - entryBBs.push(entry); - leaveBBs.push(leave); + sub.cur = getSubroutine(prog->main); if (info->io.genUserClip > 0) { for (int c = 0; c < 4; ++c) |