1bf215546Sopenharmony_ci// 2bf215546Sopenharmony_ci// Copyright 2012-2016 Francisco Jerez 3bf215546Sopenharmony_ci// Copyright 2012-2016 Advanced Micro Devices, Inc. 4bf215546Sopenharmony_ci// Copyright 2015 Zoltan Gilian 5bf215546Sopenharmony_ci// 6bf215546Sopenharmony_ci// Permission is hereby granted, free of charge, to any person obtaining a 7bf215546Sopenharmony_ci// copy of this software and associated documentation files (the "Software"), 8bf215546Sopenharmony_ci// to deal in the Software without restriction, including without limitation 9bf215546Sopenharmony_ci// the rights to use, copy, modify, merge, publish, distribute, sublicense, 10bf215546Sopenharmony_ci// and/or sell copies of the Software, and to permit persons to whom the 11bf215546Sopenharmony_ci// Software is furnished to do so, subject to the following conditions: 12bf215546Sopenharmony_ci// 13bf215546Sopenharmony_ci// The above copyright notice and this permission notice shall be included in 14bf215546Sopenharmony_ci// all copies or substantial portions of the Software. 15bf215546Sopenharmony_ci// 16bf215546Sopenharmony_ci// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17bf215546Sopenharmony_ci// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18bf215546Sopenharmony_ci// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19bf215546Sopenharmony_ci// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20bf215546Sopenharmony_ci// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21bf215546Sopenharmony_ci// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22bf215546Sopenharmony_ci// OTHER DEALINGS IN THE SOFTWARE. 23bf215546Sopenharmony_ci// 24bf215546Sopenharmony_ci 25bf215546Sopenharmony_ci/// 26bf215546Sopenharmony_ci/// \file 27bf215546Sopenharmony_ci/// Codegen back-end-independent part of the construction of an executable 28bf215546Sopenharmony_ci/// clover::binary, including kernel argument metadata extraction and 29bf215546Sopenharmony_ci/// formatting of the pre-generated binary code in a form that can be 30bf215546Sopenharmony_ci/// understood by pipe drivers. 31bf215546Sopenharmony_ci/// 32bf215546Sopenharmony_ci 33bf215546Sopenharmony_ci#include <llvm/IR/Type.h> 34bf215546Sopenharmony_ci#include <llvm/Support/Allocator.h> 35bf215546Sopenharmony_ci 36bf215546Sopenharmony_ci#include "llvm/codegen.hpp" 37bf215546Sopenharmony_ci#include "llvm/metadata.hpp" 38bf215546Sopenharmony_ci 39bf215546Sopenharmony_ci#include "CL/cl.h" 40bf215546Sopenharmony_ci 41bf215546Sopenharmony_ci#include "pipe/p_state.h" 42bf215546Sopenharmony_ci#include "util/u_math.h" 43bf215546Sopenharmony_ci 44bf215546Sopenharmony_ci#include <clang/Basic/TargetInfo.h> 45bf215546Sopenharmony_ci 46bf215546Sopenharmony_ciusing clover::binary; 47bf215546Sopenharmony_ciusing clover::detokenize; 48bf215546Sopenharmony_ciusing namespace clover::llvm; 49bf215546Sopenharmony_ci 50bf215546Sopenharmony_ciusing ::llvm::Module; 51bf215546Sopenharmony_ciusing ::llvm::Function; 52bf215546Sopenharmony_ciusing ::llvm::Type; 53bf215546Sopenharmony_ciusing ::llvm::isa; 54bf215546Sopenharmony_ciusing ::llvm::cast; 55bf215546Sopenharmony_ciusing ::llvm::dyn_cast; 56bf215546Sopenharmony_ci 57bf215546Sopenharmony_cinamespace { 58bf215546Sopenharmony_ci enum binary::argument::type 59bf215546Sopenharmony_ci get_image_type(const std::string &type, 60bf215546Sopenharmony_ci const std::string &qual) { 61bf215546Sopenharmony_ci if (type == "image1d_t" || type == "image2d_t" || type == "image3d_t") { 62bf215546Sopenharmony_ci if (qual == "read_only") 63bf215546Sopenharmony_ci return binary::argument::image_rd; 64bf215546Sopenharmony_ci else if (qual == "write_only") 65bf215546Sopenharmony_ci return binary::argument::image_wr; 66bf215546Sopenharmony_ci } 67bf215546Sopenharmony_ci 68bf215546Sopenharmony_ci unreachable("Unsupported image type"); 69bf215546Sopenharmony_ci } 70bf215546Sopenharmony_ci 71bf215546Sopenharmony_ci binary::arg_info create_arg_info(const std::string &arg_name, 72bf215546Sopenharmony_ci const std::string &type_name, 73bf215546Sopenharmony_ci const std::string &type_qualifier, 74bf215546Sopenharmony_ci const uint64_t address_qualifier, 75bf215546Sopenharmony_ci const std::string &access_qualifier) { 76bf215546Sopenharmony_ci 77bf215546Sopenharmony_ci cl_kernel_arg_type_qualifier cl_type_qualifier = 78bf215546Sopenharmony_ci CL_KERNEL_ARG_TYPE_NONE; 79bf215546Sopenharmony_ci if (type_qualifier.find("const") != std::string::npos) 80bf215546Sopenharmony_ci cl_type_qualifier |= CL_KERNEL_ARG_TYPE_CONST; 81bf215546Sopenharmony_ci if (type_qualifier.find("restrict") != std::string::npos) 82bf215546Sopenharmony_ci cl_type_qualifier |= CL_KERNEL_ARG_TYPE_RESTRICT; 83bf215546Sopenharmony_ci if (type_qualifier.find("volatile") != std::string::npos) 84bf215546Sopenharmony_ci cl_type_qualifier |= CL_KERNEL_ARG_TYPE_VOLATILE; 85bf215546Sopenharmony_ci 86bf215546Sopenharmony_ci cl_kernel_arg_address_qualifier cl_address_qualifier = 87bf215546Sopenharmony_ci CL_KERNEL_ARG_ADDRESS_PRIVATE; 88bf215546Sopenharmony_ci if (address_qualifier == 1) 89bf215546Sopenharmony_ci cl_address_qualifier = CL_KERNEL_ARG_ADDRESS_GLOBAL; 90bf215546Sopenharmony_ci else if (address_qualifier == 2) 91bf215546Sopenharmony_ci cl_address_qualifier = CL_KERNEL_ARG_ADDRESS_CONSTANT; 92bf215546Sopenharmony_ci else if (address_qualifier == 3) 93bf215546Sopenharmony_ci cl_address_qualifier = CL_KERNEL_ARG_ADDRESS_LOCAL; 94bf215546Sopenharmony_ci 95bf215546Sopenharmony_ci cl_kernel_arg_access_qualifier cl_access_qualifier = 96bf215546Sopenharmony_ci CL_KERNEL_ARG_ACCESS_NONE; 97bf215546Sopenharmony_ci if (access_qualifier == "read_only") 98bf215546Sopenharmony_ci cl_access_qualifier = CL_KERNEL_ARG_ACCESS_READ_ONLY; 99bf215546Sopenharmony_ci else if (access_qualifier == "write_only") 100bf215546Sopenharmony_ci cl_access_qualifier = CL_KERNEL_ARG_ACCESS_WRITE_ONLY; 101bf215546Sopenharmony_ci else if (access_qualifier == "read_write") 102bf215546Sopenharmony_ci cl_access_qualifier = CL_KERNEL_ARG_ACCESS_READ_WRITE; 103bf215546Sopenharmony_ci 104bf215546Sopenharmony_ci return binary::arg_info(arg_name, type_name, cl_type_qualifier, 105bf215546Sopenharmony_ci cl_address_qualifier, cl_access_qualifier); 106bf215546Sopenharmony_ci } 107bf215546Sopenharmony_ci 108bf215546Sopenharmony_ci std::vector<size_t> 109bf215546Sopenharmony_ci get_reqd_work_group_size(const Module &mod, 110bf215546Sopenharmony_ci const std::string &kernel_name) { 111bf215546Sopenharmony_ci const Function &f = *mod.getFunction(kernel_name); 112bf215546Sopenharmony_ci auto vector_metadata = get_uint_vector_kernel_metadata(f, "reqd_work_group_size"); 113bf215546Sopenharmony_ci 114bf215546Sopenharmony_ci return vector_metadata.empty() ? std::vector<size_t>({0, 0, 0}) : vector_metadata; 115bf215546Sopenharmony_ci } 116bf215546Sopenharmony_ci 117bf215546Sopenharmony_ci 118bf215546Sopenharmony_ci std::string 119bf215546Sopenharmony_ci kernel_attributes(const Module &mod, const std::string &kernel_name) { 120bf215546Sopenharmony_ci std::vector<std::string> attributes; 121bf215546Sopenharmony_ci 122bf215546Sopenharmony_ci const Function &f = *mod.getFunction(kernel_name); 123bf215546Sopenharmony_ci 124bf215546Sopenharmony_ci auto vec_type_hint = get_type_kernel_metadata(f, "vec_type_hint"); 125bf215546Sopenharmony_ci if (!vec_type_hint.empty()) 126bf215546Sopenharmony_ci attributes.emplace_back("vec_type_hint(" + vec_type_hint + ")"); 127bf215546Sopenharmony_ci 128bf215546Sopenharmony_ci auto work_group_size_hint = get_uint_vector_kernel_metadata(f, "work_group_size_hint"); 129bf215546Sopenharmony_ci if (!work_group_size_hint.empty()) { 130bf215546Sopenharmony_ci std::string s = "work_group_size_hint("; 131bf215546Sopenharmony_ci s += detokenize(work_group_size_hint, ","); 132bf215546Sopenharmony_ci s += ")"; 133bf215546Sopenharmony_ci attributes.emplace_back(s); 134bf215546Sopenharmony_ci } 135bf215546Sopenharmony_ci 136bf215546Sopenharmony_ci auto reqd_work_group_size = get_uint_vector_kernel_metadata(f, "reqd_work_group_size"); 137bf215546Sopenharmony_ci if (!reqd_work_group_size.empty()) { 138bf215546Sopenharmony_ci std::string s = "reqd_work_group_size("; 139bf215546Sopenharmony_ci s += detokenize(reqd_work_group_size, ","); 140bf215546Sopenharmony_ci s += ")"; 141bf215546Sopenharmony_ci attributes.emplace_back(s); 142bf215546Sopenharmony_ci } 143bf215546Sopenharmony_ci 144bf215546Sopenharmony_ci auto nosvm = get_str_kernel_metadata(f, "nosvm"); 145bf215546Sopenharmony_ci if (!nosvm.empty()) 146bf215546Sopenharmony_ci attributes.emplace_back("nosvm"); 147bf215546Sopenharmony_ci 148bf215546Sopenharmony_ci return detokenize(attributes, " "); 149bf215546Sopenharmony_ci } 150bf215546Sopenharmony_ci 151bf215546Sopenharmony_ci std::vector<binary::argument> 152bf215546Sopenharmony_ci make_kernel_args(const Module &mod, const std::string &kernel_name, 153bf215546Sopenharmony_ci const clang::CompilerInstance &c) { 154bf215546Sopenharmony_ci std::vector<binary::argument> args; 155bf215546Sopenharmony_ci const Function &f = *mod.getFunction(kernel_name); 156bf215546Sopenharmony_ci ::llvm::DataLayout dl(&mod); 157bf215546Sopenharmony_ci const auto size_type = 158bf215546Sopenharmony_ci dl.getSmallestLegalIntType(mod.getContext(), sizeof(cl_uint) * 8); 159bf215546Sopenharmony_ci 160bf215546Sopenharmony_ci for (const auto &arg : f.args()) { 161bf215546Sopenharmony_ci const auto arg_type = arg.getType(); 162bf215546Sopenharmony_ci 163bf215546Sopenharmony_ci // OpenCL 1.2 specification, Ch. 6.1.5: "A built-in data 164bf215546Sopenharmony_ci // type that is not a power of two bytes in size must be 165bf215546Sopenharmony_ci // aligned to the next larger power of two. 166bf215546Sopenharmony_ci // This rule applies to built-in types only, not structs or unions." 167bf215546Sopenharmony_ci const unsigned arg_api_size = dl.getTypeAllocSize(arg_type); 168bf215546Sopenharmony_ci 169bf215546Sopenharmony_ci const unsigned target_size = dl.getTypeStoreSize(arg_type); 170bf215546Sopenharmony_ci const unsigned target_align = dl.getABITypeAlignment(arg_type); 171bf215546Sopenharmony_ci 172bf215546Sopenharmony_ci const auto type_name = get_str_argument_metadata(f, arg, 173bf215546Sopenharmony_ci "kernel_arg_type"); 174bf215546Sopenharmony_ci if (type_name == "image2d_t" || type_name == "image3d_t") { 175bf215546Sopenharmony_ci // Image. 176bf215546Sopenharmony_ci const auto access_qual = get_str_argument_metadata( 177bf215546Sopenharmony_ci f, arg, "kernel_arg_access_qual"); 178bf215546Sopenharmony_ci args.emplace_back(get_image_type(type_name, access_qual), 179bf215546Sopenharmony_ci target_size, target_size, 180bf215546Sopenharmony_ci target_align, binary::argument::zero_ext); 181bf215546Sopenharmony_ci 182bf215546Sopenharmony_ci } else if (type_name == "sampler_t") { 183bf215546Sopenharmony_ci args.emplace_back(binary::argument::sampler, arg_api_size, 184bf215546Sopenharmony_ci target_size, target_align, 185bf215546Sopenharmony_ci binary::argument::zero_ext); 186bf215546Sopenharmony_ci 187bf215546Sopenharmony_ci } else if (type_name == "__llvm_image_size") { 188bf215546Sopenharmony_ci // Image size implicit argument. 189bf215546Sopenharmony_ci args.emplace_back(binary::argument::scalar, sizeof(cl_uint), 190bf215546Sopenharmony_ci dl.getTypeStoreSize(size_type), 191bf215546Sopenharmony_ci dl.getABITypeAlignment(size_type), 192bf215546Sopenharmony_ci binary::argument::zero_ext, 193bf215546Sopenharmony_ci binary::argument::image_size); 194bf215546Sopenharmony_ci 195bf215546Sopenharmony_ci } else if (type_name == "__llvm_image_format") { 196bf215546Sopenharmony_ci // Image format implicit argument. 197bf215546Sopenharmony_ci args.emplace_back(binary::argument::scalar, sizeof(cl_uint), 198bf215546Sopenharmony_ci dl.getTypeStoreSize(size_type), 199bf215546Sopenharmony_ci dl.getABITypeAlignment(size_type), 200bf215546Sopenharmony_ci binary::argument::zero_ext, 201bf215546Sopenharmony_ci binary::argument::image_format); 202bf215546Sopenharmony_ci 203bf215546Sopenharmony_ci } else { 204bf215546Sopenharmony_ci // Other types. 205bf215546Sopenharmony_ci const auto actual_type = 206bf215546Sopenharmony_ci isa< ::llvm::PointerType>(arg_type) && arg.hasByValAttr() ? 207bf215546Sopenharmony_ci cast< ::llvm::PointerType>(arg_type)->getPointerElementType() : arg_type; 208bf215546Sopenharmony_ci 209bf215546Sopenharmony_ci if (actual_type->isPointerTy()) { 210bf215546Sopenharmony_ci const unsigned address_space = 211bf215546Sopenharmony_ci cast< ::llvm::PointerType>(actual_type)->getAddressSpace(); 212bf215546Sopenharmony_ci 213bf215546Sopenharmony_ci const auto &map = c.getTarget().getAddressSpaceMap(); 214bf215546Sopenharmony_ci const auto offset = 215bf215546Sopenharmony_ci static_cast<unsigned>(clang::LangAS::opencl_local); 216bf215546Sopenharmony_ci if (address_space == map[offset]) { 217bf215546Sopenharmony_ci const auto pointee_type = cast< 218bf215546Sopenharmony_ci ::llvm::PointerType>(actual_type)->getPointerElementType(); 219bf215546Sopenharmony_ci args.emplace_back(binary::argument::local, arg_api_size, 220bf215546Sopenharmony_ci target_size, 221bf215546Sopenharmony_ci dl.getABITypeAlignment(pointee_type), 222bf215546Sopenharmony_ci binary::argument::zero_ext); 223bf215546Sopenharmony_ci } else { 224bf215546Sopenharmony_ci // XXX: Correctly handle constant address space. There is no 225bf215546Sopenharmony_ci // way for r600g to pass a handle for constant buffers back 226bf215546Sopenharmony_ci // to clover like it can for global buffers, so 227bf215546Sopenharmony_ci // creating constant arguments will break r600g. For now, 228bf215546Sopenharmony_ci // continue treating constant buffers as global buffers 229bf215546Sopenharmony_ci // until we can come up with a way to create handles for 230bf215546Sopenharmony_ci // constant buffers. 231bf215546Sopenharmony_ci args.emplace_back(binary::argument::global, arg_api_size, 232bf215546Sopenharmony_ci target_size, target_align, 233bf215546Sopenharmony_ci binary::argument::zero_ext); 234bf215546Sopenharmony_ci } 235bf215546Sopenharmony_ci 236bf215546Sopenharmony_ci } else { 237bf215546Sopenharmony_ci const bool needs_sign_ext = f.getAttributes().hasParamAttr( 238bf215546Sopenharmony_ci arg.getArgNo(), ::llvm::Attribute::SExt); 239bf215546Sopenharmony_ci 240bf215546Sopenharmony_ci args.emplace_back(binary::argument::scalar, arg_api_size, 241bf215546Sopenharmony_ci target_size, target_align, 242bf215546Sopenharmony_ci (needs_sign_ext ? binary::argument::sign_ext : 243bf215546Sopenharmony_ci binary::argument::zero_ext)); 244bf215546Sopenharmony_ci } 245bf215546Sopenharmony_ci 246bf215546Sopenharmony_ci // Add kernel argument infos if built with -cl-kernel-arg-info. 247bf215546Sopenharmony_ci if (c.getCodeGenOpts().EmitOpenCLArgMetadata) { 248bf215546Sopenharmony_ci args.back().info = create_arg_info( 249bf215546Sopenharmony_ci get_str_argument_metadata(f, arg, "kernel_arg_name"), 250bf215546Sopenharmony_ci type_name, 251bf215546Sopenharmony_ci get_str_argument_metadata(f, arg, "kernel_arg_type_qual"), 252bf215546Sopenharmony_ci get_uint_argument_metadata(f, arg, "kernel_arg_addr_space"), 253bf215546Sopenharmony_ci get_str_argument_metadata(f, arg, "kernel_arg_access_qual")); 254bf215546Sopenharmony_ci } 255bf215546Sopenharmony_ci } 256bf215546Sopenharmony_ci } 257bf215546Sopenharmony_ci 258bf215546Sopenharmony_ci // Append implicit arguments. XXX - The types, ordering and 259bf215546Sopenharmony_ci // vector size of the implicit arguments should depend on the 260bf215546Sopenharmony_ci // target according to the selected calling convention. 261bf215546Sopenharmony_ci args.emplace_back(binary::argument::scalar, sizeof(cl_uint), 262bf215546Sopenharmony_ci dl.getTypeStoreSize(size_type), 263bf215546Sopenharmony_ci dl.getABITypeAlignment(size_type), 264bf215546Sopenharmony_ci binary::argument::zero_ext, 265bf215546Sopenharmony_ci binary::argument::grid_dimension); 266bf215546Sopenharmony_ci 267bf215546Sopenharmony_ci args.emplace_back(binary::argument::scalar, sizeof(cl_uint), 268bf215546Sopenharmony_ci dl.getTypeStoreSize(size_type), 269bf215546Sopenharmony_ci dl.getABITypeAlignment(size_type), 270bf215546Sopenharmony_ci binary::argument::zero_ext, 271bf215546Sopenharmony_ci binary::argument::grid_offset); 272bf215546Sopenharmony_ci 273bf215546Sopenharmony_ci return args; 274bf215546Sopenharmony_ci } 275bf215546Sopenharmony_ci 276bf215546Sopenharmony_ci binary::section 277bf215546Sopenharmony_ci make_text_section(const std::vector<char> &code) { 278bf215546Sopenharmony_ci const pipe_binary_program_header header { uint32_t(code.size()) }; 279bf215546Sopenharmony_ci binary::section text { 0, binary::section::text_executable, 280bf215546Sopenharmony_ci header.num_bytes, {} }; 281bf215546Sopenharmony_ci 282bf215546Sopenharmony_ci text.data.insert(text.data.end(), reinterpret_cast<const char *>(&header), 283bf215546Sopenharmony_ci reinterpret_cast<const char *>(&header) + sizeof(header)); 284bf215546Sopenharmony_ci text.data.insert(text.data.end(), code.begin(), code.end()); 285bf215546Sopenharmony_ci 286bf215546Sopenharmony_ci return text; 287bf215546Sopenharmony_ci } 288bf215546Sopenharmony_ci} 289bf215546Sopenharmony_ci 290bf215546Sopenharmony_cibinary 291bf215546Sopenharmony_ciclover::llvm::build_module_common(const Module &mod, 292bf215546Sopenharmony_ci const std::vector<char> &code, 293bf215546Sopenharmony_ci const std::map<std::string, 294bf215546Sopenharmony_ci unsigned> &offsets, 295bf215546Sopenharmony_ci const clang::CompilerInstance &c) { 296bf215546Sopenharmony_ci binary b; 297bf215546Sopenharmony_ci 298bf215546Sopenharmony_ci for (const auto &llvm_name : map(std::mem_fn(&Function::getName), 299bf215546Sopenharmony_ci get_kernels(mod))) { 300bf215546Sopenharmony_ci const ::std::string name(llvm_name); 301bf215546Sopenharmony_ci if (offsets.count(name)) 302bf215546Sopenharmony_ci b.syms.emplace_back(name, kernel_attributes(mod, name), 303bf215546Sopenharmony_ci get_reqd_work_group_size(mod, name), 304bf215546Sopenharmony_ci 0, offsets.at(name), 305bf215546Sopenharmony_ci make_kernel_args(mod, name, c)); 306bf215546Sopenharmony_ci } 307bf215546Sopenharmony_ci 308bf215546Sopenharmony_ci b.secs.push_back(make_text_section(code)); 309bf215546Sopenharmony_ci return b; 310bf215546Sopenharmony_ci} 311