Read-only and write-only image arguments are recognized and distinguished. Attributes of the image arguments are passed to the kernel as implicit arguments. --- src/gallium/state_trackers/clover/core/kernel.cpp | 27 ++++++ src/gallium/state_trackers/clover/core/kernel.hpp | 13 ++- src/gallium/state_trackers/clover/core/memory.cpp | 2 +- src/gallium/state_trackers/clover/core/module.hpp | 3 +- .../state_trackers/clover/llvm/invocation.cpp | 102 ++++++++++++++++++++- 5 files changed, 140 insertions(+), 7 deletions(-)
diff --git a/src/gallium/state_trackers/clover/core/kernel.cpp b/src/gallium/state_trackers/clover/core/kernel.cpp index 0756f06..d7d42a6 100644 --- a/src/gallium/state_trackers/clover/core/kernel.cpp +++ b/src/gallium/state_trackers/clover/core/kernel.cpp @@ -159,6 +159,14 @@ kernel::exec_context::bind(intrusive_ptr<command_queue> _q, auto msec = find(type_equals(module::section::text), m.secs); auto explicit_arg = kern._args.begin(); + std::vector<image_argument*> image_args; + for (const auto& arg: kern._args) { + if (auto img_arg = dynamic_cast<image_argument*>(arg.get())) { + image_args.push_back(img_arg); + } + } + auto image_arg = image_args.begin(); + for (auto &marg : margs) { switch (marg.semantic) { case module::argument::general: @@ -182,9 +190,28 @@ kernel::exec_context::bind(intrusive_ptr<command_queue> _q, } break; } + case module::argument::image_attributes: { + auto img = (*image_arg++)->get_image(); + cl_image_format fmt = img->format(); + auto attributes = std::vector<cl_int>({ + static_cast<cl_int>(img->width()), + static_cast<cl_int>(img->height()), + static_cast<cl_int>(img->depth()), + static_cast<cl_int>(fmt.image_channel_data_type), + static_cast<cl_int>(fmt.image_channel_order)}); + + for (auto x: attributes) { + auto arg = argument::create(marg); + + arg->set(sizeof(x), &x); + arg->bind(*this, marg); + } + break; + } } } + // Create a new compute state if anything changed. if (!st || q != _q || cs.req_local_mem != mem_local || diff --git a/src/gallium/state_trackers/clover/core/kernel.hpp b/src/gallium/state_trackers/clover/core/kernel.hpp index d6432a4..be9f783 100644 --- a/src/gallium/state_trackers/clover/core/kernel.hpp +++ b/src/gallium/state_trackers/clover/core/kernel.hpp @@ -190,7 +190,14 @@ namespace clover { pipe_surface *st; }; - class image_rd_argument : public argument { + class image_argument : public argument { + public: + const image *get_image() const { return img; } + protected: + image *img; + }; + + class image_rd_argument : public image_argument { public: virtual void set(size_t size, const void *value); virtual void bind(exec_context &ctx, @@ -198,11 +205,10 @@ namespace clover { virtual void unbind(exec_context &ctx); private: - image *img; pipe_sampler_view *st; }; - class image_wr_argument : public argument { + class image_wr_argument : public image_argument { public: virtual void set(size_t size, const void *value); virtual void bind(exec_context &ctx, @@ -210,7 +216,6 @@ namespace clover { virtual void unbind(exec_context &ctx); private: - image *img; pipe_surface *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/core/module.hpp b/src/gallium/state_trackers/clover/core/module.hpp index 9d65688..99b1490 100644 --- a/src/gallium/state_trackers/clover/core/module.hpp +++ b/src/gallium/state_trackers/clover/core/module.hpp @@ -72,7 +72,8 @@ namespace clover { enum semantic { general, grid_dimension, - grid_offset + grid_offset, + image_attributes }; argument(enum type type, size_t size, diff --git a/src/gallium/state_trackers/clover/llvm/invocation.cpp b/src/gallium/state_trackers/clover/llvm/invocation.cpp index 9b91fee..d0c9fcb 100644 --- a/src/gallium/state_trackers/clover/llvm/invocation.cpp +++ b/src/gallium/state_trackers/clover/llvm/invocation.cpp @@ -80,6 +80,7 @@ using namespace clover; namespace { + #if 0 void build_binary(const std::string &source, const std::string &target, @@ -340,17 +341,66 @@ namespace { PM.run(*mod); } + const llvm::MDNode * + get_kernel_metadata(const llvm::Function *kernel_func) { + auto mod = kernel_func->getParent(); + auto kernels_node = mod->getNamedMetadata("opencl.kernels"); + if (!kernels_node) { + return nullptr; + } + + const llvm::MDNode *kernel_node = nullptr; + for (unsigned i = 0; i < kernels_node->getNumOperands(); ++i) { +#if HAVE_LLVM >= 0x0306 + auto func = llvm::mdconst::dyn_extract<llvm::Function>( +#else + auto func = llvm::dyn_cast<llvm::Function>( +#endif + kernels_node->getOperand(i)->getOperand(0)); + if (func == kernel_func) { + kernel_node = kernels_node->getOperand(i); + break; + } + } + + return kernel_node; + } + + std::vector<llvm::StringRef> + get_kernel_access_qualifiers(const llvm::Function *kernel_func) { + auto num_args = kernel_func->getArgumentList().size(); + auto access_quals = std::vector<llvm::StringRef>(num_args); + + auto kernel_node = get_kernel_metadata(kernel_func); + auto aq_node = llvm::cast<llvm::MDNode>(kernel_node->getOperand(2)); + auto str_node = llvm::cast<llvm::MDString>(aq_node->getOperand(0)); + assert(str_node->getString() == "kernel_arg_access_qual" && + "Cannot find kernel_arg_access_qual metadata node."); + assert(aq_node->getNumOperands() == num_args + 1 && + "Wrong number of operands in kernel_arg_access_qual metadata."); + + for (unsigned i = 1; i < aq_node->getNumOperands(); ++i) { + auto aq = llvm::cast<llvm::MDString>(aq_node->getOperand(i)); + access_quals[i-1] = aq->getString(); + } + + return access_quals; + } + std::vector<module::argument> get_kernel_args(const llvm::Module *mod, const std::string &kernel_name, const clang::LangAS::Map &address_spaces) { std::vector<module::argument> args; llvm::Function *kernel_func = mod->getFunction(kernel_name); + auto access_quals = get_kernel_access_qualifiers(kernel_func); llvm::DataLayout TD(mod); + unsigned arg_idx = 0; + unsigned num_img_args = 0; for (llvm::Function::const_arg_iterator I = kernel_func->arg_begin(), - E = kernel_func->arg_end(); I != E; ++I) { + E = kernel_func->arg_end(); I != E; ++I, ++arg_idx) { const llvm::Argument &arg = *I; llvm::Type *arg_type = arg.getType(); @@ -375,6 +425,43 @@ 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()) { + llvm::StringRef type_name = elem_type->getStructName(); + llvm::StringRef access_qual = access_quals[arg_idx]; + + bool is_image2d = type_name.startswith("opencl.image2d_t"); + bool is_image3d = type_name.startswith("opencl.image3d_t"); + bool is_write_only = access_qual == "write_only"; + bool is_read_only = access_qual == "read_only"; + + assert(((!is_image2d && !is_image3d) || + is_write_only || is_read_only) && + "Wrong image access qualifier"); + + typename module::argument::type marg_type; + if (is_image2d && is_read_only) { + marg_type = module::argument::image2d_rd; + } else if (is_image2d && is_write_only) { + marg_type = module::argument::image2d_wr; + } else if (is_image3d && is_read_only) { + marg_type = module::argument::image3d_rd; + } else if (is_image3d && is_write_only) { + marg_type = module::argument::image3d_wr; + } + + if (is_image2d || is_image3d) { + args.push_back(module::argument(marg_type, + arg_store_size, target_size, + target_align, + module::argument::zero_ext)); + num_img_args++; + continue; + } + } unsigned address_space = llvm::cast<llvm::PointerType>(arg_type)->getAddressSpace(); if (address_space == address_spaces[clang::LangAS::opencl_local - clang::LangAS::Offset]) { @@ -430,6 +517,19 @@ namespace { module::argument::zero_ext, module::argument::grid_offset)); + llvm::Type *img_attr_type = + TD.getSmallestLegalIntType(mod->getContext(), sizeof(cl_int) * 8); + + auto img_attr_arg = + module::argument(module::argument::scalar, sizeof(cl_int), + TD.getTypeStoreSize(img_attr_type), + TD.getABITypeAlignment(img_attr_type), + module::argument::zero_ext, + module::argument::image_attributes); + for (unsigned i = 0; i < num_img_args; ++i) { + args.push_back(img_attr_arg); + } + return args; } -- 2.4.2 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev