Started to implement support for byte and shorts
authorBenjamin Segovia <devnull@localhost>
Mon, 7 May 2012 23:49:54 +0000 (23:49 +0000)
committerKeith Packard <keithp@keithp.com>
Fri, 10 Aug 2012 23:17:09 +0000 (16:17 -0700)
backend/src/backend/gen_context.cpp
backend/src/backend/gen_defs.hpp
backend/src/backend/gen_eu.cpp
backend/src/backend/gen_eu.hpp
backend/src/ir/instruction.cpp
backend/src/ir/type.cpp
backend/src/llvm/llvm_gen_backend.cpp

index 77912a4..519a476 100644 (file)
@@ -384,6 +384,10 @@ namespace gbe
     switch (opcode) {
       case OP_ADD: p->ADD(dst, src0, src1); break;
       case OP_SUB: p->ADD(dst, src0, GenReg::negate(src1)); break;
+      case OP_AND: p->AND(dst, src0, src1); break;
+      case OP_XOR: p->XOR(dst, src0, src1); break;
+      case OP_OR:  p->OR(dst, src0,  src1); break;
+      case OP_SHL: p->SHL(dst, src0, src1); break;
       case OP_MUL: 
       {
         if (type == TYPE_FLOAT)
@@ -394,12 +398,21 @@ namespace gbe
           NOT_IMPLEMENTED;
         break;
       }
+      case OP_DIV:
+      {
+        p->MATH(dst, GEN_MATH_FUNCTION_INV, src0, src1);
+        break;
+      }
       default: NOT_IMPLEMENTED;
     }
   }
 
-  void GenContext::emitTernaryInstruction(const ir::TernaryInstruction &insn) {}
-  void GenContext::emitSelectInstruction(const ir::SelectInstruction &insn) {}
+  void GenContext::emitTernaryInstruction(const ir::TernaryInstruction &insn) {
+    NOT_IMPLEMENTED;
+  }
+  void GenContext::emitSelectInstruction(const ir::SelectInstruction &insn) {
+    NOT_IMPLEMENTED;
+  }
 
   void GenContext::emitCompareInstruction(const ir::CompareInstruction &insn) {
     using namespace ir;
@@ -449,7 +462,14 @@ namespace gbe
     p->pop();
   }
 
-  void GenContext::emitConvertInstruction(const ir::ConvertInstruction &insn) {}
+  void GenContext::emitConvertInstruction(const ir::ConvertInstruction &insn) {
+    const ir::Type dstType = insn.getDstType();
+    const ir::Type srcType = insn.getSrcType();
+    const GenReg dst = this->genReg(insn.getDst(0), dstType);
+    const GenReg src = this->genReg(insn.getSrc(0), srcType);
+    p->MOV(dst, src);
+  }
+
   void GenContext::emitBranchInstruction(const ir::BranchInstruction &insn) {
     using namespace ir;
     const Opcode opcode = insn.getOpcode();
@@ -473,7 +493,10 @@ namespace gbe
     } else
       NOT_IMPLEMENTED;
   }
