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; }
uint8_t *resourceTargets; // TGSI_TEXTURE_*
unsigned resourceCount;
- Subroutine *subroutines;
- unsigned subroutineCount;
-
private:
int inferSysValDirection(unsigned sn) const;
bool scanDeclaration(const struct tgsi_full_declaration *);
tgsi_dump(tokens, 0);
resourceTargets = NULL;
- subroutines = NULL;
mainTempsInLMem = FALSE;
}
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);
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;
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);
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);
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);
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;
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];
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 *
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);
}
}
(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
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");
}
}
}
+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)
{
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)
{
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);
}
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)