namespace gbe {
namespace ir {
- Context::Context(Unit &unit) : unit(unit), fn(NULL), bb(NULL) {}
+ Context::Context(Unit &unit) :
+ unit(unit), fn(NULL), bb(NULL), usedLabels(NULL) {}
+
+ Context::~Context(void) {
+ for (auto it = fnStack.begin(); it != fnStack.end(); ++it)
+ GBE_SAFE_DELETE(it->usedLabels);
+ GBE_SAFE_DELETE(usedLabels);
+ }
void Context::startFunction(const std::string &name) {
- fnStack.push_back(StackElem(fn,bb));
+ fnStack.push_back(StackElem(fn,bb,usedLabels));
fn = unit.newFunction(name);
+ usedLabels = GBE_NEW(vector<uint8_t>);
+ bb = NULL;
}
void Context::endFunction(void) {
GBE_ASSERTM(fn != NULL, "No function to end");
GBE_ASSERT(fnStack.size() != 0);
+ GBE_ASSERT(usedLabels != NULL);
+
+ // Check first that all branch instructions point to valid labels
+ for (auto it = usedLabels->begin(); it != usedLabels->end(); ++it)
+ GBE_ASSERTM(*it != LABEL_IS_POINTED, "A label is used and not defined");
+
+ GBE_DELETE(usedLabels);
const StackElem elem = fnStack.back();
fnStack.pop_back();
fn = elem.fn;
bb = elem.bb;
+ usedLabels = elem.usedLabels;
}
Register Context::reg(RegisterData::Family family) {
LabelIndex Context::label(void) {
GBE_ASSERTM(fn != NULL, "No function currently defined");
- return fn->newLabel();
+ const LabelIndex index = fn->newLabel();
+ if (index >= usedLabels->size()) {
+ usedLabels->resize(index + 1);
+ (*usedLabels)[index] = 0;
+ }
+ return index;
}
void Context::input(Register reg) {
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;
+
+ // Now the label index is properly defined
+ GBE_ASSERT(index < usedLabels->size());
+ (*usedLabels)[index] |= LABEL_IS_DEFINED;
}
// 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 LabelIndex index = this->label();
const Instruction insn = ir::LABEL(index);
this->append(insn);
}
bb->append(*insnPtr);
// Close the current block if this is a branch
- if (insn.isMemberOf<BranchInstruction>() == true)
+ if (insn.isMemberOf<BranchInstruction>() == true) {
+ // We must book keep the fact that the label is used
+ if (insn.getOpcode() == OP_BRA) {
+ const BranchInstruction &branch = cast<BranchInstruction>(insn);
+ const LabelIndex index = branch.getLabelIndex();
+ GBE_ASSERT(index < usedLabels->size());
+ (*usedLabels)[index] |= LABEL_IS_POINTED;
+ }
this->endBlock();
+ }
}
} /* namespace ir */
public:
/*! Create a new context for this unit */
Context(Unit &unit);
+ /*! Free resources needed by context */
+ ~Context(void);
/*! Create a new function "name" */
void startFunction(const std::string &name);
/*! Close the function */
Unit &unit; //!< A unit is associated to a contect
Function *fn; //!< Current function we are processing
BasicBlock *bb; //!< Current basic block we are filling
+ static const uint8_t LABEL_IS_POINTED = 1 << 0; //!< Branch is using it
+ static const uint8_t LABEL_IS_DEFINED = 1 << 1; //!< Label is defining it
+ vector<uint8_t> *usedLabels;
/*! Functions can be defined recursiely */
struct StackElem {
- INLINE StackElem(Function *fn, BasicBlock *bb) : fn(fn), bb(bb) {}
- Function *fn;
- BasicBlock *bb;
+ INLINE StackElem(Function *fn, BasicBlock *bb, vector<uint8_t> *usedLabels)
+ : fn(fn), bb(bb), usedLabels(usedLabels)
+ {}
+ Function *fn; //!< Function to process
+ BasicBlock *bb; //!< Basic block currently processed
+ vector<uint8_t> *usedLabels; //!< Store all labels that are defined
};
vector<StackElem> fnStack; //!< Stack of functions still to finish
GBE_CLASS(Context);
* file
* 2 - branches point to basic blocks of the same function
*/
- class BasicBlock
+ class BasicBlock : public NonCopyable
{
public:
/*! Empty basic block */
friend class Function; //!< Owns the basic blocks
list<Instruction*> instructions; //!< Sequence of instructions in the block
Function &fn; //!< Function the block belongs to
+ GBE_CLASS(BasicBlock);
};
/*! A function is no more that a set of declared registers and a set of
* basic blocks
*/
- class Function
+ class Function : public NonCopyable
{
public:
/*! Create an empty function */
namespace ir {
///////////////////////////////////////////////////////////////////////////
- // Implements the concrete implementations of the instruction classes. We just
+ // Implements the concrete implementations of the instruction classes. We
// cast an instruction to an internal class to run the given member function
///////////////////////////////////////////////////////////////////////////
namespace internal
}
INLINE Type getType(void) const { return this->type; }
INLINE bool wellFormed(const Function &fn, std::string &whyNot) const;
- Type type; //!< Type of the instruction
- Register dst; //!< Index of the register in the register file
- Register src[srcNum];//!< Indices of the sources
+ Type type; //!< Type of the instruction
+ Register dst; //!< Index of the register in the register file
+ Register src[srcNum]; //!< Indices of the sources
};
/*! All 1-source arithmetic instructions */
}
INLINE Type getType(void) const { return this->type; }
INLINE bool wellFormed(const Function &fn, std::string &whyNot) const;
- 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
+ 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
};
/*! Comparison instructions take two sources of the same type and return a
* steal all the methods from it, except wellFormed (dst register is always
* a boolean value)
*/
- class ALIGNED_INSTRUCTION CompareInstruction : public NaryInstruction<2>
+ class ALIGNED_INSTRUCTION CompareInstruction :
+ public NaryInstruction<2>
{
public:
CompareInstruction(Opcode opcode,
INLINE bool wellFormed(const Function &fn, std::string &whyNot) const;
};
- class ConvertInstruction : public BasePolicy
+ class ALIGNED_INSTRUCTION ConvertInstruction :
+ public BasePolicy
{
public:
ConvertInstruction(Type dstType,
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
+ Register dst; //!< Converted value
+ Register src; //!< To convert
+ Type dstType; //!< Type to convert to
+ Type srcType; //!< Type to convert from
};
- class BranchInstruction : public BasePolicy, public NoDstPolicy
+ class ALIGNED_INSTRUCTION BranchInstruction :
+ public BasePolicy, public NoDstPolicy
{
public:
INLINE BranchInstruction(LabelIndex labelIndex, Register predicate) {
this->labelIndex = labelIndex;
this->hasPredicate = false;
}
+ INLINE LabelIndex getLabelIndex(void) const { return labelIndex; }
INLINE uint32_t getSrcNum(void) const { return hasPredicate ? 1 : 0; }
INLINE Register getSrcIndex(const Function &fn, uint32_t ID) const {
GBE_ASSERTM(hasPredicate, "No source for unpredicated branches");
DECL_MEM_FN(LoadImmInstruction, Type, getType(void), getType())
DECL_MEM_FN(LabelInstruction, LabelIndex, getLabelIndex(void), getLabelIndex())
DECL_MEM_FN(BranchInstruction, bool, isPredicated(void), isPredicated())
+DECL_MEM_FN(BranchInstruction, LabelIndex, getLabelIndex(void), getLabelIndex())
#undef DECL_MEM_FN
#include "ir/type.hpp"
#include "sys/platform.hpp"
+#include <ostream>
+
namespace gbe {
namespace ir {
char opaque[opaqueSize]; //!< Remainder of it
};
+ /*! To output the instruction in any stream */
+ std::ostream &operator<< (std::ostream &out, const Instruction &insn);
+
// Check that the instruction is properly formed by the compiler
static_assert(sizeof(Instruction)==sizeof(uint64_t), "Bad instruction size");
GBE_ASSERTM(this->isPredicated() == true, "Branch is not predicated");
return this->getSrcIndex(fn, 0);
}
+ /*! Return the label index pointed by the branch */
+ LabelIndex getLabelIndex(void) const;
/*! Return true if the given instruction is an instance of this class */
static bool isClassOf(const Instruction &insn);
};
/**
* \file unit.cpp
- *
* \author Benjamin Segovia <benjamin.segovia@intel.com>
*/
#include "ir/unit.hpp"
namespace gbe {
namespace ir {
- Unit::Unit(void) {}
+ Unit::Unit(PointerSize pointerSize) : pointerSize(pointerSize) {}
Unit::~Unit(void) {
for (auto it = functions.begin(); it != functions.end(); ++it)
GBE_DELETE(it->second);
/**
* \file unit.hpp
- *
* \author Benjamin Segovia <benjamin.segovia@intel.com>
*/
#ifndef __GBE_IR_UNIT_HPP__
// A unit contains a set of functions
class Function;
+ /*! Defines the size of the pointers. All the functions from the unit will
+ * use the same pointer size as the unit they belong to
+ */
+ enum PointerSize {
+ POINTER_32_BITS = 0,
+ POINTER_64_BITS = 1
+ };
+
/*! Complete unit of compilation. It contains a set of functions and a set of
* constant the functions may refer to.
*/
- class Unit
+ class Unit : public NonCopyable
{
public:
/*! Create an empty unit */
- Unit(void);
+ Unit(PointerSize pointerSize = POINTER_32_BITS);
/*! Release everything (*including* the function pointers) */
~Unit(void);
/*! Retrieve the function by its name */
void newConstant(const char*, const std::string&, uint32_t size, uint32_t alignment);
private:
hash_map<std::string, Function*> functions; //!< All the defined functions
- ConstantSet constantSet; //!< All the constants defined in the unit
+ ConstantSet constantSet; //!< All the constants defined in the unit
+ PointerSize pointerSize; //!< Size shared by all pointers
+ GBE_CLASS(Unit);
};
} /* namespace ir */
/**
* \file assert.cpp
- *
* \author Benjamin Segovia <benjamin.segovia@intel.com>
*/
#if GBE_COMPILE_UTESTS
ctx.MAD(TYPE_FLOAT, reg0, reg0, reg1, reg2);
ctx.startFunction("bip");
const LabelIndex label = ctx.label();
+ ctx.LABEL(label);
ctx.BRA(label);
ctx.endFunction();
ctx.endFunction();
ctx.LABEL(label);
ctx.endFunction();
}
+ static void labelNotDefined(void) {
+ Unit unit;
+ Context ctx(unit);
+ ctx.startFunction("hop");
+ const LabelIndex label = ctx.label();
+ ctx.BRA(label);
+ ctx.endFunction();
+ }
} /* namespace gbe */
static void utestContext(void)
UTEST_EXPECT_FAILED(gbe::noStartFunction());
UTEST_EXPECT_SUCCESS(gbe::recursiveDefinition());
UTEST_EXPECT_FAILED(gbe::labelUsedTwice());
+ UTEST_EXPECT_FAILED(gbe::labelNotDefined());
}
UTEST_REGISTER(utestContext)