}
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();
}
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);
}
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<LabelInstruction>() == true) {
this->endBlock();
this->startBlock();
+ const LabelIndex index = cast<LabelInstruction>(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
#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); \
}
Function *fn; //!< Current function we are processing
BasicBlock *bb; //!< Current basic block we are filling
vector<Function*> fnStack;//!< Stack of functions still to finish
+ GBE_CLASS(Context);
};
template <typename... Args>
INLINE Tuple Context::tuple(Args...args) {
- GBE_ASSERT(fn != NULL);
+ GBE_ASSERTM(fn != NULL, "No function currently defined");
return fn->file.appendTuple(args...);
}
#define DECL_INSN(NAME, FAMILY) \
template <typename... Args> \
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); \
}
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)
}
/*! 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) */
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 */
INLINE uint32_t immediateNum(void) const { return immediates.size(); }
private:
- friend class Context; //!< Can freely modify a function
- vector<Register> input; //!< Input registers of the function
- vector<Register> output; //!< Output registers of the function
- vector<BasicBlock*> labels; //!< Each label points to a basic block
- vector<Immediate> immediates; //!< All immediate values in the function
- vector<BasicBlock*> blocks; //!< All chained basic blocks
- RegisterFile file; //!< RegisterDatas used by the instructions
+ friend class Context; //!< Can freely modify a function
+ vector<Register> input; //!< Input registers of the function
+ vector<Register> output; //!< Output registers of the function
+ vector<BasicBlock*> labels; //!< Each label points to a basic block
+ vector<Immediate> immediates; //!< All immediate values in the function
+ vector<BasicBlock*> blocks; //!< All chained basic blocks
+ RegisterFile file; //!< RegisterDatas used by the instructions
GrowingPool<Instruction> insnPool; //!< For fast instruction allocation
GBE_CLASS(Function);
};
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
};
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
};
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
}
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
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; }
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
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
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
};
}
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
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
};
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
};
/*! 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:
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 */
*/
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);
};
*/
template <typename T>
INLINE T *cast(Instruction *insn) {
- assert(insn->isMemberOf<T>() == true);
+ GBE_ASSERTM(insn->isMemberOf<T>() == true, "Invalid instruction cast");
return reinterpret_cast<T*>(insn);
}
template <typename T>
INLINE const T *cast(const Instruction *insn) {
- assert(insn->isMemberOf<T>() == true);
+ GBE_ASSERTM(insn->isMemberOf<T>() == true, "Invalid instruction cast");
return reinterpret_cast<const T*>(insn);
}
template <typename T>
INLINE T &cast(Instruction &insn) {
- assert(insn.isMemberOf<T>() == true);
+ GBE_ASSERTM(insn.isMemberOf<T>() == true, "Invalid instruction cast");
return reinterpret_cast<T&>(insn);
}
template <typename T>
INLINE const T &cast(const Instruction &insn) {
- assert(insn.isMemberOf<T>() == true);
+ GBE_ASSERTM(insn.isMemberOf<T>() == true, "Invalid instruction cast");
return reinterpret_cast<const T&>(insn);
}
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);
template <typename First, typename... Rest>
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;
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 */
/*! Number of tuples in the register file */
INLINE uint32_t tupleNum(void) const { return regTuples.size(); }
private:
- vector<RegisterData> regs; //!< All the registers together
- vector<Register> regTuples; //!< Tuples are used for many src / dst
- enum { MAX_INDEX = 0xffff }; //!< register and tuple indices are short
+ vector<RegisterData> regs; //!< All the registers together
+ vector<Register> regTuples; //!< Tuples are used for many src / dst
+ enum { MAX_INDEX = 0xffff }; //!< register and tuple indices are short
GBE_CLASS(RegisterFile);
};
#include "assert.hpp"
#include "exception.hpp"
+#include <cassert>
+
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 */
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);
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__ */
/*! 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 */