util/tuple.hpp
LLVM_SOURCES := \
+ llvm/codegen/common.cpp \
+ llvm/codegen.hpp \
llvm/compat.hpp \
llvm/invocation.cpp \
llvm/metadata.hpp \
--- /dev/null
+//
+// Copyright 2016 Francisco Jerez
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+
+///
+/// \file
+/// Tools to generate various forms of binary code from existing LLVM IR in
+/// the given llvm::Module object and output the result as a clover::module.
+///
+
+#ifndef CLOVER_LLVM_CODEGEN_HPP
+#define CLOVER_LLVM_CODEGEN_HPP
+
+#include "core/module.hpp"
+
+#include <llvm/IR/Module.h>
+
+#include <clang/Frontend/CompilerInstance.h>
+
+namespace clover {
+ namespace llvm {
+ module
+ build_module_common(const ::llvm::Module &mod,
+ const std::vector<char> &code,
+ const std::map<std::string, unsigned> &offsets,
+ const clang::CompilerInstance &c);
+ }
+}
+
+#endif
--- /dev/null
+//
+// Copyright 2012-2016 Francisco Jerez
+// Copyright 2012-2016 Advanced Micro Devices, Inc.
+// Copyright 2015 Zoltan Gilian
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+
+///
+/// \file
+/// Codegen back-end-independent part of the construction of an executable
+/// clover::module, including kernel argument metadata extraction and
+/// formatting of the pre-generated binary code in a form that can be
+/// understood by pipe drivers.
+///
+
+#include "llvm/codegen.hpp"
+#include "llvm/metadata.hpp"
+
+#include "CL/cl.h"
+
+#include "pipe/p_state.h"
+#include "util/u_math.h"
+
+#include <clang/Basic/TargetInfo.h>
+
+using namespace clover;
+using namespace clover::llvm;
+
+using ::llvm::Module;
+using ::llvm::Function;
+using ::llvm::Type;
+using ::llvm::isa;
+using ::llvm::cast;
+using ::llvm::dyn_cast;
+
+namespace {
+ enum module::argument::type
+ get_image_type(const std::string &type,
+ const std::string &qual) {
+ if (type == "image2d_t" && qual == "read_only")
+ return module::argument::image2d_rd;
+ else if (type == "image2d_t" && qual == "write_only")
+ return module::argument::image2d_wr;
+ else if (type == "image3d_t" && qual == "read_only")
+ return module::argument::image3d_rd;
+ else if (type == "image3d_t" && qual == "write_only")
+ return module::argument::image3d_wr;
+ else
+ unreachable("Unknown image type");
+ }
+
+ std::vector<module::argument>
+ make_kernel_args(const Module &mod, const std::string &kernel_name,
+ const clang::CompilerInstance &c) {
+ std::vector<module::argument> args;
+ const auto address_spaces = c.getTarget().getAddressSpaceMap();
+ const Function &f = *mod.getFunction(kernel_name);
+ ::llvm::DataLayout dl(&mod);
+ const auto size_type =
+ dl.getSmallestLegalIntType(mod.getContext(), sizeof(cl_uint) * 8);
+
+ for (const auto &arg : f.args()) {
+ const auto arg_type = arg.getType();
+
+ // OpenCL 1.2 specification, Ch. 6.1.5: "A built-in data
+ // type that is not a power of two bytes in size must be
+ // aligned to the next larger power of two". We need this
+ // alignment for three element vectors, which have
+ // non-power-of-2 store size.
+ const unsigned arg_store_size = dl.getTypeStoreSize(arg_type);
+ const unsigned arg_api_size = util_next_power_of_two(arg_store_size);
+
+ const auto target_type = !arg_type->isIntegerTy() ? arg_type :
+ dl.getSmallestLegalIntType(mod.getContext(), arg_store_size * 8);
+ const unsigned target_size = dl.getTypeStoreSize(target_type);
+ const unsigned target_align = dl.getABITypeAlignment(target_type);
+
+ const auto type_name = get_argument_metadata(f, arg,
+ "kernel_arg_type");
+
+ if (type_name == "image2d_t" || type_name == "image3d_t") {
+ // Image.
+ const auto access_qual = get_argument_metadata(
+ f, arg, "kernel_arg_access_qual");
+ args.emplace_back(get_image_type(type_name, access_qual),
+ arg_store_size, target_size,
+ target_align, module::argument::zero_ext);
+
+ } else if (type_name == "__llvm_image_size") {
+ // Image size implicit argument.
+ args.emplace_back(module::argument::scalar, sizeof(cl_uint),
+ dl.getTypeStoreSize(size_type),
+ dl.getABITypeAlignment(size_type),
+ module::argument::zero_ext,
+ module::argument::image_size);
+
+ } else if (type_name == "__llvm_image_format") {
+ // Image format implicit argument.
+ args.emplace_back(module::argument::scalar, sizeof(cl_uint),
+ dl.getTypeStoreSize(size_type),
+ dl.getABITypeAlignment(size_type),
+ module::argument::zero_ext,
+ module::argument::image_format);
+
+ } else {
+ // Other types.
+ const auto actual_type =
+ isa<::llvm::PointerType>(arg_type) && arg.hasByValAttr() ?
+ cast<::llvm::PointerType>(arg_type)->getElementType() : arg_type;
+
+ if (actual_type->isPointerTy()) {
+ const unsigned address_space =
+ cast<::llvm::PointerType>(actual_type)->getAddressSpace();
+
+ if (address_space == address_spaces[clang::LangAS::opencl_local
+ - clang::LangAS::Offset]) {
+ args.emplace_back(module::argument::local, arg_api_size,
+ target_size, target_align,
+ module::argument::zero_ext);
+ } else {
+ // XXX: Correctly handle constant address space. There is no
+ // way for r600g to pass a handle for constant buffers back
+ // to clover like it can for global buffers, so
+ // creating constant arguments will break r600g. For now,
+ // continue treating constant buffers as global buffers
+ // until we can come up with a way to create handles for
+ // constant buffers.
+ args.emplace_back(module::argument::global, arg_api_size,
+ target_size, target_align,
+ module::argument::zero_ext);
+ }
+
+ } else {
+ const bool needs_sign_ext = f.getAttributes().hasAttribute(
+ arg.getArgNo() + 1, ::llvm::Attribute::SExt);
+
+ args.emplace_back(module::argument::scalar, arg_api_size,
+ target_size, target_align,
+ (needs_sign_ext ? module::argument::sign_ext :
+ module::argument::zero_ext));
+ }
+ }
+ }
+
+ // 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.
+ args.emplace_back(module::argument::scalar, sizeof(cl_uint),
+ dl.getTypeStoreSize(size_type),
+ dl.getABITypeAlignment(size_type),
+ module::argument::zero_ext,
+ module::argument::grid_dimension);
+
+ args.emplace_back(module::argument::scalar, sizeof(cl_uint),
+ dl.getTypeStoreSize(size_type),
+ dl.getABITypeAlignment(size_type),
+ module::argument::zero_ext,
+ module::argument::grid_offset);
+
+ return args;
+ }
+
+ module::section
+ make_text_section(const std::vector<char> &code) {
+ const pipe_llvm_program_header header { uint32_t(code.size()) };
+ module::section text { 0, module::section::text, header.num_bytes, {} };
+
+ text.data.insert(text.data.end(), reinterpret_cast<const char *>(&header),
+ reinterpret_cast<const char *>(&header) + sizeof(header));
+ text.data.insert(text.data.end(), code.begin(), code.end());
+
+ return text;
+ }
+}
+
+module
+clover::llvm::build_module_common(const Module &mod,
+ const std::vector<char> &code,
+ const std::map<std::string,
+ unsigned> &offsets,
+ const clang::CompilerInstance &c) {
+ module m;
+
+ for (const auto &name : map(std::mem_fn(&Function::getName),
+ get_kernels(mod))) {
+ if (offsets.count(name))
+ m.syms.emplace_back(name, 0, offsets.at(name),
+ make_kernel_args(mod, name, c));
+ }
+
+ m.secs.push_back(make_text_section(code));
+ return m;
+}
// OTHER DEALINGS IN THE SOFTWARE.
//
+#include "llvm/codegen.hpp"
#include "llvm/compat.hpp"
#include "llvm/metadata.hpp"
#include "llvm/util.hpp"
pm.run(mod);
}
- enum module::argument::type
- get_image_type(const std::string &type,
- const std::string &qual) {
- if (type == "image2d_t" && qual == "read_only")
- return module::argument::image2d_rd;
- else if (type == "image2d_t" && qual == "write_only")
- return module::argument::image2d_wr;
- else if (type == "image3d_t" && qual == "read_only")
- return module::argument::image3d_rd;
- else if (type == "image3d_t" && qual == "write_only")
- return module::argument::image3d_wr;
- else
- unreachable("Unknown image type");
- }
-
- std::vector<module::argument>
- make_kernel_args(const Module &mod, const std::string &kernel_name,
- const clang::CompilerInstance &c) {
- std::vector<module::argument> args;
- const auto address_spaces = c.getTarget().getAddressSpaceMap();
- const Function &f = *mod.getFunction(kernel_name);
- ::llvm::DataLayout dl(&mod);
- const auto size_type =
- dl.getSmallestLegalIntType(mod.getContext(), sizeof(cl_uint) * 8);
-
- for (const auto &arg : f.args()) {
- const auto arg_type = arg.getType();
-
- // OpenCL 1.2 specification, Ch. 6.1.5: "A built-in data
- // type that is not a power of two bytes in size must be
- // aligned to the next larger power of two". We need this
- // alignment for three element vectors, which have
- // non-power-of-2 store size.
- const unsigned arg_store_size = dl.getTypeStoreSize(arg_type);
- const unsigned arg_api_size = util_next_power_of_two(arg_store_size);
-
- const auto target_type = !arg_type->isIntegerTy() ? arg_type :
- dl.getSmallestLegalIntType(mod.getContext(), arg_store_size * 8);
- const unsigned target_size = dl.getTypeStoreSize(target_type);
- const unsigned target_align = dl.getABITypeAlignment(target_type);
-
- const auto type_name = get_argument_metadata(f, arg,
- "kernel_arg_type");
-
- if (type_name == "image2d_t" || type_name == "image3d_t") {
- // Image.
- const auto access_qual = get_argument_metadata(
- f, arg, "kernel_arg_access_qual");
- args.emplace_back(get_image_type(type_name, access_qual),
- arg_store_size, target_size,
- target_align, module::argument::zero_ext);
-
- } else if (type_name == "__llvm_image_size") {
- // Image size implicit argument.
- args.emplace_back(module::argument::scalar, sizeof(cl_uint),
- dl.getTypeStoreSize(size_type),
- dl.getABITypeAlignment(size_type),
- module::argument::zero_ext,
- module::argument::image_size);
-
- } else if (type_name == "__llvm_image_format") {
- // Image format implicit argument.
- args.emplace_back(module::argument::scalar, sizeof(cl_uint),
- dl.getTypeStoreSize(size_type),
- dl.getABITypeAlignment(size_type),
- module::argument::zero_ext,
- module::argument::image_format);
-
- } else {
- // Other types.
- const auto actual_type =
- isa<::llvm::PointerType>(arg_type) && arg.hasByValAttr() ?
- cast<::llvm::PointerType>(arg_type)->getElementType() : arg_type;
-
- if (actual_type->isPointerTy()) {
- const unsigned address_space =
- cast<::llvm::PointerType>(actual_type)->getAddressSpace();
-
- if (address_space == address_spaces[clang::LangAS::opencl_local
- - clang::LangAS::Offset]) {
- args.emplace_back(module::argument::local, arg_api_size,
- target_size, target_align,
- module::argument::zero_ext);
- } else {
- // XXX: Correctly handle constant address space. There is no
- // way for r600g to pass a handle for constant buffers back
- // to clover like it can for global buffers, so
- // creating constant arguments will break r600g. For now,
- // continue treating constant buffers as global buffers
- // until we can come up with a way to create handles for
- // constant buffers.
- args.emplace_back(module::argument::global, arg_api_size,
- target_size, target_align,
- module::argument::zero_ext);
- }
-
- } else {
- const bool needs_sign_ext = f.getAttributes().hasAttribute(
- arg.getArgNo() + 1, ::llvm::Attribute::SExt);
-
- args.emplace_back(module::argument::scalar, arg_api_size,
- target_size, target_align,
- (needs_sign_ext ? module::argument::sign_ext :
- module::argument::zero_ext));
- }
- }
- }
-
- // 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.
- args.emplace_back(module::argument::scalar, sizeof(cl_uint),
- dl.getTypeStoreSize(size_type),
- dl.getABITypeAlignment(size_type),
- module::argument::zero_ext,
- module::argument::grid_dimension);
-
- args.emplace_back(module::argument::scalar, sizeof(cl_uint),
- dl.getTypeStoreSize(size_type),
- dl.getABITypeAlignment(size_type),
- module::argument::zero_ext,
- module::argument::grid_offset);
-
- return args;
- }
-
- module::section
- make_text_section(const std::vector<char> &code) {
- const pipe_llvm_program_header header { uint32_t(code.size()) };
- module::section text { 0, module::section::text, header.num_bytes, {} };
-
- text.data.insert(text.data.end(), reinterpret_cast<const char *>(&header),
- reinterpret_cast<const char *>(&header) + sizeof(header));
- text.data.insert(text.data.end(), code.begin(), code.end());
-
- return text;
- }
-
- module
- build_module_common(const Module &mod,
- const std::vector<char> &code,
- const std::map<std::string,
- unsigned> &offsets,
- const clang::CompilerInstance &c) {
- module m;
-
- for (const auto &name : map(std::mem_fn(&Function::getName),
- get_kernels(mod))) {
- if (offsets.count(name))
- m.syms.emplace_back(name, 0, offsets.at(name),
- make_kernel_args(mod, name, c));
- }
-
- m.secs.push_back(make_text_section(code));
- return m;
- }
-
std::map<std::string, unsigned>
get_symbol_offsets(const ::llvm::Module &mod) {
std::map<std::string, unsigned> offsets;