Keep on implementing instruction class implementation. This basically a set of classe...
authorbsegovia <bsegovia@bsegovia-PC>
Sun, 5 Feb 2012 19:15:24 +0000 (11:15 -0800)
committerKeith Packard <keithp@keithp.com>
Fri, 10 Aug 2012 23:15:12 +0000 (16:15 -0700)
backend/src/CMakeLists.txt
backend/src/ir/ir_function.hpp
backend/src/ir/ir_instruction.cpp
backend/src/ir/ir_instruction.hpp
backend/src/ir/ir_register.hpp
backend/src/sys/alloc.hpp
backend/src/utest/utest.hpp

index f26cf5c..41972a8 100644 (file)
@@ -28,7 +28,9 @@ set (GBE_SRC
   ir/ir_instruction.cpp
   ir/ir_instruction.hpp
   ir/ir_register.cpp
-  ir/ir_register.hpp)
+  ir/ir_register.hpp
+  ir/ir_function.cpp
+  ir/ir_function.hpp)
 
 set (COMPILE_UTEST false CACHE bool "Compile or not the unit tests")
 if (COMPILE_UTEST)
index 187d6e1..3954991 100644 (file)
 #ifndef __GBE_IR_FUNCTION_HPP__
 #define __GBE_IR_FUNCTION_HPP__
 
+#include "ir_value.hpp"
+#include "ir_register.hpp"
+#include "ir_instruction.hpp"
+#include "sys/vector.hpp"
+
 namespace gbe
 {
   /*! A function is no more that a set of declared registers and a set of
@@ -49,12 +54,17 @@ namespace gbe
 
     /*! Extract the register from the register file */
     INLINE Register getRegister(uint32 ID) const { return file.get(ID); }
+    /*! Get the register index from the tuple vector */
+    INLINE RegisterIndex getRegisterIndex(TupleIndex ID, uint32 which) const {
+      return file.get(ID, which);
+    }
 
   private:
     /*! Create a function by sequential appending of instructions and registers */
     friend class FunctionContext;
     vector<uint16> input;    //!< Input registers of the function
     vector<uint16> output;   //!< Output registers of the function
+    vector<Value> immediate; //!< All immediate values stored in the function
     vector<BasicBlock> insn; //!< All the basic blocks one after the others
     RegisterFile file;       //!< All the registers used in the instructions
   };