-  void GenContext::emitTextureInstruction(const ir::TextureInstruction &insn) {}
+
+  void GenContext::emitTextureInstruction(const ir::TextureInstruction &insn) {
+    NOT_IMPLEMENTED;
+  }
 
   void GenContext::emitLoadImmInstruction(const ir::LoadImmInstruction &insn) {
     using namespace ir;
index 870895c..1bbf536 100644 (file)
@@ -247,9 +247,15 @@ enum GenMessageTarget {
 #define GEN_UNTYPED_SIMD16  1
 #define GEN_UNTYPED_SIMD8   2
 
+/* SIMD mode for byte scatters / gathers */
+#define GEN_BYTE_SCATTER_SIMD8    0
+#define GEN_BYTE_SCATTER_SIMD16   1
+
 /* Data port message type */
 #define GEN_UNTYPED_READ    5
 #define GEN_UNTYPED_WRITE  13
+#define GEN_BYTE_GATHER     4
+#define GEN_BYTE_SCATTER   12
 
 #define GEN_SAMPLER_RETURN_FORMAT_FLOAT32     0
 #define GEN_SAMPLER_RETURN_FORMAT_UINT32      2
@@ -660,6 +666,22 @@ struct GenInstruction
          uint32_t end_of_thread:1;
       } gen7_untyped_rw;
 
+      /*! Data port byte scatter / gather */
+      struct {
+         uint32_t bti:8;
+         uint32_t simd_mode:1;
+         uint32_t ignored0:1;
+         uint32_t data_size:2;
+         uint32_t ignored1:2;
+         uint32_t msg_type:4;
+         uint32_t category:1;
+         uint32_t header_present:1;
+         uint32_t response_length:5;
+         uint32_t msg_length:4;
+         uint32_t pad2:2;
+         uint32_t end_of_thread:1;
+      } gen7_byte_rw;
+
       struct {
          uint32_t src1_subreg_nr_high:1;
          uint32_t src1_reg_nr:8;
index a58d2bc..89e8d8b 100644 (file)
@@ -307,6 +307,28 @@ namespace gbe
        NOT_SUPPORTED;
   }
 
+  void
+  set_dp_byte_scatter_gather(GenEmitter *p,
+                             GenInstruction *insn,
+                             uint32_t bti,
+                             uint32_t elem_size,
+                             uint32_t msg_type,
+                             uint32_t msg_length,
+                             uint32_t response_length)
+  {
+     GenMessageTarget sfid = GEN_SFID_DATAPORT_DATA_CACHE;
+     brw_set_message_descriptor(p, insn, sfid, msg_length, response_length);
+     insn->bits3.gen7_byte_rw.msg_type = msg_type;
+     insn->bits3.gen7_byte_rw.bti = bti;
+     insn->bits3.gen7_byte_rw.data_size = elem_size;
+     if (p->curr.execWidth == 8)
+       insn->bits3.gen7_byte_rw.simd_mode = GEN_BYTE_SCATTER_SIMD8;
+     else if (p->curr.execWidth == 16)
+       insn->bits3.gen7_byte_rw.simd_mode = GEN_BYTE_SCATTER_SIMD16;
+     else
+       NOT_SUPPORTED;
+  }
+
   static const uint32_t untypedRWMask[] = {
     GEN_UNTYPED_ALPHA|GEN_UNTYPED_BLUE|GEN_UNTYPED_GREEN|GEN_UNTYPED_RED,
     GEN_UNTYPED_ALPHA|GEN_UNTYPED_BLUE|GEN_UNTYPED_GREEN,
@@ -372,6 +394,60 @@ namespace gbe
                       response_length);
   }
 
+  void
+  GenEmitter::BYTE_GATHER(GenReg dst, GenReg src, uint32_t bti, uint32_t elemSize)
+  {
+    GenInstruction *insn = this->next(GEN_OPCODE_SEND);
+    uint32_t msg_length = 0;
+    uint32_t response_length = 0;
+    if (this->curr.execWidth == 8) {
+      msg_length = 1;
+      response_length = 1;
+    } else if (this->curr.execWidth == 16) {
+      msg_length = 2;
+      response_length = 2;
+    } else
+      NOT_IMPLEMENTED;
+
+    this->setHeader(insn);
+    this->setDst(insn, GenReg::uw16grf(dst.nr, 0));
+    this->setSrc0(insn, GenReg::ud8grf(src.nr, 0));
+    this->setSrc1(insn, GenReg::immud(0));
+    set_dp_byte_scatter_gather(this,
+                               insn,
+                               bti,
+                               elemSize,
+                               GEN_BYTE_GATHER,
+                               msg_length,
+                               response_length);
+  }
+
+  void
+  GenEmitter::BYTE_SCATTER(GenReg msg, uint32_t bti, uint32_t elemSize)
+  {
+    GenInstruction *insn = this->next(GEN_OPCODE_SEND);
+    uint32_t msg_length = 0;
+    uint32_t response_length = 0;
+    this->setHeader(insn);
+    if (this->curr.execWidth == 8) {
+      this->setDst(insn, GenReg::retype(GenReg::null(), GEN_TYPE_UD));
+      msg_length = 1;
+    } else if (this->curr.execWidth == 16) {
+      this->setDst(insn, GenReg::retype(GenReg::null(), GEN_TYPE_UW));
+      msg_length = 2;
+    } else
+      NOT_IMPLEMENTED;
+    this->setSrc0(insn, GenReg::ud8grf(msg.nr, 0));
+    this->setSrc1(insn, GenReg::immud(0));
+    set_dp_byte_scatter_gather(this,
+                               insn,
+                               bti,
+                               elemSize,
+                               GEN_BYTE_SCATTER,
+                               msg_length,
+                               response_length);
+  }
+
   void set_sampler_message(GenEmitter *p,
                            GenInstruction *insn,
                            uint32_t bti,
@@ -639,36 +715,7 @@ namespace gbe
      insn->header.quarter_control = 0;
   }
 
