[Beignet] [PATCH v2 1/7] GBE: refine the sampler implementation to comply with spec.

Zhigang Gong zhigang.gong at linux.intel.com
Sun May 12 20:32:18 PDT 2013


The previous implementation is to use a new address space pointer to
represent a sampler. The reason is that there is no specified data
type for sampler_t in LLVM front end thus we can't determine the
sampler argument type if we use a normal interger to represnet the
sampler. But that breaks the OCL spec, the spec allows the kernel
to define and initialize sampler variables in kernel side.

Now I use a little tricky way to fix this problem. First, I decide
to use normal unsigned interger to represent sampler_t in kernel side.
Then at compile time, I check read_imagexxx function's sampler
arguments. If the argument is a constant value, then it should be a
kernel side defined sampler, then I insert the sampler type into a
global sampler set for the current kernel function. If the argument
is not a constant value, then I will check whether it's a kernel
argument, if it is, then I fix up the corresponding kernel arg type
to SAMPLER there.

To unify the kernel side defined sampler and kernel argument sampler,
I add two new gbe API. To export all the kernel side defined sampler
data and size to the runtime library. Then latter, the runtime library
can use this information to append new sampler to the unified sampler
buffer and bind all the sampler at one time.

Signed-off-by: Zhigang Gong <zhigang.gong at linux.intel.com>
---
 backend/src/CMakeLists.txt            |  2 ++
 backend/src/backend/program.cpp       | 20 ++++++++++-
 backend/src/backend/program.h         |  8 +++++
 backend/src/backend/program.hpp       | 11 ++++++
 backend/src/ir/function.cpp           |  1 +
 backend/src/ir/function.hpp           | 11 ++++++
 backend/src/ir/sampler.cpp            | 46 ++++++++++++++++++++++++
 backend/src/ir/sampler.hpp            | 67 +++++++++++++++++++++++++++++++++++
 backend/src/llvm/llvm_gen_backend.cpp | 22 +++++++++++-
 backend/src/ocl_stdlib.h              |  6 ++--
 10 files changed, 189 insertions(+), 5 deletions(-)
 create mode 100644 backend/src/ir/sampler.cpp
 create mode 100644 backend/src/ir/sampler.hpp

diff --git a/backend/src/CMakeLists.txt b/backend/src/CMakeLists.txt
index ac7e1da..04e758f 100644
--- a/backend/src/CMakeLists.txt
+++ b/backend/src/CMakeLists.txt
@@ -61,6 +61,8 @@ else (GBE_USE_BLOB)
     ir/unit.hpp
     ir/constant.cpp
     ir/constant.hpp
+    ir/sampler.cpp
+    ir/sampler.hpp
     ir/instruction.cpp
     ir/instruction.hpp
     ir/liveness.cpp
