Path: blob/21.2-virgl/src/gallium/frontends/clover/llvm/codegen/common.cpp
4574 views
//1// Copyright 2012-2016 Francisco Jerez2// Copyright 2012-2016 Advanced Micro Devices, Inc.3// Copyright 2015 Zoltan Gilian4//5// Permission is hereby granted, free of charge, to any person obtaining a6// copy of this software and associated documentation files (the "Software"),7// to deal in the Software without restriction, including without limitation8// the rights to use, copy, modify, merge, publish, distribute, sublicense,9// and/or sell copies of the Software, and to permit persons to whom the10// Software is furnished to do so, subject to the following conditions:11//12// The above copyright notice and this permission notice shall be included in13// all copies or substantial portions of the Software.14//15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL18// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR19// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,20// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR21// OTHER DEALINGS IN THE SOFTWARE.22//2324///25/// \file26/// Codegen back-end-independent part of the construction of an executable27/// clover::module, including kernel argument metadata extraction and28/// formatting of the pre-generated binary code in a form that can be29/// understood by pipe drivers.30///3132#include <llvm/Support/Allocator.h>3334#include "llvm/codegen.hpp"35#include "llvm/metadata.hpp"3637#include "CL/cl.h"3839#include "pipe/p_state.h"40#include "util/u_math.h"4142#include <clang/Basic/TargetInfo.h>4344using clover::module;45using clover::detokenize;46using namespace clover::llvm;4748using ::llvm::Module;49using ::llvm::Function;50using ::llvm::Type;51using ::llvm::isa;52using ::llvm::cast;53using ::llvm::dyn_cast;5455namespace {56enum module::argument::type57get_image_type(const std::string &type,58const std::string &qual) {59if (type == "image1d_t" || type == "image2d_t" || type == "image3d_t") {60if (qual == "read_only")61return module::argument::image_rd;62else if (qual == "write_only")63return module::argument::image_wr;64}6566unreachable("Unsupported image type");67}6869module::arg_info create_arg_info(const std::string &arg_name,70const std::string &type_name,71const std::string &type_qualifier,72const uint64_t address_qualifier,73const std::string &access_qualifier) {7475cl_kernel_arg_type_qualifier cl_type_qualifier =76CL_KERNEL_ARG_TYPE_NONE;77if (type_qualifier.find("const") != std::string::npos)78cl_type_qualifier |= CL_KERNEL_ARG_TYPE_CONST;79if (type_qualifier.find("restrict") != std::string::npos)80cl_type_qualifier |= CL_KERNEL_ARG_TYPE_RESTRICT;81if (type_qualifier.find("volatile") != std::string::npos)82cl_type_qualifier |= CL_KERNEL_ARG_TYPE_VOLATILE;8384cl_kernel_arg_address_qualifier cl_address_qualifier =85CL_KERNEL_ARG_ADDRESS_PRIVATE;86if (address_qualifier == 1)87cl_address_qualifier = CL_KERNEL_ARG_ADDRESS_GLOBAL;88else if (address_qualifier == 2)89cl_address_qualifier = CL_KERNEL_ARG_ADDRESS_CONSTANT;90else if (address_qualifier == 3)91cl_address_qualifier = CL_KERNEL_ARG_ADDRESS_LOCAL;9293cl_kernel_arg_access_qualifier cl_access_qualifier =94CL_KERNEL_ARG_ACCESS_NONE;95if (access_qualifier == "read_only")96cl_access_qualifier = CL_KERNEL_ARG_ACCESS_READ_ONLY;97else if (access_qualifier == "write_only")98cl_access_qualifier = CL_KERNEL_ARG_ACCESS_WRITE_ONLY;99else if (access_qualifier == "read_write")100cl_access_qualifier = CL_KERNEL_ARG_ACCESS_READ_WRITE;101102return module::arg_info(arg_name, type_name, cl_type_qualifier,103cl_address_qualifier, cl_access_qualifier);104}105106std::vector<size_t>107get_reqd_work_group_size(const Module &mod,108const std::string &kernel_name) {109const Function &f = *mod.getFunction(kernel_name);110auto vector_metadata = get_uint_vector_kernel_metadata(f, "reqd_work_group_size");111112return vector_metadata.empty() ? std::vector<size_t>({0, 0, 0}) : vector_metadata;113}114115116std::string117kernel_attributes(const Module &mod, const std::string &kernel_name) {118std::vector<std::string> attributes;119120const Function &f = *mod.getFunction(kernel_name);121122auto vec_type_hint = get_type_kernel_metadata(f, "vec_type_hint");123if (!vec_type_hint.empty())124attributes.emplace_back("vec_type_hint(" + vec_type_hint + ")");125126auto work_group_size_hint = get_uint_vector_kernel_metadata(f, "work_group_size_hint");127if (!work_group_size_hint.empty()) {128std::string s = "work_group_size_hint(";129s += detokenize(work_group_size_hint, ",");130s += ")";131attributes.emplace_back(s);132}133134auto reqd_work_group_size = get_uint_vector_kernel_metadata(f, "reqd_work_group_size");135if (!reqd_work_group_size.empty()) {136std::string s = "reqd_work_group_size(";137s += detokenize(reqd_work_group_size, ",");138s += ")";139attributes.emplace_back(s);140}141142auto nosvm = get_str_kernel_metadata(f, "nosvm");143if (!nosvm.empty())144attributes.emplace_back("nosvm");145146return detokenize(attributes, " ");147}148149std::vector<module::argument>150make_kernel_args(const Module &mod, const std::string &kernel_name,151const clang::CompilerInstance &c) {152std::vector<module::argument> args;153const Function &f = *mod.getFunction(kernel_name);154::llvm::DataLayout dl(&mod);155const auto size_type =156dl.getSmallestLegalIntType(mod.getContext(), sizeof(cl_uint) * 8);157158for (const auto &arg : f.args()) {159const auto arg_type = arg.getType();160161// OpenCL 1.2 specification, Ch. 6.1.5: "A built-in data162// type that is not a power of two bytes in size must be163// aligned to the next larger power of two.164// This rule applies to built-in types only, not structs or unions."165const unsigned arg_api_size = dl.getTypeAllocSize(arg_type);166167const unsigned target_size = dl.getTypeStoreSize(arg_type);168const unsigned target_align = dl.getABITypeAlignment(arg_type);169170const auto type_name = get_str_argument_metadata(f, arg,171"kernel_arg_type");172if (type_name == "image2d_t" || type_name == "image3d_t") {173// Image.174const auto access_qual = get_str_argument_metadata(175f, arg, "kernel_arg_access_qual");176args.emplace_back(get_image_type(type_name, access_qual),177target_size, target_size,178target_align, module::argument::zero_ext);179180} else if (type_name == "sampler_t") {181args.emplace_back(module::argument::sampler, arg_api_size,182target_size, target_align,183module::argument::zero_ext);184185} else if (type_name == "__llvm_image_size") {186// Image size implicit argument.187args.emplace_back(module::argument::scalar, sizeof(cl_uint),188dl.getTypeStoreSize(size_type),189dl.getABITypeAlignment(size_type),190module::argument::zero_ext,191module::argument::image_size);192193} else if (type_name == "__llvm_image_format") {194// Image format implicit argument.195args.emplace_back(module::argument::scalar, sizeof(cl_uint),196dl.getTypeStoreSize(size_type),197dl.getABITypeAlignment(size_type),198module::argument::zero_ext,199module::argument::image_format);200201} else {202// Other types.203const auto actual_type =204isa< ::llvm::PointerType>(arg_type) && arg.hasByValAttr() ?205cast< ::llvm::PointerType>(arg_type)->getElementType() : arg_type;206207if (actual_type->isPointerTy()) {208const unsigned address_space =209cast< ::llvm::PointerType>(actual_type)->getAddressSpace();210211const auto &map = c.getTarget().getAddressSpaceMap();212const auto offset =213static_cast<unsigned>(clang::LangAS::opencl_local);214if (address_space == map[offset]) {215args.emplace_back(module::argument::local, arg_api_size,216target_size, target_align,217module::argument::zero_ext);218} else {219// XXX: Correctly handle constant address space. There is no220// way for r600g to pass a handle for constant buffers back221// to clover like it can for global buffers, so222// creating constant arguments will break r600g. For now,223// continue treating constant buffers as global buffers224// until we can come up with a way to create handles for225// constant buffers.226args.emplace_back(module::argument::global, arg_api_size,227target_size, target_align,228module::argument::zero_ext);229}230231} else {232const bool needs_sign_ext = f.getAttributes().hasAttribute(233arg.getArgNo() + 1, ::llvm::Attribute::SExt);234235args.emplace_back(module::argument::scalar, arg_api_size,236target_size, target_align,237(needs_sign_ext ? module::argument::sign_ext :238module::argument::zero_ext));239}240241// Add kernel argument infos if built with -cl-kernel-arg-info.242if (c.getCodeGenOpts().EmitOpenCLArgMetadata) {243args.back().info = create_arg_info(244get_str_argument_metadata(f, arg, "kernel_arg_name"),245type_name,246get_str_argument_metadata(f, arg, "kernel_arg_type_qual"),247get_uint_argument_metadata(f, arg, "kernel_arg_addr_space"),248get_str_argument_metadata(f, arg, "kernel_arg_access_qual"));249}250}251}252253// Append implicit arguments. XXX - The types, ordering and254// vector size of the implicit arguments should depend on the255// target according to the selected calling convention.256args.emplace_back(module::argument::scalar, sizeof(cl_uint),257dl.getTypeStoreSize(size_type),258dl.getABITypeAlignment(size_type),259module::argument::zero_ext,260module::argument::grid_dimension);261262args.emplace_back(module::argument::scalar, sizeof(cl_uint),263dl.getTypeStoreSize(size_type),264dl.getABITypeAlignment(size_type),265module::argument::zero_ext,266module::argument::grid_offset);267268return args;269}270271module::section272make_text_section(const std::vector<char> &code) {273const pipe_binary_program_header header { uint32_t(code.size()) };274module::section text { 0, module::section::text_executable,275header.num_bytes, {} };276277text.data.insert(text.data.end(), reinterpret_cast<const char *>(&header),278reinterpret_cast<const char *>(&header) + sizeof(header));279text.data.insert(text.data.end(), code.begin(), code.end());280281return text;282}283}284285module286clover::llvm::build_module_common(const Module &mod,287const std::vector<char> &code,288const std::map<std::string,289unsigned> &offsets,290const clang::CompilerInstance &c) {291module m;292293for (const auto &llvm_name : map(std::mem_fn(&Function::getName),294get_kernels(mod))) {295const ::std::string name(llvm_name);296if (offsets.count(name))297m.syms.emplace_back(name, kernel_attributes(mod, name),298get_reqd_work_group_size(mod, name),2990, offsets.at(name),300make_kernel_args(mod, name, c));301}302303m.secs.push_back(make_text_section(code));304return m;305}306307308