-  void GenEmitter::MATH(GenReg dest,
-                        uint32_t function,
-                        uint32_t saturate,
-                        uint32_t msg_reg_nr,
-                        GenReg src,
-                        uint32_t data_type,
-                        uint32_t precision)
-  {
-    GenInstruction *insn = this->next(GEN_OPCODE_MATH);
-
-    assert(dest.file == GEN_GENERAL_REGISTER_FILE);
-    assert(src.file == GEN_GENERAL_REGISTER_FILE);
-    assert(dest.hstride == GEN_HORIZONTAL_STRIDE_1);
-
-    if (function == GEN_MATH_FUNCTION_INT_DIV_QUOTIENT ||
-        function == GEN_MATH_FUNCTION_INT_DIV_REMAINDER ||
-        function == GEN_MATH_FUNCTION_INT_DIV_QUOTIENT_AND_REMAINDER) {
-      assert(src.type != GEN_TYPE_F);
-    } else
-      assert(src.type == GEN_TYPE_F);
-
-    insn->header.destreg_or_condmod = function;
-    insn->header.saturate = saturate;
-    this->setDst(insn, dest);
-    this->setSrc0(insn, src);
-    this->setSrc1(insn, GenReg::null());
-  }
-
-
-  void GenEmitter::MATH2(GenReg dest, uint32_t function, GenReg src0, GenReg src1)
+  void GenEmitter::MATH(GenReg dest, uint32_t function, GenReg src0, GenReg src1)
   {
      GenInstruction *insn = this->next(GEN_OPCODE_MATH);
 
@@ -694,38 +741,6 @@ namespace gbe
      this->setSrc1(insn, src1);
   }
 
