GBE: fix the large if/endif block issue.
authorZhigang Gong <zhigang.gong@intel.com>
Fri, 25 Apr 2014 07:38:22 +0000 (15:38 +0800)
committerZhigang Gong <zhigang.gong@intel.com>
Tue, 29 Apr 2014 04:39:23 +0000 (12:39 +0800)
Some test cases have some very large block which contains
more than 32768/2 instructions which could fit into one
if/endif block.

This patch introduce a ifendif fix switch at the GenContext.
Once we encounter one of such error, we set the switch on
and then recompile the kernel. When the switch is on, we will
insert extra endif/if pair to the block to split one if/endif
block to multiple ones to fix the large if/endif issue.

Signed-off-by: Zhigang Gong <zhigang.gong@intel.com>
Reviewed-by: "Yang, Rong R" <rong.r.yang@intel.com>
backend/src/backend/gen_context.cpp
backend/src/backend/gen_context.hpp
backend/src/backend/gen_insn_selection.cpp
backend/src/backend/gen_program.cpp
backend/src/backend/gen_reg_allocation.cpp

index ef18577..62b58bd 100644 (file)
@@ -52,6 +52,7 @@ namespace gbe
     this->p = NULL;
     this->sel = NULL;
     this->ra = NULL;
+    this->ifEndifFix = false;
   }
 
   GenContext::~GenContext(void) {
@@ -73,6 +74,7 @@ namespace gbe
     this->branchPos2.clear();
     this->branchPos3.clear();
     this->labelPos.clear();
+    this->errCode = NO_ERROR;
   }
 
   void GenContext::emitInstructionStream(void) {
@@ -98,7 +100,7 @@ namespace gbe
        p->NOP();
   }
 
