Added more functionalities for the context Started to implement wellFormed function...
authorBenjamin Segovia <segovia.benjamin@gmail.com>
Mon, 13 Feb 2012 19:04:16 +0000 (19:04 +0000)
committerKeith Packard <keithp@keithp.com>
Fri, 10 Aug 2012 23:15:16 +0000 (16:15 -0700)
backend/CMakeLists.txt
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/register.hpp
backend/src/ir/type.hpp
backend/src/sys/platform.hpp

index 81274c4..1ff20a6 100644 (file)
@@ -48,7 +48,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
   set (VISIBILITY_FLAG "-fvisibility=hidden")
 
   if (COMPILER STREQUAL "GCC")
-    set (CMAKE_CXX_FLAGS "-Wstrict-aliasing=2 -Wno-invalid-offsetof -fno-strict-aliasing -msse2 -ffast-math -fPIC -Wall -fno-rtti -std=c++0x")
+    set (CMAKE_CXX_FLAGS "-Wstrict-aliasing=2 -Wno-invalid-offsetof -fstrict-aliasing -msse2 -ffast-math -fPIC -Wall -fno-rtti -std=c++0x")
     set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GBE_DEBUG_MEMORY_FLAG}")
     set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GBE_COMPILE_UTESTS_FLAG}")
     set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${VISIBILITY_FLAG} -Wl,-E")
@@ -64,7 +64,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
     set (CMAKE_C_FLAGS_RELEASE        "-O3 -DNDEBUG")
     set (CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g")
     set (CMAKE_CXX_COMPILER             "clang++")
-    set (CMAKE_CXX_FLAGS "-fno-strict-aliasing -msse2 -ffast-math -fPIC -Wall -Wno-format-security -Wno-invalid-offsetof -std=c++0x")
+    set (CMAKE_CXX_FLAGS "-fstrict-aliasing -msse2 -ffast-math -fPIC -Wall -Wno-format-security -Wno-invalid-offsetof -std=c++0x")
     set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GBE_DEBUG_MEMORY_FLAG}")
     set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GBE_COMPILE_UTESTS_FLAG}")
     set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${VISIBILITY_FLAG}")
@@ -80,7 +80,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
   elseif (COMPILER STREQUAL "ICC")
     set (CMAKE_CXX_COMPILER "icpc")
     set (CMAKE_C_COMPILER "icc")
-    set (CMAKE_CXX_FLAGS "-std=c++0x -wd2928 -Wall -fPIC -fno-strict-aliasing -fp-model fast -xSSE2")
+    set (CMAKE_CXX_FLAGS "-std=c++0x -wd2928 -Wall -fPIC -fstrict-aliasing -fp-model fast -xSSE2")
     set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GBE_DEBUG_MEMORY_FLAG}")
     set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GBE_COMPILE_UTESTS_FLAG}")
     set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${VISIBILITY_FLAG} -Wl,-E")
index 51adf59..074b7ad 100644 (file)
@@ -31,9 +31,32 @@ namespace ir {
   Context::Context(Unit &unit) : unit(unit), fn(NULL), bb(NULL) {}
 
   void Context::startFunction(const std::string &name) {
-    Function *fn = unit.newFunction(name);
+    if (fn != NULL) fnStack.push_back(fn);
+    fn = unit.newFunction(name);
+  }
+
+  void Context::endFunction(void) {
+    GBE_ASSERT(fn != NULL);
+    if (fnStack.size() != 0) {
+      fn = fnStack.back();
+      fnStack.pop_back();
+    } else
+      fn = NULL;
+  }
+
+  RegisterIndex Context::reg(Register::Family family) {
     GBE_ASSERT(fn != NULL);
-    fnStack.push_back(fn);
+    return fn->file.append(family);
+  }
+
+  void Context::input(RegisterIndex reg) {
+    GBE_ASSERT(fn != NULL && reg < fn->file.regNum());
+    fn->input.push_back(reg);
+  }
+
+  void Context::output(RegisterIndex reg) {
+    GBE_ASSERT(fn != NULL && reg < fn->file.regNum());
+    fn->output.push_back(reg);
   }
 
 } /* namespace ir */
index 0927642..07e7b4e 100644 (file)
@@ -29,6 +29,7 @@
 #include "ir/function.hpp"
 #include "ir/register.hpp"
 #include "sys/vector.hpp"
