[Mesa-dev] [PATCH] clover: Pass image attributes to the kernel
Zoltan Gilian
zoltan.gilian at gmail.com
Tue Jul 21 10:49:44 PDT 2015
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 | 46 ++++++-
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 | 4 +-
.../state_trackers/clover/llvm/invocation.cpp | 147 ++++++++++++++++++++-
5 files changed, 198 insertions(+), 14 deletions(-)
diff --git a/src/gallium/state_trackers/clover/core/kernel.cpp b/src/gallium/state_trackers/clover/core/kernel.cpp
index 0756f06..1a6c28f 100644
--- a/src/gallium/state_trackers/clover/core/kernel.cpp
+++ b/src/gallium/state_trackers/clover/core/kernel.cpp
@@ -158,13 +158,18 @@ kernel::exec_context::bind(intrusive_ptr<command_queue> _q,
auto margs = find(name_equals(kern.name()), m.syms).args;
auto msec = find(type_equals(module::section::text), m.secs);
auto explicit_arg = kern._args.begin();
+ image_argument *last_image_arg = nullptr;
for (auto &marg : margs) {
switch (marg.semantic) {
- case module::argument::general:
+ case module::argument::general: {
+ auto image_arg = dynamic_cast<image_argument*>(explicit_arg->get());
+ if (image_arg) {
+ last_image_arg = image_arg;
+ }
(*(explicit_arg++))->bind(*this, marg);
break;
-
+ }
case module::argument::grid_dimension: {
const cl_uint dimension = grid_offset.size();
auto arg = argument::create(marg);
@@ -182,6 +187,36 @@ kernel::exec_context::bind(intrusive_ptr<command_queue> _q,
}
break;
}
+ case module::argument::image_size: {
+ assert(last_image_arg);
+ auto img = last_image_arg->get();
+ std::vector<cl_uint> image_size({
+ img->width(),
+ img->height(),
+ img->depth()});
+ for (auto x: image_size) {
+ auto arg = argument::create(marg);
+
+ arg->set(sizeof(x), &x);
+ arg->bind(*this, marg);
+ }
+ break;
+ }
+ case module::argument::image_format: {
+ assert(last_image_arg);
+ auto img = last_image_arg->get();
+ cl_image_format fmt = img->format();
+ std::vector<cl_uint> image_format({
+ fmt.image_channel_data_type,
+ fmt.image_channel_order});
+ for (auto x: image_format) {
+ auto arg = argument::create(marg);
+
+ arg->set(sizeof(x), &x);
+ arg->bind(*this, marg);
+ }
+ break;
+ }
}
}
@@ -532,6 +567,13 @@ kernel::sampler_argument::set(size_t size, const void *value) {
void
kernel::sampler_argument::bind(exec_context &ctx,
const module::argument &marg) {
+ auto v = bytes(ctx.samplers.size());
+
+ 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);
+
st = s->bind(*ctx.q);
ctx.samplers.push_back(st);
}
diff --git a/src/gallium/state_trackers/clover/core/kernel.hpp b/src/gallium/state_trackers/clover/core/kernel.hpp
index d6432a4..007ffcc 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() 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..5db0548 100644
--- a/src/gallium/state_trackers/clover/core/module.hpp
+++ b/src/gallium/state_trackers/clover/core/module.hpp
@@ -72,7 +72,9 @@ namespace clover {
enum semantic {
general,
grid_dimension,
- grid_offset
+ grid_offset,
+ image_size,
+ image_format
};
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 967284d..e5cd59c 100644
--- a/src/gallium/state_trackers/clover/llvm/invocation.cpp
+++ b/src/gallium/state_trackers/clover/llvm/invocation.cpp
@@ -340,18 +340,91 @@ namespace {
PM.run(*mod);
}
+ // Kernel metadata
+
+ 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;
+ }
+
+ llvm::MDNode*
+ node_from_op_checked(const llvm::MDOperand &md_operand,
+ llvm::StringRef expect_name,
+ unsigned expect_num_args)
+ {
+ auto node = llvm::cast<llvm::MDNode>(md_operand);
+ assert(node->getNumOperands() == expect_num_args &&
+ "Wrong number of operands.");
+
+ auto str_node = llvm::cast<llvm::MDString>(node->getOperand(0));
+ assert(str_node->getString() == expect_name &&
+ "Wrong metadata node name.");
+
+ return node;
+ }
+
+ struct kernel_arg_md {
+ llvm::StringRef type_name;
+ llvm::StringRef access_qual;
+ kernel_arg_md(llvm::StringRef type_name_, llvm::StringRef access_qual_):
+ type_name(type_name_), access_qual(access_qual_) {}
+ };
+
+ std::vector<kernel_arg_md>
+ get_kernel_arg_md(const llvm::Function *kernel_func) {
+ auto num_args = kernel_func->getArgumentList().size();
+
+ auto kernel_node = get_kernel_metadata(kernel_func);
+ auto aq = node_from_op_checked(kernel_node->getOperand(2),
+ "kernel_arg_access_qual", num_args + 1);
+ auto ty = node_from_op_checked(kernel_node->getOperand(3),
+ "kernel_arg_type", num_args + 1);
+
+ auto res = std::vector<kernel_arg_md>();
+ res.reserve(num_args);
+ for (unsigned i = 0; i < num_args; ++i) {
+ res.push_back(kernel_arg_md(
+ llvm::cast<llvm::MDString>(ty->getOperand(i+1))->getString(),
+ llvm::cast<llvm::MDString>(aq->getOperand(i+1))->getString()));
+ }
+
+ return res;
+ }
+
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);
+ assert(kernel_func && "Kernel name not found in module.");
+ auto arg_md = get_kernel_arg_md(kernel_func);
llvm::DataLayout TD(mod);
+ llvm::Type *size_type =
+ TD.getSmallestLegalIntType(mod->getContext(), sizeof(cl_uint) * 8);
- for (llvm::Function::const_arg_iterator I = kernel_func->arg_begin(),
- E = kernel_func->arg_end(); I != E; ++I) {
- const llvm::Argument &arg = *I;
+ for (const auto &arg: kernel_func->args()) {
llvm::Type *arg_type = arg.getType();
const unsigned arg_store_size = TD.getTypeStoreSize(arg_type);
@@ -369,6 +442,68 @@ namespace {
unsigned target_size = TD.getTypeStoreSize(target_type);
unsigned target_align = TD.getABITypeAlignment(target_type);
+ llvm::StringRef type_name = arg_md[arg.getArgNo()].type_name;
+ llvm::StringRef access_qual = arg_md[arg.getArgNo()].access_qual;
+
+ // Image
+ bool is_image2d = type_name == "image2d_t";
+ bool is_image3d = type_name == "image3d_t";
+ if (is_image2d || is_image3d) {
+ bool is_write_only = access_qual == "write_only";
+ bool is_read_only = access_qual == "read_only";
+
+ 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;
+ } else {
+ assert(0 && "Wrong image access qualifier");
+ }
+
+ args.push_back(module::argument(marg_type,
+ arg_store_size, target_size,
+ target_align,
+ module::argument::zero_ext));
+ continue;
+ }
+
+ // Sampler
+ if (type_name == "sampler_t") {
+ args.push_back(module::argument(module::argument::sampler,
+ arg_store_size, target_size,
+ target_align,
+ module::argument::zero_ext));
+ continue;
+ }
+
+ // Image size implicit argument
+ if (type_name == "image_size") {
+ args.push_back(module::argument(module::argument::scalar,
+ sizeof(cl_uint),
+ TD.getTypeStoreSize(size_type),
+ TD.getABITypeAlignment(size_type),
+ module::argument::zero_ext,
+ module::argument::image_size));
+ continue;
+ }
+
+ // Image format implicit argument
+ if (type_name == "image_format") {
+ args.push_back(module::argument(module::argument::scalar,
+ sizeof(cl_uint),
+ TD.getTypeStoreSize(size_type),
+ TD.getABITypeAlignment(size_type),
+ module::argument::zero_ext,
+ module::argument::image_format));
+ continue;
+ }
+
+ // Other types
if (llvm::isa<llvm::PointerType>(arg_type) && arg.hasByValAttr()) {
arg_type =
llvm::dyn_cast<llvm::PointerType>(arg_type)->getElementType();
@@ -413,9 +548,6 @@ namespace {
// Append implicit arguments. XXX - The types, ordering and
// vector size of the implicit arguments should depend on the
// target according to the selected calling convention.
- llvm::Type *size_type =
- TD.getSmallestLegalIntType(mod->getContext(), sizeof(cl_uint) * 8);
-
args.push_back(
module::argument(module::argument::scalar, sizeof(cl_uint),
TD.getTypeStoreSize(size_type),
@@ -744,6 +876,9 @@ clover::compile_program_llvm(const std::string &source,
std::vector<char> code = compile_native(mod, triple, processor,
get_debug_flags() & DBG_ASM,
r_log);
+ // Target-specific passes may alter functions
+ kernels.clear();
+ find_kernels(mod, kernels);
m = build_module_native(code, mod, kernels, address_spaces, r_log);
break;
}
--
2.4.6
More information about the mesa-dev
mailing list