From: Benjamin Segovia Date: Mon, 20 Feb 2012 02:52:19 +0000 (+0000) Subject: Improved error messages with better assertions X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=5b73477aac3f9b227adbbcfbbb7ee1a0e5330588;p=contrib%2Fbeignet.git Improved error messages with better assertions --- diff --git a/backend/src/ir/context.cpp b/backend/src/ir/context.cpp index 2294f5e..5822c04 100644 --- a/backend/src/ir/context.cpp +++ b/backend/src/ir/context.cpp @@ -35,7 +35,7 @@ namespace ir { } void Context::endFunction(void) { - GBE_ASSERT(fn != NULL); + GBE_ASSERTM(fn != NULL, "No function to end"); if (fnStack.size() != 0) { fn = fnStack.back(); fnStack.pop_back(); @@ -44,22 +44,24 @@ namespace ir { } Register Context::reg(RegisterData::Family family) { - GBE_ASSERT(fn != NULL); + GBE_ASSERTM(fn != NULL, "No function currently defined"); return fn->file.append(family); } void Context::input(Register reg) { - GBE_ASSERT(fn != NULL && reg < fn->file.regNum()); + GBE_ASSERTM(fn != NULL, "No function currently defined"); + GBE_ASSERTM(reg < fn->file.regNum(), "Out-of-bound register"); fn->input.push_back(reg); } void Context::output(Register reg) { - GBE_ASSERT(fn != NULL && reg < fn->file.regNum()); + GBE_ASSERTM(fn != NULL, "No function currently defined"); + GBE_ASSERTM(reg < fn->file.regNum(), "Out-of-bound register"); fn->output.push_back(reg); } void Context::startBlock(void) { - GBE_ASSERT(fn != NULL); + GBE_ASSERTM(fn != NULL, "No function currently defined"); this->bb = GBE_NEW(BasicBlock, *fn); fn->blocks.push_back(bb); } @@ -68,18 +70,34 @@ namespace ir { this->bb = NULL; } - void Context::append(const Instruction &insn) { + void Context::append(const Instruction &insn) + { + GBE_ASSERTM(fn != NULL, "No function currently defined"); // Start a new block if this is a label if (insn.isMemberOf() == true) { this->endBlock(); this->startBlock(); + const LabelIndex index = cast(insn).getLabelIndex(); + GBE_ASSERTM(index < fn->labelNum(), "Out-of-bound label"); + GBE_ASSERTM(fn->labels[index] == NULL, "Label used in a previous block"); + fn->labels[index] = bb; + } + // We create a new label for a new block if the user did not do it + else if (bb == NULL) { + this->startBlock(); + const LabelIndex index = fn->newLabel(); + const Instruction insn = ir::LABEL(index); + this->append(insn); } // Append the instruction in the stream - GBE_ASSERT(fn != NULL && bb != NULL); Instruction *insnPtr = fn->newInstruction(); *insnPtr = insn; +#ifndef NDEBUG + std::string whyNot; + GBE_ASSERTM(insn.wellFormed(*fn, whyNot), whyNot.c_str()); +#endif /* NDEBUG */ bb->append(*insnPtr); // Close the current block if this is a branch diff --git a/backend/src/ir/context.hpp b/backend/src/ir/context.hpp index b4ef213..4bf4fd6 100644 --- a/backend/src/ir/context.hpp +++ b/backend/src/ir/context.hpp @@ -95,9 +95,9 @@ namespace ir { #define DECL_CMP(NAME) \ void NAME(Type type, \ - Register dst, \ - Register src0, \ - Register src1) \ + Register dst, \ + Register src0, \ + Register src1) \ { \ this->CMP(type, CMP_##NAME, dst, src0, src1); \ } @@ -120,11 +120,12 @@ DECL_CMP(GE) Function *fn; //!< Current function we are processing BasicBlock *bb; //!< Current basic block we are filling vector fnStack;//!< Stack of functions still to finish + GBE_CLASS(Context); }; template INLINE Tuple Context::tuple(Args...args) { - GBE_ASSERT(fn != NULL); + GBE_ASSERTM(fn != NULL, "No function currently defined"); return fn->file.appendTuple(args...); } @@ -132,7 +133,7 @@ DECL_CMP(GE) #define DECL_INSN(NAME, FAMILY) \ template \ INLINE void Context::NAME(Args...args) { \ - GBE_ASSERT(fn != NULL); \ + GBE_ASSERTM(fn != NULL, "No function currently defined"); \ const Instruction insn = gbe::ir::NAME(args...); \ this->append(insn); \ } diff --git a/backend/src/ir/function.cpp b/backend/src/ir/function.cpp index a319dba..cb5d700 100644 --- a/backend/src/ir/function.cpp +++ b/backend/src/ir/function.cpp @@ -32,6 +32,13 @@ namespace ir { for (auto it = blocks.begin(); it != blocks.end(); ++it) GBE_DELETE(*it); } + LabelIndex Function::newLabel(void) { + GBE_ASSERTM(labels.size() < 0xffff, + "Too many labels are defined (65536 only are supported)"); + const LabelIndex index(labels.size()); + labels.push_back(NULL); + return index; + } BasicBlock::BasicBlock(Function &fn) : fn(fn) {} BasicBlock::~BasicBlock(void) { for (auto it = instructions.begin(); it != instructions.end(); ++it) diff --git a/backend/src/ir/function.hpp b/backend/src/ir/function.hpp index 32cd8e2..f199b2f 100644 --- a/backend/src/ir/function.hpp +++ b/backend/src/ir/function.hpp @@ -76,7 +76,7 @@ namespace ir { } /*! Get the given value ie immediate from the function */ INLINE Immediate getImmediate(uint32_t ID) const { - GBE_ASSERT(ID < immediates.size()); + GBE_ASSERTM(ID < immediates.size(), "Out-of-bound immediate"); return immediates[ID]; } /*! Allocate a new instruction (with the growing pool) */ @@ -87,6 +87,8 @@ namespace ir { INLINE void deleteInstruction(Instruction *insn) { insnPool.deallocate(insn); } + /*! Create a new label (still not bound to a basic block) */ + LabelIndex newLabel(void); /*! Number of registers in the register file */ INLINE uint32_t regNum(void) const { return file.regNum(); } /*! Number of register tuples in the register file */ @@ -97,13 +99,13 @@ namespace ir { INLINE uint32_t immediateNum(void) const { return immediates.size(); } private: - friend class Context; //!< Can freely modify a function - vector input; //!< Input registers of the function - vector output; //!< Output registers of the function - vector labels; //!< Each label points to a basic block - vector immediates; //!< All immediate values in the function - vector blocks; //!< All chained basic blocks - RegisterFile file; //!< RegisterDatas used by the instructions + friend class Context; //!< Can freely modify a function + vector input; //!< Input registers of the function + vector output; //!< Output registers of the function + vector labels; //!< Each label points to a basic block + vector immediates; //!< All immediate values in the function + vector blocks; //!< All chained basic blocks + RegisterFile file; //!< RegisterDatas used by the instructions GrowingPool insnPool; //!< For fast instruction allocation GBE_CLASS(Function); }; diff --git a/backend/src/ir/instruction.cpp b/backend/src/ir/instruction.cpp index 45ab094..9393848 100644 --- a/backend/src/ir/instruction.cpp +++ b/backend/src/ir/instruction.cpp @@ -71,16 +71,16 @@ namespace ir { INLINE uint32_t getSrcNum(void) const { return srcNum; } INLINE uint32_t getDstNum(void) const { return 1; } INLINE Register getDstIndex(const Function &fn, uint32_t ID) const { - assert(ID == 0); + GBE_ASSERTM(ID == 0, "Only one destination for the instruction"); return dst; } INLINE Register getSrcIndex(const Function &fn, uint32_t ID) const { - assert(ID <= srcNum); + GBE_ASSERTM(ID < srcNum, "Out-of-bound source"); return src[ID]; } INLINE Type getType(void) const { return this->type; } INLINE bool wellFormed(const Function &fn, std::string &whyNot) const; - Type type; //!< Type of the instruction + Type type; //!< Type of the instruction Register dst; //!< Index of the register in the register file Register src[srcNum];//!< Indices of the sources }; @@ -136,16 +136,16 @@ namespace ir { INLINE uint32_t getSrcNum(void) const { return 3; } INLINE uint32_t getDstNum(void) const { return 1; } INLINE Register getDstIndex(const Function &fn, uint32_t ID) const { - assert(ID == 0); + GBE_ASSERTM(ID == 0, "Only one destination for the instruction"); return dst; } INLINE Register getSrcIndex(const Function &fn, uint32_t ID) const { - assert(ID <= 3); + GBE_ASSERTM(ID < 3, "Out-of-bound source register"); return fn.getRegister(src, ID); } INLINE Type getType(void) const { return this->type; } INLINE bool wellFormed(const Function &fn, std::string &whyNot) const; - Type type; //!< Type of the instruction + Type type; //!< Type of the instruction Register dst; //!< Dst is the register index Tuple src; //!< 3 sources do not fit in 8 bytes -> use a tuple }; @@ -191,18 +191,18 @@ namespace ir { INLINE uint32_t getSrcNum(void) const { return 1; } INLINE uint32_t getDstNum(void) const { return 1; } INLINE Register getDstIndex(const Function &fn, uint32_t ID) const { - assert(ID == 0); + GBE_ASSERTM(ID == 0, "Only one destination for the convert instruction"); return dst; } INLINE Register getSrcIndex(const Function &fn, uint32_t ID) const { - assert(ID == 0); + GBE_ASSERTM(ID == 0, "Only one source for the convert instruction"); return src; } INLINE bool wellFormed(const Function &fn, std::string &whyNot) const; Register dst; //!< Converted value Register src; //!< To convert - Type dstType; //!< Type to convert to - Type srcType; //!< Type to convert from + Type dstType; //!< Type to convert to + Type srcType; //!< Type to convert from }; class BranchInstruction : public BasePolicy, public NoDstPolicy @@ -221,14 +221,15 @@ namespace ir { } INLINE uint32_t getSrcNum(void) const { return hasPredicate ? 1 : 0; } INLINE Register getSrcIndex(const Function &fn, uint32_t ID) const { - assert(ID == 0 && hasPredicate); + GBE_ASSERTM(hasPredicate, "No source for unpredicated branches"); + GBE_ASSERTM(ID == 0, "Only one source for the branch instruction"); return predicate; } INLINE bool isPredicated(void) const { return hasPredicate; } INLINE bool wellFormed(const Function &fn, std::string &why) const; - Register predicate; //!< Predication means conditional branch - LabelIndex labelIndex; //!< Index of the label the branch targets - bool hasPredicate; //!< Is it predicated? + Register predicate; //!< Predication means conditional branch + LabelIndex labelIndex; //!< Index of the label the branch targets + bool hasPredicate; //!< Is it predicated? }; class LoadInstruction : public BasePolicy @@ -248,12 +249,12 @@ namespace ir { this->valueNum = valueNum; } INLINE Register getSrcIndex(const Function &fn, uint32_t ID) const { - assert(ID == 0u); + GBE_ASSERTM(ID == 0, "Only one source for the load instruction"); return offset; } INLINE uint32_t getSrcNum(void) const { return 1; } INLINE Register getDstIndex(const Function &fn, uint32_t ID) const { - assert(ID < valueNum); + GBE_ASSERTM(ID < valueNum, "Out-of-bound source register"); return fn.getRegister(values, ID); } INLINE uint32_t getDstNum(void) const { return valueNum; } @@ -262,10 +263,10 @@ namespace ir { INLINE MemorySpace getAddressSpace(void) const { return memSpace; } INLINE bool wellFormed(const Function &fn, std::string &why) const; Type type; //!< Type to store - Register offset; //!< First source is the offset where to store - Tuple values; //!< Values to load + Register offset; //!< First source is the offset where to store + Tuple values; //!< Values to load MemorySpace memSpace; //!< Where to store - uint16_t valueNum; //!< Number of values to store + uint16_t valueNum; //!< Number of values to store }; class StoreInstruction : public BasePolicy, public NoDstPolicy @@ -285,7 +286,7 @@ namespace ir { this->valueNum = valueNum; } INLINE Register getSrcIndex(const Function &fn, uint32_t ID) const { - assert(ID < valueNum + 1u); // offset + values to store + GBE_ASSERTM(ID < valueNum + 1u, "Out-of-bound source register for store"); if (ID == 0u) return offset; else @@ -297,8 +298,8 @@ namespace ir { INLINE MemorySpace getAddressSpace(void) const { return memSpace; } INLINE bool wellFormed(const Function &fn, std::string &why) const; Type type; //!< Type to store - Register offset; //!< First source is the offset where to store - Tuple values; //!< Values to store + Register offset; //!< First source is the offset where to store + Tuple values; //!< Values to store MemorySpace memSpace; //!< Where to store uint16_t valueNum; //!< Number of values to store }; @@ -327,14 +328,14 @@ namespace ir { } INLINE uint32_t getDstNum(void) const{ return 1; } INLINE Register getDstIndex(const Function &fn, uint32_t ID) const { - assert(ID == 0); + GBE_ASSERTM(ID == 0, "Only one destination is supported for load immediate"); return dst; } INLINE Type getType(void) const { return this->type; } bool wellFormed(const Function &fn, std::string &why) const; - Register dst; //!< RegisterData to store into - ImmediateIndex immediateIndex; //!< Index in the vector of immediates - Type type; //!< Type of the immediate + Register dst; //!< RegisterData to store into + ImmediateIndex immediateIndex; //!< Index in the vector of immediates + Type type; //!< Type of the immediate }; class FenceInstruction : public BasePolicy, public NoSrcPolicy, public NoDstPolicy @@ -355,6 +356,7 @@ namespace ir { this->opcode = OP_LABEL; this->labelIndex = labelIndex; } + INLINE LabelIndex getLabelIndex(void) const { return labelIndex; } INLINE bool wellFormed(const Function &fn, std::string &why) const; LabelIndex labelIndex; //!< Index of the label }; @@ -684,6 +686,7 @@ DECL_MEM_FN(LoadInstruction, uint32_t, getValueNum(void), getValueNum()) DECL_MEM_FN(LoadInstruction, MemorySpace, getAddressSpace(void), getAddressSpace()) DECL_MEM_FN(LoadImmInstruction, Immediate, getImmediate(const Function &fn), getImmediate(fn)) DECL_MEM_FN(LoadImmInstruction, Type, getType(void), getType()) +DECL_MEM_FN(LabelInstruction, LabelIndex, getLabelIndex(void), getLabelIndex()) DECL_MEM_FN(BranchInstruction, bool, isPredicated(void), isPredicated()) #undef DECL_MEM_FN diff --git a/backend/src/ir/instruction.hpp b/backend/src/ir/instruction.hpp index f6d0cd0..b140c81 100644 --- a/backend/src/ir/instruction.hpp +++ b/backend/src/ir/instruction.hpp @@ -201,9 +201,10 @@ namespace ir { }; /*! Load immediate instruction loads an typed immediate value into the given - * register. Since double and uint64_t values will not fit into an instruction, - * the immediate themselves are stored in the function core. Contrary to - * regular load instructions, there is only one destination possible + * register. Since double and uint64_t values will not fit into an + * instruction, the immediate themselves are stored in the function core. + * Contrary to regular load instructions, there is only one destination + * possible */ class LoadImmInstruction : public Instruction { public: @@ -224,12 +225,12 @@ namespace ir { bool isPredicated(void) const; /*! Return the predicate register (if predicated) */ RegisterData getPredicate(const Function &fn) const { - assert(this->isPredicated() == true); + GBE_ASSERTM(this->isPredicated() == true, "Branch is not predicated"); return this->getSrc(fn, 0); } /*! Return the predicate register index (if predicated) */ Register getPredicateIndex(const Function &fn) const { - assert(this->isPredicated() == true); + GBE_ASSERTM(this->isPredicated() == true, "Branch is not predicated"); return this->getSrcIndex(fn, 0); } /*! Return true if the given instruction is an instance of this class */ @@ -241,6 +242,8 @@ namespace ir { */ class LabelInstruction : public Instruction { public: + /*! Return the label index of the instruction */ + LabelIndex getLabelIndex(void) const; /*! Return true if the given instruction is an instance of this class */ static bool isClassOf(const Instruction &insn); }; @@ -266,22 +269,22 @@ namespace ir { */ template INLINE T *cast(Instruction *insn) { - assert(insn->isMemberOf() == true); + GBE_ASSERTM(insn->isMemberOf() == true, "Invalid instruction cast"); return reinterpret_cast(insn); } template INLINE const T *cast(const Instruction *insn) { - assert(insn->isMemberOf() == true); + GBE_ASSERTM(insn->isMemberOf() == true, "Invalid instruction cast"); return reinterpret_cast(insn); } template INLINE T &cast(Instruction &insn) { - assert(insn.isMemberOf() == true); + GBE_ASSERTM(insn.isMemberOf() == true, "Invalid instruction cast"); return reinterpret_cast(insn); } template INLINE const T &cast(const Instruction &insn) { - assert(insn.isMemberOf() == true); + GBE_ASSERTM(insn.isMemberOf() == true, "Invalid instruction cast"); return reinterpret_cast(insn); } diff --git a/backend/src/ir/register.hpp b/backend/src/ir/register.hpp index 63fa183..c6d355b 100644 --- a/backend/src/ir/register.hpp +++ b/backend/src/ir/register.hpp @@ -74,9 +74,10 @@ namespace ir { class RegisterFile { public: - /*! Return the index of a newly allocated register register */ + /*! Return the index of a newly allocated register */ INLINE Register append(RegisterData::Family family) { - GBE_ASSERT(regNum() <= MAX_INDEX); + GBE_ASSERTM(regNum() <= MAX_INDEX, + "Too many defined registers (only 65536 are supported)"); const uint16_t index = regNum(); const RegisterData reg(family); regs.push_back(reg); @@ -86,7 +87,7 @@ namespace ir { template INLINE Tuple appendTuple(First first, Rest... rest) { const Tuple index = Tuple(regTuples.size()); - GBE_ASSERT(first < regNum()); + GBE_ASSERTM(first < regNum(), "Out-of-bound register"); regTuples.push_back(first); appendTuple(rest...); return index; @@ -95,12 +96,13 @@ namespace ir { INLINE void appendTuple(void) {} /*! Return a copy of the register at index */ INLINE RegisterData get(Register index) const { - GBE_ASSERT(index < regNum()); + GBE_ASSERTM(index < regNum(), "Out-of-bound register"); return regs[index]; } /*! Get the register index from the tuple */ INLINE Register get(Tuple index, uint32_t which) const { - GBE_ASSERT(uint16_t(index) + which < regTuples.size()); + GBE_ASSERTM(uint16_t(index) + which < regTuples.size(), + "Out-of-bound index in the tuple file"); return regTuples[uint16_t(index) + which]; } /*! Number of registers in the register file */ @@ -108,9 +110,9 @@ namespace ir { /*! Number of tuples in the register file */ INLINE uint32_t tupleNum(void) const { return regTuples.size(); } private: - vector regs; //!< All the registers together - vector regTuples; //!< Tuples are used for many src / dst - enum { MAX_INDEX = 0xffff }; //!< register and tuple indices are short + vector regs; //!< All the registers together + vector regTuples; //!< Tuples are used for many src / dst + enum { MAX_INDEX = 0xffff }; //!< register and tuple indices are short GBE_CLASS(RegisterFile); }; diff --git a/backend/src/sys/assert.cpp b/backend/src/sys/assert.cpp index ff17f54..9d5ae2a 100644 --- a/backend/src/sys/assert.cpp +++ b/backend/src/sys/assert.cpp @@ -26,16 +26,21 @@ #include "assert.hpp" #include "exception.hpp" +#include + namespace gbe { - void onFailedAssert(const char *file, const char *fn, int line) + void onFailedAssertion(const char *msg, const char *file, const char *fn, int line) { char lineString[256]; sprintf(lineString, "%i", line); - const std::string msg = "file " + std::string(file) + assert(msg != NULL && file != NULL && fn != NULL); + const std::string str = "Compiler error: " + + std::string(msg) + "\n at file " + + std::string(file) + ", function " + std::string(fn) + ", line " + std::string(lineString); - throw Exception(msg); + throw Exception(str); } } /* namespace gbe */ @@ -48,10 +53,12 @@ namespace gbe namespace gbe { - void onFailedAssert(const char *file, const char *fn, int32_t line) + void onFailedAssertion(const char *msg, const char *file, const char *fn, int32_t line) { - fprintf(stderr, " ASSERTION FAILED: file %s, function %s, line %i\n", - file, fn, line); + assert(msg != NULL && file != NULL && fn != NULL); + fprintf(stderr, "ASSERTION FAILED: %s\n" + " at file %s, function %s, line %i\n", + msg, file, fn, line); fflush(stdout); DEBUGBREAK(); _exit(-1); diff --git a/backend/src/sys/assert.hpp b/backend/src/sys/assert.hpp index 9b031c0..553e391 100644 --- a/backend/src/sys/assert.hpp +++ b/backend/src/sys/assert.hpp @@ -28,7 +28,7 @@ namespace gbe { /*! To ensure that condition truth. Optional message is supported */ - void onFailedAssert(const char *file, const char *fn, int line); + void onFailedAssertion(const char *msg, const char *file, const char *fn, int line); } /* namespace gbe */ #endif /* __GBE_ASSERT_HPP__ */ diff --git a/backend/src/sys/platform.hpp b/backend/src/sys/platform.hpp index 88f217e..f74f7fc 100644 --- a/backend/src/sys/platform.hpp +++ b/backend/src/sys/platform.hpp @@ -209,12 +209,17 @@ /*! Run-time assertion */ #ifndef NDEBUG -#define GBE_ASSERT(EXPR) do { \ - if (UNLIKELY(!(EXPR))) \ - gbe::onFailedAssert(__FILE__, __FUNCTION__, __LINE__); \ +#define GBE_ASSERT(EXPR) do { \ + if (UNLIKELY(!(EXPR))) \ + gbe::onFailedAssertion(#EXPR, __FILE__, __FUNCTION__, __LINE__);\ +} while (0) +#define GBE_ASSERTM(EXPR, MSG) do { \ + if (UNLIKELY(!(EXPR))) \ + gbe::onFailedAssertion(MSG, __FILE__, __FUNCTION__, __LINE__); \ } while (0) #else #define GBE_ASSERT(EXPR) do { } while (0) +#define GBE_ASSERT_M(EXPR) do { } while (0) #endif /*! Fatal error macros */