diff --git a/src/gallium/frontends/clover/api/kernel.cpp b/src/gallium/frontends/clover/api/kernel.cpp index 31a87b63868..501e2677862 100644 --- a/src/gallium/frontends/clover/api/kernel.cpp +++ b/src/gallium/frontends/clover/api/kernel.cpp @@ -192,9 +192,46 @@ 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 }; + + auto info = obj(d_kern).args_infos().at(idx); + + if (info.arg_name.empty()) + return CL_KERNEL_ARG_INFO_NOT_AVAILABLE; + + switch (param) { + case CL_KERNEL_ARG_ADDRESS_QUALIFIER: + buf.as_scalar() = info.address_qualifier; + break; + + case CL_KERNEL_ARG_ACCESS_QUALIFIER: + buf.as_scalar() = 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() = 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 (std::out_of_range &e) { + return CL_INVALID_ARG_INDEX; + +} catch (error &e) { + return e.get(); } namespace { diff --git a/src/gallium/frontends/clover/core/kernel.cpp b/src/gallium/frontends/clover/core/kernel.cpp index 3000b7cc2ad..56d30eda655 100644 --- a/src/gallium/frontends/clover/core/kernel.cpp +++ b/src/gallium/frontends/clover/core/kernel.cpp @@ -153,6 +153,16 @@ kernel::args() const { return map(derefs(), _args); } +std::vector +kernel::args_infos() { + std::vector infos; + for (auto &marg: find(name_equals(_name), program().symbols()).args) + if (marg.semantic == clover::module::argument::general) + infos.emplace_back(marg.info); + + return infos; +} + const module & kernel::module(const command_queue &q) const { return program().build(q.device()).binary; diff --git a/src/gallium/frontends/clover/core/kernel.hpp b/src/gallium/frontends/clover/core/kernel.hpp index 4d6dcfbb8a5..d7185bc90a0 100644 --- a/src/gallium/frontends/clover/core/kernel.hpp +++ b/src/gallium/frontends/clover/core/kernel.hpp @@ -141,6 +141,7 @@ namespace clover { argument_range args(); const_argument_range args() const; + std::vector args_infos(); const intrusive_ref program; diff --git a/src/gallium/frontends/clover/core/module.hpp b/src/gallium/frontends/clover/core/module.hpp index fa9f7dda7f7..1d938dfb300 100644 --- a/src/gallium/frontends/clover/core/module.hpp +++ b/src/gallium/frontends/clover/core/module.hpp @@ -26,6 +26,8 @@ #include #include +#include "CL/cl.h" + namespace clover { struct module { typedef uint32_t resource_id; @@ -53,6 +55,25 @@ namespace clover { std::vector data; }; + struct arg_info { + arg_info(const std::string &arg_name, const std::string &type_name, + const cl_kernel_arg_type_qualifier type_qualifier, + const cl_kernel_arg_address_qualifier address_qualifier, + const cl_kernel_arg_access_qualifier access_qualifier) : + arg_name(arg_name), type_name(type_name), + type_qualifier(type_qualifier), + address_qualifier(address_qualifier), + access_qualifier(access_qualifier) { }; + arg_info() : arg_name(""), type_name(""), type_qualifier(0), + address_qualifier(0), access_qualifier(0) { }; + + std::string arg_name; + std::string type_name; + cl_kernel_arg_type_qualifier type_qualifier; + cl_kernel_arg_address_qualifier address_qualifier; + cl_kernel_arg_access_qualifier access_qualifier; + }; + struct argument { enum type { scalar, @@ -103,6 +124,7 @@ namespace clover { size_t target_align; ext_type ext_type; semantic semantic; + arg_info info; }; struct symbol { diff --git a/src/gallium/frontends/clover/llvm/codegen/common.cpp b/src/gallium/frontends/clover/llvm/codegen/common.cpp index 3404087a000..d2bbe7ae28e 100644 --- a/src/gallium/frontends/clover/llvm/codegen/common.cpp +++ b/src/gallium/frontends/clover/llvm/codegen/common.cpp @@ -66,6 +66,43 @@ namespace { unreachable("Unknown image type"); } + module::arg_info create_arg_info(const std::string &arg_name, + const std::string &type_name, + const std::string &type_qualifier, + const int address_qualifier, + const std::string &access_qualifier) { + + cl_kernel_arg_type_qualifier cl_type_qualifier = + CL_KERNEL_ARG_TYPE_NONE; + if (type_qualifier.find("const") != std::string::npos) + cl_type_qualifier |= CL_KERNEL_ARG_TYPE_CONST; + if (type_qualifier.find("restrict") != std::string::npos) + cl_type_qualifier |= CL_KERNEL_ARG_TYPE_RESTRICT; + if (type_qualifier.find("volatile") != std::string::npos) + cl_type_qualifier |= CL_KERNEL_ARG_TYPE_VOLATILE; + + cl_kernel_arg_address_qualifier cl_address_qualifier = + CL_KERNEL_ARG_ADDRESS_PRIVATE; + if (address_qualifier == 1) + cl_address_qualifier = CL_KERNEL_ARG_ADDRESS_GLOBAL; + else if (address_qualifier == 2) + cl_address_qualifier = CL_KERNEL_ARG_ADDRESS_CONSTANT; + else if (address_qualifier == 3) + cl_address_qualifier = CL_KERNEL_ARG_ADDRESS_LOCAL; + + cl_kernel_arg_access_qualifier cl_access_qualifier = + CL_KERNEL_ARG_ACCESS_NONE; + if (access_qualifier == "read_only") + cl_access_qualifier = CL_KERNEL_ARG_ACCESS_READ_ONLY; + else if (access_qualifier == "write_only") + cl_access_qualifier = CL_KERNEL_ARG_ACCESS_WRITE_ONLY; + else if (access_qualifier == "read_write") + cl_access_qualifier = CL_KERNEL_ARG_ACCESS_READ_WRITE; + + return module::arg_info(arg_name, type_name, cl_type_qualifier, + cl_address_qualifier, cl_access_qualifier); + } + std::vector make_kernel_args(const Module &mod, const std::string &kernel_name, const clang::CompilerInstance &c) { @@ -87,12 +124,11 @@ namespace { const unsigned target_size = dl.getTypeStoreSize(arg_type); const unsigned target_align = dl.getABITypeAlignment(arg_type); - const auto type_name = get_argument_metadata(f, arg, - "kernel_arg_type"); - + const auto type_name = get_str_argument_metadata(f, arg, + "kernel_arg_type"); if (type_name == "image2d_t" || type_name == "image3d_t") { // Image. - const auto access_qual = get_argument_metadata( + const auto access_qual = get_str_argument_metadata( f, arg, "kernel_arg_access_qual"); args.emplace_back(get_image_type(type_name, access_qual), target_size, target_size, @@ -153,6 +189,16 @@ namespace { (needs_sign_ext ? module::argument::sign_ext : module::argument::zero_ext)); } + + // Add kernel argument infos if built with -cl-kernel-arg-info. + if (c.getCodeGenOpts().EmitOpenCLArgMetadata) { + args.back().info = create_arg_info( + get_str_argument_metadata(f, arg, "kernel_arg_name"), + type_name, + get_str_argument_metadata(f, arg, "kernel_arg_type_qual"), + get_uint_argument_metadata(f, arg, "kernel_arg_addr_space"), + get_str_argument_metadata(f, arg, "kernel_arg_access_qual")); + } } } diff --git a/src/gallium/frontends/clover/llvm/metadata.hpp b/src/gallium/frontends/clover/llvm/metadata.hpp index 58042f4b4da..8519d9856a5 100644 --- a/src/gallium/frontends/clover/llvm/metadata.hpp +++ b/src/gallium/frontends/clover/llvm/metadata.hpp @@ -48,7 +48,10 @@ namespace clover { get_kernel_metadata_operands(const ::llvm::Function &f, const std::string &name) { const auto data_node = f.getMetadata(name); - return range(data_node->op_begin(), data_node->op_end()); + if (data_node) + return range(data_node->op_begin(), data_node->op_end()); + else + return iterator_range< ::llvm::MDNode::op_iterator>(); } } @@ -57,12 +60,35 @@ namespace clover { /// argument given by \p arg. /// inline std::string - get_argument_metadata(const ::llvm::Function &f, + get_str_argument_metadata(const ::llvm::Function &f, const ::llvm::Argument &arg, const std::string &name) { - return ::llvm::cast< ::llvm::MDString>( - detail::get_kernel_metadata_operands(f, name)[arg.getArgNo()]) - ->getString().str(); + auto operands = detail::get_kernel_metadata_operands(f, name); + if (operands.size() > arg.getArgNo()) { + return ::llvm::cast< ::llvm::MDString>(operands[arg.getArgNo()]) + ->getString().str(); + } else { + return ""; + } + } + + /// + /// Extract the int metadata node \p name corresponding to the kernel + /// argument given by \p arg. + /// + inline uint + get_uint_argument_metadata(const ::llvm::Function &f, + const ::llvm::Argument &arg, + const std::string &name) { + auto operands = detail::get_kernel_metadata_operands(f, name); + if (operands.size() >= arg.getArgNo()) { + auto meta_arg_value = ::llvm::cast< ::llvm::ConstantAsMetadata>( + operands[arg.getArgNo()])->getValue(); + return ::llvm::cast< ::llvm::ConstantInt>(meta_arg_value) + ->getLimitedValue(UINT_MAX); + } else { + return 0; + } } ///