index ba0d0ef..0db1e81 100644 (file)
 
 namespace gbe
 {
+  ///////////////////////////////////////////////////////////////////////////
+  // Implements the concrete implementations of the instruction classes
+  ///////////////////////////////////////////////////////////////////////////
   namespace internal
   {
+#define ALIGNED_INSTRUCTION ALIGNED(AlignOf<Instruction>::value) 
+
     /*! All unary and binary arithmetic instructions */
     template <uint32 srcNum> // 1 or 2
-    class ALIGNED(AlignOf<Instruction>::value) NaryInstruction
+    class ALIGNED_INSTRUCTION NaryInstruction
     {
     public:
       INLINE uint32 getSrcNum(void) const { return srcNum; }
       INLINE uint32 getDstNum(void) const { return 1; }
-      INLINE uint32 getDstIndex(const Function &fn, uint32 ID) const {
+      INLINE RegisterIndex getDstIndex(const Function &fn, uint32 ID) const {
         assert(ID == 0);
         return dst;
       }
-      INLINE uint32 getSrcIndex(const Function &fn, uint32 ID) const {
+      INLINE RegisterIndex getSrcIndex(const Function &fn, uint32 ID) const {
         assert(ID <= srcNum);
         return src[ID];
       }
-      INLINE Register getDst(const Function &fn, uint32 ID) const {
-        return fn.getRegister(this->getDstIndex(fn, ID));
-      }
-      INLINE Register getSrc(const Function &fn, uint32 ID) const {
-        return fn.getRegister(this->getSrcIndex(fn, ID));
-      }
-    protected:
-      uint8 opcode;       //!< Instruction opcode
+      INLINE Type getType(void) const { return this->type; }
+      Opcode opcode;      //!< Instruction opcode
       uint8 type;         //!< Type of the instruction
       uint16 dst;         //!< Index of the register in the register file
       uint16 src[srcNum]; //!< Indices of the sources
     };
 
     /*! All 1-source arithmetic instructions */
-    class UnaryInstruction : public NaryInstruction<1>
+    class ALIGNED_INSTRUCTION UnaryInstruction : public NaryInstruction<1>
     {
     public:
-      UnaryInstruction(uint32 opcode, uint32 type, uint32 dst, uint32 src) {
+      UnaryInstruction(Opcode opcode,
+                       Type type,
+                       RegisterIndex dst,
+                       RegisterIndex src) {
         this->opcode = opcode;
         this->type = type;
         this->dst = dst;
@@ -65,10 +67,14 @@ namespace gbe
     };
 
     /*! All 2-source arithmetic instructions */
-    class BinaryInstruction : public NaryInstruction<2>
+    class ALIGNED_INSTRUCTION BinaryInstruction : public NaryInstruction<2>
     {
     public:
-      BinaryInstruction(uint32 opcode, uint32 type, uint32 dst, uint32 src0, uint32 src1) {
+      BinaryInstruction(Opcode opcode,
+                        Type type,
+                        RegisterIndex dst,
+                        RegisterIndex src0,
+                        RegisterIndex src1) {
         this->opcode = opcode;
         this->type = type;
         this->dst = dst;
@@ -77,9 +83,306 @@ namespace gbe
       }
     };
 
-    STATIC_ASSERT(sizeof(UnaryInstruction) <= sizeof(Instruction));
-    STATIC_ASSERT(sizeof(BinaryInstruction) <= sizeof(Instruction));
+    /*! This is for MADs mostly. Since three sources cannot be encoded in 64
+     *  bytes, we use tuples of registers
+     */
+    class ALIGNED_INSTRUCTION TernaryInstruction
+    {
+    public:
+      TernaryInstruction(Opcode opcode,
+                         Type type,
+                         RegisterIndex dst,
+                         TupleIndex src)
+      {
+        this->opcode = opcode;
+        this->type = type;
+        this->dst = dst;
+        this->src = src;
+      }
+      INLINE uint32 getSrcNum(void) const { return 3; }
+      INLINE uint32 getDstNum(void) const { return 1; }
+      INLINE RegisterIndex getDstIndex(const Function &fn, uint32 ID) const {
+        assert(ID == 0);
+        return dst;
+      }
+      INLINE RegisterIndex getSrcIndex(const Function &fn, uint32 ID) const {
+        assert(ID <= 3);
+        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
+    {
+    public:
+      ConvertInstruction(RegisterIndex dst,
+                         RegisterIndex src,
+                         Type dstType,
+                         Type srcType)
+      {
+        this->opcode = OP_CVT;
+        this->dst = dst;
+        this->src = src;
+        this->dstType = dstType;
+        this->srcType = srcType;
+      }
+      INLINE Type getSrcType(void) const { return this->srcType; }
+      INLINE Type getDstType(void) const { return this->dstType; }
+      INLINE RegisterIndex getDstIndex(const Function &fn, uint32 ID) const {
+        assert(ID == 0);
+        return dst;
+      }
+      INLINE RegisterIndex getSrcIndex(const Function &fn, uint32 ID) const {
+        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:
+      INLINE BranchInstruction(LabelIndex labelIndex, RegisterIndex predicate)
+      {
+        this->opcode = OP_BRA;
+        this->predicate = predicate;
+        this->labelIndex = labelIndex;
+        this->hasPredicate = true;
+      }
+      INLINE BranchInstruction(LabelIndex labelIndex)
+      {
+        this->opcode = OP_BRA;
+        this->labelIndex = labelIndex;
+        this->hasPredicate = false;
+      }
+      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
+    {
+    public:
+      LoadInstruction(Type type,
+                      RegisterIndex offset,
+                      TupleIndex values,
+                      MemorySpace memSpace,
+                      uint16 valueNum)
+      {
+        this->opcode = OP_STORE;
+        this->type = type;
+        this->offset = offset;
+        this->values = values;
+        this->memSpace = memSpace;
+        this->valueNum = valueNum;
+      }
+      INLINE RegisterIndex getSrcIndex(const Function &fn, uint32 ID) const {
+        assert(ID == 0u);
+        return offset;
+      }
+      INLINE RegisterIndex getDstIndex(const Function &fn, uint32 ID) const {
+        assert(ID < valueNum);
+        return fn.getRegisterIndex(values, ID);
+      }
+      INLINE uint32 getValueNum(void) const { return valueNum; }
+      INLINE MemorySpace getAddressSpace(void) const { return memSpace; }
+      Opcode opcode;        //!< Opcode of the instruction
+      Type type;            //!< Type to store
+      RegisterIndex offset; //!< First source is the offset where to store
+      TupleIndex values;    //!< Values to load
+      MemorySpace memSpace; //!< Where to store
+      uint16 valueNum;      //!< Number of values to store
+    };
+
+    class ALIGNED_INSTRUCTION StoreInstruction
+    {
+    public:
+      StoreInstruction(Type type,
+                       RegisterIndex offset,
+                       TupleIndex values,
+                       MemorySpace memSpace,
+                       uint16 valueNum)
+      {
+        this->opcode = OP_STORE;
+        this->type = type;
+        this->offset = offset;
+        this->values = values;
+        this->memSpace = memSpace;
+        this->valueNum = valueNum;
+      }
+      INLINE RegisterIndex getSrcIndex(const Function &fn, uint32 ID) {
+        assert(ID < valueNum + 1u); // offset + values to store
+        if (ID == 0u)
+          return offset;
+        else
+          return fn.getRegisterIndex(values, ID - 1);
+      }
+      INLINE RegisterIndex getDstIndex(const Function &fn, uint32 ID) {
+        NOT_IMPLEMENTED;
+        return 0u;
+      }
+      INLINE uint32 getValueNum(void) const { return valueNum; }
+      INLINE MemorySpace getAddressSpace(void) const { return memSpace; }
+      Opcode opcode;        //!< Opcode of the instruction
+      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 valueNum;      //!< Number of values to store
+    };
+
+    class ALIGNED_INSTRUCTION TextureInstruction
+    {
+    public:
+      INLINE TextureInstruction(void) { this->opcode = OP_TEX; }
+      Opcode opcode; //!< Opcode of the instruction
+    };
+
+    class ALIGNED_INSTRUCTION LoadImmInstruction
+    {
+    public:
+      INLINE LoadImmInstruction(ValueIndex valueIndex, Type type) {
+        this->opcode = OP_LOADI;
+        this->valueIndex = valueIndex;
+        this->type = type;
+      }
+      INLINE Type getType(void) const { return this->type; }
+      Opcode opcode;        //!< Opcode of the instruction
+      ValueIndex valueIndex;//!< Index in the vector of immediates
+      Type type;            //!< Type of the immediate
+    };
+
+    class ALIGNED_INSTRUCTION FenceInstruction
+    {
+    public:
+      INLINE FenceInstruction(MemorySpace memSpace) {
+        this->opcode = OP_FENCE;
+        this->memSpace = memSpace;
+      }
+      Opcode opcode;        //!< Opcode of the instruction
+      MemorySpace memSpace; //!< The loads and stores to order
+    };
+
+    class ALIGNED_INSTRUCTION LabelInstruction
+    {
+    public:
+      INLINE LabelInstruction(LabelIndex labelIndex) {
+        this->opcode = OP_LABEL;
+        this->labelIndex = labelIndex;
+      }
+      Opcode opcode;          //!< Opcode of the instruction
+      LabelIndex labelIndex;  //!< Index of the label
+    };
 
   } /* namespace internal */
+
+  ///////////////////////////////////////////////////////////////////////////
+  // Implements the various instrospection functions
+  ///////////////////////////////////////////////////////////////////////////
+  template <typename T, typename U> struct HelperIntrospection {
+    enum { value = 0 };
+  };
+  template <typename T> struct HelperIntrospection<T,T> {
+    enum { value = 1 };
+  };
+
+  Register Instruction::getDst(const Function &fn, uint32 ID) const {
+    return fn.getRegister(this->getDstIndex(fn, ID));
+  }
+  Register Instruction::getSrc(const Function &fn, uint32 ID) const {
+    return fn.getRegister(this->getSrcIndex(fn, ID));
+  }
+
+#define DECL_INSN(OPCODE, CLASS)                           \
+  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;                           \
+    switch (op) {
+
+#define END_INTROSPECTION(CLASS)  \
+      default: return false;      \
+    };                            \
+  }                               \
+  STATIC_ASSERT(offsetof(internal::CLASS, opcode) == 0);
+
+START_INTROSPECTION(UnaryInstruction)
+#include "ir_instruction.hxx"
+END_INTROSPECTION(UnaryInstruction)
+
+START_INTROSPECTION(BinaryInstruction)
+#include "ir_instruction.hxx"
+END_INTROSPECTION(BinaryInstruction)
+
+START_INTROSPECTION(TernaryInstruction)
+#include "ir_instruction.hxx"
+END_INTROSPECTION(TernaryInstruction)
+
+START_INTROSPECTION(ConvertInstruction)
+#include "ir_instruction.hxx"
+END_INTROSPECTION(ConvertInstruction)
+
+START_INTROSPECTION(BranchInstruction)
+#include "ir_instruction.hxx"
+END_INTROSPECTION(BranchInstruction)
+
+START_INTROSPECTION(TextureInstruction)
+#include "ir_instruction.hxx"
+END_INTROSPECTION(TextureInstruction)
+
+START_INTROSPECTION(LoadImmInstruction)
+#include "ir_instruction.hxx"
+END_INTROSPECTION(LoadImmInstruction)
+
+START_INTROSPECTION(LoadInstruction)
+#include "ir_instruction.hxx"
+END_INTROSPECTION(LoadInstruction)
+
+START_INTROSPECTION(StoreInstruction)
+#include "ir_instruction.hxx"
+END_INTROSPECTION(StoreInstruction)
+
+START_INTROSPECTION(FenceInstruction)
+#include "ir_instruction.hxx"
+END_INTROSPECTION(FenceInstruction)
+
+START_INTROSPECTION(LabelInstruction)
+#include "ir_instruction.hxx"
+END_INTROSPECTION(LabelInstruction)
+
+#undef END_INTROSPECTION
+#undef START_INTROSPECTION
+#undef DECL_INSN
+#undef ALIGNED_INSTRUCTION
+
+#if 0
+  ///////////////////////////////////////////////////////////////////////////
+  // Implements the function dispatching from public to internal
+  ///////////////////////////////////////////////////////////////////////////
+#define DECL_INSN(OPCODE, CLASS)                           \
+  case OP_##OPCODE: return cast<CLASS>(this)->getSrcNum();
+
+  uint32 Instruction::getSrcNum(void) const {
+    const Opcode op = this->getOpcode();
+    switch (op) {
+      #include "ir_instruction.hxx"
+    };
+    return 0;
+  }
+#endif
 } /* namespace gbe */
 
index 0938f49..edd6fba 100644 (file)
 
 #include "sys/platform.hpp"
 #include "ir_register.hpp"
+#include "ir_value.hpp"
+#include "ir_type.hpp"
 
 namespace gbe
 {
   /*! All opcodes */
-  enum {
+  enum Opcode : uint8 {
 #define DECL_INSN(INSN, FAMILY) OP_##INSN,
 #include "ir_instruction.hxx"
 #undef DECL_INSN
-    OP_INVALID
   };
 
   /*! Different memory spaces */
-  enum {
-    MEM_GLOBAL = 0, /*! Global memory (a la OCL) */
-    MEM_LOCAL,      /*! Local memory (thread group memory) */
-    MEM_PRIVATE     /*! Per thread private memory */
+  enum MemorySpace : uint8 {
+    MEM_GLOBAL = 0, //!< Global memory (a la OCL)
+    MEM_LOCAL,      //!< Local memory (thread group memory)
+    MEM_PRIVATE     //!< Per thread private memory
   };
 
-  /*! All types possibly supported by the instruction */
-  enum {
-    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 */
-  };
+  /*! A label is identified with an unsigned short */
+  typedef uint16 LabelIndex;
+
+  /*! A value is stored in a per-function vector. This is the index to it */
+  typedef uint16 ValueIndex;
 
   /*! Function class contains the register file and the register tuple. Any
    *  information related to the registers may therefore require a function
@@ -64,88 +57,105 @@ namespace gbe
   {
   public:
     /*! Get the instruction opcode */
-    INLINE uint32 getOpcode(void) const { return op; }
+    INLINE Opcode getOpcode(void) const { return opcode; }
     /*! Get the number of sources for this instruction  */
     uint32 getSrcNum(void) const;
     /*! Get the number of destination for this instruction */
     uint32 getDstNum(void) const;
     /*! Get the register index of the given source */
-    uint32 getSrcIndex(const Function &fn, uint32 ID) const;
+    RegisterIndex getSrcIndex(const Function &fn, uint32 ID = 0u) const;
     /*! Get the register index of the given destination */
-    uint32 getDstIndex(const Function &fn, uint32 ID) const;
+    RegisterIndex getDstIndex(const Function &fn, uint32 ID = 0u) const;
     /*! Get the register of the given source */
-    Register getSrc(const Function &fn, uint32 ID) const;
+    Register getDst(const Function &fn, uint32 ID = 0u) const;
     /*! Get the register of the given destination */
-    Register getDst(const Function &fn, uint32 ID) const;
+    Register getSrc(const Function &fn, uint32 ID = 0u) const;
     /*! Check that the instruction is well formed. Return true if well formed.
+     *  j
      *  Otherwise, fill the string with a help message
      */
     bool check(void) const;
     /*! Indicates if the instruction belongs to instruction type T. Typically, T
      *  can be BinaryInstruction, UnaryInstruction, LoadInstruction and so on
      */
-    template <typename T> bool isTypeOf(void) const;
+    template <typename T> INLINE bool isMemberOf(void) const {
+      return T::isClassOf(*this);
+    }
   protected:
-    uint8 op;                                   //!< Idendifies the instruction
-    uint8 opaque[sizeof(uint64)-sizeof(uint8)]; //!< Remainder of it
+    Opcode opcode;                             //!< Idendifies the instruction
+    uint8 opaque[sizeof(uint64)-sizeof(uint8)];//!< Remainder of it
   };
 
   // Check that the instruction is properly formed by the compiler
   STATIC_ASSERT(sizeof(Instruction) == sizeof(uint64));
 
+  /*! Unary instructions are typed. dst and sources share the same type */
+  class UnaryInstruction : public Instruction {
+  public:
+    /*! Get the type manipulated by the instruction */
+    Type getType(void) const;
+    /*! Return true if the given instruction is an instance of this class */
+    static bool isClassOf(const Instruction &insn);
+  };
+
   /*! Binary instructions are typed. dst and sources share the same type */
-  class BinaryInstruction : public Instruction
-  {
+  class BinaryInstruction : public Instruction {
   public:
     /*! Get the type manipulated by the instruction */
-    uint32 getType(void) const;
+    Type getType(void) const;
+    /*! Return true if the given instruction is an instance of this class */
+    static bool isClassOf(const Instruction &insn);
   };
 
   /*! Ternary instructions is mostly for MADs */
-  class TernaryInstruction : public Instruction
-  {
+  class TernaryInstruction : public Instruction {
   public:
     /*! Get the type manipulated by the instruction */
-    uint32 getType(void) const;
+    Type getType(void) const;
+    /*! Return true if the given instruction is an instance of this class */
+    static bool isClassOf(const Instruction &insn);
   };
 
   /*! Conversion instruction converts from one type to another */
-  class ConvertInstruction : public Instruction
-  {
+  class ConvertInstruction : public Instruction {
   public:
     /*! Get the type of the source */
-    uint32 getSrcType(void) const;
+    Type getSrcType(void) const;
     /*! Get the type of the destination */
-    uint32 getDstType(void) const;
+    Type getDstType(void) const;
+    /*! Return true if the given instruction is an instance of this class */
+    static bool isClassOf(const Instruction &insn);
   };
 
   /*! Store instruction. First source is the address. Next sources are the
    *  values to store contiguously at the given address
    */
-  class StoreInstruction : public Instruction
-  {
+  class StoreInstruction : public Instruction {
   public:
     /*! Return the types of the values to store */
-    uint32 getValueType(void) const;
+    Type getValueType(void) const;
     /*! Give the number of values the instruction is storing (srcNum-1) */
     uint32 getValueNum(void) const;
     /*! Address space that is manipulated here */
-    uint32 getAddressSpace(void) const;
+    MemorySpace getAddressSpace(void) const;
+    /*! Return true if the given instruction is an instance of this class */
+    static bool isClassOf(const Instruction &insn);
   };
 
   /*! Load instruction. The source is simply the address where to get the data.
    *  The multiple destinations are the contiguous values loaded at the given
    *  address
    */
-  class LoadInstruction : public Instruction
-  {
+  class LoadInstruction : public Instruction {
   public:
     /*! Type of the loaded values (ie type of all the destinations) */
-    uint32 getValueType(void) const;
+    Type getValueType(void) const;
     /*! Number of values loaded (ie number of destinations) */
     uint32 getValueNum(void) const;
     /*! Address space that is manipulated here */
-    uint32 getAddressSpace(void) const;
+    MemorySpace getAddressSpace(void) const;
+    /*! Return true if the given instruction is an instance of this class */
+    static bool isClassOf(const Instruction &insn);
   };
 
   /*! Load immediate instruction loads an typed immediate value into the given
@@ -153,39 +163,83 @@ namespace gbe
    * the immediate themselves are stored in the function core. Contrary to
    * regular load instructions, there is only one destination possible
    */
-  class LoadImmInstruction : public Instruction
-  {
-    /*! The value as stored in the instruction */
-    union Value {
-      int8 s8;
-      uint8 u8;
-      int16 i16;
-      uint16 u16;
-      int32 i32;
-      uint32 u32;
-      int64 i64;
-      uint64 u64;
-      float f32;
-      double f64;
-    };
+  class LoadImmInstruction : public Instruction {
     /*! Return the value stored in the instruction */
     Value getValue(void) const;
     /*! Return the type of the stored value */
-    uint32 getType(void) const;
+    Type getType(void) const;
+    /*! Return true if the given instruction is an instance of this class */
+    static bool isClassOf(const Instruction &insn);
   };
 
-  /*! Prevents all cast to non-instruction types */
-  template <typename T> INLINE bool Instruction::isTypeOf(void) const {
-    return false;
-  }
+  /*! Branch instruction is the unified way to branch (with or without
+   *  predicate)
+   */
+  class BranchInstruction : public Instruction {
+  public:
+    /*! Indicate if the branch is predicated */
+    bool isPredicated(void) const;
+    /*! Return the predicate register (if predicated) */
+    Register getPredicate(const Function &fn) const {
+      assert(this->isPredicated() == true);
+      return this->getSrc(fn, 0);
+    }
+    /*! Return the predicate register index (if predicated) */
+    Register getPredicateIndex(const Function &fn) const {
+      assert(this->isPredicated() == true);
+      return this->getSrcIndex(fn, 0);
+    }
+    /*! Return true if the given instruction is an instance of this class */
+    static bool isClassOf(const Instruction &insn);
+  };
+
+  /*! Label instruction are actual no-op but are referenced by branches as their
+   *  targets
+   */
+  class LabelInstruction : public Instruction {
+  public:
+    /*! Return true if the given instruction is an instance of this class */
+    static bool isClassOf(const Instruction &insn);
+  };
+
+  /*! Texture instruction are used for any texture mapping requests */
+  class TextureInstruction : public Instruction {
+  public:
+    /*! Return true if the given instruction is an instance of this class */
+    static bool isClassOf(const Instruction &insn);
+  };
+
+  /*! Fence instructions are used to order loads and stores for a given memory
+   *  space
+   */
+  class FenceInstruction : public Instruction {
+  public:
+    /*! Return true if the given instruction is an instance of this class */
+    static bool isClassOf(const Instruction &insn);
+  };
 
   /*! Specialize the instruction. Also performs typechecking first based on the
    *  opcode. Crashes if it fails
    */
   template <typename T>
-  T *cast(Instruction *insn)
-  {
-
+  INLINE T *cast(Instruction *insn) {
+    assert(insn->isMemberOf<T>() == true);
+    return reinterpret_cast<T*>(insn);
+  }
+  template <typename T>
+  INLINE const T *cast(const Instruction *insn) {
+    assert(insn->isMemberOf<T>() == true);
+    return reinterpret_cast<const T*>(insn);
+  }
+  template <typename T>
+  INLINE T &cast(Instruction &insn) {
+    assert(insn.isMemberOf<T>() == true);
+    return reinterpret_cast<T&>(insn);
+  }
+  template <typename T>
+  INLINE const T &castc(const Instruction &insn) {
+    assert(insn.isMemberOf<T>() == true);
+    return reinterpret_cast<const T&>(insn);
   }
 
 } /* namespace gbe */
index afcd88e..7a63874 100644 (file)
@@ -53,6 +53,12 @@ namespace gbe
     GBE_CLASS(Register);
   };
 
+  /*! Register index is the position of the register in the register file */
+  typedef uint16 RegisterIndex;
+
+  /*! Tuple index is the position of the register index in the tuple vector */
+  typedef uint32 TupleIndex;
+
   /*! A register file allocates and destroys registers. Basically, we will have
    *  one register file per function
    */
@@ -60,23 +66,39 @@ namespace gbe
   {
   public:
     /*! Return the index of a newly allocated register register */
-    INLINE uint32 append(uint32 type) {
+    INLINE RegisterIndex append(uint32 type) {
       const uint32 index = regs.size();
       const Register reg(type);
       assert(index <= MAX_INDEX);
       regs.push_back(reg);
       return index;
     }
+    /*! Make a tuple and return the index to the first element of the tuple */
+    template <typename First, typename... Rest>
+    INLINE TupleIndex appendTuple(First first, Rest... rest) {
+      const TupleIndex index = regTuples.size();
+      regTuples.push_back(first);
+      appendTuple(rest...);
+      return index;
+    }
+    /*! To terminate variadic recursion */
+    INLINE void appendTuple(void) {}
     /*! Return a copy of the register at index */
-    INLINE Register get(uint32 index) const {
+    INLINE Register get(RegisterIndex index) const {
       assert(index < regs.size() && index <= MAX_INDEX);
       return regs[index];
     }
+    /*! Get the register index from the tuple */
+    INLINE RegisterIndex get(TupleIndex index, uint32 which) const {
+      assert(index + which < regTuples.size());
+      return regTuples[index + which];
+    }
     /*! Number of registers in the register file */
     INLINE uint32 regNum(void) const { return regs.size(); }
   private:
-    enum { MAX_INDEX = 0xffff }; //!< We encode indices in 2 bytes
-    vector<Register> regs;       //!< All the registers together
+    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 758aaa1..f856b0e 100644 (file)
@@ -64,30 +64,30 @@ namespace gbe
 } /* namespace gbe */
 
 /*! Declare a structure with custom allocators */
-#define GBE_STRUCT(TYPE)                                      \
+#define GBE_STRUCT(TYPE)                                     \
   void* operator new(size_t size)   {                        \
     if (AlignOf<TYPE>::value > sizeof(uintptr_t))            \
-      return gbe::alignedMalloc(size, AlignOf<TYPE>::value);  \
+      return gbe::alignedMalloc(size, AlignOf<TYPE>::value); \
     else                                                     \
-      return gbe::malloc(size);                               \
+      return gbe::malloc(size);                              \
   }                                                          \
   void* operator new[](size_t size)   {                      \
     if (AlignOf<TYPE>::value > sizeof(uintptr_t))            \
-      return gbe::alignedMalloc(size, AlignOf<TYPE>::value);  \
+      return gbe::alignedMalloc(size, AlignOf<TYPE>::value); \
     else                                                     \
-      return gbe::malloc(size);                               \
+      return gbe::malloc(size);                              \
   }                                                          \
   void  operator delete(void* ptr) {                         \
     if (AlignOf<TYPE>::value > sizeof(uintptr_t))            \
-      return gbe::alignedFree(ptr);                           \
+      return gbe::alignedFree(ptr);                          \
     else                                                     \
-      return gbe::free(ptr);                                  \
+      return gbe::free(ptr);                                 \
   }                                                          \
   void  operator delete[](void* ptr) {                       \
     if (AlignOf<TYPE>::value > sizeof(uintptr_t))            \
-      return gbe::alignedFree(ptr);                           \
+      return gbe::alignedFree(ptr);                          \
     else                                                     \
-      return gbe::free(ptr);                                  \
+      return gbe::free(ptr);                                 \
   }                                                          \
 
 /*! Declare a class with custom allocators */
@@ -196,8 +196,8 @@ namespace gbe
     ~GrowingPool(void) { GBE_ASSERT(current); GBE_DELETE(current); }
     T *allocate(void) {
       if (this->freeList != NULL) {
-        T *data = freeList;
-        this->freeList = *(void**) free;
+        T *data = (T*) freeList;
+        this->freeList = *(void**) freeList;
       }
       if (UNLIKELY(current->allocated == current->maxElemNum)) {
         GrowingPoolElem *elem = GBE_NEW(GrowingPoolElem, 2 * current->maxElemNum);
index 9d69095..cdd7df3 100644 (file)
@@ -22,7 +22,7 @@
 
 #include <vector>
 
-namespace pf
+namespace gbe
 {
   /*! Quick and dirty Unit test system with registration */
   struct UTest
@@ -44,10 +44,10 @@ namespace pf
     /*! Run all the tests */
     static void runAll(void);
   };
-} /* namespace pf */
+} /* namespace gbe */
 
 /*! Register a new unit test */
-#define UTEST_REGISTER(FN) static const pf::UTest __##NAME##__(FN, #FN);
+#define UTEST_REGISTER(FN) static const gbe::UTest __##NAME##__(FN, #FN);
 
 #endif /* __GBE_UTEST_HPP__ */