[Mesa-dev] [PATCH 1/2] clover: Implement image attribute getters
Zoltan Gilian
zoltan.gilian at gmail.com
Mon Jun 8 04:20:24 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 | 13 ++
src/gallium/state_trackers/clover/core/memory.cpp | 2 +-
.../state_trackers/clover/llvm/invocation.cpp | 158 ++++++++++++++++++++-
3 files changed, 170 insertions(+), 3 deletions(-)
diff --git a/src/gallium/state_trackers/clover/core/kernel.cpp b/src/gallium/state_trackers/clover/core/kernel.cpp
index 0756f06..4703899 100644
--- a/src/gallium/state_trackers/clover/core/kernel.cpp
+++ b/src/gallium/state_trackers/clover/core/kernel.cpp
@@ -483,6 +483,19 @@ kernel::image_rd_argument::bind(exec_context &ctx,
align(ctx.input, marg.target_align);
insert(ctx.input, v);
+ cl_image_format fmt = img->format();
+ cl_uint image_attribs[] = {img->width(), img->height(), img->depth(),
+ fmt.image_channel_data_type,
+ fmt.image_channel_order};
+ for (int i = 0; i < 5; i++) {
+ auto v = bytes(image_attribs[i]);
+
+ 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 = img->resource(*ctx.q).bind_sampler_view(*ctx.q);
ctx.sviews.push_back(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..5d5e619 100644
--- a/src/gallium/state_trackers/clover/llvm/invocation.cpp
+++ b/src/gallium/state_trackers/clover/llvm/invocation.cpp
@@ -33,6 +33,8 @@
#include <llvm/IR/DiagnosticInfo.h>
#include <llvm/IR/DiagnosticPrinter.h>
#include <llvm/IR/DerivedTypes.h>
+#include <llvm/IR/InstIterator.h>
+#include <llvm/IR/Instructions.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/Support/SourceMgr.h>
@@ -80,6 +82,130 @@
using namespace clover;
namespace {
+
+ /* LLVM pass to resolve get_image_* OpenCL builtins.
+ * The image attributes (e.g. width or channel order) are passed as hidden
+ * arguments to the kernel.
+ * This pass replaces specific function calls with the appropriate hidden
+ * arguments. The libclc library needs to implements the get_image_*
+ * builtins as these specific functions to avoid dealing with name mangling
+ * here.
+ */
+ struct OpenCLImageBuiltinPass : public llvm::FunctionPass {
+ static char ID;
+
+ OpenCLImageBuiltinPass(): llvm::FunctionPass(ID) {}
+ bool runOnFunction(llvm::Function &F) override;
+
+ struct ImageAttribArgs {
+ ImageAttribArgs(): image_arg(0),
+ width_arg(0),
+ heigth_arg(0),
+ depth_arg(0),
+ channel_data_type_arg(0),
+ channel_order_arg(0) {}
+ llvm::Argument* image_arg;
+ llvm::Argument* width_arg;
+ llvm::Argument* heigth_arg;
+ llvm::Argument* depth_arg;
+ llvm::Argument* channel_data_type_arg;
+ llvm::Argument* channel_order_arg;
+ };
+ };
+
+ char OpenCLImageBuiltinPass::ID = 0;
+
+ bool
+ OpenCLImageBuiltinPass::runOnFunction(llvm::Function& F)
+ {
+ llvm::Module* mod = F.getParent();
+ llvm::DataLayout TD(mod);
+ llvm::Type* cl_int_type =
+ TD.getSmallestLegalIntType(mod->getContext(), sizeof(cl_int));
+
+ std::vector<ImageAttribArgs> img_args;
+ for (auto arg = F.arg_begin(), E = F.arg_end(); arg != E; ++arg) {
+
+ llvm::Type *arg_type = arg->getType();
+ if (!arg_type->isPointerTy()) continue;
+
+ llvm::Type *elem_type = arg_type->getPointerElementType();
+ if (!elem_type->isStructTy()) continue;
+
+ const llvm::StringRef &type_name = elem_type->getStructName();
+ if (!type_name.startswith("opencl.image2d_t")) continue;
+
+ auto name_suffix = llvm::Twine(img_args.size());
+ ImageAttribArgs attrib_args;
+ attrib_args.image_arg = arg;
+ attrib_args.width_arg = new llvm::Argument(
+ cl_int_type, "image_width" + name_suffix);
+ attrib_args.heigth_arg = new llvm::Argument(
+ cl_int_type, "image_height" + name_suffix);
+ attrib_args.depth_arg = new llvm::Argument(
+ cl_int_type, "image_depth" + name_suffix);
+ attrib_args.channel_data_type_arg = new llvm::Argument(
+ cl_int_type, "image_channel_data_type" + name_suffix);
+ attrib_args.channel_order_arg = new llvm::Argument(
+ cl_int_type, "image_channel_order" + name_suffix);
+
+ auto& args = F.getArgumentList();
+ args.insertAfter(arg, attrib_args.channel_order_arg);
+ args.insertAfter(arg, attrib_args.channel_data_type_arg);
+ args.insertAfter(arg, attrib_args.depth_arg);
+ args.insertAfter(arg, attrib_args.heigth_arg);
+ args.insertAfter(arg, attrib_args.width_arg);
+
+ img_args.push_back(attrib_args);
+ }
+ std::vector<llvm::Instruction*> insts_to_erase;
+ for (auto I = llvm::inst_begin(F), E = llvm::inst_end(F); I != E; ++I) {
+ llvm::CallInst* callInst = llvm::dyn_cast<llvm::CallInst>(&*I);
+ if (!callInst) continue;
+
+ for (auto& op: callInst->arg_operands()) {
+ auto op_arg = op.get();
+ auto image_arg = std::find_if(
+ img_args.begin(), img_args.end(),
+ [op_arg](const ImageAttribArgs& x) {
+ return x.image_arg == op_arg;
+ });
+ if (image_arg == img_args.end()) continue;
+
+ llvm::Function* callee = callInst->getCalledFunction();
+ if (!callee) continue;
+
+ auto callee_name = callee->getName();
+ if (callee_name.startswith(
+ "llvm.opencl.image.get.width")) {
+ callInst->replaceAllUsesWith(image_arg->width_arg);
+ insts_to_erase.push_back(callInst);
+ } else if (callee_name.startswith(
+ "llvm.opencl.image.get.height")) {
+ callInst->replaceAllUsesWith(image_arg->heigth_arg);
+ insts_to_erase.push_back(callInst);
+ } else if (callee_name.startswith(
+ "llvm.opencl.image.get.depth")) {
+ callInst->replaceAllUsesWith(image_arg->depth_arg);
+ insts_to_erase.push_back(callInst);
+ } else if (callee_name.startswith(
+ "llvm.opencl.image.get.channel_data_type")) {
+ callInst->replaceAllUsesWith(image_arg->channel_data_type_arg);
+ insts_to_erase.push_back(callInst);
+ } else if (callee_name.startswith(
+ "llvm.opencl.image.get.channel_order")) {
+ callInst->replaceAllUsesWith(image_arg->channel_order_arg);
+ insts_to_erase.push_back(callInst);
+ }
+ }
+ }
+ for (auto inst: insts_to_erase) {
+ inst->eraseFromParent();
+ }
+
+ return (img_args.size() > 0);
+ }
+
#if 0
void
build_binary(const std::string &source, const std::string &target,
@@ -263,10 +389,21 @@ namespace {
sizeof(address_spaces));
#if HAVE_LLVM >= 0x0306
- return act.takeModule().release();
+ llvm::Module * module = act.takeModule().release();
+#else
+ llvm::Module * module = act.takeModule();
+#endif
+
+ // Resolve get_image_* builtins.
+#if HAVE_LLVM >= 0x0307
+ llvm::legacy::PassManager PM;
#else
- return act.takeModule();
+ llvm::PassManager PM;
#endif
+ PM.add(new OpenCLImageBuiltinPass());
+ PM.run(*module);
+
+ return module;
}
void
@@ -375,6 +512,23 @@ 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()) {
+ const llvm::StringRef &type_name = elem_type->getStructName();
+
+ if (type_name.startswith("opencl.image2d_t")) {
+ args.push_back(module::argument(module::argument::image2d_rd,
+ arg_store_size, target_size, target_align,
+ module::argument::zero_ext));
+ // Skip hidden image attribute arguments.
+ // XXX: Do this based on some kind of metadata.
+ std::advance(I, 5);
+ 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