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 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev