Added a clean interface for instruction (encoding in 8 bytes with alternative encodin...
authorBenjamin Segovia <segovia.benjamin@gmail.com>
Wed, 1 Feb 2012 08:22:00 +0000 (08:22 +0000)
committerKeith Packard <keithp@keithp.com>
Fri, 10 Aug 2012 23:15:10 +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_instruction.hxx [new file with mode: 0644]
backend/src/ir/ir_register.cpp
backend/src/ir/ir_register.hpp
backend/src/sys/platform.hpp

index edd3ec1..f26cf5c 100644 (file)
@@ -25,6 +25,8 @@ set (GBE_SRC
   sys/logging.hpp
   sys/default_path.cpp
   sys/default_path.hpp
+  ir/ir_instruction.cpp
+  ir/ir_instruction.hpp
   ir/ir_register.cpp
   ir/ir_register.hpp)
 
index b14ac8a..187d6e1 100644 (file)
 #ifndef __GBE_IR_FUNCTION_HPP__
 #define __GBE_IR_FUNCTION_HPP__
 
+namespace gbe
+{
+  /*! A function is no more that a set of declared registers and a set of
+   *  basic blocks
+   */
+  class Function
+  {
+  public:
+    /*! Create an empty function */
+    Function(void);
+
+    /*! Function basic blocks really belong to a function since:
+     * 1 - registers used in the basic blocks belongs to the function register
+     * file
+     * 2 - branches point to basic blocks of the same function
+     */
+    class BasicBlock
+    {
+    public:
+      /*! Empty basic block */
+      BasicBlock(void);
+      /*! Return the number of instruction in the block */
+      INLINE uint32 getInsnNum(void) { return insn.size(); }
+    private:
+      vector<Instruction> insn; //!< Sequence of instructions in the block
+    };
+
+    /*! Extract the register from the register file */
+    INLINE Register getRegister(uint32 ID) const { return file.get(ID); }
+
+  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<BasicBlock> insn; //!< All the basic blocks one after the others
+    RegisterFile file;       //!< All the registers used in the instructions
+  };
+
+} /* namespace gbe */
+
 #endif /* __GBE_IR_FUNCTION_HPP__ */
 
index e17d18d..56b7d5e 100644 (file)
  */
 
 #include "ir_instruction.hpp"
+#include "ir_function.hpp"
+
+namespace gbe
+{
+  namespace internal
+  {
+    /*! All unary and binary arithmetic instructions */
+    template <uint32 srcNum> // 1 or 2
+    class ALIGNED(AlignOf<Instruction>::value) NaryInstruction
+    {
+    public:
+      INLINE uint32 getOpcode(void) const { return opcode; }
+      INLINE uint32 getSrcNum(void) const { return srcNum; }
+      INLINE uint32 getDstNum(void) const { return 1; }
+      INLINE uint32 getDstIndex(const Function &fn, uint32 ID) const {
+        assert(ID == 0);
+        return dst;
+      }
+      INLINE uint32 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
+      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>
+    {
+    public:
+      UnaryInstruction(uint32 opcode, uint32 type, uint32 dst, uint32 src) {
+        this->opcode = opcode;
+        this->type = type;
+        this->dst = dst;
+        this->src[0] = src;
+      }
+    };
+
+    /*! All 2-source arithmetic instructions */
+    class BinaryInstruction : public NaryInstruction<2>
+    {
+    public:
+      BinaryInstruction(uint32 opcode, uint32 type, uint32 dst, uint32 src0, uint32 src1) {
+        this->opcode = opcode;
+        this->type = type;
+        this->dst = dst;
+        this->src[0] = src0;
+        this->src[1] = src1;
+      }
+    };
+
+    STATIC_ASSERT(sizeof(UnaryInstruction) <= sizeof(Instruction));
+    STATIC_ASSERT(sizeof(BinaryInstruction) <= sizeof(Instruction));
+
+  } /* namespace internal */
+} /* namespace gbe */
 
index a82d768..07df92e 100644 (file)
 #ifndef __GBE_IR_INSTRUCTION_HPP__
 #define __GBE_IR_INSTRUCTION_HPP__
 
-#endif /* __GBE_IR_INSTRUCTION_HPP__ */
+#include "sys/platform.hpp"
+#include "ir_register.hpp"
+
+namespace gbe
+{
+  /*! All opcodes */
+  enum {
+#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 */
+  };
+
+  /*! 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 */
+  };
+
+  /*! Function class contains the register file and the register tuple. Any
+   *  information related to the registers may therefore require a function
+   */
+  class Function;
+
+  /*! Store the instruction description in 8 bytes */
+  class Instruction
+  {
+  public:
+    /*! Get the instruction opcode */
+    uint32 getOpcode(void) const;
+    /*! 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;
+    /*! Get the register index of the given destination */
+    uint32 getDstIndex(const Function &fn, uint32 ID) const;
+    /*! Get the register of the given source */
+    Register getSrc(const Function &fn, uint32 ID) const;
+    /*! Get the register of the given destination */
+    Register getDst(const Function &fn, uint32 ID) const;
+    /*! Check that the instruction is well formed. Return true if well formed.
+     *  Otherwise, fill the string with a help message
+     */
+    bool check(void) const;
+  protected:
+    uint64 opaque; //!< Data depends on the instruction itself
+  };
+
+  /*! Binary instructions are typed. dst and sources share the same type */
+  class BinaryInstruction : public Instruction
+  {
+  public:
+    /*! Get the type manipulated by the instruction */
+    uint32 getType(void) const;
+  };
 
+  /*! Ternary instructions is mostly for MADs */
+  class TernaryInstruction : public Instruction
+  {
+  public:
+    /*! Get the type manipulated by the instruction */
+    uint32 getType(void) const;
+  };
+
+  /*! Conversion instruction converts from one type to another */
+  class ConvertInstruction : public Instruction
+  {
+  public:
+    /*! Get the type of the source */
+    uint32 getSrcType(void) const;
+    /*! Get the type of the destination */
+    uint32 getDstType(void) const;
+  };
+
+  /*! Store instruction */
+  class StoreInstruction : public Instruction
+  {
+  public:
+
+  };
+
+} /* namespace gbe */
+
+#endif /* __GBE_IR_INSTRUCTION_HPP__ */
 
diff --git a/backend/src/ir/ir_instruction.hxx b/backend/src/ir/ir_instruction.hxx
new file mode 100644 (file)
index 0000000..aa3bd9b
--- /dev/null
@@ -0,0 +1,48 @@
+// ======================================================================== //
+// Copyright (C) 2012 Benjamin Segovia                                      //
+//                                                                          //
+// Licensed under the Apache License, Version 2.0 (the "License");          //
+// you may not use this file except in compliance with the License.         //
+// You may obtain a copy of the License at                                  //
+//                                                                          //
+//     http://www.apache.org/licenses/LICENSE-2.0                           //
+//                                                                          //
+// Unless required by applicable law or agreed to in writing, software      //
+// distributed under the License is distributed on an "AS IS" BASIS,        //
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
+// See the License for the specific language governing permissions and      //
+// limitations under the License.                                           //
+// ======================================================================== //
+
+DECL_INSN(MOV, UnaryInstruction)
+DECL_INSN(COS, UnaryInstruction)
+DECL_INSN(SIN, UnaryInstruction)
+DECL_INSN(TAN, UnaryInstruction)
+DECL_INSN(LOG, UnaryInstruction)
+DECL_INSN(SQR, UnaryInstruction)
+DECL_INSN(RSQ, UnaryInstruction)
+DECL_INSN(EXP2, UnaryInstruction)
+DECL_INSN(POW, BinaryInstruction)
+DECL_INSN(MUL, BinaryInstruction)
+DECL_INSN(ADD, BinaryInstruction)
+DECL_INSN(SUB, BinaryInstruction)
+DECL_INSN(DIV, BinaryInstruction)
+DECL_INSN(REM, BinaryInstruction)
+DECL_INSN(SHL, BinaryInstruction)
+DECL_INSN(SHR, BinaryInstruction)
+DECL_INSN(ASR, BinaryInstruction)
+DECL_INSN(BSF, BinaryInstruction)
+DECL_INSN(BSB, BinaryInstruction)
+DECL_INSN(OR, BinaryInstruction)
+DECL_INSN(XOR, BinaryInstruction)
+DECL_INSN(AND, BinaryInstruction)
+DECL_INSN(MAD, TernaryInstruction)
+DECL_INSN(CVT, ConvertInstruction)
+DECL_INSN(BRA, BranchInstruction)
+DECL_INSN(TEX, TextureInstruction)
+DECL_INSN(LOADI, LoadImmInstruction)
+DECL_INSN(LOAD, LoadInstruction)
+DECL_INSN(STORE, StoreInstruction)
+DECL_INSN(FENCE, FenceInstruction)
+DECL_INSN(LABEL, LabelInstruction)
+
index 8b88ac9..bca6a9b 100644 (file)
  */
 
 #include "ir_register.hpp"
-#include "sys/map.hpp"
-#include "sys/fixed_array.hpp"
-#include "sys/vector.hpp"
 
 namespace gbe
 {
-  const uint8 Register::familySize[] = {
-    1, // bool
-    1, // byte
-    2, // word
-    4, // dword
-    5, // qword
-  };
-
-  /*! Implement register file class */
-  class RegisterFileInternal : public RegisterFile
-  {
-    // Implements base class methods
-    virtual ~RegisterFileInternal(void);
-    virtual Register *create(Register::Family family, uint8 width);
-    virtual Register *get(uint32 id);
-    virtual void destroy(Register *reg);
-
-    
-  };
 
 } /* namespace gbe */
 
index 8fec296..afcd88e 100644 (file)
 #ifndef __GBE_IR_REGISTER_HPP__
 #define __GBE_IR_REGISTER_HPP__
 
-#include "sys/ref.hpp"
-#include <new>
+#include "sys/vector.hpp"
 
 namespace gbe
 {
-  /*! Describe a register in GBE register file. Each register can be either a
-   *  boolean value or a {8|16|32|64} bit word. Also, each register contains some
-   *  number of lanes that describes its SIMD width
+  /*! A register can be either a byte, a word, a dword or a qword. It can be
+   *  either scalar or a vector. Everything is packed in 32 bits
    */
-  class Register : public RefCount, public NonCopyable
+  class Register
   {
   public:
-    /*! Family basically gives the size of each register lane */
-    enum Family
-    {
+    /*! Build a register. All fields will be immutable */
+    INLINE Register(uint8 type) : type(type) {}
+    /*! Copy constructor */
+    INLINE Register(const Register &other) : type(other.type) {}
+    /*! Copy operator */
+    Register &operator= (const Register &other) {
+      *this = Register(other.type);
+      return *this;
+    }
+    /*! Nothing really happens here */
+    INLINE ~Register(void) {}
+    /*! Register type */
+    enum {
       BOOL  = 0,
       BYTE  = 1,
       WORD  = 2,
       DWORD = 3,
       QWORD = 4
     };
-    friend class RegisterFile; // Allocates and destroys registers
-    /*! Get the register identifier */
-    INLINE uint32 id(void)     const { return this->_id; }
-    /*! Get the register width (ie number of lanes) */
-    INLINE uint16 width(void)  const { return this->_width; }
-    /*! Get the register family */
-    INLINE Family family(void) const { return this->_family; }
-    /*! Get the register *individual* lane size */
-    INLINE uint8  size(void)   const { return this->_size; }
-  private:
-    /*! */
-    INLINE Register(uint32 id, Family family, uint8 width) :
-      _id(id), _width(width), _family(family), _size(familySize[family]) {}
-    INLINE ~Register(void) {}
-    const uint32 _id;     //!< Uniquely identifies the register
-    const uint16 _width;  //!< Number of lane in the vector
-    const Family _family; //!< From Family enum
-    const uint8 _size;    //!< Directly related to its type
-    /*! Gives the size for each family */
-    static const uint8 familySize[];
+    const uint8 type;
     GBE_CLASS(Register);
   };
 
-  /*! Registers are equal if they have same width, ID and family */
-  INLINE bool operator== (const Register &a, const Register &b) {
-    return a.id() == b.id() &&
-           a.width() == b.width() &&
-           a.family() == b.family();
-  }
-
-  /*! != is just "not equal" */
-  INLINE bool operator!= (const Register &a, const Register &b) {
-    return !(a == b);
-  }
-
-  /*! To sort registers */
-  INLINE bool operator< (const Register &a, const Register &b) {
-    if (a.family() != b.family()) return a.family() < b.family();
-    if (a.width() != b.width()) return a.width() < b.width();
-    if (a.id() != b.id()) return a.id() < b.id();
-    return false;
-  }
-
   /*! A register file allocates and destroys registers. Basically, we will have
    *  one register file per function
    */
-  class RegisterFile : public RefCount
+  class RegisterFile
   {
   public:
-    /*! Destroy the register file */
-    virtual ~RegisterFile(void) = 0;
-    /*! Allocate and return a valid register */
-    virtual Register *create(Register::Family family, uint8 width) = 0;
-    /*! Get the register with index id */
-    virtual Register *get(uint32 id) = 0;
-    /*! Deallocate the register */
-    virtual void destroy(Register *reg) = 0;
+    /*! Return the index of a newly allocated register register */
+    INLINE uint32 append(uint32 type) {
+      const uint32 index = regs.size();
+      const Register reg(type);
+      assert(index <= MAX_INDEX);
+      regs.push_back(reg);
+      return index;
+    }
+    /*! Return a copy of the register at index */
+    INLINE Register get(uint32 index) const {
+      assert(index < regs.size() && index <= MAX_INDEX);
+      return regs[index];
+    }
+    /*! 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
+    GBE_CLASS(RegisterFile);
   };
 
-  /*! Allocate a new register file */
-  RegisterFile *RegisterFileNew(void);
-
 } /* namespace gbe */
 
 #endif /* __GBE_IR_REGISTER_HPP__ */
index 921c4a5..b1451d2 100644 (file)
@@ -238,7 +238,7 @@ template <typename T>
 struct AlignOf
 {
   struct Helper { char x; T t; };
-  static const size_t value = offsetof(Helper, t);
+  enum { value = offsetof(Helper, t) };
 };
 
 ////////////////////////////////////////////////////////////////////////////////