Add atomic help functions.
authorYang Rong <rong.r.yang@intel.com>
Thu, 27 Jun 2013 08:47:55 +0000 (16:47 +0800)
committerZhigang Gong <zhigang.gong@linux.intel.com>
Thu, 27 Jun 2013 10:53:49 +0000 (18:53 +0800)
Use the data port message "Untyped Atomic Operation" to implement openCL atomic functions.
This message can handle both global memory and SLM.
For all atomic functions, the operands will be treated as unsigned int, except imax/imin.
Only add one opcode Atomic for all atomic functions in ir, and identify the atomic function
by ir::AtomicOps.

Signed-off-by: Yang Rong <rong.r.yang@intel.com>
Reviewed-by: Zhigang Gong <zhigang.gong@linux.intel.com>
12 files changed:
backend/src/backend/gen_context.cpp
backend/src/backend/gen_context.hpp
backend/src/backend/gen_defs.hpp
backend/src/backend/gen_encoder.cpp
backend/src/backend/gen_encoder.hpp
backend/src/backend/gen_insn_gen7_schedule_info.hxx
backend/src/backend/gen_insn_selection.cpp
backend/src/backend/gen_insn_selection.hpp
backend/src/backend/gen_insn_selection.hxx
backend/src/ir/instruction.cpp
backend/src/ir/instruction.hpp
backend/src/ir/instruction.hxx

index 93d3932..41cab90 100644 (file)
@@ -226,6 +226,15 @@ namespace gbe
     }
   }
 
