From d0a177d76c4fbcefec5fe15c19cc446facf0c71b Mon Sep 17 00:00:00 2001 From: Zhigang Gong Date: Fri, 25 Apr 2014 15:38:22 +0800 Subject: [PATCH] GBE: fix the large if/endif block issue. 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 Reviewed-by: "Yang, Rong R" --- backend/src/backend/gen_context.cpp | 21 ++++++++++++++------- backend/src/backend/gen_context.hpp | 16 +++++++++++++++- backend/src/backend/gen_insn_selection.cpp | 19 ++++++++++++++++--- backend/src/backend/gen_program.cpp | 8 ++++++++ backend/src/backend/gen_reg_allocation.cpp | 10 ++++------ 5 files changed, 57 insertions(+), 17 deletions(-) diff --git a/backend/src/backend/gen_context.cpp b/backend/src/backend/gen_context.cpp index ef18577..62b58bd 100644 --- a/backend/src/backend/gen_context.cpp +++ b/backend/src/backend/gen_context.cpp @@ -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); } diff --git a/backend/src/backend/gen_context.hpp b/backend/src/backend/gen_context.hpp index dfddd28..3b59797 100644 --- a/backend/src/backend/gen_context.hpp +++ b/backend/src/backend/gen_context.hpp @@ -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 */ diff --git a/backend/src/backend/gen_insn_selection.cpp b/backend/src/backend/gen_insn_selection.cpp index 09e5423..ab885f2 100644 --- a/backend/src/backend/gen_insn_selection.cpp +++ b/backend/src/backend/gen_insn_selection.cpp @@ -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(); diff --git a/backend/src/backend/gen_program.cpp b/backend/src/backend/gen_program.cpp index 83ec5a6..dd03153 100644 --- a/backend/src/backend/gen_program.cpp +++ b/backend/src/backend/gen_program.cpp @@ -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."); diff --git a/backend/src/backend/gen_reg_allocation.cpp b/backend/src/backend/gen_reg_allocation.cpp index 54b7cac..fd0c1cf 100644 --- a/backend/src/backend/gen_reg_allocation.cpp +++ b/backend/src/backend/gen_reg_allocation.cpp @@ -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; } -- 2.7.4