nv50/ir/tgsi: Replace the inlining logic with proper function calls.
authorFrancisco Jerez <currojerez@riseup.net>
Tue, 27 Mar 2012 15:29:55 +0000 (17:29 +0200)
committerChristoph Bumiller <e0425955@student.tuwien.ac.at>
Sat, 14 Apr 2012 19:54:02 +0000 (21:54 +0200)
src/gallium/drivers/nv50/codegen/nv50_ir.cpp
src/gallium/drivers/nv50/codegen/nv50_ir.h
src/gallium/drivers/nv50/codegen/nv50_ir_build_util.cpp
src/gallium/drivers/nv50/codegen/nv50_ir_build_util.h
src/gallium/drivers/nv50/codegen/nv50_ir_from_tgsi.cpp

index 698a122..314701b 100644 (file)
@@ -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 ||
index 93e3008..0a8a074 100644 (file)
@@ -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;
index cb63854..dcae25b 100644 (file)
@@ -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);
 
index 6915886..022a27f 100644 (file)
@@ -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);
 
index 9f735bf..f4199c3 100644 (file)
@@ -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)