-  void GenContext::patchBranches(void) {
+  bool GenContext::patchBranches(void) {
     using namespace ir;
     for (auto pair : branchPos2) {
       const LabelIndex label = pair.first;
@@ -109,14 +111,17 @@ namespace gbe
     for (auto pair : branchPos3) {
       const LabelPair labelPair = pair.first;
       const int32_t insnID = pair.second;
-      // FIXME the 'labelPair' implementation must be fixed, as it is hard to
-      // convert InstructionSelection offset to ASM offset since asm maybe compacted
       const int32_t jip = labelPos.find(labelPair.l0)->second;
       const int32_t uip = labelPos.find(labelPair.l1)->second;
-      assert((jip - insnID) < 32767 && (jip - insnID) > -32768);
-      assert((uip - insnID) < 32767 && (uip - insnID) > -32768);
+      if (((jip - insnID) > 32767 || (jip - insnID) < -32768) ||
+          ((uip - insnID) > 32768 || (uip - insnID) < -32768)) {
+        // The only possible error instruction is if/endif here.
+        errCode = OUT_OF_RANGE_IF_ENDIF; 
+        return false;
+      }
       p->patchJMPI(insnID, (((uip - insnID)) << 16) | ((jip - insnID)));
     }
+    return true;
   }
 
   void GenContext::clearFlagRegister(void) {
@@ -2014,7 +2019,8 @@ namespace gbe
     this->clearFlagRegister();
     this->emitStackPointer();
     this->emitInstructionStream();
-    this->patchBranches();
+    if (this->patchBranches() == false)
+      return false;
     genKernel->insnNum = p->store.size();
     genKernel->insns = GBE_NEW_ARRAY_NO_ARG(GenInstruction, genKernel->insnNum);
     std::memcpy(genKernel->insns, &p->store[0], genKernel->insnNum * sizeof(GenInstruction));
@@ -2025,7 +2031,8 @@ namespace gbe
       GenNativeInstruction insn;
       std::cout << "  L0:" << std::endl;
       for (uint32_t insnID = 0; insnID < genKernel->insnNum; ) {
-        if (labelPos.find((ir::LabelIndex)(curLabel + 1))->second == insnID) {
+        if (labelPos.find((ir::LabelIndex)(curLabel + 1))->second == insnID &&
+            curLabel < this->getFunction().labelNum()) {
           std::cout << "  L" << curLabel + 1 << ":" << std::endl;
           curLabel = (ir::LabelIndex)(curLabel + 1);
         }
index dfddd28..3b59797 100644 (file)
@@ -42,6 +42,13 @@ namespace gbe
   class SelectionInstruction; // Pre-RA Gen instruction
   class SelectionReg;         // Pre-RA Gen register
   class GenRegister;
+  typedef enum {
+    NO_ERROR,
+    REGISTER_ALLOCATION_FAIL,
+    REGISTER_SPILL_EXCEED_THRESHOLD,
+    REGISTER_SPILL_FAIL,
+    OUT_OF_RANGE_IF_ENDIF,
+  } CompileErrorCode;
 
   /*! Context is the helper structure to build the Gen ISA or simulation code
    *  from GenIR
@@ -73,7 +80,7 @@ namespace gbe
     /*! Emit the instructions */
     void emitInstructionStream(void);
     /*! Set the correct target values for the branches */
-    void patchBranches(void);
+    bool patchBranches(void);
     /*! Forward ir::Function isSpecialReg method */
     INLINE bool isSpecialReg(ir::Register reg) const {
       return fn.isSpecialReg(reg);
@@ -177,12 +184,19 @@ namespace gbe
     uint32_t reservedSpillRegs;
     bool limitRegisterPressure;
     bool relaxMath;
+    const bool getIFENDIFFix(void) const { return ifEndifFix; }
+    void setIFENDIFFix(bool fix) { ifEndifFix = fix; }
+    const CompileErrorCode getErrCode() { return errCode; }
   private:
+    CompileErrorCode errCode;
+    bool ifEndifFix;
     /*! Build the curbe patch list for the given kernel */
     void buildPatchList(void);
     /*! allocate a new curbe register and insert to curbe pool. */
     void allocCurbeReg(ir::Register reg, gbe_curbe_type value, uint32_t subValue = 0);
 
+    friend GenRegAllocator;               //!< need to access errCode directly. 
+
   };
 
 } /* namespace gbe */
index 09e5423..ab885f2 100644 (file)
@@ -196,7 +196,7 @@ namespace gbe
   // SelectionBlock
   ///////////////////////////////////////////////////////////////////////////
 
-  SelectionBlock::SelectionBlock(const ir::BasicBlock *bb) : bb(bb) {}
+  SelectionBlock::SelectionBlock(const ir::BasicBlock *bb) : bb(bb), endifLabel( (ir::LabelIndex) 0){}
 
   void SelectionBlock::append(ir::Register reg) { tmp.push_back(reg); }
 
@@ -981,7 +981,7 @@ namespace gbe
     this->LABEL(this->block->endifLabel);
     SelectionInstruction *insn = this->appendInsn(SEL_OP_ENDIF, 0, 1);
     insn->src(0) = src;
-    insn->index = uint16_t(jip);
+    insn->index = uint16_t(this->block->endifLabel);
   }
 
   void Selection::Opaque::CMP(uint32_t conditional, Reg src0, Reg src1, Reg dst) {
@@ -1482,13 +1482,26 @@ namespace gbe
         // If there is no branch at the end of this block.
 
         // Try all the patterns from best to worst
-
         do {
           if ((*it)->emit(*this, dag))
             break;
           ++it;
         } while (it != end);
         GBE_ASSERT(it != end);
+        // If we are in if/endif fix mode, and this block is
+        // large enough, we need to insert endif/if pair to eliminate
+        // the too long if/endif block.
+        if (this->ctx.getIFENDIFFix() &&
+            this->block->insnList.size() != 0 &&
+            this->block->insnList.size() % 1000 == 0 &&
+            (uint16_t)this->block->endifLabel != 0) {
+          ir::LabelIndex jip = this->block->endifLabel;
+          this->ENDIF(GenRegister::immd(0), jip);
+          this->push();
+            this->curr.predicate = GEN_PREDICATE_NORMAL;
+            this->IF(GenRegister::immd(0), jip, jip);
+          this->pop();
+        }
 
         if (needEndif) {
           const ir::BasicBlock *curr = insn.getParent();
index 83ec5a6..dd03153 100644 (file)
@@ -116,9 +116,17 @@ namespace gbe {
       ctx->startNewCG(simdWidth, reservedSpillRegs, limitRegisterPressure);
       kernel = ctx->compileKernel();
       if (kernel != NULL) {
+        GBE_ASSERT(ctx->getErrCode() == NO_ERROR);
         break;
       }
       fn->getImageSet()->clearInfo();
+      // If we get a out of range if/endif error.
+      // We need to set the context to if endif fix mode and restart the previous compile.
+      if ( ctx->getErrCode() == OUT_OF_RANGE_IF_ENDIF && !ctx->getIFENDIFFix() ) {
+        ctx->setIFENDIFFix(true);
+        codeGen--;
+      } else
+        GBE_ASSERT(!(ctx->getErrCode() == OUT_OF_RANGE_IF_ENDIF && ctx->getIFENDIFFix()));
     }
 
     GBE_ASSERTM(kernel != NULL, "Fail to compile kernel, may need to increase reserved registers for spilling.");
index 54b7cac..fd0c1cf 100644 (file)
@@ -598,6 +598,7 @@ namespace gbe
   IVAR(OCL_SIMD16_SPILL_THRESHOLD, 0, 16, 256);
   bool GenRegAllocator::Opaque::allocateGRFs(Selection &selection) {
     // Perform the linear scan allocator
+    ctx.errCode = REGISTER_ALLOCATION_FAIL;
     const uint32_t regNum = ctx.sel->getRegNum();
     for (uint32_t startID = 0; startID < regNum; ++startID) {
       const GenRegInterval &interval = *this->starting[startID];
@@ -651,21 +652,18 @@ namespace gbe
       GBE_ASSERT(reservedReg != 0);
       if (ctx.getSimdWidth() == 16) {
         if (spilledRegs.size() > (unsigned int)OCL_SIMD16_SPILL_THRESHOLD) {
-          if (GBE_DEBUG)
-            std::cerr << "WARN: exceed simd 16 spill threshold ("
-                      << spilledRegs.size() << ">" << OCL_SIMD16_SPILL_THRESHOLD
-                      << ")" << std::endl;
+          ctx.errCode = REGISTER_SPILL_EXCEED_THRESHOLD;
           return false;
         }
       }
       allocateScratchForSpilled();
       bool success = selection.spillRegs(spilledRegs, reservedReg);
       if (!success) {
-        if (GBE_DEBUG)
-          std::cerr << "Fail to spill registers." << std::endl;
+        ctx.errCode = REGISTER_SPILL_FAIL;
         return false;
       }
     }
+    ctx.errCode = NO_ERROR;
     return true;
   }