[Mesa-dev] [PATCH] clover: Implement image attribute getters
Zoltan Gilian
zoltan.gilian at gmail.com
Thu Jun 18 04:25:04 PDT 2015
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 | 26 +++++++
src/gallium/state_trackers/clover/core/kernel.hpp | 13 ++--
src/gallium/state_trackers/clover/core/memory.cpp | 2 +-
.../state_trackers/clover/llvm/invocation.cpp | 81 +++++++++++++++++++++-
4 files changed, 116 insertions(+), 6 deletions(-)
diff --git a/src/gallium/state_trackers/clover/core/kernel.cpp b/src/gallium/state_trackers/clover/core/kernel.cpp
index 0756f06..291c799 100644
--- a/src/gallium/state_trackers/clover/core/kernel.cpp
+++ b/src/gallium/state_trackers/clover/core/kernel.cpp
@@ -185,6 +185,13 @@ kernel::exec_context::bind(intrusive_ptr<command_queue> _q,
}
}
+ // Bind image attribute args.
+ for (const auto& arg: kern._args) {
+ if (auto img_arg = dynamic_cast<image_argument*>(arg.get())) {
+ img_arg->bind_attributes(*this);
+ }
+ }
+
// Create a new compute state if anything changed.
if (!st || q != _q ||
cs.req_local_mem != mem_local ||
@@ -465,6 +472,25 @@ kernel::constant_argument::unbind(exec_context &ctx) {
}
void
+kernel::image_argument::bind_attributes(exec_context &ctx) {
+ cl_image_format format = img->format();
+ cl_uint attributes[] = {
+ static_cast<cl_uint>(img->width()),
+ static_cast<cl_uint>(img->height()),
+ static_cast<cl_uint>(img->depth()),
+ format.image_channel_data_type,
+ format.image_channel_order};
+ for (unsigned i = 0; i < 5; ++i) {
+ auto v = bytes(attributes[i]);
+
+ extend(v, module::argument::zero_ext, sizeof(cl_uint));
+ byteswap(v, ctx.q->device().endianness());
+ align(ctx.input, sizeof(cl_uint));
+ insert(ctx.input, v);
+ }
+}
+
+void
kernel::image_rd_argument::set(size_t size, const void *value) {
if (size != sizeof(cl_mem))
throw error(CL_INVALID_ARG_SIZE);
diff --git a/src/gallium/state_trackers/clover/core/kernel.hpp b/src/gallium/state_trackers/clover/core/kernel.hpp
index d6432a4..8c15b2f 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:
+ void bind_attributes(exec_context &ctx);
+ 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/llvm/invocation.cpp b/src/gallium/state_trackers/clover/llvm/invocation.cpp
index 9b91fee..a33d450 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,65 @@ 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;
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 +424,36 @@ 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];
+
+ typename module::argument::type marg_type;
+ if (type_name.startswith("opencl.image2d_t")) {
+ if (access_qual == "write_only") {
+ marg_type = module::argument::image2d_wr;
+ } else {
+ marg_type = module::argument::image2d_rd;
+ }
+ } else if (type_name.startswith("opencl.image3d_t")) {
+ if (access_qual == "write_only") {
+ marg_type = module::argument::image3d_wr;
+ } else {
+ marg_type = module::argument::image3d_rd;
+ }
+ } else {
+ continue;
+ }
+
+ args.push_back(module::argument(marg_type,
+ arg_store_size, target_size, target_align,
+ module::argument::zero_ext));
+ 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
More information about the mesa-dev
mailing list