[Mesa-dev] [PATCH 1/2] clover: Implement image attribute getters

Zoltán Gilián zoltan.gilian at gmail.com
Tue Jun 9 02:09:02 PDT 2015


Ok, thanks for the feedback.

On Mon, Jun 8, 2015 at 2:18 PM, Francisco Jerez <currojerez at riseup.net>
wrote:

> Zoltan Gilian <zoltan.gilian at gmail.com> writes:
>
> > Image attributes are passed to the kernel as hidden parameters after the
> > image attribute itself. An llvm pass replaces the getter builtins to
> > the appropriate parameters.
> > ---
> >  src/gallium/state_trackers/clover/core/kernel.cpp  |  13 ++
> >  src/gallium/state_trackers/clover/core/memory.cpp  |   2 +-
> >  .../state_trackers/clover/llvm/invocation.cpp      | 158
> ++++++++++++++++++++-
> >  3 files changed, 170 insertions(+), 3 deletions(-)
> >
> > diff --git a/src/gallium/state_trackers/clover/core/kernel.cpp
> b/src/gallium/state_trackers/clover/core/kernel.cpp
> > index 0756f06..4703899 100644
> > --- a/src/gallium/state_trackers/clover/core/kernel.cpp
> > +++ b/src/gallium/state_trackers/clover/core/kernel.cpp
> > @@ -483,6 +483,19 @@ kernel::image_rd_argument::bind(exec_context &ctx,
> >     align(ctx.input, marg.target_align);
> >     insert(ctx.input, v);
> >
> > +   cl_image_format fmt = img->format();
> > +   cl_uint image_attribs[] = {img->width(), img->height(), img->depth(),
> > +                              fmt.image_channel_data_type,
> > +                              fmt.image_channel_order};
> > +   for (int i = 0; i < 5; i++) {
> > +      auto v = bytes(image_attribs[i]);
> > +
> > +      extend(v, module::argument::zero_ext, marg.target_size);
> > +      byteswap(v, ctx.q->device().endianness());
> > +      align(ctx.input, marg.target_align);
> > +      insert(ctx.input, v);
> > +   }
> > +
> This seems to be implementing driver-specific policy in a
> hardware-independent state tracker.  Whether you need to pass the image
> dimensions and data type to the kernel as explicit parameters or not
> (e.g. because your hardware already supports some sort of image metadata
> query opcode) is driver-specific, so it would probably be a better idea
> to append these parameters at the end of the input buffer in the r600
> pipe driver itself.
>
> >     st = img->resource(*ctx.q).bind_sampler_view(*ctx.q);
> >     ctx.sviews.push_back(st);
> >  }
> > diff --git a/src/gallium/state_trackers/clover/core/memory.cpp
> b/src/gallium/state_trackers/clover/core/memory.cpp
> > index 055336a..b852e68 100644
> > --- a/src/gallium/state_trackers/clover/core/memory.cpp
> > +++ b/src/gallium/state_trackers/clover/core/memory.cpp
> > @@ -189,7 +189,7 @@ image2d::image2d(clover::context &ctx, cl_mem_flags
> flags,
> >                   const cl_image_format *format, size_t width,
> >                   size_t height, size_t row_pitch,
> >                   void *host_ptr) :
> > -   image(ctx, flags, format, width, height, 0,
> > +   image(ctx, flags, format, width, height, 1,
> >           row_pitch, 0, height * row_pitch, host_ptr) {
> >  }
> >
> > diff --git a/src/gallium/state_trackers/clover/llvm/invocation.cpp
> b/src/gallium/state_trackers/clover/llvm/invocation.cpp
> > index 9b91fee..5d5e619 100644
> > --- a/src/gallium/state_trackers/clover/llvm/invocation.cpp
> > +++ b/src/gallium/state_trackers/clover/llvm/invocation.cpp
> > @@ -33,6 +33,8 @@
> >  #include <llvm/IR/DiagnosticInfo.h>
> >  #include <llvm/IR/DiagnosticPrinter.h>
> >  #include <llvm/IR/DerivedTypes.h>
> > +#include <llvm/IR/InstIterator.h>
> > +#include <llvm/IR/Instructions.h>
> >  #include <llvm/IR/LLVMContext.h>
> >  #include <llvm/IR/Module.h>
> >  #include <llvm/Support/SourceMgr.h>
> > @@ -80,6 +82,130 @@
> >  using namespace clover;
> >
> >  namespace {
> > +
> > +   /* LLVM pass to resolve get_image_* OpenCL builtins.
> > +    * The image attributes (e.g. width or channel order) are passed as
> hidden
> > +    * arguments to the kernel.
> > +    * This pass replaces specific function calls with the appropriate
> hidden
> > +    * arguments. The libclc library needs to implements the get_image_*
> > +    * builtins as these specific functions to avoid dealing with name
> mangling
> > +    * here.
> > +    */
> > +   struct OpenCLImageBuiltinPass : public llvm::FunctionPass {
> > +      static char ID;
> > +
> > +      OpenCLImageBuiltinPass(): llvm::FunctionPass(ID) {}
> > +      bool runOnFunction(llvm::Function &F) override;
> > +
> > +      struct ImageAttribArgs {
> > +         ImageAttribArgs(): image_arg(0),
> > +                            width_arg(0),
> > +                            heigth_arg(0),
> > +                            depth_arg(0),
> > +                            channel_data_type_arg(0),
> > +                            channel_order_arg(0) {}
> > +         llvm::Argument* image_arg;
> > +         llvm::Argument* width_arg;
> > +         llvm::Argument* heigth_arg;
> > +         llvm::Argument* depth_arg;
> > +         llvm::Argument* channel_data_type_arg;
> > +         llvm::Argument* channel_order_arg;
> > +      };
> > +   };
> > +
> > +   char OpenCLImageBuiltinPass::ID = 0;
> > +
> > +   bool
> > +   OpenCLImageBuiltinPass::runOnFunction(llvm::Function& F)
> > +   {
> > +      llvm::Module* mod = F.getParent();
> > +      llvm::DataLayout TD(mod);
> > +      llvm::Type* cl_int_type =
> > +         TD.getSmallestLegalIntType(mod->getContext(), sizeof(cl_int));
> > +
> > +      std::vector<ImageAttribArgs> img_args;
> > +      for (auto arg = F.arg_begin(), E = F.arg_end(); arg != E; ++arg) {
> > +
> > +         llvm::Type *arg_type = arg->getType();
> > +         if (!arg_type->isPointerTy()) continue;
> > +
> > +         llvm::Type *elem_type = arg_type->getPointerElementType();
> > +         if (!elem_type->isStructTy()) continue;
> > +
> > +         const llvm::StringRef &type_name = elem_type->getStructName();
> > +         if (!type_name.startswith("opencl.image2d_t")) continue;
> > +
> > +         auto name_suffix = llvm::Twine(img_args.size());
> > +         ImageAttribArgs attrib_args;
> > +         attrib_args.image_arg = arg;
> > +         attrib_args.width_arg = new llvm::Argument(
> > +            cl_int_type, "image_width" + name_suffix);
> > +         attrib_args.heigth_arg = new llvm::Argument(
> > +            cl_int_type, "image_height" + name_suffix);
> > +         attrib_args.depth_arg = new llvm::Argument(
> > +            cl_int_type, "image_depth" + name_suffix);
> > +         attrib_args.channel_data_type_arg = new llvm::Argument(
> > +            cl_int_type, "image_channel_data_type" + name_suffix);
> > +         attrib_args.channel_order_arg = new llvm::Argument(
> > +            cl_int_type, "image_channel_order" + name_suffix);
> > +
> > +         auto& args = F.getArgumentList();
> > +         args.insertAfter(arg, attrib_args.channel_order_arg);
> > +         args.insertAfter(arg, attrib_args.channel_data_type_arg);
> > +         args.insertAfter(arg, attrib_args.depth_arg);
> > +         args.insertAfter(arg, attrib_args.heigth_arg);
> > +         args.insertAfter(arg, attrib_args.width_arg);
> > +
> > +         img_args.push_back(attrib_args);
> > +      }
> > +      std::vector<llvm::Instruction*> insts_to_erase;
> > +      for (auto I = llvm::inst_begin(F), E = llvm::inst_end(F); I != E;
> ++I) {
> > +         llvm::CallInst* callInst = llvm::dyn_cast<llvm::CallInst>(&*I);
> > +         if (!callInst) continue;
> > +
> > +         for (auto& op: callInst->arg_operands()) {
> > +            auto op_arg = op.get();
> > +            auto image_arg = std::find_if(
> > +               img_args.begin(), img_args.end(),
> > +               [op_arg](const ImageAttribArgs& x) {
> > +                  return x.image_arg == op_arg;
> > +               });
> > +            if (image_arg == img_args.end()) continue;
> > +
> > +            llvm::Function* callee = callInst->getCalledFunction();
> > +            if (!callee) continue;
> > +
> > +            auto callee_name = callee->getName();
> > +            if (callee_name.startswith(
> > +                  "llvm.opencl.image.get.width")) {
> > +               callInst->replaceAllUsesWith(image_arg->width_arg);
> > +               insts_to_erase.push_back(callInst);
> > +            } else if (callee_name.startswith(
> > +                  "llvm.opencl.image.get.height")) {
> > +               callInst->replaceAllUsesWith(image_arg->heigth_arg);
> > +               insts_to_erase.push_back(callInst);
> > +            } else if (callee_name.startswith(
> > +                  "llvm.opencl.image.get.depth")) {
> > +               callInst->replaceAllUsesWith(image_arg->depth_arg);
> > +               insts_to_erase.push_back(callInst);
> > +            } else if (callee_name.startswith(
> > +                  "llvm.opencl.image.get.channel_data_type")) {
> > +
>  callInst->replaceAllUsesWith(image_arg->channel_data_type_arg);
> > +               insts_to_erase.push_back(callInst);
> > +            } else if (callee_name.startswith(
> > +                  "llvm.opencl.image.get.channel_order")) {
> > +
>  callInst->replaceAllUsesWith(image_arg->channel_order_arg);
> > +               insts_to_erase.push_back(callInst);
> > +            }
> > +         }
> > +      }
> > +      for (auto inst: insts_to_erase) {
> > +         inst->eraseFromParent();
> > +      }
> > +
> > +      return (img_args.size() > 0);
> > +   }
> > +
> >  #if 0
> >     void
> >     build_binary(const std::string &source, const std::string &target,
> > @@ -263,10 +389,21 @@ namespace {
> >
> sizeof(address_spaces));
> >
> >  #if HAVE_LLVM >= 0x0306
> > -      return act.takeModule().release();
> > +      llvm::Module * module = act.takeModule().release();
> > +#else
> > +      llvm::Module * module = act.takeModule();
> > +#endif
> > +
> > +      // Resolve get_image_* builtins.
> > +#if HAVE_LLVM >= 0x0307
> > +      llvm::legacy::PassManager PM;
> >  #else
> > -      return act.takeModule();
> > +      llvm::PassManager PM;
> >  #endif
> > +      PM.add(new OpenCLImageBuiltinPass());
> > +      PM.run(*module);
> > +
> > +      return module;
> >     }
> >
> >     void
> > @@ -375,6 +512,23 @@ namespace {
> >           }
> >
> >           if (arg_type->isPointerTy()) {
> > +            // XXX: Figure out LLVM->OpenCL address space mappings for
> each
> > +            // target.  I think we need to ask clang what these are.
> For now,
> > +            // pretend everything is in the global address space.
> > +            llvm::Type *elem_type = arg_type->getPointerElementType();
> > +            if (elem_type->isStructTy()) {
> > +               const llvm::StringRef &type_name =
> elem_type->getStructName();
> > +
> > +               if (type_name.startswith("opencl.image2d_t")) {
> > +
> args.push_back(module::argument(module::argument::image2d_rd,
> > +                                 arg_store_size, target_size,
> target_align,
> > +                                 module::argument::zero_ext));
> > +                  // Skip hidden image attribute arguments.
> > +                  // XXX: Do this based on some kind of metadata.
> > +                  std::advance(I, 5);
> > +                  continue;
> > +               }
> > +            }
> >              unsigned address_space =
> llvm::cast<llvm::PointerType>(arg_type)->getAddressSpace();
> >              if (address_space ==
> address_spaces[clang::LangAS::opencl_local
> >                                                       -
> clang::LangAS::Offset]) {
> > --
> > 2.4.2
> >
> > _______________________________________________
> > mesa-dev mailing list
> > mesa-dev at lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/mesa-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/mesa-dev/attachments/20150609/48e6eca8/attachment-0001.html>


More information about the mesa-dev mailing list