+  void GenContext::emitAtomicInstruction(const SelectionInstruction &insn) {
+    const GenRegister src = ra->genReg(insn.src(0));
+    const GenRegister dst = ra->genReg(insn.dst(0));
+    const uint32_t function = insn.extra.function;
+    const uint32_t bti = insn.extra.elem;
+
+    p->ATOMIC(dst, function, src, bti, insn.srcNum);
+  }
+
   void GenContext::emitIndirectMoveInstruction(const SelectionInstruction &insn) {
     GenRegister src = ra->genReg(insn.src(0));
     if(isScalarReg(src.reg()))
index 804384d..5dfaef9 100644 (file)
@@ -91,6 +91,7 @@ namespace gbe
     void emitWriteFloat64Instruction(const SelectionInstruction &insn);
     void emitUntypedReadInstruction(const SelectionInstruction &insn);
     void emitUntypedWriteInstruction(const SelectionInstruction &insn);
+    void emitAtomicInstruction(const SelectionInstruction &insn);
     void emitByteGatherInstruction(const SelectionInstruction &insn);
     void emitByteScatterInstruction(const SelectionInstruction &insn);
     void emitSampleInstruction(const SelectionInstruction &insn);
index d1ce6b2..61412c4 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * Copyright © 2012 Intel Corporation
  *
  * This library is free software; you can redistribute it and/or
@@ -21,7 +21,7 @@
  Copyright (C) Intel Corp.  2006.  All Rights Reserved.
  Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
  develop this 3D driver.
+
  Permission is hereby granted, free of charge, to any person obtaining
  a copy of this software and associated documentation files (the
  "Software"), to deal in the Software without restriction, including
  distribute, sublicense, and/or sell copies of the Software, and to
  permit persons to whom the Software is furnished to do so, subject to
  the following conditions:
+
  The above copyright notice and this permission notice (including the
  next paragraph) shall be included in all copies or substantial
  portions of the Software.
+
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
@@ -41,7 +41,7 @@
  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
  **********************************************************************/
  /*
   * Authors:
@@ -169,6 +169,28 @@ enum opcode {
   GEN_OPCODE_NOP = 126,
 };
 
+#define GEN_ATOMIC_SIMD16   0
+#define GEN_ATOMIC_SIMD8    1
+
+enum GenAtomicOpCode {
+  GEN_ATOMIC_OP_CMPWR8B   = 0,
+  GEN_ATOMIC_OP_AND       = 1,
+  GEN_ATOMIC_OP_OR        = 2,
+  GEN_ATOMIC_OP_XOR       = 3,
+  GEN_ATOMIC_OP_MOV       = 4,
+  GEN_ATOMIC_OP_INC       = 5,
+  GEN_ATOMIC_OP_DEC       = 6,
+  GEN_ATOMIC_OP_ADD       = 7,
+  GEN_ATOMIC_OP_SUB       = 8,
+  GEN_ATOMIC_OP_REVSUB    = 9,
+  GEN_ATOMIC_OP_IMAX      = 10,
+  GEN_ATOMIC_OP_IMIN      = 11,
+  GEN_ATOMIC_OP_UMAX      = 12,
+  GEN_ATOMIC_OP_UMIN      = 13,
+  GEN_ATOMIC_OP_CMPWR     = 14,
+  GEN_ATOMIC_OP_PREDEC    = 15
+};
+
 /*! Gen SFID */
 enum GenMessageTarget {
   GEN_SFID_NULL                     = 0,
@@ -772,7 +794,7 @@ struct GenInstruction
     /*! Memory fence */
     struct {
       uint32_t bti:8;
-      uint32_t ingored:5;
+      uint32_t pad:5;
       uint32_t commit_enable:1;
       uint32_t msg_type:4;
       uint32_t pad2:1;
@@ -783,6 +805,21 @@ struct GenInstruction
       uint32_t end_of_thread:1;
     } gen7_memory_fence;
 
+    /*! atomic messages */
+    struct {
+      uint32_t bti:8;
+      uint32_t aop_type:4;
+      uint32_t simd_mode:1;
+      uint32_t return_data:1;
+      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 pad3:2;
+      uint32_t end_of_thread:1;
+    } gen7_atomic_op;
+
     struct {
       uint32_t src1_subreg_nr_high:1;
       uint32_t src1_reg_nr:8;
index e96678b..43658e8 100644 (file)
@@ -558,6 +558,41 @@ namespace gbe
                            response_length);
   }
 
+  void GenEncoder::ATOMIC(GenRegister dst, uint32_t function, GenRegister src, uint32_t bti, uint32_t srcNum) {
+    GenInstruction *insn = this->next(GEN_OPCODE_SEND);
+    uint32_t msg_length = 0;
+    uint32_t response_length = 0;
+
+    if (this->curr.execWidth == 8) {
+      msg_length = srcNum;
+      response_length = 1;
+    } else if (this->curr.execWidth == 16) {
+      msg_length = 2*srcNum;
+      response_length = 2;
+    } else
+      NOT_IMPLEMENTED;
+
+    this->setHeader(insn);
+    this->setDst(insn, GenRegister::uw16grf(dst.nr, 0));
+    this->setSrc0(insn, GenRegister::ud8grf(src.nr, 0));
+    this->setSrc1(insn, GenRegister::immud(0));
+
+    const GenMessageTarget sfid = GEN_SFID_DATAPORT_DATA_CACHE;
+    setMessageDescriptor(this, insn, sfid, msg_length, response_length);
+    insn->bits3.gen7_atomic_op.msg_type = GEN_UNTYPED_ATOMIC_READ;
+    insn->bits3.gen7_atomic_op.bti = bti;
+    insn->bits3.gen7_atomic_op.return_data = 1;
+    insn->bits3.gen7_atomic_op.aop_type = function;
+
+    if (this->curr.execWidth == 8)
+      insn->bits3.gen7_atomic_op.simd_mode = GEN_ATOMIC_SIMD8;
+    else if (this->curr.execWidth == 16)
+      insn->bits3.gen7_atomic_op.simd_mode = GEN_ATOMIC_SIMD16;
+    else
+      NOT_SUPPORTED;
+
+  }
+
   GenInstruction *GenEncoder::next(uint32_t opcode) {
      GenInstruction insn;
      std::memset(&insn, 0, sizeof(GenInstruction));
index 88a3e77..3ff8c97 100644 (file)
@@ -136,6 +136,8 @@ namespace gbe
     void NOP(void);
     /*! Wait instruction (used for the barrier) */
     void WAIT(void);
+    /*! Atomic instructions */
+    void ATOMIC(GenRegister dst, uint32_t function, GenRegister src, uint32_t bti, uint32_t srcNum);
     /*! Read 64-bits float arrays */
     void READ_FLOAT64(GenRegister dst, GenRegister src, uint32_t bti, uint32_t elemNum);
     /*! Write 64-bits float arrays */
index a3b4621..f3f4a25 100644 (file)
@@ -21,4 +21,4 @@ DECL_GEN7_SCHEDULE(ByteScatter,     80,        1,        1)
 DECL_GEN7_SCHEDULE(Sample,          80,        1,        1)
 DECL_GEN7_SCHEDULE(TypedWrite,      80,        1,        1)
 DECL_GEN7_SCHEDULE(GetImageInfo,    20,        4,        2)
-
+DECL_GEN7_SCHEDULE(Atomic,          80,        1,        1)
index a20eff0..3d0fbbf 100644 (file)
@@ -168,12 +168,14 @@ namespace gbe
   bool SelectionInstruction::isRead(void) const {
     return this->opcode == SEL_OP_UNTYPED_READ ||
            this->opcode == SEL_OP_READ_FLOAT64 ||
+           this->opcode == SEL_OP_ATOMIC       ||
            this->opcode == SEL_OP_BYTE_GATHER;
   }
 
   bool SelectionInstruction::isWrite(void) const {
     return this->opcode == SEL_OP_UNTYPED_WRITE ||
            this->opcode == SEL_OP_WRITE_FLOAT64 ||
+           this->opcode == SEL_OP_ATOMIC        ||
            this->opcode == SEL_OP_BYTE_SCATTER;
   }
 
@@ -456,6 +458,8 @@ namespace gbe
     void NOP(void);
     /*! Wait instruction (used for the barrier) */
     void WAIT(void);
+    /*! Atomic instruction */
+    void ATOMIC(Reg dst, uint32_t function, uint32_t srcNum, Reg src0, Reg src1, Reg src2, uint32_t bti);
     /*! Read 64 bits float array */
     void READ_FLOAT64(Reg addr, const GenRegister *dst, uint32_t elemNum, uint32_t bti);
     /*! Write 64 bits float array */
@@ -730,6 +734,23 @@ namespace gbe
     insn->src(0) = src;
   }
 
+  void Selection::Opaque::ATOMIC(Reg dst, uint32_t function,
+                                     uint32_t srcNum, Reg src0,
+                                     Reg src1, Reg src2, uint32_t bti) {
+    SelectionInstruction *insn = this->appendInsn(SEL_OP_ATOMIC, 1, srcNum);
+    insn->dst(0) = dst;
+    insn->src(0) = src0;
+    if(srcNum > 1) insn->src(1) = src1;
+    if(srcNum > 2) insn->src(2) = src2;
+    insn->extra.function = function;
+    insn->extra.elem     = bti;
+    SelectionVector *vector = this->appendVector();
+
+    vector->regNum = srcNum;
+    vector->reg = &insn->src(0);
+    vector->isSrc = 1;
+  }
+
   void Selection::Opaque::EOT(void) { this->appendInsn(SEL_OP_EOT, 0, 0); }
   void Selection::Opaque::NOP(void) { this->appendInsn(SEL_OP_NOP, 0, 0); }
   void Selection::Opaque::WAIT(void) { this->appendInsn(SEL_OP_WAIT, 0, 0); }
@@ -2064,6 +2085,28 @@ namespace gbe
     DECL_CTOR(ConvertInstruction, 1, 1);
   };
 
