Added more tests
authorBenjamin Segovia <segovia.benjamin@gmail.com>
Mon, 20 Feb 2012 06:45:16 +0000 (06:45 +0000)
committerKeith Packard <keithp@keithp.com>
Fri, 10 Aug 2012 23:15:23 +0000 (16:15 -0700)
backend/src/ir/context.cpp
backend/src/ir/context.hpp
backend/src/ir/function.hpp
backend/src/ir/instruction.cpp
backend/src/ir/instruction.hpp
backend/src/ir/unit.cpp
backend/src/ir/unit.hpp
backend/src/sys/assert.cpp
backend/src/utest/utest_context.cpp

index d08c50d..e85d0b0 100644 (file)
 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) {
@@ -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<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 */
index da37e40..70d5c90 100644 (file)
@@ -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<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);
index f199b2f..b110259 100644 (file)
@@ -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<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 */
index ba8006f..2fac8d5 100644 (file)
@@ -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
 
index f16eb1b..dff2543 100644 (file)
@@ -29,6 +29,8 @@
 #include "ir/type.hpp"
 #include "sys/platform.hpp"
 
+#include <ostream>
+
 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);
   };
index 338f7d5..5ce3a91 100644 (file)
@@ -19,7 +19,6 @@
 
 /**
  * \file unit.cpp
- *
  * \author Benjamin Segovia <benjamin.segovia@intel.com>
  */
 #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);
index cc8c101..accad83 100644 (file)
@@ -19,7 +19,6 @@
 
 /**
  * \file unit.hpp
- *
  * \author Benjamin Segovia <benjamin.segovia@intel.com>
  */
 #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<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 */
index 9d5ae2a..0a0eccd 100644 (file)
@@ -19,7 +19,6 @@
 
 /**
  * \file assert.cpp
- *
  * \author Benjamin Segovia <benjamin.segovia@intel.com>
  */
 #if GBE_COMPILE_UTESTS
index 69d8efd..725455b 100644 (file)
@@ -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)