Added support for output streams for functions
authorBenjamin Segovia <segovia.benjamin@gmail.com>
Tue, 21 Feb 2012 05:29:00 +0000 (05:29 +0000)
committerKeith Packard <keithp@keithp.com>
Fri, 10 Aug 2012 23:15:23 +0000 (16:15 -0700)
15 files changed:
backend/src/CMakeLists.txt
backend/src/blob.cpp
backend/src/ir/context.cpp
backend/src/ir/function.cpp
backend/src/ir/function.hpp
backend/src/ir/instruction.cpp
backend/src/ir/instruction.hpp
backend/src/ir/register.cpp
backend/src/ir/register.hpp
backend/src/ir/type.hpp
backend/src/ir/unit.cpp
backend/src/ir/value.hpp
backend/src/sys/string.hpp
backend/src/utest/utest.hpp
backend/src/utest/utest_context.cpp

index 3b61e1e..cbf34d6 100644 (file)
@@ -23,6 +23,8 @@ else (GBE_USE_BLOB)
     sys/platform.hpp
     ir/context.cpp
     ir/context.hpp
+    ir/type.cpp
+    ir/type.hpp
     ir/unit.cpp
     ir/unit.hpp
     ir/constant.cpp
@@ -34,22 +36,22 @@ else (GBE_USE_BLOB)
     ir/function.cpp
     ir/function.hpp)
 
-  if (GBE_COMPILE_UTEST)
+  if (GBE_COMPILE_UTESTS)
     set (GBE_SRC
       ${GBE_SRC}
       utest/utest_test_utest.cpp
       utest/utest_context.cpp
       utest/utest.cpp
       utest/utest.hpp)
-  endif (GBE_COMPILE_UTEST)
+  endif (GBE_COMPILE_UTESTS)
 endif (GBE_USE_BLOB)
 
 include_directories (.)
 add_library (gbe SHARED ${GBE_SRC})
 
-if (GBE_COMPILE_UTEST)
+if (GBE_COMPILE_UTESTS)
   set (TESTER_SRC utest/tester.cpp)
   add_executable (tester utest/tester.cpp)
   target_link_libraries (tester gbe)
-endif (GBE_COMPILE_UTEST)
+endif (GBE_COMPILE_UTESTS)
 
index 9a66689..9d308aa 100644 (file)
@@ -33,6 +33,7 @@
 #include "sys/condition.cpp"
 #include "sys/platform.cpp"
 #include "ir/context.cpp"
+#include "ir/type.cpp"
 #include "ir/unit.cpp"
 #include "ir/constant.cpp"
 #include "ir/instruction.cpp"
@@ -42,5 +43,6 @@
 #if GBE_COMPILE_UTESTS
 #include "utest/utest.cpp"
 #include "utest/utest_test_utest.cpp"
+#include "utest/utest_context.cpp"
 #endif /* GBE_COMPILE_UTESTS */
 