+  /*! Convert instruction pattern */
+  DECL_PATTERN(AtomicInstruction)
+  {
+    INLINE bool emitOne(Selection::Opaque &sel, const ir::AtomicInstruction &insn) const
+    {
+      using namespace ir;
+      const AtomicOps atomicOp = insn.getAtomicOpcode();
+      const AddressSpace space = insn.getAddressSpace();
+      const uint32_t bti = space == MEM_LOCAL ? 0xfe : 0x01;
+      const uint32_t srcNum = insn.getSrcNum();
+      const GenRegister src0 = sel.selReg(insn.getSrc(0), TYPE_U32);   //address
+      GenRegister src1 = src0, src2 = src0;
+      if(srcNum > 1) src1 = sel.selReg(insn.getSrc(1), TYPE_U32);
+      if(srcNum > 2) src2 = sel.selReg(insn.getSrc(2), TYPE_U32);
+      GenRegister dst  = sel.selReg(insn.getDst(0), TYPE_U32);
+      GenAtomicOpCode genAtomicOp = (GenAtomicOpCode)atomicOp;
+      sel.ATOMIC(dst, genAtomicOp, srcNum, src0, src1, src2, bti);
+      return true;
+    }
+    DECL_CTOR(AtomicInstruction, 1, 1);
+  };
+
   /*! Select instruction pattern */
   class SelectInstructionPattern : public SelectionPattern
   {
@@ -2410,6 +2453,7 @@ namespace gbe
     this->insert<SelectInstructionPattern>();
     this->insert<CompareInstructionPattern>();
     this->insert<ConvertInstructionPattern>();
+    this->insert<AtomicInstructionPattern>();
     this->insert<LabelInstructionPattern>();
     this->insert<BranchInstructionPattern>();
     this->insert<Int32x32MulInstructionPattern>();
index 778eb1f..5ae6e42 100644 (file)
@@ -92,9 +92,9 @@ namespace gbe
     GenInstructionState state;
     union {
       struct {
-        /*! Store bti for loads/stores and function for math and compares */
+        /*! Store bti for loads/stores and function for math, atomic and compares */
         uint16_t function:8;
-        /*! elemSize for byte scatters / gathers, elemNum for untyped msg */
+        /*! elemSize for byte scatters / gathers, elemNum for untyped msg, bti for atomic */
         uint16_t elem:8;
       };
       struct {
index cc2be08..f1a4701 100644 (file)
@@ -20,6 +20,7 @@ DECL_SELECTION_IR(RSL, BinaryInstruction)
 DECL_SELECTION_IR(ASR, BinaryInstruction)
 DECL_SELECTION_IR(ADD, BinaryInstruction)
 DECL_SELECTION_IR(MUL, BinaryInstruction)
+DECL_SELECTION_IR(ATOMIC, AtomicInstruction)
 DECL_SELECTION_IR(MACH, BinaryInstruction)
 DECL_SELECTION_IR(CMP, CompareInstruction)
 DECL_SELECTION_IR(SEL_CMP, CompareInstruction)
index 67a4c12..c55774f 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * Copyright © 2012 Intel Corporation
  *
  * This library is free software; you can redistribute it and/or
@@ -56,7 +56,7 @@ namespace ir {
     };
 
     /*! For regular n source instructions */
-    template <typename T, uint32_t srcNum> 
+    template <typename T, uint32_t srcNum>
     struct NSrcPolicy {
       INLINE uint32_t getSrcNum(void) const { return srcNum; }
       INLINE Register getSrc(const Function &fn, uint32_t ID) const {
@@ -246,6 +246,40 @@ namespace ir {
       Type srcType; //!< Type to convert from
     };
 
+    class ALIGNED_INSTRUCTION AtomicInstruction :
+      public BasePolicy,
+      public TupleSrcPolicy<AtomicInstruction>,
+      public NDstPolicy<AtomicInstruction, 1>
+    {
+    public:
+      AtomicInstruction(AtomicOps atomicOp,
+                         Register dst,
+                         AddressSpace addrSpace,
+                         Tuple src)
+      {
+        this->opcode = OP_ATOMIC;
+        this->atomicOp = atomicOp;
+        this->dst[0] = dst;
+        this->src = src;
+        this->addrSpace = addrSpace;
+        srcNum = 2;
+        if((atomicOp == ATOMIC_OP_INC) ||
+          (atomicOp == ATOMIC_OP_DEC))
+          srcNum = 1;
+        if(atomicOp == ATOMIC_OP_CMPXCHG)
+          srcNum = 3;
+      }
+      INLINE AddressSpace getAddressSpace(void) const { return this->addrSpace; }
+      INLINE AtomicOps getAtomicOpcode(void) const { return this->atomicOp; }
+      INLINE bool wellFormed(const Function &fn, std::string &whyNot) const;
+      INLINE void out(std::ostream &out, const Function &fn) const;
+      Register dst[1];
+      Tuple src;
+      AddressSpace addrSpace; //!< Address space
+      uint8_t srcNum:2;     //!<Source Number
+      AtomicOps atomicOp:6;     //!<Source Number
+    };
+
     class ALIGNED_INSTRUCTION BranchInstruction :
       public BasePolicy,
       public NDstPolicy<BranchInstruction, 0>
@@ -738,6 +772,20 @@ namespace ir {
       return true;
     }
 
+    // We can convert anything to anything, but types and families must match
+    INLINE bool AtomicInstruction::wellFormed(const Function &fn, std::string &whyNot) const
+    {
+      if (UNLIKELY(checkSpecialRegForWrite(dst[0], fn, whyNot) == false))
+        return false;
+      if (UNLIKELY(checkRegisterData(FAMILY_DWORD, dst[0], fn, whyNot) == false))
+        return false;
+      for (uint32_t srcID = 0; srcID < srcNum; ++srcID)
+        if (UNLIKELY(checkRegisterData(FAMILY_DWORD, getSrc(fn, srcID), fn, whyNot) == false))
+          return false;
+
+      return true;
+    }
+
     /*! Loads and stores follow the same restrictions */
     template <typename T>
     INLINE bool wellFormedLoadStore(const T &insn, const Function &fn, std::string &whyNot)
@@ -883,6 +931,15 @@ namespace ir {
       ternaryOrSelectOut(*this, out, fn);
     }
 
+    INLINE void AtomicInstruction::out(std::ostream &out, const Function &fn) const {
+      this->outOpcode(out);
+      out << "." << addrSpace;
+      out << " %" << this->getDst(fn, 0);
+      out << " {" << "%" << this->getSrc(fn, 0) << "}";
+      for (uint32_t i = 1; i < srcNum; ++i)
+        out << " %" << this->getSrc(fn, i);
+    }
+
     INLINE void ConvertInstruction::out(std::ostream &out, const Function &fn) const {
       this->outOpcode(out);
       out << "." << this->getDstType()
@@ -1009,6 +1066,10 @@ START_INTROSPECTION(ConvertInstruction)
 #include "ir/instruction.hxx"
 END_INTROSPECTION(ConvertInstruction)
 
+START_INTROSPECTION(AtomicInstruction)
+#include "ir/instruction.hxx"
+END_INTROSPECTION(AtomicInstruction)
+
 START_INTROSPECTION(SelectInstruction)
 #include "ir/instruction.hxx"
 END_INTROSPECTION(SelectInstruction)
@@ -1180,9 +1241,10 @@ END_FUNCTION(Instruction, Register)
   }
 
   bool Instruction::hasSideEffect(void) const {
-    return opcode == OP_STORE || 
+    return opcode == OP_STORE ||
            opcode == OP_TYPED_WRITE ||
-           opcode == OP_SYNC;
+           opcode == OP_SYNC ||
+           opcode == OP_ATOMIC;
   }
 
 #define DECL_MEM_FN(CLASS, RET, PROTOTYPE, CALL) \
@@ -1197,6 +1259,8 @@ DECL_MEM_FN(SelectInstruction, Type, getType(void), getType())
 DECL_MEM_FN(CompareInstruction, Type, getType(void), getType())
 DECL_MEM_FN(ConvertInstruction, Type, getSrcType(void), getSrcType())
 DECL_MEM_FN(ConvertInstruction, Type, getDstType(void), getDstType())
+DECL_MEM_FN(AtomicInstruction, AddressSpace, getAddressSpace(void), getAddressSpace())
+DECL_MEM_FN(AtomicInstruction, AtomicOps, getAtomicOpcode(void), getAtomicOpcode())
 DECL_MEM_FN(StoreInstruction, Type, getValueType(void), getValueType())
 DECL_MEM_FN(StoreInstruction, uint32_t, getValueNum(void), getValueNum())
 DECL_MEM_FN(StoreInstruction, AddressSpace, getAddressSpace(void), getAddressSpace())
@@ -1304,6 +1368,11 @@ DECL_MEM_FN(GetImageInfoInstruction, uint32_t, getInfoType(void), getInfoType())
     return internal::ConvertInstruction(dstType, srcType, dst, src).convert();
   }
 
+  // For all unary functions with given opcode
+  Instruction ATOMIC(AtomicOps atomicOp, Register dst, AddressSpace space, Tuple src) {
+    return internal::AtomicInstruction(atomicOp, dst, space, src).convert();
+  }
+
   // BRA
   Instruction BRA(LabelIndex labelIndex) {
     return internal::BranchInstruction(OP_BRA, labelIndex).convert();
index 0f3bd34..8aefc92 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * Copyright © 2012 Intel Corporation
  *
  * This library is free software; you can redistribute it and/or
@@ -53,6 +53,23 @@ namespace ir {
     MEM_INVALID
   };
 
+  enum AtomicOps {
+    ATOMIC_OP_AND       = 1,
+    ATOMIC_OP_OR        = 2,
+    ATOMIC_OP_XOR       = 3,
+    ATOMIC_OP_XCHG      = 4,
+    ATOMIC_OP_INC       = 5,
+    ATOMIC_OP_DEC       = 6,
+    ATOMIC_OP_ADD       = 7,
+    ATOMIC_OP_SUB       = 8,
+    ATOMIC_OP_IMAX      = 10,
+    ATOMIC_OP_IMIN      = 11,
+    ATOMIC_OP_UMAX      = 12,
+    ATOMIC_OP_UMIN      = 13,
+    ATOMIC_OP_CMPXCHG   = 14,
+    ATOMIC_OP_INVALID
+  };
+
   /* Vote function per hardware thread */
   enum VotePredicate : uint8_t {
     VOTE_ALL = 0,
@@ -228,6 +245,21 @@ namespace ir {
     static bool isClassOf(const Instruction &insn);
   };
 
+  /*! Atomic instruction */
+  class AtomicInstruction : public Instruction {
+  public:
+    /*! Where the address register goes */
+    static const uint32_t addressIndex = 0;
+    /*! Address space that is manipulated here */
+    AddressSpace getAddressSpace(void) const;
+    /*! Return the atomic function code */
+    AtomicOps getAtomicOpcode(void) const;
+    /*! Return the register that contains the addresses */
+    INLINE Register getAddress(void) const { return this->getSrc(addressIndex); }
+    /*! 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
    */
@@ -555,6 +587,8 @@ namespace ir {
   Instruction GT(Type type, Register dst, Register src0, Register src1);
   /*! cvt.{dstType <- srcType} dst src */
   Instruction CVT(Type dstType, Type srcType, Register dst, Register src);
+  /*! atomic dst addr.space {src1 {src2}} */
+  Instruction ATOMIC(AtomicOps opcode, Register dst, AddressSpace space, Tuple src);
   /*! bra labelIndex */
   Instruction BRA(LabelIndex labelIndex);
   /*! (pred) bra labelIndex */
index acfb45a..9c4be2e 100644 (file)
@@ -61,6 +61,7 @@ DECL_INSN(LT, CompareInstruction)
 DECL_INSN(GE, CompareInstruction)
 DECL_INSN(GT, CompareInstruction)
 DECL_INSN(CVT, ConvertInstruction)
+DECL_INSN(ATOMIC, AtomicInstruction)
 DECL_INSN(BRA, BranchInstruction)
 DECL_INSN(RET, BranchInstruction)
 DECL_INSN(LOADI, LoadImmInstruction)