[Mesa-dev] [PATCH v2] clover: add GetKernelArgInfo (CL 1.2)

Serge Martin edb+mesa at sigluy.net
Thu Nov 10 19:52:48 UTC 2016


On Sunday 30 October 2016 16:07:25 Francisco Jerez wrote:
> Serge Martin <edb+mesa at sigluy.net> writes:
> > ---
> > 
> >  src/gallium/state_trackers/clover/api/kernel.cpp   | 47
> >  ++++++++++++++++--
> >  src/gallium/state_trackers/clover/core/kernel.cpp  |  6 +++
> >  src/gallium/state_trackers/clover/core/kernel.hpp  |  1 +
> >  src/gallium/state_trackers/clover/core/module.hpp  | 19 +++++--
> >  .../state_trackers/clover/llvm/codegen/common.cpp  | 58
> >  +++++++++++++++++++++- .../state_trackers/clover/llvm/metadata.hpp      
> >   | 16 ++++++
> >  .../state_trackers/clover/tgsi/compiler.cpp        |  2 +-
> >  7 files changed, 141 insertions(+), 8 deletions(-)
> > 
> > diff --git a/src/gallium/state_trackers/clover/api/kernel.cpp
> > b/src/gallium/state_trackers/clover/api/kernel.cpp index 73ba34a..13cfc08
> > 100644
> > --- a/src/gallium/state_trackers/clover/api/kernel.cpp
> > +++ b/src/gallium/state_trackers/clover/api/kernel.cpp
> > @@ -192,9 +192,50 @@ clGetKernelWorkGroupInfo(cl_kernel d_kern,
> > cl_device_id d_dev,> 
> >  CLOVER_API cl_int
> >  clGetKernelArgInfo(cl_kernel d_kern,
> >  
> >                     cl_uint idx, cl_kernel_arg_info param,
> > 
> > -                   size_t size, void *r_buf, size_t *r_size) {
> > -   CLOVER_NOT_SUPPORTED_UNTIL("1.2");
> > -   return CL_KERNEL_ARG_INFO_NOT_AVAILABLE;
> > +                   size_t size, void *r_buf, size_t *r_size) try {
> > +   property_buffer buf { r_buf, size, r_size };
> > +   const auto &kern = obj(d_kern);
> > +   const auto args_info = kern.args_info();
> > +
> > +   if (args_info.size() == 0)
> > +      throw error(CL_KERNEL_ARG_INFO_NOT_AVAILABLE);
> > +
> > +   if (idx >= args_info.size())
> > +      throw error(CL_INVALID_ARG_INDEX);
> > +
> 
> I suggest you just handle std::out_of_range like clSetKernelArg does.
> 
> > +   const auto &info = args_info[idx];
> > +
> > +   switch (param) {
> > +   case CL_KERNEL_ARG_ADDRESS_QUALIFIER:
> > +      buf.as_scalar<cl_kernel_arg_address_qualifier>() =
> > +                                                     
> > info.address_qualifier; +      break;
> > +
> > +   case CL_KERNEL_ARG_ACCESS_QUALIFIER:
> > +      buf.as_scalar<cl_kernel_arg_access_qualifier>() =
> > +                                                     
> > info.access_qualifier; +      break;
> > +
> > +   case CL_KERNEL_ARG_TYPE_NAME:
> > +      buf.as_string() = info.type_name;
> > +      break;
> > +
> > +   case CL_KERNEL_ARG_TYPE_QUALIFIER:
> > +      buf.as_scalar<cl_kernel_arg_type_qualifier>() =
> > info.type_qualifier;
> > +      break;
> > +
> > +   case CL_KERNEL_ARG_NAME:
> > +      buf.as_string() = info.arg_name;
> > +      break;
> > +
> > +   default:
> > +      throw error(CL_INVALID_VALUE);
> > +   }
> > +
> > +   return CL_SUCCESS;
> > +
> > +} catch (error &e) {
> > +   return e.get();
> > 
> >  }
> >  
> >  namespace {
> > 
> > diff --git a/src/gallium/state_trackers/clover/core/kernel.cpp
> > b/src/gallium/state_trackers/clover/core/kernel.cpp index
> > 962f555..18dcd5c 100644
> > --- a/src/gallium/state_trackers/clover/core/kernel.cpp
> > +++ b/src/gallium/state_trackers/clover/core/kernel.cpp
> > @@ -140,6 +140,12 @@ kernel::args() const {
> > 
> >     return map(derefs(), _args);
> >  
> >  }
> > 
> > +std::vector<clover::module::argument_info>
> > +kernel::args_info() const {
> > +   const auto &syms = program().symbols();
> > +   return find(name_equals(_name), syms).args_info;
> > +}
> > +
> 
> This method saves literally one line of code in clGetKernelArgInfo.
> Maybe just open-code it?
> 
> >  const module &
> >  kernel::module(const command_queue &q) const {
> >  
> >     return program().build(q.device()).binary;
> > 
> > diff --git a/src/gallium/state_trackers/clover/core/kernel.hpp
> > b/src/gallium/state_trackers/clover/core/kernel.hpp index
> > 4ba6ff4..aae51bc 100644
> > --- a/src/gallium/state_trackers/clover/core/kernel.hpp
> > +++ b/src/gallium/state_trackers/clover/core/kernel.hpp
> > @@ -134,6 +134,7 @@ namespace clover {
> > 
> >        argument_range args();
> >        const_argument_range args() const;
> > 
> > +      std::vector<clover::module::argument_info> args_info() const;
> > 
> >        const intrusive_ref<clover::program> program;
> > 
> > diff --git a/src/gallium/state_trackers/clover/core/module.hpp
> > b/src/gallium/state_trackers/clover/core/module.hpp index
> > 5db0548..5ce9492 100644
> > --- a/src/gallium/state_trackers/clover/core/module.hpp
> > +++ b/src/gallium/state_trackers/clover/core/module.hpp
> > @@ -102,16 +102,29 @@ namespace clover {
> > 
> >           semantic semantic;
> >        
> >        };
> > 
> > +      struct argument_info {
> > +         argument_info() { }
> > +
> 
> If you define a constructor explicitly you should also explicitly
> initialize all POD members, otherwise their default value will be
> undefined...
> 
> > +         uint32_t address_qualifier;
> 
> As Vedran pointed out, the computation of this value seems
> AMDGPU-specific, but in fact the field seems redundant because
> module::argument::type already gives you the same information:
> 
>  module::argument::local -> CL_KERNEL_ARG_ADDRESS_LOCAL
>  module::argument::constant -> CL_KERNEL_ARG_ADDRESS_CONSTANT
>  module::argument::global -> CL_KERNEL_ARG_ADDRESS_GLOBAL
>  module::argument::image* -> CL_KERNEL_ARG_ADDRESS_GLOBAL
>  otherwise -> CL_KERNEL_ARG_ADDRESS_PRIVATE
> 
> > +         uint32_t access_qualifier;
> 
> This is also redundant with module::argument::type:
> 
>  module::argument::image*_rd -> CL_KERNEL_ARG_ACCESS_READ_ONLY
>  module::argument::image*_wr -> CL_KERNEL_ARG_ACCESS_WRITE_ONLY
>  otherwise -> CL_KERNEL_ARG_ACCESS_NONE
> 
> > +         std::string type_name;
> > +         uint32_t type_qualifier;
> 
> The module binary format is deliberately independent from CL API and
> LLVM-specific enumerants.  I suggest you just pass the qualifiers
> through as a string like the other metadata fields of this struct.
> 
> > +         std::string arg_name;
> > +      };
> > +
> 
> I'd be inclined to nest this into a "struct info" member of "struct
> argument", which would enforce a one-to-one correspondence between info
> and argument structs.  You could represent the info not being available
> as an empty (i.e. default-constructed) argument::info struct.
> 
> >        struct symbol {
> >        
> >           symbol(const std::string &name, resource_id section,
> > 
> > -                size_t offset, const std::vector<argument> &args) :
> > -                name(name), section(section), offset(offset), args(args)
> > { } -         symbol() : name(), section(0), offset(0), args() { }
> > +                size_t offset, const std::vector<argument> &args,
> > +                const std::vector<argument_info> &args_info) :
> > +                name(name), section(section), offset(offset),
> > +                args(args), args_info(args_info) { }
> > +         symbol() : name(), section(0), offset(0), args(), args_info() {
> > }
> > 
> >           std::string name;
> >           resource_id section;
> >           size_t offset;
> >           std::vector<argument> args;
> > 
> > +         std::vector<argument_info> args_info;
> > 
> >        };
> >        
> >        void serialize(std::ostream &os) const;
> 
> Looks like you're missing some serialization code for the new info
> fields you've added to the module data structure.

This is on purpose. According to the spec : "Kernel argument information is 
only available if the program object associated with kernel is created with 
clCreateProgramWithSource "

Serge

> 
> > diff --git a/src/gallium/state_trackers/clover/llvm/codegen/common.cpp
> > b/src/gallium/state_trackers/clover/llvm/codegen/common.cpp index
> > 834b06a..07f45f9 100644
> > --- a/src/gallium/state_trackers/clover/llvm/codegen/common.cpp
> > +++ b/src/gallium/state_trackers/clover/llvm/codegen/common.cpp
> > @@ -66,6 +66,60 @@ namespace {
> > 
> >           unreachable("Unknown image type");
> >     
> >     }
> > 
> > +   std::vector<module::argument_info>
> > +   make_args_infos(const Module &mod, const std::string &kernel_name,
> > +                   const bool has_args_infos) {
> 
> If you take my suggestion above to make module::argument_info part of
> module::argument you could just handle this from make_kernel_args (the
> has_args_infos boolean argument wouldn't be necessary since you could
> just ask the clang::CompilerInstance directly).
> 
> > +      if (!has_args_infos)
> > +         return {};
> > +
> > +      const Function &f = *mod.getFunction(kernel_name);
> > +
> > +      std::vector<module::argument_info> infos;
> > +      for (const auto &arg : f.args()) {
> > +         module::argument_info info;
> > +
> > +         const auto addr_space = get_uint_argument_metadata(f, arg,
> > +                                                     
> > "kernel_arg_addr_space"); +         if (addr_space == 0)
> > +            info.address_qualifier = CL_KERNEL_ARG_ADDRESS_PRIVATE;
> > +         else if (addr_space == 1)
> > +            info.address_qualifier = CL_KERNEL_ARG_ADDRESS_GLOBAL;
> > +         else if (addr_space == 2)
> > +            info.address_qualifier = CL_KERNEL_ARG_ADDRESS_CONSTANT;
> > +         else if (addr_space == 3)
> > +            info.address_qualifier = CL_KERNEL_ARG_ADDRESS_LOCAL;
> > +
> > +         const auto access_qual = get_argument_metadata(f, arg,
> > +                                                     
> > "kernel_arg_access_qual"); +         if (access_qual == "read_only")
> > +            info.access_qualifier = CL_KERNEL_ARG_ACCESS_READ_ONLY;
> > +         else if (access_qual == "write_only")
> > +            info.access_qualifier = CL_KERNEL_ARG_ACCESS_WRITE_ONLY;
> > +         else if (access_qual == "read_write")
> > +            info.access_qualifier = CL_KERNEL_ARG_ACCESS_READ_WRITE;
> > +         else if (access_qual == "none")
> > +            info.access_qualifier = CL_KERNEL_ARG_ACCESS_NONE;
> > +
> 
> The hunk above up to the beginning of the for loop wouldn't be necessary
> if you take my suggestion not to include redundant address and access
> qualifier fields in the argument info structure.
> 
> > +         info.type_name = get_argument_metadata(f, arg,
> > "kernel_arg_type"); +
> > +         const auto type_qual = get_argument_metadata(f, arg,
> > +                                                        
> > "kernel_arg_type_qual"); +         info.type_qualifier =
> > CL_KERNEL_ARG_TYPE_NONE;
> > +         if (type_qual.find("const") != std::string::npos)
> > +            info.type_qualifier |= CL_KERNEL_ARG_TYPE_CONST;
> > +         if (type_qual.find("restrict") != std::string::npos)
> > +            info.type_qualifier |= CL_KERNEL_ARG_TYPE_RESTRICT;
> > +         if (type_qual.find("volatile") != std::string::npos)
> > +            info.type_qualifier |= CL_KERNEL_ARG_TYPE_VOLATILE;
> > +
> 
> This wouldn't be necessary if you pass the qualifiers through as a string.
> 
> > +         info.arg_name = get_argument_metadata(f, arg,
> > "kernel_arg_name");
> > +
> > +         infos.emplace_back(info);
> > +      }
> > +
> > +      return infos;
> > +   }
> > +
> > 
> >     std::vector<module::argument>
> >     make_kernel_args(const Module &mod, const std::string &kernel_name,
> >     
> >                      const clang::CompilerInstance &c) {
> > 
> > @@ -196,12 +250,14 @@ clover::llvm::build_module_common(const Module &mod,
> > 
> >                                                   unsigned> &offsets,
> >                                    
> >                                    const clang::CompilerInstance &c) {
> >     
> >     module m;
> > 
> > +   const bool has_args_infos = c.getCodeGenOpts().EmitOpenCLArgMetadata;
> > 
> >     for (const auto &name : map(std::mem_fn(&Function::getName),
> >     
> >                                 get_kernels(mod))) {
> >        
> >        if (offsets.count(name))
> >        
> >           m.syms.emplace_back(name, 0, offsets.at(name),
> > 
> > -                             make_kernel_args(mod, name, c));
> > +                             make_kernel_args(mod, name, c),
> > +                             make_args_infos(mod, name, has_args_infos));
> > 
> >     }
> >     
> >     m.secs.push_back(make_text_section(code));
> > 
> > diff --git a/src/gallium/state_trackers/clover/llvm/metadata.hpp
> > b/src/gallium/state_trackers/clover/llvm/metadata.hpp index
> > 814c830..ddc5259 100644
> > --- a/src/gallium/state_trackers/clover/llvm/metadata.hpp
> > +++ b/src/gallium/state_trackers/clover/llvm/metadata.hpp
> > @@ -32,6 +32,7 @@
> > 
> >  #include "util/algorithm.hpp"
> >  
> >  #include <vector>
> > 
> > +#include <llvm/IR/Constants.h>
> > 
> >  #include <llvm/IR/Module.h>
> >  #include <llvm/IR/Metadata.h>
> > 
> > @@ -112,6 +113,21 @@ namespace clover {
> > 
> >        }
> >        
> >        ///
> > 
> > +      /// Extract the uint metadata node \p name corresponding to the
> > kernel +      /// argument given by \p arg.
> > +      ///
> > +      inline uint64_t
> > +      get_uint_argument_metadata(const ::llvm::Function &f,
> > +                                 const ::llvm::Argument &arg,
> > +                                 const std::string &name) {
> > +         return ::llvm::cast<::llvm::ConstantInt>(
> > +            ::llvm::dyn_cast<::llvm::ConstantAsMetadata>(
> > +               detail::get_kernel_metadata_operands(f,
> > name)[arg.getArgNo()]) +               ->getValue())
> > +            ->getLimitedValue(UINT_MAX);
> > +      }
> > +
> 
> This helper function wouldn't be necessary if you take my other
> suggestions above.
> 
> > +      ///
> > 
> >        /// Return a vector with all CL kernel functions found in the LLVM
> >        /// module \p mod.
> >        ///
> > 
> > diff --git a/src/gallium/state_trackers/clover/tgsi/compiler.cpp
> > b/src/gallium/state_trackers/clover/tgsi/compiler.cpp index
> > 9bbd454..f94d19f 100644
> > --- a/src/gallium/state_trackers/clover/tgsi/compiler.cpp
> > +++ b/src/gallium/state_trackers/clover/tgsi/compiler.cpp
> > @@ -76,7 +76,7 @@ namespace {
> > 
> >              }
> >           
> >           }
> > 
> > -         m.syms.push_back({ name, 0, offset, args });
> > +         m.syms.push_back({ name, 0, offset, args, {} });
> > 
> >        }
> >     
> >     }
> > 
> > _______________________________________________
> > mesa-dev mailing list
> > mesa-dev at lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/mesa-dev



More information about the mesa-dev mailing list