-  void GenEmitter::MATH16(GenReg dest,
-                          uint32_t function,
-                          uint32_t saturate,
-                          uint32_t msg_reg_nr,
-                          GenReg src,
-                          uint32_t precision)
-  {
-     GenInstruction *insn;
-
-     insn = this->next(GEN_OPCODE_MATH);
-
-     /* Math is the same ISA format as other opcodes, except that CondModifier
-      * becomes FC[3:0] and ThreadCtrl becomes FC[5:4].
-      */
-     insn->header.destreg_or_condmod = function;
-     insn->header.saturate = saturate;
-
-     /* Source modifiers are ignored for extended math instructions. */
-     assert(!src.negate);
-     assert(!src.abs);
-
-     this->setHeader(insn);
-     this->setDst(insn, dest);
-     this->setSrc0(insn, src);
-     this->setSrc1(insn, GenReg::null());
-  }
-
-  /**
-   * Texture sample instruction.
-   * Note: the msg_type plus msg_length values determine exactly what kind
-   * of sampling operation is performed.  See volume 4, page 161 of docs.
-   */
   void GenEmitter::SAMPLE(GenReg dest,
                           uint32_t msg_reg_nr,
                           GenReg src0,
index c81595d..df2adf8 100644 (file)
@@ -633,6 +633,10 @@ namespace gbe
     void UNTYPED_READ(GenReg dst, GenReg src, uint32_t bti, uint32_t elemNum);
     /*! Untyped write (upto 4 channels) */
     void UNTYPED_WRITE(GenReg src, uint32_t bti, uint32_t elemNum);
+    /*! Byte gather (for unaligned bytes, shorts and ints) */
+    void BYTE_GATHER(GenReg dst, GenReg src, uint32_t bti, uint32_t type);
+    /*! Byte scatter (for unaligned bytes, shorts and ints) */
+    void BYTE_SCATTER(GenReg src, uint32_t bti, uint32_t type);
     /*! Send instruction for the sampler */
     void SAMPLE(GenReg dest,
                 uint32_t msg_reg_nr,
@@ -646,23 +650,8 @@ namespace gbe
                 uint32_t header_present,
                 uint32_t simd_mode,
                 uint32_t return_format);
-    /*! Extended math function, float[16] */
-    void MATH16(GenReg dest,
-                uint32_t function,
-                uint32_t saturate,
-                uint32_t msg_reg_nr,
-                GenReg src,
-                uint32_t precision);
-    /*! Extended math function, float[8] */
-    void MATH(GenReg dest,
-              uint32_t function,
-              uint32_t saturate,
-              uint32_t msg_reg_nr,
-              GenReg src,
-              uint32_t data_type,
-              uint32_t precision);
     /*! Extended math function, float[8] */
-    void MATH2(GenReg dest, uint32_t function, GenReg src0, GenReg src1);
+    void MATH(GenReg dest, uint32_t function, GenReg src0, GenReg src1);
 
     /*! Patch JMPI (located at index insnID) with the given jump distance */
     void patchJMPI(uint32_t insnID, int32_t jumpDistance);
index 586142f..ea5dd8c 100644 (file)
@@ -460,7 +460,7 @@ namespace ir {
     // Implements all the wellFormed methods
     /////////////////////////////////////////////////////////////////////////
 
-    /*! All Nary instruction register must be of the same family and properly
+    /*! All Nary instruction registers must be of the same family and properly
      *  defined (i.e. not out-of-bound)
      */
     static INLINE bool checkRegisterData(RegisterFamily family,
@@ -492,6 +492,46 @@ namespace ir {
       return true;
     }
 
+    /*! We check that the given type belongs to the provided type family */
+    static INLINE bool checkTypeFamily(const Type &type,
+                                       const Type *family,
+                                       uint32_t typeNum,
+                                       std::string &whyNot)
+    {
+      uint32_t typeID = 0;
+      for (; typeID < typeNum; ++typeID)
+        if (family[typeID] == type)
+          break;
+      if (typeID == typeNum) {
+        whyNot = "Type is not supported by the instruction";
+        return false;
+      }
+      return true;
+    }
+
+#define CHECK_TYPE(TYPE, FAMILY) \
+  do { \
+    if (UNLIKELY(checkTypeFamily(TYPE, FAMILY, FAMILY##Num, whyNot)) == false) \
+      return false; \
+  } while (0)
+
+    static const Type madType[] = {TYPE_FLOAT};
+    static const uint32_t madTypeNum = ARRAY_ELEM_NUM(madType);
+
+    // TODO add support for 64 bits values
+    static const Type allButBool[] = {TYPE_S8,  TYPE_U8,
+                                        TYPE_S16, TYPE_U16,
+                                        TYPE_S32, TYPE_U32,
+                                        TYPE_FLOAT, TYPE_DOUBLE};
+    static const uint32_t allButBoolNum = ARRAY_ELEM_NUM(allButBool);
+
+    // TODO add support for 64 bits values
+    static const Type logicalType[] = {TYPE_S8,  TYPE_U8,
+                                       TYPE_S16, TYPE_U16,
+                                       TYPE_S32, TYPE_U32,
+                                       TYPE_BOOL};
+    static const uint32_t logicalTypeNum = ARRAY_ELEM_NUM(logicalType);
+
     // Unary and binary instructions share the same rules
     template <uint32_t srcNum>
     INLINE bool NaryInstruction<srcNum>::wellFormed(const Function &fn, std::string &whyNot) const
@@ -504,6 +544,18 @@ namespace ir {
       for (uint32_t srcID = 0; srcID < srcNum; ++srcID)
         if (UNLIKELY(checkRegisterData(family, src[srcID], fn, whyNot) == false))
           return false;
+      // We actually support logical operations on boolean values for AND, OR,
+      // and XOR
+      switch (this->opcode) {
+        case OP_OR:
+        case OP_XOR:
+        case OP_AND:
+          CHECK_TYPE(this->type, logicalType);
+          break;
+        default:
+          CHECK_TYPE(this->type, allButBool);
+          break;
+      }
       return true;
     }
 
@@ -524,6 +576,10 @@ namespace ir {
         if (UNLIKELY(checkRegisterData(family, regID, fn, whyNot) == false))
           return false;
       }
+      if (this->opcode == OP_MAD)
+        CHECK_TYPE(this->type, madType);
+      else
+        NOT_IMPLEMENTED;
       return true;
     }
 
@@ -547,6 +603,7 @@ namespace ir {
         if (UNLIKELY(checkRegisterData(family, regID, fn, whyNot) == false))
           return false;
       }
+      CHECK_TYPE(this->type, allButBool);
       return true;
     }
 
@@ -562,6 +619,7 @@ namespace ir {
       for (uint32_t srcID = 0; srcID < 2; ++srcID)
         if (UNLIKELY(checkRegisterData(family, src[srcID], fn, whyNot) == false))
           return false;
+      CHECK_TYPE(this->type, allButBool);
       return true;
     }
 
@@ -576,6 +634,8 @@ namespace ir {
         return false;
       if (UNLIKELY(checkRegisterData(srcFamily, src, fn, whyNot) == false))
         return false;
+      CHECK_TYPE(this->dstType, allButBool);
+      CHECK_TYPE(this->srcType, allButBool);
       return true;
     }
 
@@ -598,6 +658,7 @@ namespace ir {
         if (UNLIKELY(checkRegisterData(family, regID, fn, whyNot) == false))
           return false;
       }
+      CHECK_TYPE(insn.type, allButBool);
       return true;
     }
 
@@ -639,6 +700,7 @@ namespace ir {
         return false;
       if (UNLIKELY(checkRegisterData(family, dst, fn, whyNot) == false))
         return false;
+      CHECK_TYPE(this->type, allButBool);
       return true;
     }
 
@@ -671,6 +733,7 @@ namespace ir {
           return false;
       return true;
     }
+#undef CHECK_TYPE
 
     /////////////////////////////////////////////////////////////////////////
     // Implements all the output stream methods
index 0de58da..a6a2e44 100644 (file)
@@ -30,7 +30,7 @@ namespace ir {
     switch (type) {
       case TYPE_BOOL: return out << "bool";
       case TYPE_S8: return out << "int8";
-      case TYPE_U8: return out << "uin8";
+      case TYPE_U8: return out << "uint8";
       case TYPE_S16: return out << "int16";
       case TYPE_U16: return out << "uin16";
       case TYPE_S32: return out << "int32";
index 0d95748..d67a857 100644 (file)
@@ -736,8 +736,18 @@ namespace gbe
   }
 
   void GenWriter::emitBinaryOperator(Instruction &I) {
-    GBE_ASSERT(I.getType()->isPointerTy() == false &&
-               I.getType() != Type::getInt1Ty(I.getContext()));
+#if GBE_DEBUG
+    GBE_ASSERT(I.getType()->isPointerTy() == false);
+    // We accept logical operations on booleans
+    switch (I.getOpcode()) {
+      case Instruction::And:
+      case Instruction::Or:
+      case Instruction::Xor:
+        break;
+      default:
+        GBE_ASSERT(I.getType() != Type::getInt1Ty(I.getContext()));
+    }
+#endif /* GBE_DEBUG */
 
     // Get the element type for a vector
     uint32_t elemNum;