diff --git a/backend/src/backend/program.cpp b/backend/src/backend/program.cpp
index 38cc236..49c1337 100644
--- a/backend/src/backend/program.cpp
+++ b/backend/src/backend/program.cpp
@@ -49,10 +49,11 @@
 namespace gbe {
 
   Kernel::Kernel(const std::string &name) :
-    name(name), args(NULL), argNum(0), curbeSize(0), stackSize(0), useSLM(false), ctx(NULL)
+    name(name), args(NULL), argNum(0), curbeSize(0), stackSize(0), useSLM(false), ctx(NULL), samplerSet(NULL)
   {}
   Kernel::~Kernel(void) {
     if(ctx) GBE_DELETE(ctx);
+    if(samplerSet) GBE_DELETE(samplerSet);
     GBE_SAFE_DELETE_ARRAY(args);
   }
   int32_t Kernel::getCurbeOffset(gbe_curbe_type type, uint32_t subType) const {
@@ -90,6 +91,7 @@ namespace gbe {
     for (const auto &pair : set) {
       const std::string &name = pair.first;
       Kernel *kernel = this->compileKernel(unit, name);
+      kernel->setSamplerSet(pair.second->getSamplerSet());
       kernels.insert(std::make_pair(name, kernel));
     }
     return true;
@@ -250,6 +252,18 @@ namespace gbe {
     return kernel->setConstBufSize(argID, sz);
   }
 
+  static size_t kernelGetSamplerSize(gbe_kernel gbeKernel) {
+    if (gbeKernel == NULL) return 0;
+    const gbe::Kernel *kernel = (const gbe::Kernel*) gbeKernel;
+    return kernel->getSamplerSize();
+  }
+
+  static void kernelGetSamplerData(gbe_kernel gbeKernel, uint32_t *samplers) {
+    if (gbeKernel == NULL) return;
+    const gbe::Kernel *kernel = (const gbe::Kernel*) gbeKernel;
+    kernel->getSamplerData(samplers);
+  }
+
   static uint32_t kernelGetRequiredWorkGroupSize(gbe_kernel kernel, uint32_t dim) {
     return 0u;
   }
@@ -277,6 +291,8 @@ GBE_EXPORT_SYMBOL gbe_kernel_get_stack_size_cb *gbe_kernel_get_stack_size = NULL
 GBE_EXPORT_SYMBOL gbe_kernel_set_const_buffer_size_cb *gbe_kernel_set_const_buffer_size = NULL;
 GBE_EXPORT_SYMBOL gbe_kernel_get_required_work_group_size_cb *gbe_kernel_get_required_work_group_size = NULL;
 GBE_EXPORT_SYMBOL gbe_kernel_use_slm_cb *gbe_kernel_use_slm = NULL;
+GBE_EXPORT_SYMBOL gbe_kernel_get_sampler_size_cb *gbe_kernel_get_sampler_size = NULL;
+GBE_EXPORT_SYMBOL gbe_kernel_get_sampler_data_cb *gbe_kernel_get_sampler_data = NULL;
 
 namespace gbe
 {
@@ -304,6 +320,8 @@ namespace gbe
       gbe_kernel_set_const_buffer_size = gbe::kernelSetConstBufSize;
       gbe_kernel_get_required_work_group_size = gbe::kernelGetRequiredWorkGroupSize;
       gbe_kernel_use_slm = gbe::kernelUseSLM;
+      gbe_kernel_get_sampler_size = gbe::kernelGetSamplerSize;
+      gbe_kernel_get_sampler_data = gbe::kernelGetSamplerData;
       genSetupCallBacks();
     }
   };
diff --git a/backend/src/backend/program.h b/backend/src/backend/program.h
index 575196a..f678b14 100644
--- a/backend/src/backend/program.h
+++ b/backend/src/backend/program.h
@@ -114,6 +114,14 @@ extern gbe_program_get_global_constant_size_cb *gbe_program_get_global_constant_
 typedef void (gbe_program_get_global_constant_data_cb)(gbe_program gbeProgram, char *mem);
 extern gbe_program_get_global_constant_data_cb *gbe_program_get_global_constant_data;
 
+/*! Get the size of defined samplers */
+typedef size_t (gbe_kernel_get_sampler_size_cb)(gbe_kernel gbeKernel);
+extern gbe_kernel_get_sampler_size_cb *gbe_kernel_get_sampler_size;
+
+/*! Get the content of defined samplers */
+typedef void (gbe_kernel_get_sampler_data_cb)(gbe_kernel gbeKernel, uint32_t *samplers);
+extern gbe_kernel_get_sampler_data_cb *gbe_kernel_get_sampler_data;
+
 /*! Destroy and deallocate the given program */
 typedef void (gbe_program_delete_cb)(gbe_program);
 extern gbe_program_delete_cb *gbe_program_delete;
diff --git a/backend/src/backend/program.hpp b/backend/src/backend/program.hpp
index e754899..480ab0d 100644
--- a/backend/src/backend/program.hpp
+++ b/backend/src/backend/program.hpp
@@ -29,6 +29,8 @@
 #include "backend/context.hpp"
 #include "ir/constant.hpp"
 #include "ir/unit.hpp"
+#include "ir/function.hpp"
+#include "ir/sampler.hpp"
 #include "sys/hash_map.hpp"
 #include "sys/vector.hpp"
 #include <string>
@@ -108,6 +110,14 @@ namespace gbe {
       }
       return -1;
     }
+    /*! Set sampler set. */
+    void setSamplerSet(ir::SamplerSet *from) {
+      samplerSet = from;
+    }
+    /*! Get defined sampler size */
+    size_t getSamplerSize(void) const { return samplerSet->getDataSize(); }
+    /*! Get defined sampler value array */
+    void getSamplerData(uint32_t *samplers) const { samplerSet->getData(samplers); }
   protected:
     friend class Context;      //!< Owns the kernels
     const std::string name;    //!< Kernel name
@@ -119,6 +129,7 @@ namespace gbe {
     uint32_t stackSize;        //!< Stack size (may be 0 if unused)
     bool useSLM;               //!< SLM requires a special HW config
     Context *ctx;              //!< Save context after compiler to alloc constant buffer curbe
+    ir::SamplerSet *samplerSet;//!< Copy from the corresponding function.
     GBE_CLASS(Kernel);         //!< Use custom allocators
   };
 
diff --git a/backend/src/ir/function.cpp b/backend/src/ir/function.cpp
index 004afcd..ced2234 100644
--- a/backend/src/ir/function.cpp
+++ b/backend/src/ir/function.cpp
@@ -46,6 +46,7 @@ namespace ir {
     name(name), unit(unit), profile(profile), simdWidth(0), useSLM(false)
   {
     initProfile(*this);
+    samplerSet = GBE_NEW(SamplerSet);
   }
 
   Function::~Function(void) {
diff --git a/backend/src/ir/function.hpp b/backend/src/ir/function.hpp
index 43aa826..ae49eba 100644
--- a/backend/src/ir/function.hpp
+++ b/backend/src/ir/function.hpp
@@ -28,6 +28,7 @@
 #include "ir/register.hpp"
 #include "ir/instruction.hpp"
 #include "ir/profile.hpp"
+#include "ir/sampler.hpp"
 #include "sys/vector.hpp"
 #include "sys/set.hpp"
 #include "sys/map.hpp"
@@ -217,6 +218,12 @@ namespace ir {
       for (auto arg : args) if (arg->reg == reg) return arg;
       return NULL;
     }
+
+    INLINE FunctionArgument *getArg(const Register &reg) {
+      for (auto arg : args) if (arg->reg == reg) return arg;
+      return NULL;
+    }
+
     /*! Get output register */
     INLINE Register getOutput(uint32_t ID) const { return outputs[ID]; }
     /*! Get the argument location for the pushed register */
@@ -281,6 +288,9 @@ namespace ir {
     INLINE bool getUseSLM(void) const { return this->useSLM; }
     /*! Change the SLM config for the function */
     INLINE bool setUseSLM(bool useSLM) { return this->useSLM = useSLM; }
+    /*! Get sampler set in this function */
+    SamplerSet* getSamplerSet(void) {return samplerSet; }
+    //const SamplerSet& getSamplerSet(void) const {return samplerSet; }
   private:
     friend class Context;           //!< Can freely modify a function
     std::string name;               //!< Function name
@@ -296,6 +306,7 @@ namespace ir {
     LocationMap locationMap;        //!< Pushed function arguments (loc->reg)
     uint32_t simdWidth;             //!< 8 or 16 if forced, 0 otherwise
     bool useSLM;                    //!< Is SLM required?
+    SamplerSet *samplerSet;
     GBE_CLASS(Function);            //!< Use custom allocator
   };
 
diff --git a/backend/src/ir/sampler.cpp b/backend/src/ir/sampler.cpp
new file mode 100644
index 0000000..d7a8463
--- /dev/null
+++ b/backend/src/ir/sampler.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * \file sampler.cpp
+ *
+ */
+#include "sampler.hpp"
+#include "context.hpp"
+
+namespace gbe {
+namespace ir {
+
+  Register SamplerSet::append(uint32_t samplerValue, Context *ctx)
+  {
+    int i = 0;
+
+    for(auto it = regMap.begin();
+        it != regMap.end(); ++it, ++i)
+    {
+      if (it->first == samplerValue)
+        return it->second;
+    }
+    Register reg = ctx->reg(FAMILY_DWORD);
+    ctx->LOADI(ir::TYPE_S32, reg, ctx->newIntegerImmediate(i, ir::TYPE_S32));
+    regMap.insert(std::make_pair(samplerValue, reg));
+    return reg;
+  }
+
+} /* namespace ir */
+} /* namespace gbe */
diff --git a/backend/src/ir/sampler.hpp b/backend/src/ir/sampler.hpp
new file mode 100644
index 0000000..75c4753
--- /dev/null
+++ b/backend/src/ir/sampler.hpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * \file sampler.hpp
+ *
+ * \author Benjamin Segovia <benjamin.segovia at intel.com>
+ */
+#ifndef __GBE_IR_SAMPLER_HPP__
+#define __GBE_IR_SAMPLER_HPP__
+
+#include "ir/register.hpp"
+#include "sys/map.hpp"
+
+
+namespace gbe {
+namespace ir {
+
+  /*! A sampler set is a set of global samplers which are defined as constant global
+   * sampler or defined in the outermost kernel scope variables. According to the spec
+   * all the variable should have a initialized integer value and can't be modified.
+   */
+  class Context;
+
+  class SamplerSet
+  {
+  public:
+    /*! Append the specified sampler and return the allocated offset.
+     *  If the speficied sampler is exist, only return the previous offset and
+     *  don't append it again. Return -1, if failed.*/
+    Register append(uint32_t clkSamplerValue, Context *ctx);
+    size_t getDataSize(void) { return regMap.size(); }
+    size_t getDataSize(void) const { return regMap.size(); }
+    void getData(uint32_t *samplers) const {
+      for ( auto &it : regMap)
+        *samplers++ = it.first;
+    }
+
+    void operator = (const SamplerSet& other) {
+      regMap.insert(other.regMap.begin(), other.regMap.end());
+    }
+
+    SamplerSet(const SamplerSet& other) : regMap(other.regMap.begin(), other.regMap.end()) { }
+    SamplerSet() {}
+  private:
+    map<uint32_t, Register> regMap;
+    GBE_CLASS(SamplerSet);
+  };
+} /* namespace ir */
+} /* namespace gbe */
+
+#endif /* __GBE_IR_SAMPLER_HPP__ */
diff --git a/backend/src/llvm/llvm_gen_backend.cpp b/backend/src/llvm/llvm_gen_backend.cpp
index ad465e2..7379a78 100644
--- a/backend/src/llvm/llvm_gen_backend.cpp
+++ b/backend/src/llvm/llvm_gen_backend.cpp
@@ -1990,7 +1990,27 @@ namespace gbe
           case GEN_OCL_READ_IMAGE15:
           {
             GBE_ASSERT(AI != AE); const ir::Register surface_id = this->getRegister(*AI); ++AI;
-            GBE_ASSERT(AI != AE); const ir::Register sampler = this->getRegister(*AI); ++AI;
+            GBE_ASSERT(AI != AE);
+            Constant *CPV = dyn_cast<Constant>(*AI);
+            ir::Register sampler;
+            if (CPV != NULL)
+            {
+              // This is not a kernel argument sampler, we need to append it to sampler set,
+              // and allocate a sampler slot for it.
+               auto x = processConstant<ir::Immediate>(CPV, InsertExtractFunctor(ctx));
+               GBE_ASSERTM(x.type == ir::TYPE_U32 || x.type == ir::TYPE_S32, "Invalid sampler type");
+               sampler = ctx.getFunction().getSamplerSet()->append(x.data.u32, &ctx);
+            } else {
+              // XXX As LLVM 3.2/3.1 doesn't have a new data type for the sampler_t, we have to fix up the argument
+              // type here. Once we switch to the LLVM and use the new data type sampler_t, we can remove this
+              // work around.
+              sampler = this->getRegister(*AI);
+              ir::FunctionArgument *arg =  ctx.getFunction().getArg(sampler);
+              GBE_ASSERT(arg != NULL);
+              arg->type = ir::FunctionArgument::SAMPLER;
+            }
+            ++AI;
+
             GBE_ASSERT(AI != AE); const ir::Register ucoord = this->getRegister(*AI); ++AI;
             GBE_ASSERT(AI != AE); const ir::Register vcoord = this->getRegister(*AI); ++AI;
             ir::Register wcoord;
diff --git a/backend/src/ocl_stdlib.h b/backend/src/ocl_stdlib.h
index 4c0d39c..e9e407a 100644
--- a/backend/src/ocl_stdlib.h
+++ b/backend/src/ocl_stdlib.h
@@ -46,7 +46,6 @@ typedef unsigned int uintptr_t;
 #define __constant __attribute__((address_space(2)))
 #define __local __attribute__((address_space(3)))
 #define __texture __attribute__((address_space(4)))
-#define __sampler __attribute__((address_space(5)))
 #define global __global
 //#define local __local
 #define constant __constant
@@ -77,7 +76,8 @@ struct _image2d_t;
 typedef __texture struct _image2d_t* image2d_t;
 struct _image3d_t;
 typedef __texture struct _image3d_t* image3d_t;
-typedef __sampler uint* sampler_t;
+//typedef __sampler const uint* sampler_t;
+typedef uint sampler_t;
 typedef size_t event_t;
 /////////////////////////////////////////////////////////////////////////////
 // OpenCL conversions & type casting
@@ -804,7 +804,7 @@ OVERLOADABLE void __gen_ocl_write_imagef(uint surface_id, float u, float v, floa
   INLINE_OVERLOADABLE type read_image ##suffix(image2d_t cl_image, sampler_t sampler, coord_type coord) \
   {\
     GET_IMAGE(cl_image, surface_id);\
-    return __gen_ocl_read_image ##suffix(surface_id, (uint)sampler, coord.s0, coord.s1);\
+    return __gen_ocl_read_image ##suffix(surface_id, sampler, coord.s0, coord.s1);\
   }
 
 #define DECL_WRITE_IMAGE(type, suffix, coord_type) \
-- 
1.7.11.7



More information about the Beignet mailing list