+#include <tuple>
 
 namespace gbe {
 namespace ir {
@@ -48,26 +49,111 @@ namespace ir {
     void startFunction(const std::string &name);
     /*! Close the function */
     void endFunction(void);
-    /*! Create a new register for the given type */
-    RegisterIndex reg(Register::Family type);
+    /*! Create a new register for the given family */
+    RegisterIndex reg(Register::Family family);
     /*! Append a new input register for the function */
     void input(RegisterIndex reg);
     /*! Append a new output register for the function */
     void output(RegisterIndex reg);
     /*! Append a new tuple */
+    template <typename... Args> INLINE TupleIndex tuple(Args...args);
+    /*! We just use variadic templates to forward instruction functions */
+#define DECL_INSN(NAME, FAMILY)                                       \
+    template <typename... Args> INLINE void NAME(Args...args);
+#include "ir/instruction.hxx"
+#undef DECL_INSN
+
+    /*! MAD with sources directly specified */
+    INLINE void MAD(Type type,
+                    RegisterIndex dst,
+                    RegisterIndex src0,
+                    RegisterIndex src1,
+                    RegisterIndex src2)
+    {
+      const TupleIndex index = this->tuple(src0, src1, src2);
+      return this->MAD(type, dst, index);
+    }
+
+    /*! LOAD with the destinations directly specified */
+    template <typename... Args>
+    void LOAD(Type type, RegisterIndex offset, MemorySpace space, Args...values)
+    {
+      const TupleIndex index = this->tuple(values...);
+      const uint16_t valueNum = std::tuple_size<std::tuple<Args...>>::value;
+      GBE_ASSERT(valueNum > 0);
+      this->LOAD(type, index, offset, space, valueNum);
+    }
+
+    /*! STORE with the sources directly specified */
     template <typename... Args>
-    INLINE TupleIndex tuple(Args...args) {
-      if (UNLIKELY(fn == NULL))
-        throw std::exception("Tuple not defined in a function");
-      fn->file.append(args...);
+    void STORE(Type type, RegisterIndex offset, MemorySpace space, Args...values)
+    {
+      const TupleIndex index = this->tuple(values...);
+      const uint16_t valueNum = std::tuple_size<std::tuple<Args...>>::value;
+      GBE_ASSERT(valueNum > 0);
+      this->STORE(type, index, offset, space, valueNum);
     }
+
   private:
+    /*! Check out-of-bound arguments */
+    template <typename T> void outOfBoundCheck(const T &t);
+    /*! Recurse on the arguments to check their correctness */
+    template <typename First, typename... Rest>
+    INLINE void argumentCheck(First first, Rest... rest);
+    /*! Stop the argument checking */
+    INLINE void argumentCheck(void);
+    /*! A block must be started with a label */
+    void startBlock(void);
+    /*! A block must be ended with a branch */
+    void endBlock(void);
+    /*! Append the instruction in the current basic block */
+    void append(const Instruction &insn);
     Unit &unit;               //!< A unit is associated to a contect
     Function *fn;             //!< Current function we are processing
     Function::BasicBlock *bb; //!< Current basic block we are filling
     vector<Function*> fnStack;//!< Stack of functions still to finish
   };
 
+  template <typename... Args>
+  INLINE TupleIndex Context::tuple(Args...args) {
+    GBE_ASSERT(fn != NULL);
+    return fn->file.appendTuple(args...);
+  }
+
+  // Out-of-bound check for each function argument
+  template <typename T>
+  INLINE void Context::outOfBoundCheck(const T &t) { }
+  template <>
+  INLINE void Context::outOfBoundCheck<RegisterIndex>(const RegisterIndex &index) {
+    GBE_ASSERT(fn != NULL);
+    GBE_ASSERT(index < fn->regNum());
+  }
+  template <>
+  INLINE void Context::outOfBoundCheck<TupleIndex>(const TupleIndex &index) {
+    GBE_ASSERT(fn != NULL);
+    GBE_ASSERT(index < fn->tupleNum());
+  }
+
+  // Recursively check all the arguments
+  template <typename First, typename... Rest>
+  INLINE void Context::argumentCheck(First first, Rest... rest) {
+    this->outOfBoundCheck(first);
+    this->argumentCheck(rest...);
+  }
+  INLINE void Context::argumentCheck(void) {}
+
+  // Use argument checker to assert argument value correctness
+#define DECL_INSN(NAME, FAMILY)                                   \
+  template <typename... Args>                                     \
+  INLINE void Context::NAME(Args...args) {                        \
+    GBE_ASSERT(fn != NULL);                                       \
+    this->argumentCheck(args...);                                 \
+    const Instruction insn = gbe::ir::NAME(args...);              \
+    this->append(insn);                                           \
+  }
+#include "ir/instruction.hxx"
+#undef DECL_INSN
+
 } /* namespace ir */
 } /* namespace gbe */
 
index da1a054..e82f196 100644 (file)
@@ -68,16 +68,24 @@ namespace ir {
     }
     /*! Get the given value ie immediate from the function */
     INLINE Value getValue(uint32_t ID) const {
-      assert(ID < value.size());
-      return value[ID];
+      GBE_ASSERT(ID < values.size());
+      return values[ID];
     }
+    /*! 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 tupleNum(void) const { return file.tupleNum(); }
+    /*! Number of labels in the function */
+    INLINE uint32_t labelNum(void) const { return labels.size(); }
+    /*! Number of immediate values in the function */
+    INLINE uint32_t valueNum(void) const { return values.size(); }
 
   private:
     friend class Context;         //!< Can freely modify a function
     vector<RegisterIndex> input;  //!< Input registers of the function
     vector<RegisterIndex> output; //!< Output registers of the function
     vector<BasicBlock*> labels;   //!< Each label points to a basic block
-    vector<Value> value   //!< All immediate values stored in the function
+    vector<Value> values;   //!< All immediate values stored in the function
     vector<BasicBlock*> bb; //!< All the basic blocks one after the others
     RegisterFile file;      //!< All the registers used in the instructions
   };
index 58e8f9f..dbbdda0 100644 (file)
@@ -19,7 +19,6 @@
 
 /**
  * \file instruction.cpp
- *
  * \author Benjamin Segovia <benjamin.segovia@intel.com>
  */
 #include "ir/instruction.hpp"
@@ -54,9 +53,20 @@ namespace ir {
       }
     };
 
+    /*! Policy shared by all the internal instructions */
+    struct ALIGNED_INSTRUCTION BasePolicy {
+      /*! Create an instruction from its internal representation */
+      Instruction convert(void) const {
+        return Instruction(reinterpret_cast<const char *>(&this->opcode));
+      }
+      /*! Instruction opcode */
+      Opcode opcode;
+    };
+
     /*! All unary and binary arithmetic instructions */
     template <uint32_t srcNum> // 1 or 2
