From ae2c8a1c107b83498af3496a171f4f3e5a08cb2f Mon Sep 17 00:00:00 2001 From: Benjamin Segovia Date: Mon, 20 Feb 2012 06:45:16 +0000 Subject: [PATCH] Added more tests --- backend/src/ir/context.cpp | 44 ++++++++++++++++++++++++++++++++----- backend/src/ir/context.hpp | 14 +++++++++--- backend/src/ir/function.hpp | 5 +++-- backend/src/ir/instruction.cpp | 33 ++++++++++++++++------------ backend/src/ir/instruction.hpp | 7 ++++++ backend/src/ir/unit.cpp | 3 +-- backend/src/ir/unit.hpp | 17 ++++++++++---- backend/src/sys/assert.cpp | 1 - backend/src/utest/utest_context.cpp | 10 +++++++++ 9 files changed, 103 insertions(+), 31 deletions(-) diff --git a/backend/src/ir/context.cpp b/backend/src/ir/context.cpp index d08c50d..e85d0b0 100644 --- a/backend/src/ir/context.cpp +++ b/backend/src/ir/context.cpp @@ -27,20 +27,37 @@ 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); + 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) { @@ -50,7 +67,12 @@ namespace ir { 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) { @@ -87,11 +109,15 @@ namespace ir { 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); } @@ -106,8 +132,16 @@ namespace ir { bb->append(*insnPtr); // Close the current block if this is a branch - if (insn.isMemberOf() == true) + if (insn.isMemberOf() == true) { + // We must book keep the fact that the label is used + if (insn.getOpcode() == OP_BRA) { + const BranchInstruction &branch = cast(insn); + const LabelIndex index = branch.getLabelIndex(); + GBE_ASSERT(index < usedLabels->size()); + (*usedLabels)[index] |= LABEL_IS_POINTED; + } this->endBlock(); + } } } /* namespace ir */ diff --git a/backend/src/ir/context.hpp b/backend/src/ir/context.hpp index da37e40..70d5c90 100644 --- a/backend/src/ir/context.hpp +++ b/backend/src/ir/context.hpp @@ -44,6 +44,8 @@ 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 */ @@ -105,11 +107,17 @@ namespace ir { 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 *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 *usedLabels) + : fn(fn), bb(bb), usedLabels(usedLabels) + {} + Function *fn; //!< Function to process + BasicBlock *bb; //!< Basic block currently processed + vector *usedLabels; //!< Store all labels that are defined }; vector fnStack; //!< Stack of functions still to finish GBE_CLASS(Context); diff --git a/backend/src/ir/function.hpp b/backend/src/ir/function.hpp index f199b2f..b110259 100644 --- a/backend/src/ir/function.hpp +++ b/backend/src/ir/function.hpp @@ -39,7 +39,7 @@ namespace ir { * file * 2 - branches point to basic blocks of the same function */ - class BasicBlock + class BasicBlock : public NonCopyable { public: /*! Empty basic block */ @@ -56,12 +56,13 @@ namespace ir { friend class Function; //!< Owns the basic blocks list 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 */ diff --git a/backend/src/ir/instruction.cpp b/backend/src/ir/instruction.cpp index ba8006f..2fac8d5 100644 --- a/backend/src/ir/instruction.cpp +++ b/backend/src/ir/instruction.cpp @@ -28,7 +28,7 @@ namespace gbe { 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 @@ -80,9 +80,9 @@ namespace ir { } 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 */ @@ -148,9 +148,9 @@ namespace ir { } 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 @@ -158,7 +158,8 @@ namespace ir { * 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, @@ -176,7 +177,8 @@ namespace ir { INLINE bool wellFormed(const Function &fn, std::string &whyNot) const; }; - class ConvertInstruction : public BasePolicy + class ALIGNED_INSTRUCTION ConvertInstruction : + public BasePolicy { public: ConvertInstruction(Type dstType, @@ -203,13 +205,14 @@ namespace ir { 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) { @@ -223,6 +226,7 @@ namespace ir { 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"); @@ -701,6 +705,7 @@ DECL_MEM_FN(LoadImmInstruction, Immediate, getImmediate(const Function &fn), get 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 diff --git a/backend/src/ir/instruction.hpp b/backend/src/ir/instruction.hpp index f16eb1b..dff2543 100644 --- a/backend/src/ir/instruction.hpp +++ b/backend/src/ir/instruction.hpp @@ -29,6 +29,8 @@ #include "ir/type.hpp" #include "sys/platform.hpp" +#include + namespace gbe { namespace ir { @@ -105,6 +107,9 @@ 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"); @@ -221,6 +226,8 @@ namespace ir { 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); }; diff --git a/backend/src/ir/unit.cpp b/backend/src/ir/unit.cpp index 338f7d5..5ce3a91 100644 --- a/backend/src/ir/unit.cpp +++ b/backend/src/ir/unit.cpp @@ -19,7 +19,6 @@ /** * \file unit.cpp - * * \author Benjamin Segovia */ #include "ir/unit.hpp" @@ -28,7 +27,7 @@ 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); diff --git a/backend/src/ir/unit.hpp b/backend/src/ir/unit.hpp index cc8c101..accad83 100644 --- a/backend/src/ir/unit.hpp +++ b/backend/src/ir/unit.hpp @@ -19,7 +19,6 @@ /** * \file unit.hpp - * * \author Benjamin Segovia */ #ifndef __GBE_IR_UNIT_HPP__ @@ -34,14 +33,22 @@ namespace ir { // 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 */ @@ -52,7 +59,9 @@ namespace ir { void newConstant(const char*, const std::string&, uint32_t size, uint32_t alignment); private: hash_map 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 */ diff --git a/backend/src/sys/assert.cpp b/backend/src/sys/assert.cpp index 9d5ae2a..0a0eccd 100644 --- a/backend/src/sys/assert.cpp +++ b/backend/src/sys/assert.cpp @@ -19,7 +19,6 @@ /** * \file assert.cpp - * * \author Benjamin Segovia */ #if GBE_COMPILE_UTESTS diff --git a/backend/src/utest/utest_context.cpp b/backend/src/utest/utest_context.cpp index 69d8efd..725455b 100644 --- a/backend/src/utest/utest_context.cpp +++ b/backend/src/utest/utest_context.cpp @@ -61,6 +61,7 @@ namespace gbe 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(); @@ -74,6 +75,14 @@ namespace gbe 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) @@ -83,6 +92,7 @@ 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) -- 2.7.4