Debugged unstructured branch code
authorBenjamin Segovia <segovia.benjamin@gmail.com>
Fri, 4 May 2012 18:29:18 +0000 (18:29 +0000)
committerKeith Packard <keithp@keithp.com>
Fri, 10 Aug 2012 23:17:06 +0000 (16:17 -0700)
backend/src/backend/context.cpp
backend/src/backend/gen_context.cpp
backend/src/backend/gen_eu.cpp

index 2c8df7d..d21a7bf 100644 (file)
@@ -228,9 +228,15 @@ namespace gbe
     for (int32_t blockID = 0; blockID < blockNum; ++blockID) {
       const LabelIndex ownLabel = braTargets[blockID].first;
       const LabelIndex target = braTargets[blockID].second;
+      const BasicBlock &bb = fn.getBlock(ownLabel);
+      const Instruction *insn = bb.getLastInstruction();
       if (ownLabel == noTarget) continue; // unused block
       if (target == noTarget) continue; // no branch at all
-      if (target <= ownLabel) continue; // bwd branch: nothing to do
+      GBE_ASSERT(insn->isMemberOf<BranchInstruction>() == true);
+      if (target <= ownLabel) { // bwd branch: we always jump
+        JIPs.insert(std::make_pair(insn, LabelIndex(target)));
+        continue;
+      }
 
       // Traverse all previous blocks and see if we bypass their target
       uint32_t bypassedNum = 0;
@@ -245,9 +251,6 @@ namespace gbe
       }
 
       // We now have the (possibly) updated JIP for the branch
-      const BasicBlock &bb = fn.getBlock(ownLabel);
-      const Instruction *insn = bb.getLastInstruction();
-      GBE_ASSERT(insn->isMemberOf<BranchInstruction>() == true);
       JIPs.insert(std::make_pair(insn, LabelIndex(JIP)));
 
       // No bypassed targets
@@ -255,7 +258,7 @@ namespace gbe
 
       // When we have several bypassed targets, we must simply sort them and
       // chain them such target_n points to target_{n+1}
-      bypassedLabels[bypassedNum++] = ownLabel;
+      bypassedLabels[bypassedNum++] = target;
       std::sort(&bypassedLabels[0], &bypassedLabels[bypassedNum]);
 
       // Bypassed labels have a JIP now. However, we will only insert the
index bd2cfb6..77912a4 100644 (file)
@@ -248,6 +248,12 @@ namespace gbe
   {
     using namespace ir;
     const GenReg ip = this->genReg(blockIPReg, TYPE_U16);
+    const LabelIndex jip = JIPs.find(&insn)->second;
+
+    // We will not emit any jump if we must go the next block anyway
+    const BasicBlock *curr = insn.getParent();
+    const BasicBlock *next = curr->getNextBlock();
+    const LabelIndex nextLabel = next->getLabelIndex();
 
     // Inefficient code. If the instruction is predicated, we build the flag
     // register from the boolean vector
@@ -270,16 +276,13 @@ namespace gbe
         p->MOV(ip, GenReg::immuw(uint16_t(dst)));
       p->pop();
 
-      // We do not emit any jump if we must jump to the next instruction
-      const BasicBlock *curr = insn.getParent();
-      const BasicBlock *next = curr->getNextBlock();
-      const LabelIndex nextLabel = next->getLabelIndex();
-      if (nextLabel == dst) return;
+      if (nextLabel == jip) return;
 
       // It is slightly more complicated than for backward jump. We check that
       // all PcIPs are greater than the next block IP to be sure that we can
       // jump
       p->push();
+        p->curr.predicate = GEN_PREDICATE_NONE;
         p->curr.flag = 0;
         p->curr.subFlag = 1;
         p->CMP(GenReg::null(), GEN_CONDITIONAL_G, ip, GenReg::immuw(nextLabel));
@@ -301,7 +304,8 @@ namespace gbe
       // Update the PcIPs
       p->MOV(ip, GenReg::immuw(uint16_t(dst)));
 
-      // Branch to the jump target
+      // Do not emit branch when we go to the next block anyway
+      if (nextLabel == jip) return;
       this->branchPos.insert(std::make_pair(&insn, p->insnNum));
       p->push();
         p->curr.execWidth = 1;
@@ -546,6 +550,26 @@ namespace gbe
       p->curr.flag = 0;
       p->CMP(dst, GEN_CONDITIONAL_LE, GenReg::retype(src0, GEN_TYPE_UW), src1);
     p->pop();
+
+    // If it is required, insert a JUMP to bypass the block
+    auto it = JIPs.find(&insn);
+    if (it != JIPs.end()) {
+      p->push();
+        this->branchPos.insert(std::make_pair(&insn, p->insnNum));
+        if (simdWidth == 8)
+          p->curr.predicate = GEN_PREDICATE_ALIGN1_ANY8H;
+        else if (simdWidth == 16)
+          p->curr.predicate = GEN_PREDICATE_ALIGN1_ANY16H;
+        else
+          NOT_IMPLEMENTED;
+        p->curr.inversePredicate = 1;
+        p->curr.execWidth = 1;
+        p->curr.flag = 0;
+        p->curr.subFlag = 0;
+        p->curr.noMask = 1;
+        p->JMPI(GenReg::immd(0));
+      p->pop();
+    }
   }
 
   void GenContext::emitInstructionStream(void) {
@@ -573,8 +597,8 @@ namespace gbe
   void GenContext::patchBranches(void) {
     using namespace ir;
     for (auto pair : branchPos) {
-      const BranchInstruction *insn = cast<BranchInstruction>(pair.first);
-      const LabelIndex label = insn->getLabelIndex();
+      const Instruction *insn = pair.first;
+      const LabelIndex label = JIPs.find(insn)->second;
       const int32_t insnID = pair.second;
       const int32_t targetID = labelPos.find(label)->second;
       p->patchJMPI(insnID, (targetID-insnID-1) * 2);
index d560e34..a58d2bc 100644 (file)
@@ -615,10 +615,6 @@ namespace gbe
     this->setSrc1(&insn, GenReg::immd(jumpDistance));
   }
 
-  /* To integrate with the above, it makes sense that the comparison
-   * instruction should populate the flag register.  It might be simpler
-   * just to use the flag reg for most WM tasks?
-   */
   void GenEmitter::CMP(GenReg dest, uint32_t conditional, GenReg src0, GenReg src1)
   {
     GenInstruction *insn = this->next(GEN_OPCODE_CMP);
@@ -630,8 +626,6 @@ namespace gbe
     this->setSrc1(insn, src1);
   }
 
-  /* Issue 'wait' instruction for n1, host could program MMIO
-     to wake up thread. */
   void GenEmitter::WAIT(void)
   {
      GenInstruction *insn = this->next(GEN_OPCODE_WAIT);