-    class ALIGNED_INSTRUCTION NaryInstruction {
+    class NaryInstruction : public BasePolicy
+    {
     public:
       INLINE uint32_t getSrcNum(void) const { return srcNum; }
       INLINE uint32_t getDstNum(void) const { return 1; }
@@ -69,14 +79,14 @@ namespace ir {
         return src[ID];
       }
       INLINE Type getType(void) const { return this->type; }
-      Opcode opcode;            //!< Instruction opcode
       Type type;                //!< Type of the instruction
       RegisterIndex dst;        //!< Index of the register in the register file
       RegisterIndex src[srcNum];//!< Indices of the sources
     };
 
     /*! All 1-source arithmetic instructions */
-    class ALIGNED_INSTRUCTION UnaryInstruction : public NaryInstruction<1> {
+    class UnaryInstruction : public NaryInstruction<1>
+    {
     public:
       UnaryInstruction(Opcode opcode,
                        Type type,
@@ -90,7 +100,8 @@ namespace ir {
     };
 
     /*! All 2-source arithmetic instructions */
-    class ALIGNED_INSTRUCTION BinaryInstruction : public NaryInstruction<2> {
+    class BinaryInstruction : public NaryInstruction<2>
+    {
     public:
       BinaryInstruction(Opcode opcode,
                         Type type,
@@ -108,7 +119,8 @@ namespace ir {
     /*! This is for MADs mostly. Since three sources cannot be encoded in 64
      *  bytes, we use tuples of registers
      */
-    class ALIGNED_INSTRUCTION TernaryInstruction {
+    class TernaryInstruction : public BasePolicy
+    {
     public:
       TernaryInstruction(Opcode opcode,
                          Type type,
@@ -131,13 +143,13 @@ namespace ir {
         return fn.getRegisterIndex(src, ID);
       }
       INLINE Type getType(void) const { return this->type; }
-      Opcode opcode;      //!< Opcode of the instruction
       Type type;          //!< Type of the instruction
       RegisterIndex dst;  //!< Dst is the register index
       TupleIndex src;     //!< 3 sources do not fit in 8 bytes -> use a tuple
     };
 
-    class ALIGNED_INSTRUCTION ConvertInstruction {
+    class ConvertInstruction : public BasePolicy
+    {
     public:
       ConvertInstruction(Type dstType,
                          Type srcType,
@@ -162,14 +174,14 @@ namespace ir {
         assert(ID == 0);
         return src;
       }
-      Opcode opcode;      //!< Opcode of the instruction
       RegisterIndex dst;  //!< Converted value
       RegisterIndex src;  //!< To convert
       Type dstType;       //!< Type to convert to
       Type srcType;       //!< Type to convert from
     };
 
-    class ALIGNED_INSTRUCTION BranchInstruction : public NoDstPolicy {
+    class BranchInstruction : public BasePolicy, public NoDstPolicy
+    {
     public:
       INLINE BranchInstruction(LabelIndex labelIndex, RegisterIndex predicate) {
         this->opcode = OP_BRA;
@@ -188,13 +200,13 @@ namespace ir {
         return predicate;
       }
       INLINE bool isPredicated(void) const { return hasPredicate; }
-      Opcode opcode;            //!< Opcode of the instruction
       RegisterIndex predicate;  //!< Predication means conditional branch
       LabelIndex labelIndex;    //!< Index of the label the branch targets
       bool hasPredicate;        //!< Is it predicated?
     };
 
-    class ALIGNED_INSTRUCTION LoadInstruction {
+    class LoadInstruction : public BasePolicy
+    {
     public:
       LoadInstruction(Type type,
                       TupleIndex dstValues,
@@ -222,7 +234,7 @@ namespace ir {
       INLINE Type getValueType(void) const { return type; }
       INLINE uint32_t getValueNum(void) const { return valueNum; }
       INLINE MemorySpace getAddressSpace(void) const { return memSpace; }
-      Opcode opcode;        //!< Opcode of the instruction
+      INLINE bool wellFormed(const Function &fn, std::string &why) const;
       Type type;            //!< Type to store
       RegisterIndex offset; //!< First source is the offset where to store
       TupleIndex values;    //!< Values to load
@@ -230,7 +242,8 @@ namespace ir {
       uint16_t valueNum;      //!< Number of values to store
     };
 
-    class ALIGNED_INSTRUCTION StoreInstruction : public NoDstPolicy {
+    class StoreInstruction : public BasePolicy, public NoDstPolicy
+    {
     public:
       StoreInstruction(Type type,
                        RegisterIndex offset,
@@ -253,26 +266,25 @@ namespace ir {
           return fn.getRegisterIndex(values, ID - 1);
       }
       INLINE uint32_t getSrcNum(void) const { return valueNum + 1u; }
-      INLINE Type getValueType(void) const { return type; }
       INLINE uint32_t getValueNum(void) const { return valueNum; }
+      INLINE Type getValueType(void) const { return type; }
       INLINE MemorySpace getAddressSpace(void) const { return memSpace; }
-      Opcode opcode;        //!< Opcode of the instruction
+      INLINE bool wellFormed(const Function &fn, std::string &why) const;
       Type type;            //!< Type to store
       RegisterIndex offset; //!< First source is the offset where to store
       TupleIndex values;    //!< Values to store
       MemorySpace memSpace; //!< Where to store
-      uint16_t valueNum;      //!< Number of values to store
+      uint16_t valueNum;    //!< Number of values to store
     };
 
-    class ALIGNED_INSTRUCTION TextureInstruction :
-      public NoDstPolicy, public NoSrcPolicy // TODO REMOVE THIS
+    class TextureInstruction : public BasePolicy, public NoDstPolicy, public NoSrcPolicy // TODO REMOVE THIS
     {
     public:
       INLINE TextureInstruction(void) { this->opcode = OP_TEX; }
-      Opcode opcode; //!< Opcode of the instruction
     };
 
-    class ALIGNED_INSTRUCTION LoadImmInstruction : public NoSrcPolicy {
+    class LoadImmInstruction : public BasePolicy, public NoSrcPolicy
+    {
     public:
       INLINE LoadImmInstruction(Type type, RegisterIndex dst, ValueIndex valueIndex) {
         this->dst = dst;
@@ -289,37 +301,101 @@ namespace ir {
         return dst;
       }
       INLINE Type getType(void) const { return this->type; }
-      Opcode opcode;        //!< Opcode of the instruction
+      bool wellFormed(const Function &fn, std::string &why) const;
       RegisterIndex dst;    //!< Register to store into
       ValueIndex valueIndex;//!< Index in the vector of immediates
       Type type;            //!< Type of the immediate
     };
 
-    class ALIGNED_INSTRUCTION FenceInstruction :
-      public NoSrcPolicy, public NoDstPolicy
+    class FenceInstruction : public BasePolicy, public NoSrcPolicy, public NoDstPolicy
     {
     public:
       INLINE FenceInstruction(MemorySpace memSpace) {
         this->opcode = OP_FENCE;
         this->memSpace = memSpace;
       }
-      Opcode opcode;        //!< Opcode of the instruction
+      bool wellFormed(const Function &fn, std::string &why) const;
       MemorySpace memSpace; //!< The loads and stores to order
     };
 
-    class ALIGNED_INSTRUCTION LabelInstruction :
-      public NoDstPolicy, public NoSrcPolicy
+    class LabelInstruction : public BasePolicy, public NoDstPolicy, public NoSrcPolicy
     {
     public:
       INLINE LabelInstruction(LabelIndex labelIndex) {
         this->opcode = OP_LABEL;
         this->labelIndex = labelIndex;
       }
-      Opcode opcode;          //!< Opcode of the instruction
+      INLINE bool wellFormed(const Function &fn, std::string &why) const;
       LabelIndex labelIndex;  //!< Index of the label
     };
 
 #undef ALIGNED_INSTRUCTION
+
+    /////////////////////////////////////////////////////////////////////////
+    // Implements all the wellFormed methods
+    /////////////////////////////////////////////////////////////////////////
+
+    /*! Loads and stores follow the same restrictions */
+    template <typename T>
+    INLINE bool wellFormedLoadStore(const T &insn, const Function &fn, std::string &why) {
+      if (UNLIKELY(insn.offset >= fn.regNum())) {
+        why = "Out-of-bound offset register index";
+        return false;
+      } else if (UNLIKELY(insn.values + insn.valueNum > fn.tupleNum())) {
+        why = "Out-of-bound tuple index";
+        return false;
+      }
+      // Check that all the registers have the same size
+      const Register::Family family = getFamily(insn.type);
+      for (uint32_t regID = 0; regID < insn.valueNum; ++regID) {
+        const RegisterIndex index = fn.getRegisterIndex(insn.values, regID);
+        if (index > fn.regNum()) {
+          why = "Out-of-bound register index";
+          return false;
+        } else {
+          const Register reg = fn.getRegister(regID);
+          if (reg.family != family) {
+            why = "Register family does match instruction type";
+            return false;
+          }
+        }
+      }
+      return true;
+    }
+    INLINE bool LoadInstruction::wellFormed(const Function &fn, std::string &why) const {
+      return wellFormedLoadStore(*this, fn, why);
+    }
+    INLINE bool StoreInstruction::wellFormed(const Function &fn, std::string &why) const {
+      return wellFormedLoadStore(*this, fn, why);
+    }
+
+    INLINE bool LoadImmInstruction::wellFormed(const Function &fn, std::string &why) const {
+      if (UNLIKELY(dst >= fn.regNum())) {
+        why = "Out-of-bound register index";
+        return false;
+      } else if (UNLIKELY(valueIndex >= fn.valueNum())) {
+        why = "Out-of-bound immediate value index";
+        return false;
+      } else if (UNLIKELY(type != fn.getValue(valueIndex).type)) {
+        why = "Inconsistant type for the immediate value to load";
+        return false;
+      } else
+        return true;
+    }
+
+    INLINE bool FenceInstruction::wellFormed(const Function &fn, std::string &why) const {
+      return true;
+    }
+
+
+    INLINE bool LabelInstruction::wellFormed(const Function &fn, std::string &why) const {
+      if (UNLIKELY(labelIndex >= fn.labelNum())) {
+        why = "Out-of-bound label index";
+        return false;
+      } else
+        return true;
+    }
+
   } /* namespace internal */
 
   ///////////////////////////////////////////////////////////////////////////
@@ -343,18 +419,18 @@ namespace ir {
   case OP_##OPCODE:                                        \
   return HelperIntrospection<CLASS, RefClass>::value == 1;
 
-#define START_INTROSPECTION(CLASS)                    \
-  STATIC_ASSERT(sizeof(CLASS) == sizeof(Instruction));\
-  bool CLASS::isClassOf(const Instruction &insn) {    \
-    const Opcode op = insn.getOpcode();               \
-    typedef CLASS RefClass;                           \
+#define START_INTROSPECTION(CLASS)                                            \
+  static_assert(sizeof(CLASS)==sizeof(Instruction), "Bad instruction size");  \
+  bool CLASS::isClassOf(const Instruction &insn) {                            \
+    const Opcode op = insn.getOpcode();                                       \
+    typedef CLASS RefClass;                                                   \
     switch (op) {
 
-#define END_INTROSPECTION(CLASS)  \
-      default: return false;      \
-    };                            \
-  }                               \
-  STATIC_ASSERT(offsetof(internal::CLASS, opcode) == 0);
+#define END_INTROSPECTION(CLASS)                                              \
+      default: return false;                                                  \
+    };                                                                        \
+  }                                                                           \
+  static_assert(offsetof(internal::CLASS, opcode)==0, "Bad opcode offset");
 
 START_INTROSPECTION(UnaryInstruction)
 #include "ir/instruction.hxx"
@@ -476,100 +552,102 @@ DECL_MEM_FN(BranchInstruction, bool, isPredicated(void), isPredicated())
   ///////////////////////////////////////////////////////////////////////////
 
   // All unary functions
-#define DECL_EMIT_FUNCTION(NAME, OPCODE)\
-  Instruction NAME(Type type, RegisterIndex dst, RegisterIndex src) {\
-    internal::UnaryInstruction insn(OPCODE, type, dst, src);\
-    return *reinterpret_cast<Instruction*>(&insn);\
+#define DECL_EMIT_FUNCTION(NAME)                                      \
+  Instruction NAME(Type type, RegisterIndex dst, RegisterIndex src) { \
+    const internal::UnaryInstruction insn(OP_##NAME, type, dst, src); \
+    return insn.convert();                                            \
   }
 
-  DECL_EMIT_FUNCTION(mov, OP_MOV)
-  DECL_EMIT_FUNCTION(cos, OP_COS)
-  DECL_EMIT_FUNCTION(sin, OP_SIN)
-  DECL_EMIT_FUNCTION(tan, OP_TAN)
-  DECL_EMIT_FUNCTION(log, OP_LOG)
-  DECL_EMIT_FUNCTION(sqr, OP_SQR)
-  DECL_EMIT_FUNCTION(rsq, OP_RSQ)
+  DECL_EMIT_FUNCTION(MOV)
+  DECL_EMIT_FUNCTION(COS)
+  DECL_EMIT_FUNCTION(SIN)
+  DECL_EMIT_FUNCTION(TAN)
+  DECL_EMIT_FUNCTION(LOG)
+  DECL_EMIT_FUNCTION(SQR)
+  DECL_EMIT_FUNCTION(RSQ)
 
 #undef DECL_EMIT_FUNCTION
 
   // All binary functions
-#define DECL_EMIT_FUNCTION(NAME, OPCODE)\
-  Instruction NAME(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1) {\
-    internal::BinaryInstruction insn(OPCODE, type, dst, src0, src1);\
-    return *reinterpret_cast<Instruction*>(&insn);\
+#define DECL_EMIT_FUNCTION(NAME)                                              \
+  Instruction NAME(Type type, RegisterIndex dst,                              \
+                   RegisterIndex src0,                                        \
+                   RegisterIndex src1) {                                      \
+    const internal::BinaryInstruction insn(OP_##NAME, type, dst, src0, src1); \
+    return insn.convert();                                                    \
   }
 
-  DECL_EMIT_FUNCTION(mul, OP_MUL)
-  DECL_EMIT_FUNCTION(add, OP_ADD)
-  DECL_EMIT_FUNCTION(sub, OP_SUB)
-  DECL_EMIT_FUNCTION(div, OP_DIV)
-  DECL_EMIT_FUNCTION(rem, OP_REM)
-  DECL_EMIT_FUNCTION(shl, OP_SHL)
-  DECL_EMIT_FUNCTION(shr, OP_SHR)
-  DECL_EMIT_FUNCTION(asr, OP_ASR)
-  DECL_EMIT_FUNCTION(bsf, OP_BSF)
-  DECL_EMIT_FUNCTION(bsb, OP_BSB)
-  DECL_EMIT_FUNCTION(or$, OP_OR)
-  DECL_EMIT_FUNCTION(xor$, OP_XOR)
-  DECL_EMIT_FUNCTION(and$, OP_AND)
+  DECL_EMIT_FUNCTION(MUL)
+  DECL_EMIT_FUNCTION(ADD)
+  DECL_EMIT_FUNCTION(SUB)
+  DECL_EMIT_FUNCTION(DIV)
+  DECL_EMIT_FUNCTION(REM)
+  DECL_EMIT_FUNCTION(SHL)
+  DECL_EMIT_FUNCTION(SHR)
+  DECL_EMIT_FUNCTION(ASR)
+  DECL_EMIT_FUNCTION(BSF)
+  DECL_EMIT_FUNCTION(BSB)
+  DECL_EMIT_FUNCTION(OR)
+  DECL_EMIT_FUNCTION(XOR)
+  DECL_EMIT_FUNCTION(AND)
 
 #undef DECL_EMIT_FUNCTION
 
   // MAD
-  Instruction mad(Type type, RegisterIndex dst, TupleIndex src) {
+  Instruction MAD(Type type, RegisterIndex dst, TupleIndex src) {
     internal::TernaryInstruction insn(OP_MAD, type, dst, src);
-    return *reinterpret_cast<Instruction*>(&insn);
+    return insn.convert();
   }
 
   // CVT
-  Instruction cvt(Type dstType, Type srcType, RegisterIndex dst, TupleIndex src) {
+  Instruction CVT(Type dstType, Type srcType, RegisterIndex dst, TupleIndex src) {
     internal::ConvertInstruction insn(dstType, srcType, dst, src);
-    return *reinterpret_cast<Instruction*>(&insn);
+    return insn.convert();
   }
 
   // BRA
-  Instruction bra(LabelIndex labelIndex) {
+  Instruction BRA(LabelIndex labelIndex) {
     internal::BranchInstruction insn(labelIndex);
-    return *reinterpret_cast<Instruction*>(&insn);
+    return insn.convert();
   }
-  Instruction bra(LabelIndex labelIndex, RegisterIndex pred) {
+  Instruction BRA(LabelIndex labelIndex, RegisterIndex pred) {
     internal::BranchInstruction insn(labelIndex, pred);
-    return *reinterpret_cast<Instruction*>(&insn);
+    return insn.convert();
   }
 
   // LOADI
-  Instruction loadi(Type type, RegisterIndex dst, ValueIndex value) {
+  Instruction LOADI(Type type, RegisterIndex dst, ValueIndex value) {
     internal::LoadImmInstruction insn(type, dst, value);
-    return *reinterpret_cast<Instruction*>(&insn);
+    return insn.convert();
   }
 
   // LOAD and STORE
-#define DECL_EMIT_FUNCTION(NAME, CLASS)   \
-  Instruction NAME(Type type,             \
-                   TupleIndex tuple,      \
-                   RegisterIndex offset,  \
-                   MemorySpace space,     \
-                   uint16_t valueNum)       \
-  {                                       \
+#define DECL_EMIT_FUNCTION(NAME, CLASS)                               \
+  Instruction NAME(Type type,                                         \
+                   TupleIndex tuple,                                  \
+                   RegisterIndex offset,                              \
+                   MemorySpace space,                                 \
+                   uint16_t valueNum)                                 \
+  {                                                                   \
     const internal::CLASS insn(type, tuple, offset, space, valueNum); \
-    return *reinterpret_cast<const Instruction*>(&insn);              \
+    return insn.convert();                                            \
   }
 
-  DECL_EMIT_FUNCTION(load, LoadInstruction)
-  DECL_EMIT_FUNCTION(store, StoreInstruction)
+  DECL_EMIT_FUNCTION(LOAD, LoadInstruction)
+  DECL_EMIT_FUNCTION(STORE, StoreInstruction)
 
 #undef DECL_EMIT_FUNCTION
 
   // FENCE
-  Instruction fence(MemorySpace space) {
-    internal::FenceInstruction insn(space);
-    return *reinterpret_cast<Instruction*>(&insn);
+  Instruction FENCE(MemorySpace space) {
+    const internal::FenceInstruction insn(space);
+    return insn.convert();
   }
 
   // LABEL
-  Instruction label(LabelIndex labelIndex) {
-    internal::LabelInstruction insn(labelIndex);
-    return *reinterpret_cast<Instruction*>(&insn);
+  Instruction LABEL(LabelIndex labelIndex) {
+    const internal::LabelInstruction insn(labelIndex);
+    return insn.convert();
   }
 
 } /* namespace ir */
index 8913212..80b30d3 100644 (file)
 #ifndef __GBE_IR_INSTRUCTION_HPP__
 #define __GBE_IR_INSTRUCTION_HPP__
 
-#include "sys/platform.hpp"
 #include "ir/register.hpp"
 #include "ir/value.hpp"
 #include "ir/type.hpp"
+#include "sys/platform.hpp"
 
 namespace gbe {
 namespace ir {
 
   /*! All opcodes */
-  enum Opcode : uint8_t {
+  enum Opcode : char {
 #define DECL_INSN(INSN, FAMILY) OP_##INSN,
 #include "ir/instruction.hxx"
 #undef DECL_INSN
@@ -67,6 +67,14 @@ namespace ir {
   class ALIGNED(sizeof(uint64_t)) Instruction
   {
   public:
+    /*! Initialize the instruction from a 8 bytes stream */
+    INLINE Instruction(const char *stream) {
+      opcode = Opcode(stream[0]);
+      for (uint32_t byte = 0; byte < opaqueSize; ++byte)
+        opaque[byte] = stream[byte+1];
+    }
+    /*! Uninitialize instruction */
+    INLINE Instruction(void) {}
     /*! Get the instruction opcode */
     INLINE Opcode getOpcode(void) const { return opcode; }
     /*! Get the number of sources for this instruction  */
@@ -81,11 +89,11 @@ namespace ir {
     Register getDst(const Function &fn, uint32_t ID = 0u) const;
     /*! Get the register of the given destination */
     Register getSrc(const Function &fn, uint32_t ID = 0u) const;
-    /*! Check that the instruction is well formed. Return true if well formed.
-     *  j
-     *  Otherwise, fill the string with a help message
+    /*! Check that the instruction is well formed (type properly match,
+     *  registers not of bound and so on). If not well formed, provide a reason
+     *  in string why
      */
-    bool check(void) const;
+    bool wellFormed(const Function &fn, std::string &why) const;
     /*! Indicates if the instruction belongs to instruction type T. Typically, T
      *  can be BinaryInstruction, UnaryInstruction, LoadInstruction and so on
      */
@@ -93,12 +101,13 @@ namespace ir {
       return T::isClassOf(*this);
     }
   protected:
-    Opcode opcode;                             //!< Idendifies the instruction
-    uint8_t opaque[sizeof(uint64_t)-sizeof(uint8_t)];//!< Remainder of it
+    enum { opaqueSize = sizeof(uint64_t)-sizeof(uint8_t) };
+    Opcode opcode;           //!< Idendifies the instruction
+    char opaque[opaqueSize]; //!< Remainder of it
   };
 
   // Check that the instruction is properly formed by the compiler
-  STATIC_ASSERT(sizeof(Instruction) == sizeof(uint64_t));
+  static_assert(sizeof(Instruction)==sizeof(uint64_t), "Bad instruction size");
 
   /*! Unary instructions are typed. dst and sources share the same type */
   class UnaryInstruction : public Instruction {
@@ -259,65 +268,67 @@ namespace ir {
   ///////////////////////////////////////////////////////////////////////////
 
   /*! mov.type dst src */
-  Instruction mov(Type type, RegisterIndex dst, RegisterIndex src);
+  Instruction MOV(Type type, RegisterIndex dst, RegisterIndex src);
   /*! cos.type dst src */
-  Instruction cos(Type type, RegisterIndex dst, RegisterIndex src);
+  Instruction COS(Type type, RegisterIndex dst, RegisterIndex src);
   /*! sin.type dst src */
-  Instruction sin(Type type, RegisterIndex dst, RegisterIndex src);
+  Instruction SIN(Type type, RegisterIndex dst, RegisterIndex src);
   /*! tan.type dst src */
-  Instruction tan(Type type, RegisterIndex dst, RegisterIndex src);
+  Instruction TAN(Type type, RegisterIndex dst, RegisterIndex src);
   /*! log.type dst src */
-  Instruction log(Type type, RegisterIndex dst, RegisterIndex src);
+  Instruction LOG(Type type, RegisterIndex dst, RegisterIndex src);
   /*! sqr.type dst src */
-  Instruction sqr(Type type, RegisterIndex dst, RegisterIndex src);
+  Instruction SQR(Type type, RegisterIndex dst, RegisterIndex src);
   /*! rsq.type dst src */
-  Instruction rsq(Type type, RegisterIndex dst, RegisterIndex src);
+  Instruction RSQ(Type type, RegisterIndex dst, RegisterIndex src);
   /*! pow.type dst src0 src1 */
-  Instruction pow(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
+  Instruction POW(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
   /*! mul.type dst src0 src1 */
-  Instruction mul(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
+  Instruction MUL(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
   /*! add.type dst src0 src1 */
-  Instruction add(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
+  Instruction ADD(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
   /*! sub.type dst src0 src1 */
-  Instruction sub(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
+  Instruction SUB(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
   /*! div.type dst src0 src1 */
-  Instruction div(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
+  Instruction DIV(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
   /*! rem.type dst src0 src1 */
-  Instruction rem(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
+  Instruction REM(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
   /*! shl.type dst src0 src1 */
-  Instruction shl(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
+  Instruction SHL(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
   /*! shr.type dst src0 src1 */
-  Instruction shr(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
+  Instruction SHR(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
   /*! asr.type dst src0 src1 */
-  Instruction asr(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
+  Instruction ASR(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
   /*! bsf.type dst src0 src1 */
-  Instruction bsf(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
+  Instruction BSF(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
   /*! bsb.type dst src0 src1 */
-  Instruction bsb(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
+  Instruction BSB(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
   /*! or.type dst src0 src1 */
-  Instruction or$(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
+  Instruction OR(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
   /*! xor.type dst src0 src1 */
-  Instruction xor$(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
+  Instruction XOR(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
   /*! and.type dst src0 src1 */
-  Instruction and$(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
+  Instruction AND(Type type, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
   /*! mad.type dst {src0, src1, src2} == src */
-  Instruction mad(Type type, RegisterIndex dst, TupleIndex src);
+  Instruction MAD(Type type, RegisterIndex dst, TupleIndex src);
   /*! cvt.{dstType <- srcType} dst src */
-  Instruction cvt(Type dstType, Type srcType, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
+  Instruction CVT(Type dstType, Type srcType, RegisterIndex dst, RegisterIndex src0, RegisterIndex src1);
   /*! bra labelIndex */
-  Instruction bra(LabelIndex labelIndex);
+  Instruction BRA(LabelIndex labelIndex);
   /*! (pred) bra labelIndex */
-  Instruction bra(LabelIndex labelIndex, RegisterIndex pred);
+  Instruction BRA(LabelIndex labelIndex, RegisterIndex pred);
   /*! loadi.type dst value */
-  Instruction loadi(Type type, RegisterIndex dst, ValueIndex value);
+  Instruction LOADI(Type type, RegisterIndex dst, ValueIndex value);
   /*! load.type.space {dst1,...,dst_valueNum} offset value */
-  Instruction load(Type type, TupleIndex dst, RegisterIndex offset, MemorySpace space, uint16_t valueNum);
+  Instruction LOAD(Type type, TupleIndex dst, RegisterIndex offset, MemorySpace space, uint16_t valueNum);
   /*! store.type.space offset {src1,...,src_valueNum} value */
-  Instruction store(Type type, TupleIndex src, RegisterIndex offset, MemorySpace space, uint16_t valueNum);
+  Instruction STORE(Type type, TupleIndex src, RegisterIndex offset, MemorySpace space, uint16_t valueNum);
   /*! fence.space */
-  Instruction fence(MemorySpace space);
+  Instruction FENCE(MemorySpace space);
   /*! label labelIndex */
-  Instruction label(LabelIndex labelIndex);
+  Instruction LABEL(LabelIndex labelIndex);
+  /*! texture instruction TODO */
+  Instruction TEX(void);
 
 } /* namespace ir */
 } /* namespace gbe */
index c227fc9..cf97095 100644 (file)
@@ -73,9 +73,9 @@ namespace ir {
   public:
     /*! Return the index of a newly allocated register register */
     INLINE RegisterIndex append(Register::Family family) {
-      const uint32_t index = regs.size();
+      const uint32_t index = regNum();
       const Register reg(family);
-      assert(index <= MAX_INDEX);
+      GBE_ASSERT(index <= MAX_INDEX);
       regs.push_back(reg);
       return index;
     }
@@ -83,7 +83,7 @@ namespace ir {
     template <typename First, typename... Rest>
     INLINE TupleIndex appendTuple(First first, Rest... rest) {
       const TupleIndex index = regTuples.size();
-      assert(first < regs.size());
+      GBE_ASSERT(first < regNum());
       regTuples.push_back(first);
       appendTuple(rest...);
       return index;
@@ -92,18 +92,19 @@ namespace ir {
     INLINE void appendTuple(void) {}
     /*! Return a copy of the register at index */
     INLINE Register get(RegisterIndex index) const {
-      assert(index < regs.size() && index <= MAX_INDEX);
+      GBE_ASSERT(index < regNum());
       return regs[index];
     }
     /*! Get the register index from the tuple */
     INLINE RegisterIndex get(TupleIndex index, uint32_t which) const {
-      assert(index + which < regTuples.size());
+      GBE_ASSERT(index + which < regTuples.size());
       return regTuples[index + which];
     }
     /*! Number of registers in the register file */
     INLINE uint32_t regNum(void) const { return regs.size(); }
+    /*! Number of tuples in the register file */
+    INLINE uint32_t tupleNum(void) const { return regTuples.size(); }
   private:
-    enum { MAX_INDEX = 0xffff };     //!< We encode indices in 2 bytes
     vector<Register> regs;           //!< All the registers together
     vector<RegisterIndex> regTuples; //!< Tuples are used for many src / dst
     GBE_CLASS(RegisterFile);
index 3190e72..52dd5c0 100644 (file)
 #define __GBE_IR_TYPE_HPP__
 
 #include "sys/platform.hpp"
+#include "ir/register.hpp"
 
 namespace gbe {
 namespace ir {
 
   /*! All types possibly supported by the instruction */
   enum Type : uint8_t {
-    TYPE_S8 = 0,  //!< signed 8 bits integer
-    TYPE_U8,      //!< unsigned 8 bits integer
-    TYPE_S16,     //!< signed 16 bits integer
-    TYPE_U16,     //!< unsigned 16 bits integer
-    TYPE_S32,     //!< signed 32 bits integer
-    TYPE_U32,     //!< unsigned 32 bits integer
-    TYPE_S64,     //!< signed 64 bits integer
-    TYPE_U64,     //!< unsigned 64 bits integer
-    TYPE_FLOAT,   //!< 32 bits floating point value
-    TYPE_DOUBLE   //!< 64 bits floating point value
+    TYPE_BOOL = 0, //!< boolean value
+    TYPE_S8,       //!< signed 8 bits integer
+    TYPE_U8,       //!< unsigned 8 bits integer
+    TYPE_S16,      //!< signed 16 bits integer
+    TYPE_U16,      //!< unsigned 16 bits integer
+    TYPE_S32,      //!< signed 32 bits integer
+    TYPE_U32,      //!< unsigned 32 bits integer
+    TYPE_S64,      //!< signed 64 bits integer
+    TYPE_U64,      //!< unsigned 64 bits integer
+    TYPE_HALF,     //!< 16 bits floating point value
+    TYPE_FLOAT,    //!< 32 bits floating point value
+    TYPE_DOUBLE    //!< 64 bits floating point value
   };
 
+  /*! Get the register family for each type */
+  INLINE Register::Family getFamily(Type type) {
+    switch (type) {
+      case TYPE_BOOL:
+        return Register::BOOL;
+      case TYPE_S8:
+      case TYPE_U8:
+        return Register::BYTE;
+      case TYPE_S16:
+      case TYPE_U16:
+      case TYPE_HALF:
+        return Register::WORD;
+      case TYPE_S32:
+      case TYPE_U32:
+      case TYPE_FLOAT:
+        return Register::DWORD;
+      case TYPE_S64:
+      case TYPE_U64:
+      case TYPE_DOUBLE:
+        return Register::QWORD;
+    };
+  }
+
 } /* namespace ir */
 } /* namespace gbe */
 
index 0fee89e..d4c451e 100644 (file)
 #define GBE_ASSERT(EXPR) do { } while (0)
 #endif
 
-/*! Compile-time assertion */
-#define STATIC_ASSERT(value)                                     \
-  struct JOIN(__,JOIN(__,__LINE__)) { int x[(value) ? 1 : -1]; }
-
 /*! Fatal error macros */
 #define NOT_IMPLEMENTED FATAL ("Not implemented")
 #define FATAL_IF(COND, MSG)                          \