1 // 2 // Copyright 2012-2016 Francisco Jerez 3 // Copyright 2012-2016 Advanced Micro Devices, Inc. 4 // Copyright 2015 Zoltan Gilian 5 // 6 // Permission is hereby granted, free of charge, to any person obtaining a 7 // copy of this software and associated documentation files (the "Software"), 8 // to deal in the Software without restriction, including without limitation 9 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 // and/or sell copies of the Software, and to permit persons to whom the 11 // Software is furnished to do so, subject to the following conditions: 12 // 13 // The above copyright notice and this permission notice shall be included in 14 // all copies or substantial portions of the Software. 15 // 16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 // OTHER DEALINGS IN THE SOFTWARE. 23 // 24 25 /// 26 /// \file 27 /// Codegen back-end-independent part of the construction of an executable 28 /// clover::module, including kernel argument metadata extraction and 29 /// formatting of the pre-generated binary code in a form that can be 30 /// understood by pipe drivers. 31 /// 32 33 #include "llvm/codegen.hpp" 34 #include "llvm/metadata.hpp" 35 36 #include "CL/cl.h" 37 38 #include "pipe/p_state.h" 39 #include "util/u_math.h" 40 41 #include <clang/Basic/TargetInfo.h> 42 43 using namespace clover; 44 using namespace clover::llvm; 45 46 using ::llvm::Module; 47 using ::llvm::Function; 48 using ::llvm::Type; 49 using ::llvm::isa; 50 using ::llvm::cast; 51 using ::llvm::dyn_cast; 52 53 namespace { 54 enum module::argument::type get_image_type(const std::string & type,const std::string & qual)55 get_image_type(const std::string &type, 56 const std::string &qual) { 57 if (type == "image2d_t" && qual == "read_only") 58 return module::argument::image2d_rd; 59 else if (type == "image2d_t" && qual == "write_only") 60 return module::argument::image2d_wr; 61 else if (type == "image3d_t" && qual == "read_only") 62 return module::argument::image3d_rd; 63 else if (type == "image3d_t" && qual == "write_only") 64 return module::argument::image3d_wr; 65 else 66 unreachable("Unknown image type"); 67 } 68 69 std::vector<module::argument> make_kernel_args(const Module & mod,const std::string & kernel_name,const clang::CompilerInstance & c)70 make_kernel_args(const Module &mod, const std::string &kernel_name, 71 const clang::CompilerInstance &c) { 72 std::vector<module::argument> args; 73 const Function &f = *mod.getFunction(kernel_name); 74 ::llvm::DataLayout dl(&mod); 75 const auto size_type = 76 dl.getSmallestLegalIntType(mod.getContext(), sizeof(cl_uint) * 8); 77 78 for (const auto &arg : f.args()) { 79 const auto arg_type = arg.getType(); 80 81 // OpenCL 1.2 specification, Ch. 6.1.5: "A built-in data 82 // type that is not a power of two bytes in size must be 83 // aligned to the next larger power of two. 84 // This rule applies to built-in types only, not structs or unions." 85 const unsigned arg_store_size = dl.getTypeStoreSize(arg_type); 86 const unsigned arg_api_size = dl.getTypeAllocSize(arg_type); 87 88 const auto target_type = !arg_type->isIntegerTy() ? arg_type : 89 dl.getSmallestLegalIntType(mod.getContext(), arg_store_size * 8); 90 const unsigned target_size = dl.getTypeStoreSize(target_type); 91 const unsigned target_align = dl.getABITypeAlignment(target_type); 92 93 const auto type_name = get_argument_metadata(f, arg, 94 "kernel_arg_type"); 95 96 if (type_name == "image2d_t" || type_name == "image3d_t") { 97 // Image. 98 const auto access_qual = get_argument_metadata( 99 f, arg, "kernel_arg_access_qual"); 100 args.emplace_back(get_image_type(type_name, access_qual), 101 arg_store_size, target_size, 102 target_align, module::argument::zero_ext); 103 104 } else if (type_name == "__llvm_image_size") { 105 // Image size implicit argument. 106 args.emplace_back(module::argument::scalar, sizeof(cl_uint), 107 dl.getTypeStoreSize(size_type), 108 dl.getABITypeAlignment(size_type), 109 module::argument::zero_ext, 110 module::argument::image_size); 111 112 } else if (type_name == "__llvm_image_format") { 113 // Image format implicit argument. 114 args.emplace_back(module::argument::scalar, sizeof(cl_uint), 115 dl.getTypeStoreSize(size_type), 116 dl.getABITypeAlignment(size_type), 117 module::argument::zero_ext, 118 module::argument::image_format); 119 120 } else { 121 // Other types. 122 const auto actual_type = 123 isa< ::llvm::PointerType>(arg_type) && arg.hasByValAttr() ? 124 cast< ::llvm::PointerType>(arg_type)->getElementType() : arg_type; 125 126 if (actual_type->isPointerTy()) { 127 const unsigned address_space = 128 cast< ::llvm::PointerType>(actual_type)->getAddressSpace(); 129 130 if (address_space == compat::target_address_space( 131 c.getTarget(), clang::LangAS::opencl_local)) { 132 args.emplace_back(module::argument::local, arg_api_size, 133 target_size, target_align, 134 module::argument::zero_ext); 135 } else { 136 // XXX: Correctly handle constant address space. There is no 137 // way for r600g to pass a handle for constant buffers back 138 // to clover like it can for global buffers, so 139 // creating constant arguments will break r600g. For now, 140 // continue treating constant buffers as global buffers 141 // until we can come up with a way to create handles for 142 // constant buffers. 143 args.emplace_back(module::argument::global, arg_api_size, 144 target_size, target_align, 145 module::argument::zero_ext); 146 } 147 148 } else { 149 const bool needs_sign_ext = f.getAttributes().hasAttribute( 150 arg.getArgNo() + 1, ::llvm::Attribute::SExt); 151 152 args.emplace_back(module::argument::scalar, arg_api_size, 153 target_size, target_align, 154 (needs_sign_ext ? module::argument::sign_ext : 155 module::argument::zero_ext)); 156 } 157 } 158 } 159 160 // Append implicit arguments. XXX - The types, ordering and 161 // vector size of the implicit arguments should depend on the 162 // target according to the selected calling convention. 163 args.emplace_back(module::argument::scalar, sizeof(cl_uint), 164 dl.getTypeStoreSize(size_type), 165 dl.getABITypeAlignment(size_type), 166 module::argument::zero_ext, 167 module::argument::grid_dimension); 168 169 args.emplace_back(module::argument::scalar, sizeof(cl_uint), 170 dl.getTypeStoreSize(size_type), 171 dl.getABITypeAlignment(size_type), 172 module::argument::zero_ext, 173 module::argument::grid_offset); 174 175 return args; 176 } 177 178 module::section make_text_section(const std::vector<char> & code)179 make_text_section(const std::vector<char> &code) { 180 const pipe_llvm_program_header header { uint32_t(code.size()) }; 181 module::section text { 0, module::section::text_executable, 182 header.num_bytes, {} }; 183 184 text.data.insert(text.data.end(), reinterpret_cast<const char *>(&header), 185 reinterpret_cast<const char *>(&header) + sizeof(header)); 186 text.data.insert(text.data.end(), code.begin(), code.end()); 187 188 return text; 189 } 190 } 191 192 module 193 clover::llvm::build_module_common(const Module &mod, 194 const std::vector<char> &code, 195 const std::map<std::string, 196 unsigned> &offsets, 197 const clang::CompilerInstance &c) { 198 module m; 199 200 for (const auto &name : map(std::mem_fn(&Function::getName), 201 get_kernels(mod))) { 202 if (offsets.count(name)) 203 m.syms.emplace_back(name, 0, offsets.at(name), 204 make_kernel_args(mod, name, c)); 205 } 206 207 m.secs.push_back(make_text_section(code)); 208 return m; 209 } 210