index e85d0b0..ffc7c8c 100644 (file)
@@ -78,13 +78,13 @@ namespace ir {
   void Context::input(Register reg) {
     GBE_ASSERTM(fn != NULL, "No function currently defined");
     GBE_ASSERTM(reg < fn->file.regNum(), "Out-of-bound register");
-    fn->input.push_back(reg);
+    fn->inputs.push_back(reg);
   }
 
   void Context::output(Register reg) {
     GBE_ASSERTM(fn != NULL, "No function currently defined");
     GBE_ASSERTM(reg < fn->file.regNum(), "Out-of-bound register");
-    fn->output.push_back(reg);
+    fn->outputs.push_back(reg);
   }
 
   void Context::startBlock(void) {
index cb5d700..a3efbf0 100644 (file)
 
 /**
  * \file function.cpp
- *
  * \author Benjamin Segovia <benjamin.segovia@intel.com>
  */
 #include "ir/function.hpp"
+#include "sys/string.hpp"
 
 namespace gbe {
 namespace ir {
 
-  Function::Function(void) {}
+  Function::Function(const std::string &name) : name(name) {}
+
   Function::~Function(void) {
     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)");
@@ -39,6 +41,52 @@ namespace ir {
     labels.push_back(NULL);
     return index;
   }
+
+  std::ostream &Function::outImmediate(std::ostream &out, ImmediateIndex index) const {
+    GBE_ASSERT(index < immediates.size());
+    const Immediate imm = immediates[index];
+    switch (imm.type) {
+      case TYPE_BOOL: return out << !!imm.data.u8;
+      case TYPE_S8: return out << imm.data.s8;
+      case TYPE_U8: return out << imm.data.u8;
+      case TYPE_S16: return out << imm.data.s16;
+      case TYPE_U16: return out << imm.data.u16;
+      case TYPE_S32: return out << imm.data.s32;
+      case TYPE_U32: return out << imm.data.u32;
+      case TYPE_S64: return out << imm.data.s64;
+      case TYPE_U64: return out << imm.data.u64;
+      case TYPE_HALF: return out << "half(" << imm.data.u16 << ")";
+      case TYPE_FLOAT: return out << imm.data.f32;
+      case TYPE_DOUBLE: return out << imm.data.f64;
+    };
+    return out;
+  }
+
+  std::ostream &operator<< (std::ostream &out, const Function &fn)
+  {
+    out << ".decl_function " << fn.getName() << std::endl << std::endl;
+    out << fn.getRegisterFile();
+    out << "## " << fn.inputNum() << " input register"
+        << plural(fn.inputNum())  << " ##" << std::endl;
+    for (uint32_t i = 0; i < fn.inputNum(); ++i)
+      out << "decl_input %" << fn.getInput(i) << std::endl;
+    out << "## " << fn.outputNum() << " output register"
+        << plural(fn.outputNum()) << " ##" << std::endl;
+    for (uint32_t i = 0; i < fn.outputNum(); ++i)
+      out << "decl_output %" << fn.getOutput(i) << std::endl;
+    out << "## " << fn.blockNum() << " block"
+        << plural(fn.blockNum()) << " ##" << std::endl;
+    for (uint32_t i = 0; i < fn.blockNum(); ++i) {
+      const BasicBlock &bb = fn.getBlock(i);
+      bb.map([&out, &fn] (const Instruction &insn) {
+        out << insn.proxy(fn) << std::endl;
+      });
+      out << std::endl;
+    }
+    out << ".end_function" << std::endl;
+    return out;
+  }
+
   BasicBlock::BasicBlock(Function &fn) : fn(fn) {}
   BasicBlock::~BasicBlock(void) {
     for (auto it = instructions.begin(); it != instructions.end(); ++it)
index b110259..0272dcd 100644 (file)
@@ -31,6 +31,8 @@
 #include "sys/list.hpp"
 #include "sys/alloc.hpp"
 
+#include <ostream>
+
 namespace gbe {
 namespace ir {
 
@@ -47,11 +49,15 @@ namespace ir {
     /*! Releases all the instructions */
     ~BasicBlock(void);
     /*! Append a new instruction in the stream */
-    void append(Instruction &insn) {
-      instructions.push_back(&insn);
-    }
+    void append(Instruction &insn) { instructions.push_back(&insn); }
     /*! Return the number of instruction in the block */
     INLINE uint32_t insnNum(void) { return instructions.size(); }
+    /*! Apply the given functor on all instructions */
+    template <typename T>
+    INLINE void map(const T &functor) const {
+      for (auto it = instructions.begin(); it != instructions.end(); ++it)
+        functor(**it);
+    }
   private:
     friend class Function;           //!< Owns the basic blocks
     list<Instruction*> instructions; //!< Sequence of instructions in the block
@@ -66,18 +72,22 @@ namespace ir {
   {
   public:
     /*! Create an empty function */
-    Function(void);
+    Function(const std::string &name);
     /*! Release everything *including* the basic block pointers */
     ~Function(void);
+    /*! Get the function name */
+    const std::string &getName(void) const { return name; }
     /*! Extract the register from the register file */
     INLINE RegisterData getRegisterData(Register ID) const { return file.get(ID); }
     /*! Get the register index from the tuple vector */
     INLINE Register getRegister(Tuple ID, uint32_t which) const {
       return file.get(ID, which);
     }
+    /*! Get the register file */
+    INLINE const RegisterFile &getRegisterFile(void) const { return file; }
     /*! Get the given value ie immediate from the function */
     INLINE Immediate getImmediate(uint32_t ID) const {
-      GBE_ASSERTM(ID < immediates.size(), "Out-of-bound immediate");
+      GBE_ASSERT(ID < immediateNum());
       return immediates[ID];
     }
     /*! Allocate a new instruction (with the growing pool) */
@@ -88,6 +98,22 @@ namespace ir {
     INLINE void deleteInstruction(Instruction *insn) {
       insnPool.deallocate(insn);
     }
+    /*! Get input register */
+    INLINE Register getInput(uint32_t ID) const {
+      GBE_ASSERT(ID < inputNum());
+      return inputs[ID];
+    }
+    /*! Get output register */
+    INLINE Register getOutput(uint32_t ID) const {
+      GBE_ASSERT(ID < outputNum());
+      return outputs[ID];
+    }
+    /*! Get block ID */
+    INLINE const BasicBlock &getBlock(uint32_t ID) const {
+      GBE_ASSERT(ID < blockNum());
+      GBE_ASSERT(blocks[ID] != NULL);
+      return *blocks[ID];
+    }
     /*! Create a new label (still not bound to a basic block) */
     LabelIndex newLabel(void);
     /*! Number of registers in the register file */
@@ -98,11 +124,19 @@ namespace ir {
     INLINE uint32_t labelNum(void) const { return labels.size(); }
     /*! Number of immediate values in the function */
     INLINE uint32_t immediateNum(void) const { return immediates.size(); }
-
+    /*! Get the number of input register */
+    INLINE uint32_t inputNum(void) const { return inputs.size(); }
+    /*! Get the number of output register */
+    INLINE uint32_t outputNum(void) const { return outputs.size(); }
+    /*! Number of blocks in the function */
+    INLINE uint32_t blockNum(void) const { return blocks.size(); }
+    /*! Output an immediate value in a stream */
+    std::ostream &outImmediate(std::ostream &out, ImmediateIndex index) const;
   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
+    std::string name;             //!< Function name
+    vector<Register> inputs;      //!< Input registers of the function
+    vector<Register> outputs;     //!< 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
@@ -111,6 +145,9 @@ namespace ir {
     GBE_CLASS(Function);
   };
 
+  /*! Output the function string in the given stream */
+  std::ostream &operator<< (std::ostream &out, const Function &fn);
+
 } /* namespace ir */
 } /* namespace gbe */
 
index 2fac8d5..d60dd35 100644 (file)
@@ -59,6 +59,15 @@ namespace ir {
       Instruction convert(void) const {
         return Instruction(reinterpret_cast<const char *>(&this->opcode));
       }
+      /*! Output the opcode in the given stream */
+      INLINE void outOpcode(std::ostream &out) const {
+        switch (opcode) {
+#define DECL_INSN(OPCODE, CLASS) case OP_##OPCODE: out << #OPCODE; break;
+#include "instruction.hxx"
+#undef DECL_INSN
+        };
+      }
+
       /*! Instruction opcode */
       Opcode opcode;
     };
@@ -80,6 +89,7 @@ namespace ir {
       }
       INLINE Type getType(void) const { return this->type; }
       INLINE bool wellFormed(const Function &fn, std::string &whyNot) const;
+      INLINE void out(std::ostream &out, const Function &fn) const;
       Type type;            //!< Type of the instruction
       Register dst;         //!< Index of the register in the register file
       Register src[srcNum]; //!< Indices of the sources
@@ -148,6 +158,7 @@ namespace ir {
       }
       INLINE Type getType(void) const { return this->type; }
       INLINE bool wellFormed(const Function &fn, std::string &whyNot) const;
+      INLINE void out(std::ostream &out, const Function &fn) 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
@@ -205,6 +216,7 @@ namespace ir {
         return src;
       }
       INLINE bool wellFormed(const Function &fn, std::string &whyNot) const;
+      INLINE void out(std::ostream &out, const Function &fn) const;
       Register dst; //!< Converted value
       Register src; //!< To convert
       Type dstType; //!< Type to convert to
@@ -235,6 +247,7 @@ namespace ir {
       }
       INLINE bool isPredicated(void) const { return hasPredicate; }
       INLINE bool wellFormed(const Function &fn, std::string &why) const;
+      INLINE void out(std::ostream &out, const Function &fn) const;
       Register predicate;    //!< Predication means conditional branch
       LabelIndex labelIndex; //!< Index of the label the branch targets
       bool hasPredicate;     //!< Is it predicated?
@@ -272,6 +285,7 @@ namespace ir {
       INLINE uint32_t getValueNum(void) const { return valueNum; }
       INLINE MemorySpace getAddressSpace(void) const { return memSpace; }
       INLINE bool wellFormed(const Function &fn, std::string &why) const;
+      INLINE void out(std::ostream &out, const Function &fn) const;
       Type type;            //!< Type to store
       Register offset;      //!< First source is the offset where to store
       Tuple values;         //!< Values to load
@@ -309,6 +323,7 @@ namespace ir {
       INLINE Type getValueType(void) const { return type; }
       INLINE MemorySpace getAddressSpace(void) const { return memSpace; }
       INLINE bool wellFormed(const Function &fn, std::string &why) const;
+      INLINE void out(std::ostream &out, const Function &fn) const;
       Type type;            //!< Type to store
       Register offset;      //!< First source is the offset where to store
       Tuple values;         //!< Values to store
@@ -322,19 +337,21 @@ namespace ir {
     public:
       INLINE TextureInstruction(void) { this->opcode = OP_TEX; }
       INLINE bool wellFormed(const Function &fn, std::string &why) const;
+      INLINE void out(std::ostream &out, const Function &fn) const {
+        this->outOpcode(out);
+        out << " ... TODO";
+      }
     };
 
     class ALIGNED_INSTRUCTION LoadImmInstruction :
       public BasePolicy, public NoSrcPolicy
     {
     public:
-      INLINE LoadImmInstruction(Type type,
-                                Register dst,
-                                ImmediateIndex immediateIndex)
+      INLINE LoadImmInstruction(Type type, Register dst, ImmediateIndex index)
       {
         this->dst = dst;
         this->opcode = OP_LOADI;
-        this->immediateIndex = immediateIndex;
+        this->immediateIndex = index;
         this->type = type;
       }
       INLINE Immediate getImmediate(const Function &fn) const {
@@ -347,6 +364,7 @@ namespace ir {
       }
       INLINE Type getType(void) const { return this->type; }
       bool wellFormed(const Function &fn, std::string &why) const;
+      INLINE void out(std::ostream &out, const Function &fn) const;
       Register dst;                  //!< RegisterData to store into
       ImmediateIndex immediateIndex; //!< Index in the vector of immediates
       Type type;                     //!< Type of the immediate
@@ -361,6 +379,10 @@ namespace ir {
         this->memSpace = memSpace;
       }
       bool wellFormed(const Function &fn, std::string &why) const;
+      INLINE void out(std::ostream &out, const Function &fn) const {
+        this->outOpcode(out);
+        out << "." << memSpace;
+      }
       MemorySpace memSpace; //!< The loads and stores to order
     };
 
@@ -374,6 +396,7 @@ namespace ir {
       }
       INLINE LabelIndex getLabelIndex(void) const { return labelIndex; }
       INLINE bool wellFormed(const Function &fn, std::string &why) const;
+      INLINE void out(std::ostream &out, const Function &fn) const;
       LabelIndex labelIndex;  //!< Index of the label
     };
 
@@ -387,9 +410,9 @@ namespace ir {
      *  defined (i.e. not out-of-bound)
      */
     static INLINE bool checkRegisterData(RegisterData::Family family,
-                                     const Register ID,
-                                     const Function &fn,
-                                     std::string &whyNot)
+                                         const Register ID,
+                                         const Function &fn,
+                                         std::string &whyNot)
     {
       if (UNLIKELY(uint16_t(ID) >= fn.regNum())) {
         whyNot = "Out-of-bound destination register index";
@@ -543,8 +566,85 @@ namespace ir {
       return true;
     }
 
+    /////////////////////////////////////////////////////////////////////////
+    // Implements all the output stream methods
+    /////////////////////////////////////////////////////////////////////////
+    template <uint32_t srcNum>
+    INLINE void NaryInstruction<srcNum>::out(std::ostream &out, const Function &fn) const {
+      this->outOpcode(out);
+      out << "." << this->getType()
+          << " %" << this->getDstIndex(fn, 0);
+      for (uint32_t i = 0; i < srcNum; ++i)
+        out << " %" << this->getSrcIndex(fn, i);
+    }
+
+    INLINE void TernaryInstruction::out(std::ostream &out, const Function &fn) const {
+      this->outOpcode(out);
+      out << "." << this->getType()
+          << " %" << this->getDstIndex(fn, 0)
+          << " %" << this->getSrcIndex(fn, 0)
+          << " %" << this->getSrcIndex(fn, 1)
+          << " %" << this->getSrcIndex(fn, 2);
+    }
+
+    INLINE void ConvertInstruction::out(std::ostream &out, const Function &fn) const {
+      this->outOpcode(out);
+      out << "." << this->getDstType()
+          << "." << this->getSrcType()
+          << " %" << this->getDstIndex(fn, 0)
+          << " %" << this->getSrcIndex(fn, 0)
+          << " %" << this->getSrcIndex(fn, 1);
+    }
+
+    INLINE void LoadInstruction::out(std::ostream &out, const Function &fn) const {
+      this->outOpcode(out);
+      out << "." << type << "." << memSpace << " {";
+      for (uint32_t i = 0; i < valueNum; ++i)
+        out << this->getDstIndex(fn, i);
+      out << "}";
+      out << " %" << this->getSrcIndex(fn, 0);
+    }
+
+    INLINE void StoreInstruction::out(std::ostream &out, const Function &fn) const {
+      this->outOpcode(out);
+      out << "." << type << "." << memSpace;
+      out << " %" << this->getSrcIndex(fn, 0) << " {";
+      for (uint32_t i = 0; i < valueNum; ++i)
+        out << this->getSrcIndex(fn, i+1);
+      out << "}";
+    }
+
+    INLINE void LabelInstruction::out(std::ostream &out, const Function &fn) const {
+      this->outOpcode(out);
+      out << " $" << labelIndex;
+    }
+
+    INLINE void BranchInstruction::out(std::ostream &out, const Function &fn) const {
+      this->outOpcode(out);
+      if (hasPredicate)
+        out << "<%" << this->getSrcIndex(fn, 0) << ">";
+      out << " -> label$" << labelIndex;
+    }
+
+    INLINE void LoadImmInstruction::out(std::ostream &out, const Function &fn) const {
+      this->outOpcode(out);
+      out << "." << type;
+      out << " %" << this->getSrcIndex(fn,0);
+      out << " " << fn.outImmediate(out, immediateIndex);
+    }
+
   } /* namespace internal */
 
+  std::ostream &operator<< (std::ostream &out, MemorySpace memSpace) {
+    switch (memSpace) {
+      case MEM_GLOBAL: return out << "global";
+      case MEM_LOCAL: return out << "local";
+      case MEM_CONSTANT: return out << "constant";
+      case MEM_PRIVATE: return out << "private";
+    };
+    return out;
+  }
+
   ///////////////////////////////////////////////////////////////////////////
   // Implements the various instrospection functions
   ///////////////////////////////////////////////////////////////////////////
@@ -681,6 +781,7 @@ START_FUNCTION(Instruction, bool, wellFormed(const Function &fn, std::string &wh
 END_FUNCTION(Instruction, bool)
 #undef CALL
 
+#undef DECL_INSN
 #undef END_FUNCTION
 #undef START_FUNCTION
 
@@ -777,23 +878,23 @@ DECL_MEM_FN(BranchInstruction, LabelIndex, getLabelIndex(void), getLabelIndex())
 
   // CVT
   Instruction CVT(Type dstType, Type srcType, Register dst, Register src) {
-    internal::ConvertInstruction insn(dstType, srcType, dst, src);
+    const internal::ConvertInstruction insn(dstType, srcType, dst, src);
     return insn.convert();
   }
 
   // BRA
   Instruction BRA(LabelIndex labelIndex) {
-    internal::BranchInstruction insn(labelIndex);
+    const internal::BranchInstruction insn(labelIndex);
     return insn.convert();
   }
   Instruction BRA(LabelIndex labelIndex, Register pred) {
-    internal::BranchInstruction insn(labelIndex, pred);
+    const internal::BranchInstruction insn(labelIndex, pred);
     return insn.convert();
   }
 
   // LOADI
   Instruction LOADI(Type type, Register dst, ImmediateIndex value) {
-    internal::LoadImmInstruction insn(type, dst, value);
+    const internal::LoadImmInstruction insn(type, dst, value);
     return insn.convert();
   }
 
@@ -826,6 +927,21 @@ DECL_MEM_FN(BranchInstruction, LabelIndex, getLabelIndex(void), getLabelIndex())
     return insn.convert();
   }
 
+  std::ostream &operator<< (std::ostream &out, const Instruction::Proxy &proxy)
+  {
+    const Instruction &insn = proxy.insn;
+    const Function &fn = proxy.fn;
+    switch (insn.getOpcode()) {
+#define DECL_INSN(OPCODE, CLASS)                                     \
+      case OP_##OPCODE:                                              \
+        reinterpret_cast<const internal::CLASS&>(insn).out(out, fn); \
+        break;
+#include "instruction.hxx"
+#undef DECL_INSN
+    };
+    return out;
+  }
+
 } /* namespace ir */
 } /* namespace gbe */
 
index dff2543..7c7aed7 100644 (file)
@@ -49,6 +49,9 @@ namespace ir {
     MEM_PRIVATE     //!< Per thread private memory
   };
 
+  /*! Output the memory space */
+  std::ostream &operator<< (std::ostream &out, MemorySpace memSpace);
+
   /*! A label is identified with an unsigned short */
   TYPE_SAFE(LabelIndex, uint16_t)
 
@@ -101,14 +104,27 @@ namespace ir {
     template <typename T> INLINE bool isMemberOf(void) const {
       return T::isClassOf(*this);
     }
+    /*! Since we need the function to get all the instruction information, we
+     *  build a small temporary structure to forward both the instruction and
+     *  the function
+     */
+    struct Proxy {
+      INLINE Proxy(const Function &fn, const Instruction &insn) :
+        fn(fn), insn(insn) {}
+      const Function &fn;
+      const Instruction &insn;
+    };
+    /*! Build a proxy from the instruction */
+    INLINE Proxy proxy(const Function &fn) const { return Proxy(fn, *this); }
+
   protected:
     enum { opaqueSize = sizeof(uint64_t)-sizeof(uint8_t) };
     Opcode opcode;           //!< Idendifies the instruction
     char opaque[opaqueSize]; //!< Remainder of it
   };
 
-  /*! To output the instruction in any stream */
-  std::ostream &operator<< (std::ostream &out, const Instruction &insn);
+  /*! Output the instruction string in the given stream */
+  std::ostream &operator<< (std::ostream &out, const Instruction::Proxy &proxy);
 
   // Check that the instruction is properly formed by the compiler
   static_assert(sizeof(Instruction)==sizeof(uint64_t), "Bad instruction size");
index 1876371..25e20ba 100644 (file)
 
 /**
  * \file register.cpp
- *
  * \author Benjamin Segovia <benjamin.segovia@intel.com>
  */
 #include "ir/register.hpp"
+#include "sys/string.hpp"
 
 namespace gbe {
 namespace ir {
+
+  std::ostream &operator<< (std::ostream &out, const RegisterData &regData)
+  {
+    switch (regData.family) {
+      case RegisterData::BOOL: return out << "bool";
+      case RegisterData::BYTE: return out << "byte";
+      case RegisterData::WORD: return out << "word";
+      case RegisterData::DWORD: return out << "dword";
+      case RegisterData::QWORD: return out << "qword";
+    };
+    return out;
+  }
+
+  std::ostream &operator<< (std::ostream &out, const RegisterFile &file)
+  {
+    out << "## " << file.regNum() << " register"
+        << plural(file.regNum()) << " ##" << std::endl;
+    for (uint32_t i = 0; i < file.regNum(); ++i) {
+      const RegisterData reg = file.get(Register(i));
+      out << ".decl." << reg << " %" << i << std::endl;
+    }
+    return out;
+  }
+
 } /* namespace ir */
 } /* namespace gbe */
 
index c6d355b..81f769d 100644 (file)
@@ -58,6 +58,9 @@ namespace ir {
     GBE_CLASS(RegisterData);
   };
 
+  /*! Output the register file string in the given stream */
+  std::ostream &operator<< (std::ostream &out, const RegisterData &regData);
+
   /*! Register is the position of the index of the register data in the register
    *  file. We enforce type safety with this class
    */
@@ -116,6 +119,9 @@ namespace ir {
     GBE_CLASS(RegisterFile);
   };
 
+  /*! Output the register file string in the given stream */
+  std::ostream &operator<< (std::ostream &out, const RegisterFile &file);
+
 } /* namespace ir */
 } /* namespace gbe */
 
index 1607c7d..ef8f2cf 100644 (file)
@@ -28,6 +28,8 @@
 #include "sys/platform.hpp"
 #include "ir/register.hpp"
 
+#include <ostream>
+
 namespace gbe {
 namespace ir {
 
@@ -47,6 +49,9 @@ namespace ir {
     TYPE_DOUBLE    //!< 64 bits floating point value
   };
 
+  /*! Output a string for the type in the given stream */
+  std::ostream &operator<< (std::ostream &out, const Type &type);
+
   /*! Get the register family for each type */
   INLINE RegisterData::Family getFamily(Type type) {
     switch (type) {
index 5ce3a91..0e5cc73 100644 (file)
@@ -42,7 +42,7 @@ namespace ir {
     auto it = functions.find(name);
     if (it != functions.end())
       return NULL;
-    Function *fn = GBE_NEW(Function);
+    Function *fn = GBE_NEW(Function, name);
     functions[name] = fn;
     return fn;
   }
index f5aa72e..b4cdf3d 100644 (file)
@@ -43,11 +43,11 @@ namespace ir {
     union {
       int8_t s8;
       uint8_t u8;
-      int16_t i16;
+      int16_t s16;
       uint16_t u16;
-      int32_t i32;
+      int32_t s32;
       uint32_t u32;
-      int64_t i64;
+      int64_t s64;
       uint64_t u64;
       float f32;
       double f64;
index 19281a3..2b2883a 100644 (file)
@@ -31,6 +31,7 @@
 #include <string>
 #include <sstream>
 #include <fstream>
+#include <ostream>
 
 namespace std
 {
@@ -49,6 +50,8 @@ namespace gbe
   bool contains(const char *haystack, const char *needle);
   /*! Tokenize a string (like strtok_r does) */
   char* tokenize(char *s1, const char *s2, char **lasts);
+  /*! To append s or not */
+  INLINE const char *plural(uint32_t value) { return value > 1 ? "s" : ""; }
 } /* namespace gbe */
 
 #endif /* __GBE_STRING_HPP__ */
index 8581559..d65ff4b 100644 (file)
@@ -55,7 +55,7 @@ namespace gbe
 } /* namespace gbe */
 
 /*! RegisterData a new unit test */
-#define UTEST_REGISTER(FN) static const gbe::UTest __##NAME##__(FN, #FN);
+#define UTEST_REGISTER(FN) static const gbe::UTest __##FN##__(FN, #FN);
 
 /*! No assert is expected */
 #define UTEST_EXPECT_SUCCESS(EXPR)                                  \
index 725455b..34c4eba 100644 (file)
@@ -65,6 +65,10 @@ namespace gbe
         ctx.BRA(label);
       ctx.endFunction();
     ctx.endFunction();
+#if 0
+    std::cout << *unit.getFunction("hop") << std::endl;
+    std::cout << *unit.getFunction("bip") << std::endl;
+#endif
   }
   static void labelUsedTwice(void) {
     Unit unit;