1bf215546Sopenharmony_ci// 2bf215546Sopenharmony_ci// Copyright 2012-2016 Francisco Jerez 3bf215546Sopenharmony_ci// Copyright 2012-2016 Advanced Micro Devices, Inc. 4bf215546Sopenharmony_ci// Copyright 2014-2016 Jan Vesely 5bf215546Sopenharmony_ci// Copyright 2014-2015 Serge Martin 6bf215546Sopenharmony_ci// Copyright 2015 Zoltan Gilian 7bf215546Sopenharmony_ci// 8bf215546Sopenharmony_ci// Permission is hereby granted, free of charge, to any person obtaining a 9bf215546Sopenharmony_ci// copy of this software and associated documentation files (the "Software"), 10bf215546Sopenharmony_ci// to deal in the Software without restriction, including without limitation 11bf215546Sopenharmony_ci// the rights to use, copy, modify, merge, publish, distribute, sublicense, 12bf215546Sopenharmony_ci// and/or sell copies of the Software, and to permit persons to whom the 13bf215546Sopenharmony_ci// Software is furnished to do so, subject to the following conditions: 14bf215546Sopenharmony_ci// 15bf215546Sopenharmony_ci// The above copyright notice and this permission notice shall be included in 16bf215546Sopenharmony_ci// all copies or substantial portions of the Software. 17bf215546Sopenharmony_ci// 18bf215546Sopenharmony_ci// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19bf215546Sopenharmony_ci// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20bf215546Sopenharmony_ci// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21bf215546Sopenharmony_ci// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 22bf215546Sopenharmony_ci// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 23bf215546Sopenharmony_ci// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24bf215546Sopenharmony_ci// OTHER DEALINGS IN THE SOFTWARE. 25bf215546Sopenharmony_ci 26bf215546Sopenharmony_ci#include <sstream> 27bf215546Sopenharmony_ci#include <mutex> 28bf215546Sopenharmony_ci 29bf215546Sopenharmony_ci#include <llvm/ADT/ArrayRef.h> 30bf215546Sopenharmony_ci#include <llvm/IR/DiagnosticPrinter.h> 31bf215546Sopenharmony_ci#include <llvm/IR/DiagnosticInfo.h> 32bf215546Sopenharmony_ci#include <llvm/IR/LLVMContext.h> 33bf215546Sopenharmony_ci#include <llvm/IR/Type.h> 34bf215546Sopenharmony_ci#include <llvm/Support/raw_ostream.h> 35bf215546Sopenharmony_ci#include <llvm/Bitcode/BitcodeWriter.h> 36bf215546Sopenharmony_ci#include <llvm/Bitcode/BitcodeReader.h> 37bf215546Sopenharmony_ci#include <llvm-c/Core.h> 38bf215546Sopenharmony_ci#include <llvm-c/Target.h> 39bf215546Sopenharmony_ci#include <LLVMSPIRVLib/LLVMSPIRVLib.h> 40bf215546Sopenharmony_ci 41bf215546Sopenharmony_ci#include <clang/CodeGen/CodeGenAction.h> 42bf215546Sopenharmony_ci#include <clang/Lex/PreprocessorOptions.h> 43bf215546Sopenharmony_ci#include <clang/Frontend/CompilerInstance.h> 44bf215546Sopenharmony_ci#include <clang/Frontend/TextDiagnosticBuffer.h> 45bf215546Sopenharmony_ci#include <clang/Frontend/TextDiagnosticPrinter.h> 46bf215546Sopenharmony_ci#include <clang/Basic/TargetInfo.h> 47bf215546Sopenharmony_ci 48bf215546Sopenharmony_ci#include <spirv-tools/libspirv.hpp> 49bf215546Sopenharmony_ci#include <spirv-tools/linker.hpp> 50bf215546Sopenharmony_ci#include <spirv-tools/optimizer.hpp> 51bf215546Sopenharmony_ci 52bf215546Sopenharmony_ci#include "util/macros.h" 53bf215546Sopenharmony_ci#include "glsl_types.h" 54bf215546Sopenharmony_ci 55bf215546Sopenharmony_ci#include "spirv.h" 56bf215546Sopenharmony_ci 57bf215546Sopenharmony_ci#ifdef USE_STATIC_OPENCL_C_H 58bf215546Sopenharmony_ci#if LLVM_VERSION_MAJOR < 15 59bf215546Sopenharmony_ci#include "opencl-c.h.h" 60bf215546Sopenharmony_ci#endif 61bf215546Sopenharmony_ci#include "opencl-c-base.h.h" 62bf215546Sopenharmony_ci#endif 63bf215546Sopenharmony_ci 64bf215546Sopenharmony_ci#include "clc_helpers.h" 65bf215546Sopenharmony_ci 66bf215546Sopenharmony_ci/* Use the highest version of SPIRV supported by SPIRV-Tools. */ 67bf215546Sopenharmony_ciconstexpr spv_target_env spirv_target = SPV_ENV_UNIVERSAL_1_5; 68bf215546Sopenharmony_ci 69bf215546Sopenharmony_ciconstexpr SPIRV::VersionNumber invalid_spirv_trans_version = static_cast<SPIRV::VersionNumber>(0); 70bf215546Sopenharmony_ci 71bf215546Sopenharmony_ciusing ::llvm::Function; 72bf215546Sopenharmony_ciusing ::llvm::LLVMContext; 73bf215546Sopenharmony_ciusing ::llvm::Module; 74bf215546Sopenharmony_ciusing ::llvm::raw_string_ostream; 75bf215546Sopenharmony_ci 76bf215546Sopenharmony_cistatic void 77bf215546Sopenharmony_cillvm_log_handler(const ::llvm::DiagnosticInfo &di, void *data) { 78bf215546Sopenharmony_ci const clc_logger *logger = static_cast<clc_logger *>(data); 79bf215546Sopenharmony_ci 80bf215546Sopenharmony_ci std::string log; 81bf215546Sopenharmony_ci raw_string_ostream os { log }; 82bf215546Sopenharmony_ci ::llvm::DiagnosticPrinterRawOStream printer { os }; 83bf215546Sopenharmony_ci di.print(printer); 84bf215546Sopenharmony_ci 85bf215546Sopenharmony_ci clc_error(logger, "%s", log.c_str()); 86bf215546Sopenharmony_ci} 87bf215546Sopenharmony_ci 88bf215546Sopenharmony_ciclass SPIRVKernelArg { 89bf215546Sopenharmony_cipublic: 90bf215546Sopenharmony_ci SPIRVKernelArg(uint32_t id, uint32_t typeId) : id(id), typeId(typeId), 91bf215546Sopenharmony_ci addrQualifier(CLC_KERNEL_ARG_ADDRESS_PRIVATE), 92bf215546Sopenharmony_ci accessQualifier(0), 93bf215546Sopenharmony_ci typeQualifier(0) { } 94bf215546Sopenharmony_ci ~SPIRVKernelArg() { } 95bf215546Sopenharmony_ci 96bf215546Sopenharmony_ci uint32_t id; 97bf215546Sopenharmony_ci uint32_t typeId; 98bf215546Sopenharmony_ci std::string name; 99bf215546Sopenharmony_ci std::string typeName; 100bf215546Sopenharmony_ci enum clc_kernel_arg_address_qualifier addrQualifier; 101bf215546Sopenharmony_ci unsigned accessQualifier; 102bf215546Sopenharmony_ci unsigned typeQualifier; 103bf215546Sopenharmony_ci}; 104bf215546Sopenharmony_ci 105bf215546Sopenharmony_ciclass SPIRVKernelInfo { 106bf215546Sopenharmony_cipublic: 107bf215546Sopenharmony_ci SPIRVKernelInfo(uint32_t fid, const char *nm) 108bf215546Sopenharmony_ci : funcId(fid), name(nm), vecHint(0), localSize(), localSizeHint() { } 109bf215546Sopenharmony_ci ~SPIRVKernelInfo() { } 110bf215546Sopenharmony_ci 111bf215546Sopenharmony_ci uint32_t funcId; 112bf215546Sopenharmony_ci std::string name; 113bf215546Sopenharmony_ci std::vector<SPIRVKernelArg> args; 114bf215546Sopenharmony_ci unsigned vecHint; 115bf215546Sopenharmony_ci unsigned localSize[3]; 116bf215546Sopenharmony_ci unsigned localSizeHint[3]; 117bf215546Sopenharmony_ci}; 118bf215546Sopenharmony_ci 119bf215546Sopenharmony_ciclass SPIRVKernelParser { 120bf215546Sopenharmony_cipublic: 121bf215546Sopenharmony_ci SPIRVKernelParser() : curKernel(NULL) 122bf215546Sopenharmony_ci { 123bf215546Sopenharmony_ci ctx = spvContextCreate(spirv_target); 124bf215546Sopenharmony_ci } 125bf215546Sopenharmony_ci 126bf215546Sopenharmony_ci ~SPIRVKernelParser() 127bf215546Sopenharmony_ci { 128bf215546Sopenharmony_ci spvContextDestroy(ctx); 129bf215546Sopenharmony_ci } 130bf215546Sopenharmony_ci 131bf215546Sopenharmony_ci void parseEntryPoint(const spv_parsed_instruction_t *ins) 132bf215546Sopenharmony_ci { 133bf215546Sopenharmony_ci assert(ins->num_operands >= 3); 134bf215546Sopenharmony_ci 135bf215546Sopenharmony_ci const spv_parsed_operand_t *op = &ins->operands[1]; 136bf215546Sopenharmony_ci 137bf215546Sopenharmony_ci assert(op->type == SPV_OPERAND_TYPE_ID); 138bf215546Sopenharmony_ci 139bf215546Sopenharmony_ci uint32_t funcId = ins->words[op->offset]; 140bf215546Sopenharmony_ci 141bf215546Sopenharmony_ci for (auto &iter : kernels) { 142bf215546Sopenharmony_ci if (funcId == iter.funcId) 143bf215546Sopenharmony_ci return; 144bf215546Sopenharmony_ci } 145bf215546Sopenharmony_ci 146bf215546Sopenharmony_ci op = &ins->operands[2]; 147bf215546Sopenharmony_ci assert(op->type == SPV_OPERAND_TYPE_LITERAL_STRING); 148bf215546Sopenharmony_ci const char *name = reinterpret_cast<const char *>(ins->words + op->offset); 149bf215546Sopenharmony_ci 150bf215546Sopenharmony_ci kernels.push_back(SPIRVKernelInfo(funcId, name)); 151bf215546Sopenharmony_ci } 152bf215546Sopenharmony_ci 153bf215546Sopenharmony_ci void parseFunction(const spv_parsed_instruction_t *ins) 154bf215546Sopenharmony_ci { 155bf215546Sopenharmony_ci assert(ins->num_operands == 4); 156bf215546Sopenharmony_ci 157bf215546Sopenharmony_ci const spv_parsed_operand_t *op = &ins->operands[1]; 158bf215546Sopenharmony_ci 159bf215546Sopenharmony_ci assert(op->type == SPV_OPERAND_TYPE_RESULT_ID); 160bf215546Sopenharmony_ci 161bf215546Sopenharmony_ci uint32_t funcId = ins->words[op->offset]; 162bf215546Sopenharmony_ci 163bf215546Sopenharmony_ci for (auto &kernel : kernels) { 164bf215546Sopenharmony_ci if (funcId == kernel.funcId && !kernel.args.size()) { 165bf215546Sopenharmony_ci curKernel = &kernel; 166bf215546Sopenharmony_ci return; 167bf215546Sopenharmony_ci } 168bf215546Sopenharmony_ci } 169bf215546Sopenharmony_ci } 170bf215546Sopenharmony_ci 171bf215546Sopenharmony_ci void parseFunctionParam(const spv_parsed_instruction_t *ins) 172bf215546Sopenharmony_ci { 173bf215546Sopenharmony_ci const spv_parsed_operand_t *op; 174bf215546Sopenharmony_ci uint32_t id, typeId; 175bf215546Sopenharmony_ci 176bf215546Sopenharmony_ci if (!curKernel) 177bf215546Sopenharmony_ci return; 178bf215546Sopenharmony_ci 179bf215546Sopenharmony_ci assert(ins->num_operands == 2); 180bf215546Sopenharmony_ci op = &ins->operands[0]; 181bf215546Sopenharmony_ci assert(op->type == SPV_OPERAND_TYPE_TYPE_ID); 182bf215546Sopenharmony_ci typeId = ins->words[op->offset]; 183bf215546Sopenharmony_ci op = &ins->operands[1]; 184bf215546Sopenharmony_ci assert(op->type == SPV_OPERAND_TYPE_RESULT_ID); 185bf215546Sopenharmony_ci id = ins->words[op->offset]; 186bf215546Sopenharmony_ci curKernel->args.push_back(SPIRVKernelArg(id, typeId)); 187bf215546Sopenharmony_ci } 188bf215546Sopenharmony_ci 189bf215546Sopenharmony_ci void parseName(const spv_parsed_instruction_t *ins) 190bf215546Sopenharmony_ci { 191bf215546Sopenharmony_ci const spv_parsed_operand_t *op; 192bf215546Sopenharmony_ci const char *name; 193bf215546Sopenharmony_ci uint32_t id; 194bf215546Sopenharmony_ci 195bf215546Sopenharmony_ci assert(ins->num_operands == 2); 196bf215546Sopenharmony_ci 197bf215546Sopenharmony_ci op = &ins->operands[0]; 198bf215546Sopenharmony_ci assert(op->type == SPV_OPERAND_TYPE_ID); 199bf215546Sopenharmony_ci id = ins->words[op->offset]; 200bf215546Sopenharmony_ci op = &ins->operands[1]; 201bf215546Sopenharmony_ci assert(op->type == SPV_OPERAND_TYPE_LITERAL_STRING); 202bf215546Sopenharmony_ci name = reinterpret_cast<const char *>(ins->words + op->offset); 203bf215546Sopenharmony_ci 204bf215546Sopenharmony_ci for (auto &kernel : kernels) { 205bf215546Sopenharmony_ci for (auto &arg : kernel.args) { 206bf215546Sopenharmony_ci if (arg.id == id && arg.name.empty()) { 207bf215546Sopenharmony_ci arg.name = name; 208bf215546Sopenharmony_ci break; 209bf215546Sopenharmony_ci } 210bf215546Sopenharmony_ci } 211bf215546Sopenharmony_ci } 212bf215546Sopenharmony_ci } 213bf215546Sopenharmony_ci 214bf215546Sopenharmony_ci void parseTypePointer(const spv_parsed_instruction_t *ins) 215bf215546Sopenharmony_ci { 216bf215546Sopenharmony_ci enum clc_kernel_arg_address_qualifier addrQualifier; 217bf215546Sopenharmony_ci uint32_t typeId, storageClass; 218bf215546Sopenharmony_ci const spv_parsed_operand_t *op; 219bf215546Sopenharmony_ci 220bf215546Sopenharmony_ci assert(ins->num_operands == 3); 221bf215546Sopenharmony_ci 222bf215546Sopenharmony_ci op = &ins->operands[0]; 223bf215546Sopenharmony_ci assert(op->type == SPV_OPERAND_TYPE_RESULT_ID); 224bf215546Sopenharmony_ci typeId = ins->words[op->offset]; 225bf215546Sopenharmony_ci 226bf215546Sopenharmony_ci op = &ins->operands[1]; 227bf215546Sopenharmony_ci assert(op->type == SPV_OPERAND_TYPE_STORAGE_CLASS); 228bf215546Sopenharmony_ci storageClass = ins->words[op->offset]; 229bf215546Sopenharmony_ci switch (storageClass) { 230bf215546Sopenharmony_ci case SpvStorageClassCrossWorkgroup: 231bf215546Sopenharmony_ci addrQualifier = CLC_KERNEL_ARG_ADDRESS_GLOBAL; 232bf215546Sopenharmony_ci break; 233bf215546Sopenharmony_ci case SpvStorageClassWorkgroup: 234bf215546Sopenharmony_ci addrQualifier = CLC_KERNEL_ARG_ADDRESS_LOCAL; 235bf215546Sopenharmony_ci break; 236bf215546Sopenharmony_ci case SpvStorageClassUniformConstant: 237bf215546Sopenharmony_ci addrQualifier = CLC_KERNEL_ARG_ADDRESS_CONSTANT; 238bf215546Sopenharmony_ci break; 239bf215546Sopenharmony_ci default: 240bf215546Sopenharmony_ci addrQualifier = CLC_KERNEL_ARG_ADDRESS_PRIVATE; 241bf215546Sopenharmony_ci break; 242bf215546Sopenharmony_ci } 243bf215546Sopenharmony_ci 244bf215546Sopenharmony_ci for (auto &kernel : kernels) { 245bf215546Sopenharmony_ci for (auto &arg : kernel.args) { 246bf215546Sopenharmony_ci if (arg.typeId == typeId) { 247bf215546Sopenharmony_ci arg.addrQualifier = addrQualifier; 248bf215546Sopenharmony_ci if (addrQualifier == CLC_KERNEL_ARG_ADDRESS_CONSTANT) 249bf215546Sopenharmony_ci arg.typeQualifier |= CLC_KERNEL_ARG_TYPE_CONST; 250bf215546Sopenharmony_ci } 251bf215546Sopenharmony_ci } 252bf215546Sopenharmony_ci } 253bf215546Sopenharmony_ci } 254bf215546Sopenharmony_ci 255bf215546Sopenharmony_ci void parseOpString(const spv_parsed_instruction_t *ins) 256bf215546Sopenharmony_ci { 257bf215546Sopenharmony_ci const spv_parsed_operand_t *op; 258bf215546Sopenharmony_ci std::string str; 259bf215546Sopenharmony_ci 260bf215546Sopenharmony_ci assert(ins->num_operands == 2); 261bf215546Sopenharmony_ci 262bf215546Sopenharmony_ci op = &ins->operands[1]; 263bf215546Sopenharmony_ci assert(op->type == SPV_OPERAND_TYPE_LITERAL_STRING); 264bf215546Sopenharmony_ci str = reinterpret_cast<const char *>(ins->words + op->offset); 265bf215546Sopenharmony_ci 266bf215546Sopenharmony_ci size_t start = 0; 267bf215546Sopenharmony_ci enum class string_type { 268bf215546Sopenharmony_ci arg_type, 269bf215546Sopenharmony_ci arg_type_qual, 270bf215546Sopenharmony_ci } str_type; 271bf215546Sopenharmony_ci 272bf215546Sopenharmony_ci if (str.find("kernel_arg_type.") == 0) { 273bf215546Sopenharmony_ci start = sizeof("kernel_arg_type.") - 1; 274bf215546Sopenharmony_ci str_type = string_type::arg_type; 275bf215546Sopenharmony_ci } else if (str.find("kernel_arg_type_qual.") == 0) { 276bf215546Sopenharmony_ci start = sizeof("kernel_arg_type_qual.") - 1; 277bf215546Sopenharmony_ci str_type = string_type::arg_type_qual; 278bf215546Sopenharmony_ci } else { 279bf215546Sopenharmony_ci return; 280bf215546Sopenharmony_ci } 281bf215546Sopenharmony_ci 282bf215546Sopenharmony_ci for (auto &kernel : kernels) { 283bf215546Sopenharmony_ci size_t pos; 284bf215546Sopenharmony_ci 285bf215546Sopenharmony_ci pos = str.find(kernel.name, start); 286bf215546Sopenharmony_ci if (pos == std::string::npos || 287bf215546Sopenharmony_ci pos != start || str[start + kernel.name.size()] != '.') 288bf215546Sopenharmony_ci continue; 289bf215546Sopenharmony_ci 290bf215546Sopenharmony_ci pos = start + kernel.name.size(); 291bf215546Sopenharmony_ci if (str[pos++] != '.') 292bf215546Sopenharmony_ci continue; 293bf215546Sopenharmony_ci 294bf215546Sopenharmony_ci for (auto &arg : kernel.args) { 295bf215546Sopenharmony_ci if (arg.name.empty()) 296bf215546Sopenharmony_ci break; 297bf215546Sopenharmony_ci 298bf215546Sopenharmony_ci size_t entryEnd = str.find(',', pos); 299bf215546Sopenharmony_ci if (entryEnd == std::string::npos) 300bf215546Sopenharmony_ci break; 301bf215546Sopenharmony_ci 302bf215546Sopenharmony_ci std::string entryVal = str.substr(pos, entryEnd - pos); 303bf215546Sopenharmony_ci pos = entryEnd + 1; 304bf215546Sopenharmony_ci 305bf215546Sopenharmony_ci if (str_type == string_type::arg_type) { 306bf215546Sopenharmony_ci arg.typeName = std::move(entryVal); 307bf215546Sopenharmony_ci } else if (str_type == string_type::arg_type_qual) { 308bf215546Sopenharmony_ci if (entryVal.find("const") != std::string::npos) 309bf215546Sopenharmony_ci arg.typeQualifier |= CLC_KERNEL_ARG_TYPE_CONST; 310bf215546Sopenharmony_ci } 311bf215546Sopenharmony_ci } 312bf215546Sopenharmony_ci } 313bf215546Sopenharmony_ci } 314bf215546Sopenharmony_ci 315bf215546Sopenharmony_ci void applyDecoration(uint32_t id, const spv_parsed_instruction_t *ins) 316bf215546Sopenharmony_ci { 317bf215546Sopenharmony_ci auto iter = decorationGroups.find(id); 318bf215546Sopenharmony_ci if (iter != decorationGroups.end()) { 319bf215546Sopenharmony_ci for (uint32_t entry : iter->second) 320bf215546Sopenharmony_ci applyDecoration(entry, ins); 321bf215546Sopenharmony_ci return; 322bf215546Sopenharmony_ci } 323bf215546Sopenharmony_ci 324bf215546Sopenharmony_ci const spv_parsed_operand_t *op; 325bf215546Sopenharmony_ci uint32_t decoration; 326bf215546Sopenharmony_ci 327bf215546Sopenharmony_ci assert(ins->num_operands >= 2); 328bf215546Sopenharmony_ci 329bf215546Sopenharmony_ci op = &ins->operands[1]; 330bf215546Sopenharmony_ci assert(op->type == SPV_OPERAND_TYPE_DECORATION); 331bf215546Sopenharmony_ci decoration = ins->words[op->offset]; 332bf215546Sopenharmony_ci 333bf215546Sopenharmony_ci if (decoration == SpvDecorationSpecId) { 334bf215546Sopenharmony_ci uint32_t spec_id = ins->words[ins->operands[2].offset]; 335bf215546Sopenharmony_ci for (auto &c : specConstants) { 336bf215546Sopenharmony_ci if (c.second.id == spec_id) { 337bf215546Sopenharmony_ci assert(c.first == id); 338bf215546Sopenharmony_ci return; 339bf215546Sopenharmony_ci } 340bf215546Sopenharmony_ci } 341bf215546Sopenharmony_ci specConstants.emplace_back(id, clc_parsed_spec_constant{ spec_id }); 342bf215546Sopenharmony_ci return; 343bf215546Sopenharmony_ci } 344bf215546Sopenharmony_ci 345bf215546Sopenharmony_ci for (auto &kernel : kernels) { 346bf215546Sopenharmony_ci for (auto &arg : kernel.args) { 347bf215546Sopenharmony_ci if (arg.id == id) { 348bf215546Sopenharmony_ci switch (decoration) { 349bf215546Sopenharmony_ci case SpvDecorationVolatile: 350bf215546Sopenharmony_ci arg.typeQualifier |= CLC_KERNEL_ARG_TYPE_VOLATILE; 351bf215546Sopenharmony_ci break; 352bf215546Sopenharmony_ci case SpvDecorationConstant: 353bf215546Sopenharmony_ci arg.typeQualifier |= CLC_KERNEL_ARG_TYPE_CONST; 354bf215546Sopenharmony_ci break; 355bf215546Sopenharmony_ci case SpvDecorationRestrict: 356bf215546Sopenharmony_ci arg.typeQualifier |= CLC_KERNEL_ARG_TYPE_RESTRICT; 357bf215546Sopenharmony_ci break; 358bf215546Sopenharmony_ci case SpvDecorationFuncParamAttr: 359bf215546Sopenharmony_ci op = &ins->operands[2]; 360bf215546Sopenharmony_ci assert(op->type == SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE); 361bf215546Sopenharmony_ci switch (ins->words[op->offset]) { 362bf215546Sopenharmony_ci case SpvFunctionParameterAttributeNoAlias: 363bf215546Sopenharmony_ci arg.typeQualifier |= CLC_KERNEL_ARG_TYPE_RESTRICT; 364bf215546Sopenharmony_ci break; 365bf215546Sopenharmony_ci case SpvFunctionParameterAttributeNoWrite: 366bf215546Sopenharmony_ci arg.typeQualifier |= CLC_KERNEL_ARG_TYPE_CONST; 367bf215546Sopenharmony_ci break; 368bf215546Sopenharmony_ci } 369bf215546Sopenharmony_ci break; 370bf215546Sopenharmony_ci } 371bf215546Sopenharmony_ci } 372bf215546Sopenharmony_ci 373bf215546Sopenharmony_ci } 374bf215546Sopenharmony_ci } 375bf215546Sopenharmony_ci } 376bf215546Sopenharmony_ci 377bf215546Sopenharmony_ci void parseOpDecorate(const spv_parsed_instruction_t *ins) 378bf215546Sopenharmony_ci { 379bf215546Sopenharmony_ci const spv_parsed_operand_t *op; 380bf215546Sopenharmony_ci uint32_t id; 381bf215546Sopenharmony_ci 382bf215546Sopenharmony_ci assert(ins->num_operands >= 2); 383bf215546Sopenharmony_ci 384bf215546Sopenharmony_ci op = &ins->operands[0]; 385bf215546Sopenharmony_ci assert(op->type == SPV_OPERAND_TYPE_ID); 386bf215546Sopenharmony_ci id = ins->words[op->offset]; 387bf215546Sopenharmony_ci 388bf215546Sopenharmony_ci applyDecoration(id, ins); 389bf215546Sopenharmony_ci } 390bf215546Sopenharmony_ci 391bf215546Sopenharmony_ci void parseOpGroupDecorate(const spv_parsed_instruction_t *ins) 392bf215546Sopenharmony_ci { 393bf215546Sopenharmony_ci assert(ins->num_operands >= 2); 394bf215546Sopenharmony_ci 395bf215546Sopenharmony_ci const spv_parsed_operand_t *op = &ins->operands[0]; 396bf215546Sopenharmony_ci assert(op->type == SPV_OPERAND_TYPE_ID); 397bf215546Sopenharmony_ci uint32_t groupId = ins->words[op->offset]; 398bf215546Sopenharmony_ci 399bf215546Sopenharmony_ci auto lowerBound = decorationGroups.lower_bound(groupId); 400bf215546Sopenharmony_ci if (lowerBound != decorationGroups.end() && 401bf215546Sopenharmony_ci lowerBound->first == groupId) 402bf215546Sopenharmony_ci // Group already filled out 403bf215546Sopenharmony_ci return; 404bf215546Sopenharmony_ci 405bf215546Sopenharmony_ci auto iter = decorationGroups.emplace_hint(lowerBound, groupId, std::vector<uint32_t>{}); 406bf215546Sopenharmony_ci auto& vec = iter->second; 407bf215546Sopenharmony_ci vec.reserve(ins->num_operands - 1); 408bf215546Sopenharmony_ci for (uint32_t i = 1; i < ins->num_operands; ++i) { 409bf215546Sopenharmony_ci op = &ins->operands[i]; 410bf215546Sopenharmony_ci assert(op->type == SPV_OPERAND_TYPE_ID); 411bf215546Sopenharmony_ci vec.push_back(ins->words[op->offset]); 412bf215546Sopenharmony_ci } 413bf215546Sopenharmony_ci } 414bf215546Sopenharmony_ci 415bf215546Sopenharmony_ci void parseOpTypeImage(const spv_parsed_instruction_t *ins) 416bf215546Sopenharmony_ci { 417bf215546Sopenharmony_ci const spv_parsed_operand_t *op; 418bf215546Sopenharmony_ci uint32_t typeId; 419bf215546Sopenharmony_ci unsigned accessQualifier = CLC_KERNEL_ARG_ACCESS_READ; 420bf215546Sopenharmony_ci 421bf215546Sopenharmony_ci op = &ins->operands[0]; 422bf215546Sopenharmony_ci assert(op->type == SPV_OPERAND_TYPE_RESULT_ID); 423bf215546Sopenharmony_ci typeId = ins->words[op->offset]; 424bf215546Sopenharmony_ci 425bf215546Sopenharmony_ci if (ins->num_operands >= 9) { 426bf215546Sopenharmony_ci op = &ins->operands[8]; 427bf215546Sopenharmony_ci assert(op->type == SPV_OPERAND_TYPE_ACCESS_QUALIFIER); 428bf215546Sopenharmony_ci switch (ins->words[op->offset]) { 429bf215546Sopenharmony_ci case SpvAccessQualifierReadOnly: 430bf215546Sopenharmony_ci accessQualifier = CLC_KERNEL_ARG_ACCESS_READ; 431bf215546Sopenharmony_ci break; 432bf215546Sopenharmony_ci case SpvAccessQualifierWriteOnly: 433bf215546Sopenharmony_ci accessQualifier = CLC_KERNEL_ARG_ACCESS_WRITE; 434bf215546Sopenharmony_ci break; 435bf215546Sopenharmony_ci case SpvAccessQualifierReadWrite: 436bf215546Sopenharmony_ci accessQualifier = CLC_KERNEL_ARG_ACCESS_WRITE | 437bf215546Sopenharmony_ci CLC_KERNEL_ARG_ACCESS_READ; 438bf215546Sopenharmony_ci break; 439bf215546Sopenharmony_ci } 440bf215546Sopenharmony_ci } 441bf215546Sopenharmony_ci 442bf215546Sopenharmony_ci for (auto &kernel : kernels) { 443bf215546Sopenharmony_ci for (auto &arg : kernel.args) { 444bf215546Sopenharmony_ci if (arg.typeId == typeId) { 445bf215546Sopenharmony_ci arg.accessQualifier = accessQualifier; 446bf215546Sopenharmony_ci arg.addrQualifier = CLC_KERNEL_ARG_ADDRESS_GLOBAL; 447bf215546Sopenharmony_ci } 448bf215546Sopenharmony_ci } 449bf215546Sopenharmony_ci } 450bf215546Sopenharmony_ci } 451bf215546Sopenharmony_ci 452bf215546Sopenharmony_ci void parseExecutionMode(const spv_parsed_instruction_t *ins) 453bf215546Sopenharmony_ci { 454bf215546Sopenharmony_ci uint32_t executionMode = ins->words[ins->operands[1].offset]; 455bf215546Sopenharmony_ci uint32_t funcId = ins->words[ins->operands[0].offset]; 456bf215546Sopenharmony_ci 457bf215546Sopenharmony_ci for (auto& kernel : kernels) { 458bf215546Sopenharmony_ci if (kernel.funcId == funcId) { 459bf215546Sopenharmony_ci switch (executionMode) { 460bf215546Sopenharmony_ci case SpvExecutionModeVecTypeHint: 461bf215546Sopenharmony_ci kernel.vecHint = ins->words[ins->operands[2].offset]; 462bf215546Sopenharmony_ci break; 463bf215546Sopenharmony_ci case SpvExecutionModeLocalSize: 464bf215546Sopenharmony_ci kernel.localSize[0] = ins->words[ins->operands[2].offset]; 465bf215546Sopenharmony_ci kernel.localSize[1] = ins->words[ins->operands[3].offset]; 466bf215546Sopenharmony_ci kernel.localSize[2] = ins->words[ins->operands[4].offset]; 467bf215546Sopenharmony_ci case SpvExecutionModeLocalSizeHint: 468bf215546Sopenharmony_ci kernel.localSizeHint[0] = ins->words[ins->operands[2].offset]; 469bf215546Sopenharmony_ci kernel.localSizeHint[1] = ins->words[ins->operands[3].offset]; 470bf215546Sopenharmony_ci kernel.localSizeHint[2] = ins->words[ins->operands[4].offset]; 471bf215546Sopenharmony_ci default: 472bf215546Sopenharmony_ci return; 473bf215546Sopenharmony_ci } 474bf215546Sopenharmony_ci } 475bf215546Sopenharmony_ci } 476bf215546Sopenharmony_ci } 477bf215546Sopenharmony_ci 478bf215546Sopenharmony_ci void parseLiteralType(const spv_parsed_instruction_t *ins) 479bf215546Sopenharmony_ci { 480bf215546Sopenharmony_ci uint32_t typeId = ins->words[ins->operands[0].offset]; 481bf215546Sopenharmony_ci auto& literalType = literalTypes[typeId]; 482bf215546Sopenharmony_ci switch (ins->opcode) { 483bf215546Sopenharmony_ci case SpvOpTypeBool: 484bf215546Sopenharmony_ci literalType = CLC_SPEC_CONSTANT_BOOL; 485bf215546Sopenharmony_ci break; 486bf215546Sopenharmony_ci case SpvOpTypeFloat: { 487bf215546Sopenharmony_ci uint32_t sizeInBits = ins->words[ins->operands[1].offset]; 488bf215546Sopenharmony_ci switch (sizeInBits) { 489bf215546Sopenharmony_ci case 32: 490bf215546Sopenharmony_ci literalType = CLC_SPEC_CONSTANT_FLOAT; 491bf215546Sopenharmony_ci break; 492bf215546Sopenharmony_ci case 64: 493bf215546Sopenharmony_ci literalType = CLC_SPEC_CONSTANT_DOUBLE; 494bf215546Sopenharmony_ci break; 495bf215546Sopenharmony_ci case 16: 496bf215546Sopenharmony_ci /* Can't be used for a spec constant */ 497bf215546Sopenharmony_ci break; 498bf215546Sopenharmony_ci default: 499bf215546Sopenharmony_ci unreachable("Unexpected float bit size"); 500bf215546Sopenharmony_ci } 501bf215546Sopenharmony_ci break; 502bf215546Sopenharmony_ci } 503bf215546Sopenharmony_ci case SpvOpTypeInt: { 504bf215546Sopenharmony_ci uint32_t sizeInBits = ins->words[ins->operands[1].offset]; 505bf215546Sopenharmony_ci bool isSigned = ins->words[ins->operands[2].offset]; 506bf215546Sopenharmony_ci if (isSigned) { 507bf215546Sopenharmony_ci switch (sizeInBits) { 508bf215546Sopenharmony_ci case 8: 509bf215546Sopenharmony_ci literalType = CLC_SPEC_CONSTANT_INT8; 510bf215546Sopenharmony_ci break; 511bf215546Sopenharmony_ci case 16: 512bf215546Sopenharmony_ci literalType = CLC_SPEC_CONSTANT_INT16; 513bf215546Sopenharmony_ci break; 514bf215546Sopenharmony_ci case 32: 515bf215546Sopenharmony_ci literalType = CLC_SPEC_CONSTANT_INT32; 516bf215546Sopenharmony_ci break; 517bf215546Sopenharmony_ci case 64: 518bf215546Sopenharmony_ci literalType = CLC_SPEC_CONSTANT_INT64; 519bf215546Sopenharmony_ci break; 520bf215546Sopenharmony_ci default: 521bf215546Sopenharmony_ci unreachable("Unexpected int bit size"); 522bf215546Sopenharmony_ci } 523bf215546Sopenharmony_ci } else { 524bf215546Sopenharmony_ci switch (sizeInBits) { 525bf215546Sopenharmony_ci case 8: 526bf215546Sopenharmony_ci literalType = CLC_SPEC_CONSTANT_UINT8; 527bf215546Sopenharmony_ci break; 528bf215546Sopenharmony_ci case 16: 529bf215546Sopenharmony_ci literalType = CLC_SPEC_CONSTANT_UINT16; 530bf215546Sopenharmony_ci break; 531bf215546Sopenharmony_ci case 32: 532bf215546Sopenharmony_ci literalType = CLC_SPEC_CONSTANT_UINT32; 533bf215546Sopenharmony_ci break; 534bf215546Sopenharmony_ci case 64: 535bf215546Sopenharmony_ci literalType = CLC_SPEC_CONSTANT_UINT64; 536bf215546Sopenharmony_ci break; 537bf215546Sopenharmony_ci default: 538bf215546Sopenharmony_ci unreachable("Unexpected uint bit size"); 539bf215546Sopenharmony_ci } 540bf215546Sopenharmony_ci } 541bf215546Sopenharmony_ci break; 542bf215546Sopenharmony_ci } 543bf215546Sopenharmony_ci default: 544bf215546Sopenharmony_ci unreachable("Unexpected type opcode"); 545bf215546Sopenharmony_ci } 546bf215546Sopenharmony_ci } 547bf215546Sopenharmony_ci 548bf215546Sopenharmony_ci void parseSpecConstant(const spv_parsed_instruction_t *ins) 549bf215546Sopenharmony_ci { 550bf215546Sopenharmony_ci uint32_t id = ins->result_id; 551bf215546Sopenharmony_ci for (auto& c : specConstants) { 552bf215546Sopenharmony_ci if (c.first == id) { 553bf215546Sopenharmony_ci auto& data = c.second; 554bf215546Sopenharmony_ci switch (ins->opcode) { 555bf215546Sopenharmony_ci case SpvOpSpecConstant: { 556bf215546Sopenharmony_ci uint32_t typeId = ins->words[ins->operands[0].offset]; 557bf215546Sopenharmony_ci 558bf215546Sopenharmony_ci // This better be an integer or float type 559bf215546Sopenharmony_ci auto typeIter = literalTypes.find(typeId); 560bf215546Sopenharmony_ci assert(typeIter != literalTypes.end()); 561bf215546Sopenharmony_ci 562bf215546Sopenharmony_ci data.type = typeIter->second; 563bf215546Sopenharmony_ci break; 564bf215546Sopenharmony_ci } 565bf215546Sopenharmony_ci case SpvOpSpecConstantFalse: 566bf215546Sopenharmony_ci case SpvOpSpecConstantTrue: 567bf215546Sopenharmony_ci data.type = CLC_SPEC_CONSTANT_BOOL; 568bf215546Sopenharmony_ci break; 569bf215546Sopenharmony_ci default: 570bf215546Sopenharmony_ci unreachable("Composites and Ops are not directly specializable."); 571bf215546Sopenharmony_ci } 572bf215546Sopenharmony_ci } 573bf215546Sopenharmony_ci } 574bf215546Sopenharmony_ci } 575bf215546Sopenharmony_ci 576bf215546Sopenharmony_ci static spv_result_t 577bf215546Sopenharmony_ci parseInstruction(void *data, const spv_parsed_instruction_t *ins) 578bf215546Sopenharmony_ci { 579bf215546Sopenharmony_ci SPIRVKernelParser *parser = reinterpret_cast<SPIRVKernelParser *>(data); 580bf215546Sopenharmony_ci 581bf215546Sopenharmony_ci switch (ins->opcode) { 582bf215546Sopenharmony_ci case SpvOpName: 583bf215546Sopenharmony_ci parser->parseName(ins); 584bf215546Sopenharmony_ci break; 585bf215546Sopenharmony_ci case SpvOpEntryPoint: 586bf215546Sopenharmony_ci parser->parseEntryPoint(ins); 587bf215546Sopenharmony_ci break; 588bf215546Sopenharmony_ci case SpvOpFunction: 589bf215546Sopenharmony_ci parser->parseFunction(ins); 590bf215546Sopenharmony_ci break; 591bf215546Sopenharmony_ci case SpvOpFunctionParameter: 592bf215546Sopenharmony_ci parser->parseFunctionParam(ins); 593bf215546Sopenharmony_ci break; 594bf215546Sopenharmony_ci case SpvOpFunctionEnd: 595bf215546Sopenharmony_ci case SpvOpLabel: 596bf215546Sopenharmony_ci parser->curKernel = NULL; 597bf215546Sopenharmony_ci break; 598bf215546Sopenharmony_ci case SpvOpTypePointer: 599bf215546Sopenharmony_ci parser->parseTypePointer(ins); 600bf215546Sopenharmony_ci break; 601bf215546Sopenharmony_ci case SpvOpTypeImage: 602bf215546Sopenharmony_ci parser->parseOpTypeImage(ins); 603bf215546Sopenharmony_ci break; 604bf215546Sopenharmony_ci case SpvOpString: 605bf215546Sopenharmony_ci parser->parseOpString(ins); 606bf215546Sopenharmony_ci break; 607bf215546Sopenharmony_ci case SpvOpDecorate: 608bf215546Sopenharmony_ci parser->parseOpDecorate(ins); 609bf215546Sopenharmony_ci break; 610bf215546Sopenharmony_ci case SpvOpGroupDecorate: 611bf215546Sopenharmony_ci parser->parseOpGroupDecorate(ins); 612bf215546Sopenharmony_ci break; 613bf215546Sopenharmony_ci case SpvOpExecutionMode: 614bf215546Sopenharmony_ci parser->parseExecutionMode(ins); 615bf215546Sopenharmony_ci break; 616bf215546Sopenharmony_ci case SpvOpTypeBool: 617bf215546Sopenharmony_ci case SpvOpTypeInt: 618bf215546Sopenharmony_ci case SpvOpTypeFloat: 619bf215546Sopenharmony_ci parser->parseLiteralType(ins); 620bf215546Sopenharmony_ci break; 621bf215546Sopenharmony_ci case SpvOpSpecConstant: 622bf215546Sopenharmony_ci case SpvOpSpecConstantFalse: 623bf215546Sopenharmony_ci case SpvOpSpecConstantTrue: 624bf215546Sopenharmony_ci parser->parseSpecConstant(ins); 625bf215546Sopenharmony_ci break; 626bf215546Sopenharmony_ci default: 627bf215546Sopenharmony_ci break; 628bf215546Sopenharmony_ci } 629bf215546Sopenharmony_ci 630bf215546Sopenharmony_ci return SPV_SUCCESS; 631bf215546Sopenharmony_ci } 632bf215546Sopenharmony_ci 633bf215546Sopenharmony_ci bool parseBinary(const struct clc_binary &spvbin, const struct clc_logger *logger) 634bf215546Sopenharmony_ci { 635bf215546Sopenharmony_ci /* 3 passes should be enough to retrieve all kernel information: 636bf215546Sopenharmony_ci * 1st pass: all entry point name and number of args 637bf215546Sopenharmony_ci * 2nd pass: argument names and type names 638bf215546Sopenharmony_ci * 3rd pass: pointer type names 639bf215546Sopenharmony_ci */ 640bf215546Sopenharmony_ci for (unsigned pass = 0; pass < 3; pass++) { 641bf215546Sopenharmony_ci spv_diagnostic diagnostic = NULL; 642bf215546Sopenharmony_ci auto result = spvBinaryParse(ctx, reinterpret_cast<void *>(this), 643bf215546Sopenharmony_ci static_cast<uint32_t*>(spvbin.data), spvbin.size / 4, 644bf215546Sopenharmony_ci NULL, parseInstruction, &diagnostic); 645bf215546Sopenharmony_ci 646bf215546Sopenharmony_ci if (result != SPV_SUCCESS) { 647bf215546Sopenharmony_ci if (diagnostic && logger) 648bf215546Sopenharmony_ci logger->error(logger->priv, diagnostic->error); 649bf215546Sopenharmony_ci return false; 650bf215546Sopenharmony_ci } 651bf215546Sopenharmony_ci } 652bf215546Sopenharmony_ci 653bf215546Sopenharmony_ci return true; 654bf215546Sopenharmony_ci } 655bf215546Sopenharmony_ci 656bf215546Sopenharmony_ci std::vector<SPIRVKernelInfo> kernels; 657bf215546Sopenharmony_ci std::vector<std::pair<uint32_t, clc_parsed_spec_constant>> specConstants; 658bf215546Sopenharmony_ci std::map<uint32_t, enum clc_spec_constant_type> literalTypes; 659bf215546Sopenharmony_ci std::map<uint32_t, std::vector<uint32_t>> decorationGroups; 660bf215546Sopenharmony_ci SPIRVKernelInfo *curKernel; 661bf215546Sopenharmony_ci spv_context ctx; 662bf215546Sopenharmony_ci}; 663bf215546Sopenharmony_ci 664bf215546Sopenharmony_cibool 665bf215546Sopenharmony_ciclc_spirv_get_kernels_info(const struct clc_binary *spvbin, 666bf215546Sopenharmony_ci const struct clc_kernel_info **out_kernels, 667bf215546Sopenharmony_ci unsigned *num_kernels, 668bf215546Sopenharmony_ci const struct clc_parsed_spec_constant **out_spec_constants, 669bf215546Sopenharmony_ci unsigned *num_spec_constants, 670bf215546Sopenharmony_ci const struct clc_logger *logger) 671bf215546Sopenharmony_ci{ 672bf215546Sopenharmony_ci struct clc_kernel_info *kernels; 673bf215546Sopenharmony_ci struct clc_parsed_spec_constant *spec_constants = NULL; 674bf215546Sopenharmony_ci 675bf215546Sopenharmony_ci SPIRVKernelParser parser; 676bf215546Sopenharmony_ci 677bf215546Sopenharmony_ci if (!parser.parseBinary(*spvbin, logger)) 678bf215546Sopenharmony_ci return false; 679bf215546Sopenharmony_ci 680bf215546Sopenharmony_ci *num_kernels = parser.kernels.size(); 681bf215546Sopenharmony_ci *num_spec_constants = parser.specConstants.size(); 682bf215546Sopenharmony_ci if (!*num_kernels) 683bf215546Sopenharmony_ci return false; 684bf215546Sopenharmony_ci 685bf215546Sopenharmony_ci kernels = reinterpret_cast<struct clc_kernel_info *>(calloc(*num_kernels, 686bf215546Sopenharmony_ci sizeof(*kernels))); 687bf215546Sopenharmony_ci assert(kernels); 688bf215546Sopenharmony_ci for (unsigned i = 0; i < parser.kernels.size(); i++) { 689bf215546Sopenharmony_ci kernels[i].name = strdup(parser.kernels[i].name.c_str()); 690bf215546Sopenharmony_ci kernels[i].num_args = parser.kernels[i].args.size(); 691bf215546Sopenharmony_ci kernels[i].vec_hint_size = parser.kernels[i].vecHint >> 16; 692bf215546Sopenharmony_ci kernels[i].vec_hint_type = (enum clc_vec_hint_type)(parser.kernels[i].vecHint & 0xFFFF); 693bf215546Sopenharmony_ci memcpy(kernels[i].local_size, parser.kernels[i].localSize, sizeof(kernels[i].local_size)); 694bf215546Sopenharmony_ci memcpy(kernels[i].local_size_hint, parser.kernels[i].localSizeHint, sizeof(kernels[i].local_size_hint)); 695bf215546Sopenharmony_ci if (!kernels[i].num_args) 696bf215546Sopenharmony_ci continue; 697bf215546Sopenharmony_ci 698bf215546Sopenharmony_ci struct clc_kernel_arg *args; 699bf215546Sopenharmony_ci 700bf215546Sopenharmony_ci args = reinterpret_cast<struct clc_kernel_arg *>(calloc(kernels[i].num_args, 701bf215546Sopenharmony_ci sizeof(*kernels->args))); 702bf215546Sopenharmony_ci kernels[i].args = args; 703bf215546Sopenharmony_ci assert(args); 704bf215546Sopenharmony_ci for (unsigned j = 0; j < kernels[i].num_args; j++) { 705bf215546Sopenharmony_ci if (!parser.kernels[i].args[j].name.empty()) 706bf215546Sopenharmony_ci args[j].name = strdup(parser.kernels[i].args[j].name.c_str()); 707bf215546Sopenharmony_ci args[j].type_name = strdup(parser.kernels[i].args[j].typeName.c_str()); 708bf215546Sopenharmony_ci args[j].address_qualifier = parser.kernels[i].args[j].addrQualifier; 709bf215546Sopenharmony_ci args[j].type_qualifier = parser.kernels[i].args[j].typeQualifier; 710bf215546Sopenharmony_ci args[j].access_qualifier = parser.kernels[i].args[j].accessQualifier; 711bf215546Sopenharmony_ci } 712bf215546Sopenharmony_ci } 713bf215546Sopenharmony_ci 714bf215546Sopenharmony_ci if (*num_spec_constants) { 715bf215546Sopenharmony_ci spec_constants = reinterpret_cast<struct clc_parsed_spec_constant *>(calloc(*num_spec_constants, 716bf215546Sopenharmony_ci sizeof(*spec_constants))); 717bf215546Sopenharmony_ci assert(spec_constants); 718bf215546Sopenharmony_ci 719bf215546Sopenharmony_ci for (unsigned i = 0; i < parser.specConstants.size(); ++i) { 720bf215546Sopenharmony_ci spec_constants[i] = parser.specConstants[i].second; 721bf215546Sopenharmony_ci } 722bf215546Sopenharmony_ci } 723bf215546Sopenharmony_ci 724bf215546Sopenharmony_ci *out_kernels = kernels; 725bf215546Sopenharmony_ci *out_spec_constants = spec_constants; 726bf215546Sopenharmony_ci 727bf215546Sopenharmony_ci return true; 728bf215546Sopenharmony_ci} 729bf215546Sopenharmony_ci 730bf215546Sopenharmony_civoid 731bf215546Sopenharmony_ciclc_free_kernels_info(const struct clc_kernel_info *kernels, 732bf215546Sopenharmony_ci unsigned num_kernels) 733bf215546Sopenharmony_ci{ 734bf215546Sopenharmony_ci if (!kernels) 735bf215546Sopenharmony_ci return; 736bf215546Sopenharmony_ci 737bf215546Sopenharmony_ci for (unsigned i = 0; i < num_kernels; i++) { 738bf215546Sopenharmony_ci if (kernels[i].args) { 739bf215546Sopenharmony_ci for (unsigned j = 0; j < kernels[i].num_args; j++) { 740bf215546Sopenharmony_ci free((void *)kernels[i].args[j].name); 741bf215546Sopenharmony_ci free((void *)kernels[i].args[j].type_name); 742bf215546Sopenharmony_ci } 743bf215546Sopenharmony_ci } 744bf215546Sopenharmony_ci free((void *)kernels[i].name); 745bf215546Sopenharmony_ci } 746bf215546Sopenharmony_ci 747bf215546Sopenharmony_ci free((void *)kernels); 748bf215546Sopenharmony_ci} 749bf215546Sopenharmony_ci 750bf215546Sopenharmony_cistatic std::unique_ptr<::llvm::Module> 751bf215546Sopenharmony_ciclc_compile_to_llvm_module(LLVMContext &llvm_ctx, 752bf215546Sopenharmony_ci const struct clc_compile_args *args, 753bf215546Sopenharmony_ci const struct clc_logger *logger) 754bf215546Sopenharmony_ci{ 755bf215546Sopenharmony_ci std::string diag_log_str; 756bf215546Sopenharmony_ci raw_string_ostream diag_log_stream { diag_log_str }; 757bf215546Sopenharmony_ci 758bf215546Sopenharmony_ci std::unique_ptr<clang::CompilerInstance> c { new clang::CompilerInstance }; 759bf215546Sopenharmony_ci 760bf215546Sopenharmony_ci clang::DiagnosticsEngine diag { 761bf215546Sopenharmony_ci new clang::DiagnosticIDs, 762bf215546Sopenharmony_ci new clang::DiagnosticOptions, 763bf215546Sopenharmony_ci new clang::TextDiagnosticPrinter(diag_log_stream, 764bf215546Sopenharmony_ci &c->getDiagnosticOpts()) 765bf215546Sopenharmony_ci }; 766bf215546Sopenharmony_ci 767bf215546Sopenharmony_ci std::vector<const char *> clang_opts = { 768bf215546Sopenharmony_ci args->source.name, 769bf215546Sopenharmony_ci "-triple", "spir64-unknown-unknown", 770bf215546Sopenharmony_ci // By default, clang prefers to use modules to pull in the default headers, 771bf215546Sopenharmony_ci // which doesn't work with our technique of embedding the headers in our binary 772bf215546Sopenharmony_ci#if LLVM_VERSION_MAJOR >= 15 773bf215546Sopenharmony_ci "-fdeclare-opencl-builtins", 774bf215546Sopenharmony_ci#else 775bf215546Sopenharmony_ci "-finclude-default-header", 776bf215546Sopenharmony_ci#endif 777bf215546Sopenharmony_ci#if LLVM_VERSION_MAJOR >= 15 778bf215546Sopenharmony_ci "-no-opaque-pointers", 779bf215546Sopenharmony_ci#endif 780bf215546Sopenharmony_ci // Add a default CL compiler version. Clang will pick the last one specified 781bf215546Sopenharmony_ci // on the command line, so the app can override this one. 782bf215546Sopenharmony_ci "-cl-std=cl1.2", 783bf215546Sopenharmony_ci // The LLVM-SPIRV-Translator doesn't support memset with variable size 784bf215546Sopenharmony_ci "-fno-builtin-memset", 785bf215546Sopenharmony_ci // LLVM's optimizations can produce code that the translator can't translate 786bf215546Sopenharmony_ci "-O0", 787bf215546Sopenharmony_ci // Ensure inline functions are actually emitted 788bf215546Sopenharmony_ci "-fgnu89-inline" 789bf215546Sopenharmony_ci }; 790bf215546Sopenharmony_ci // We assume there's appropriate defines for __OPENCL_VERSION__ and __IMAGE_SUPPORT__ 791bf215546Sopenharmony_ci // being provided by the caller here. 792bf215546Sopenharmony_ci clang_opts.insert(clang_opts.end(), args->args, args->args + args->num_args); 793bf215546Sopenharmony_ci 794bf215546Sopenharmony_ci if (!clang::CompilerInvocation::CreateFromArgs(c->getInvocation(), 795bf215546Sopenharmony_ci#if LLVM_VERSION_MAJOR >= 10 796bf215546Sopenharmony_ci clang_opts, 797bf215546Sopenharmony_ci#else 798bf215546Sopenharmony_ci clang_opts.data(), 799bf215546Sopenharmony_ci clang_opts.data() + clang_opts.size(), 800bf215546Sopenharmony_ci#endif 801bf215546Sopenharmony_ci diag)) { 802bf215546Sopenharmony_ci clc_error(logger, "Couldn't create Clang invocation.\n"); 803bf215546Sopenharmony_ci return {}; 804bf215546Sopenharmony_ci } 805bf215546Sopenharmony_ci 806bf215546Sopenharmony_ci if (diag.hasErrorOccurred()) { 807bf215546Sopenharmony_ci clc_error(logger, "%sErrors occurred during Clang invocation.\n", 808bf215546Sopenharmony_ci diag_log_str.c_str()); 809bf215546Sopenharmony_ci return {}; 810bf215546Sopenharmony_ci } 811bf215546Sopenharmony_ci 812bf215546Sopenharmony_ci // This is a workaround for a Clang bug which causes the number 813bf215546Sopenharmony_ci // of warnings and errors to be printed to stderr. 814bf215546Sopenharmony_ci // http://www.llvm.org/bugs/show_bug.cgi?id=19735 815bf215546Sopenharmony_ci c->getDiagnosticOpts().ShowCarets = false; 816bf215546Sopenharmony_ci 817bf215546Sopenharmony_ci c->createDiagnostics(new clang::TextDiagnosticPrinter( 818bf215546Sopenharmony_ci diag_log_stream, 819bf215546Sopenharmony_ci &c->getDiagnosticOpts())); 820bf215546Sopenharmony_ci 821bf215546Sopenharmony_ci c->setTarget(clang::TargetInfo::CreateTargetInfo( 822bf215546Sopenharmony_ci c->getDiagnostics(), c->getInvocation().TargetOpts)); 823bf215546Sopenharmony_ci 824bf215546Sopenharmony_ci c->getFrontendOpts().ProgramAction = clang::frontend::EmitLLVMOnly; 825bf215546Sopenharmony_ci 826bf215546Sopenharmony_ci#ifdef USE_STATIC_OPENCL_C_H 827bf215546Sopenharmony_ci c->getHeaderSearchOpts().UseBuiltinIncludes = false; 828bf215546Sopenharmony_ci c->getHeaderSearchOpts().UseStandardSystemIncludes = false; 829bf215546Sopenharmony_ci 830bf215546Sopenharmony_ci // Add opencl-c generic search path 831bf215546Sopenharmony_ci { 832bf215546Sopenharmony_ci ::llvm::SmallString<128> system_header_path; 833bf215546Sopenharmony_ci ::llvm::sys::path::system_temp_directory(true, system_header_path); 834bf215546Sopenharmony_ci ::llvm::sys::path::append(system_header_path, "openclon12"); 835bf215546Sopenharmony_ci c->getHeaderSearchOpts().AddPath(system_header_path.str(), 836bf215546Sopenharmony_ci clang::frontend::Angled, 837bf215546Sopenharmony_ci false, false); 838bf215546Sopenharmony_ci 839bf215546Sopenharmony_ci#if LLVM_VERSION_MAJOR < 15 840bf215546Sopenharmony_ci ::llvm::sys::path::append(system_header_path, "opencl-c.h"); 841bf215546Sopenharmony_ci c->getPreprocessorOpts().addRemappedFile(system_header_path.str(), 842bf215546Sopenharmony_ci ::llvm::MemoryBuffer::getMemBuffer(llvm::StringRef(opencl_c_source, ARRAY_SIZE(opencl_c_source) - 1)).release()); 843bf215546Sopenharmony_ci#endif 844bf215546Sopenharmony_ci 845bf215546Sopenharmony_ci ::llvm::sys::path::remove_filename(system_header_path); 846bf215546Sopenharmony_ci ::llvm::sys::path::append(system_header_path, "opencl-c-base.h"); 847bf215546Sopenharmony_ci c->getPreprocessorOpts().addRemappedFile(system_header_path.str(), 848bf215546Sopenharmony_ci ::llvm::MemoryBuffer::getMemBuffer(llvm::StringRef(opencl_c_base_source, ARRAY_SIZE(opencl_c_base_source) - 1)).release()); 849bf215546Sopenharmony_ci } 850bf215546Sopenharmony_ci#else 851bf215546Sopenharmony_ci c->getHeaderSearchOpts().UseBuiltinIncludes = true; 852bf215546Sopenharmony_ci c->getHeaderSearchOpts().UseStandardSystemIncludes = true; 853bf215546Sopenharmony_ci c->getHeaderSearchOpts().ResourceDir = CLANG_RESOURCE_DIR; 854bf215546Sopenharmony_ci 855bf215546Sopenharmony_ci // Add opencl-c generic search path 856bf215546Sopenharmony_ci c->getHeaderSearchOpts().AddPath(CLANG_RESOURCE_DIR, 857bf215546Sopenharmony_ci clang::frontend::Angled, 858bf215546Sopenharmony_ci false, false); 859bf215546Sopenharmony_ci // Add opencl include 860bf215546Sopenharmony_ci#if LLVM_VERSION_MAJOR >= 15 861bf215546Sopenharmony_ci c->getPreprocessorOpts().Includes.push_back("opencl-c-base.h"); 862bf215546Sopenharmony_ci#else 863bf215546Sopenharmony_ci c->getPreprocessorOpts().Includes.push_back("opencl-c.h"); 864bf215546Sopenharmony_ci#endif 865bf215546Sopenharmony_ci#endif 866bf215546Sopenharmony_ci 867bf215546Sopenharmony_ci#if LLVM_VERSION_MAJOR >= 14 868bf215546Sopenharmony_ci c->getTargetOpts().OpenCLExtensionsAsWritten.push_back("-all"); 869bf215546Sopenharmony_ci c->getTargetOpts().OpenCLExtensionsAsWritten.push_back("+cl_khr_byte_addressable_store"); 870bf215546Sopenharmony_ci c->getTargetOpts().OpenCLExtensionsAsWritten.push_back("+cl_khr_global_int32_base_atomics"); 871bf215546Sopenharmony_ci c->getTargetOpts().OpenCLExtensionsAsWritten.push_back("+cl_khr_global_int32_extended_atomics"); 872bf215546Sopenharmony_ci c->getTargetOpts().OpenCLExtensionsAsWritten.push_back("+cl_khr_local_int32_base_atomics"); 873bf215546Sopenharmony_ci c->getTargetOpts().OpenCLExtensionsAsWritten.push_back("+cl_khr_local_int32_extended_atomics"); 874bf215546Sopenharmony_ci if (args->features.fp16) { 875bf215546Sopenharmony_ci c->getTargetOpts().OpenCLExtensionsAsWritten.push_back("+cl_khr_fp16"); 876bf215546Sopenharmony_ci } 877bf215546Sopenharmony_ci if (args->features.fp64) { 878bf215546Sopenharmony_ci c->getTargetOpts().OpenCLExtensionsAsWritten.push_back("+cl_khr_fp64"); 879bf215546Sopenharmony_ci c->getTargetOpts().OpenCLExtensionsAsWritten.push_back("+__opencl_c_fp64"); 880bf215546Sopenharmony_ci } 881bf215546Sopenharmony_ci if (args->features.int64) { 882bf215546Sopenharmony_ci c->getTargetOpts().OpenCLExtensionsAsWritten.push_back("+cles_khr_int64"); 883bf215546Sopenharmony_ci c->getTargetOpts().OpenCLExtensionsAsWritten.push_back("+__opencl_c_int64"); 884bf215546Sopenharmony_ci } 885bf215546Sopenharmony_ci if (args->features.images) { 886bf215546Sopenharmony_ci c->getTargetOpts().OpenCLExtensionsAsWritten.push_back("+__opencl_c_images"); 887bf215546Sopenharmony_ci } 888bf215546Sopenharmony_ci if (args->features.images_read_write) { 889bf215546Sopenharmony_ci c->getTargetOpts().OpenCLExtensionsAsWritten.push_back("+__opencl_c_read_write_images"); 890bf215546Sopenharmony_ci } 891bf215546Sopenharmony_ci if (args->features.images_write_3d) { 892bf215546Sopenharmony_ci c->getTargetOpts().OpenCLExtensionsAsWritten.push_back("+cl_khr_3d_image_writes"); 893bf215546Sopenharmony_ci c->getTargetOpts().OpenCLExtensionsAsWritten.push_back("+__opencl_c_3d_image_writes"); 894bf215546Sopenharmony_ci } 895bf215546Sopenharmony_ci if (args->features.intel_subgroups) { 896bf215546Sopenharmony_ci c->getTargetOpts().OpenCLExtensionsAsWritten.push_back("+cl_intel_subgroups"); 897bf215546Sopenharmony_ci } 898bf215546Sopenharmony_ci if (args->features.subgroups) { 899bf215546Sopenharmony_ci c->getTargetOpts().OpenCLExtensionsAsWritten.push_back("+cl_khr_subgroups"); 900bf215546Sopenharmony_ci } 901bf215546Sopenharmony_ci#endif 902bf215546Sopenharmony_ci 903bf215546Sopenharmony_ci if (args->num_headers) { 904bf215546Sopenharmony_ci ::llvm::SmallString<128> tmp_header_path; 905bf215546Sopenharmony_ci ::llvm::sys::path::system_temp_directory(true, tmp_header_path); 906bf215546Sopenharmony_ci ::llvm::sys::path::append(tmp_header_path, "openclon12"); 907bf215546Sopenharmony_ci 908bf215546Sopenharmony_ci c->getHeaderSearchOpts().AddPath(tmp_header_path.str(), 909bf215546Sopenharmony_ci clang::frontend::Quoted, 910bf215546Sopenharmony_ci false, false); 911bf215546Sopenharmony_ci 912bf215546Sopenharmony_ci for (size_t i = 0; i < args->num_headers; i++) { 913bf215546Sopenharmony_ci auto path_copy = tmp_header_path; 914bf215546Sopenharmony_ci ::llvm::sys::path::append(path_copy, ::llvm::sys::path::convert_to_slash(args->headers[i].name)); 915bf215546Sopenharmony_ci c->getPreprocessorOpts().addRemappedFile(path_copy.str(), 916bf215546Sopenharmony_ci ::llvm::MemoryBuffer::getMemBufferCopy(args->headers[i].value).release()); 917bf215546Sopenharmony_ci } 918bf215546Sopenharmony_ci } 919bf215546Sopenharmony_ci 920bf215546Sopenharmony_ci c->getPreprocessorOpts().addRemappedFile( 921bf215546Sopenharmony_ci args->source.name, 922bf215546Sopenharmony_ci ::llvm::MemoryBuffer::getMemBufferCopy(std::string(args->source.value)).release()); 923bf215546Sopenharmony_ci 924bf215546Sopenharmony_ci // Compile the code 925bf215546Sopenharmony_ci clang::EmitLLVMOnlyAction act(&llvm_ctx); 926bf215546Sopenharmony_ci if (!c->ExecuteAction(act)) { 927bf215546Sopenharmony_ci clc_error(logger, "%sError executing LLVM compilation action.\n", 928bf215546Sopenharmony_ci diag_log_str.c_str()); 929bf215546Sopenharmony_ci return {}; 930bf215546Sopenharmony_ci } 931bf215546Sopenharmony_ci 932bf215546Sopenharmony_ci return act.takeModule(); 933bf215546Sopenharmony_ci} 934bf215546Sopenharmony_ci 935bf215546Sopenharmony_cistatic SPIRV::VersionNumber 936bf215546Sopenharmony_cispirv_version_to_llvm_spirv_translator_version(enum clc_spirv_version version) 937bf215546Sopenharmony_ci{ 938bf215546Sopenharmony_ci switch (version) { 939bf215546Sopenharmony_ci case CLC_SPIRV_VERSION_MAX: return SPIRV::VersionNumber::MaximumVersion; 940bf215546Sopenharmony_ci case CLC_SPIRV_VERSION_1_0: return SPIRV::VersionNumber::SPIRV_1_0; 941bf215546Sopenharmony_ci case CLC_SPIRV_VERSION_1_1: return SPIRV::VersionNumber::SPIRV_1_1; 942bf215546Sopenharmony_ci case CLC_SPIRV_VERSION_1_2: return SPIRV::VersionNumber::SPIRV_1_2; 943bf215546Sopenharmony_ci case CLC_SPIRV_VERSION_1_3: return SPIRV::VersionNumber::SPIRV_1_3; 944bf215546Sopenharmony_ci#ifdef HAS_SPIRV_1_4 945bf215546Sopenharmony_ci case CLC_SPIRV_VERSION_1_4: return SPIRV::VersionNumber::SPIRV_1_4; 946bf215546Sopenharmony_ci#endif 947bf215546Sopenharmony_ci default: return invalid_spirv_trans_version; 948bf215546Sopenharmony_ci } 949bf215546Sopenharmony_ci} 950bf215546Sopenharmony_ci 951bf215546Sopenharmony_cistatic int 952bf215546Sopenharmony_cillvm_mod_to_spirv(std::unique_ptr<::llvm::Module> mod, 953bf215546Sopenharmony_ci LLVMContext &context, 954bf215546Sopenharmony_ci const struct clc_compile_args *args, 955bf215546Sopenharmony_ci const struct clc_logger *logger, 956bf215546Sopenharmony_ci struct clc_binary *out_spirv) 957bf215546Sopenharmony_ci{ 958bf215546Sopenharmony_ci std::string log; 959bf215546Sopenharmony_ci 960bf215546Sopenharmony_ci SPIRV::VersionNumber version = 961bf215546Sopenharmony_ci spirv_version_to_llvm_spirv_translator_version(args->spirv_version); 962bf215546Sopenharmony_ci if (version == invalid_spirv_trans_version) { 963bf215546Sopenharmony_ci clc_error(logger, "Invalid/unsupported SPIRV specified.\n"); 964bf215546Sopenharmony_ci return -1; 965bf215546Sopenharmony_ci } 966bf215546Sopenharmony_ci 967bf215546Sopenharmony_ci const char *const *extensions = NULL; 968bf215546Sopenharmony_ci if (args) 969bf215546Sopenharmony_ci extensions = args->allowed_spirv_extensions; 970bf215546Sopenharmony_ci if (!extensions) { 971bf215546Sopenharmony_ci /* The SPIR-V parser doesn't handle all extensions */ 972bf215546Sopenharmony_ci static const char *default_extensions[] = { 973bf215546Sopenharmony_ci "SPV_EXT_shader_atomic_float_add", 974bf215546Sopenharmony_ci "SPV_EXT_shader_atomic_float_min_max", 975bf215546Sopenharmony_ci "SPV_KHR_float_controls", 976bf215546Sopenharmony_ci NULL, 977bf215546Sopenharmony_ci }; 978bf215546Sopenharmony_ci extensions = default_extensions; 979bf215546Sopenharmony_ci } 980bf215546Sopenharmony_ci 981bf215546Sopenharmony_ci SPIRV::TranslatorOpts::ExtensionsStatusMap ext_map; 982bf215546Sopenharmony_ci for (int i = 0; extensions[i]; i++) { 983bf215546Sopenharmony_ci#define EXT(X) \ 984bf215546Sopenharmony_ci if (strcmp(#X, extensions[i]) == 0) \ 985bf215546Sopenharmony_ci ext_map.insert(std::make_pair(SPIRV::ExtensionID::X, true)); 986bf215546Sopenharmony_ci#include "LLVMSPIRVLib/LLVMSPIRVExtensions.inc" 987bf215546Sopenharmony_ci#undef EXT 988bf215546Sopenharmony_ci } 989bf215546Sopenharmony_ci SPIRV::TranslatorOpts spirv_opts = SPIRV::TranslatorOpts(version, ext_map); 990bf215546Sopenharmony_ci 991bf215546Sopenharmony_ci#if LLVM_VERSION_MAJOR >= 13 992bf215546Sopenharmony_ci /* This was the default in 12.0 and older, but currently we'll fail to parse without this */ 993bf215546Sopenharmony_ci spirv_opts.setPreserveOCLKernelArgTypeMetadataThroughString(true); 994bf215546Sopenharmony_ci#endif 995bf215546Sopenharmony_ci 996bf215546Sopenharmony_ci std::ostringstream spv_stream; 997bf215546Sopenharmony_ci if (!::llvm::writeSpirv(mod.get(), spirv_opts, spv_stream, log)) { 998bf215546Sopenharmony_ci clc_error(logger, "%sTranslation from LLVM IR to SPIR-V failed.\n", 999bf215546Sopenharmony_ci log.c_str()); 1000bf215546Sopenharmony_ci return -1; 1001bf215546Sopenharmony_ci } 1002bf215546Sopenharmony_ci 1003bf215546Sopenharmony_ci const std::string spv_out = spv_stream.str(); 1004bf215546Sopenharmony_ci out_spirv->size = spv_out.size(); 1005bf215546Sopenharmony_ci out_spirv->data = malloc(out_spirv->size); 1006bf215546Sopenharmony_ci memcpy(out_spirv->data, spv_out.data(), out_spirv->size); 1007bf215546Sopenharmony_ci 1008bf215546Sopenharmony_ci return 0; 1009bf215546Sopenharmony_ci} 1010bf215546Sopenharmony_ci 1011bf215546Sopenharmony_ciint 1012bf215546Sopenharmony_ciclc_c_to_spir(const struct clc_compile_args *args, 1013bf215546Sopenharmony_ci const struct clc_logger *logger, 1014bf215546Sopenharmony_ci struct clc_binary *out_spir) 1015bf215546Sopenharmony_ci{ 1016bf215546Sopenharmony_ci clc_initialize_llvm(); 1017bf215546Sopenharmony_ci 1018bf215546Sopenharmony_ci LLVMContext llvm_ctx; 1019bf215546Sopenharmony_ci llvm_ctx.setDiagnosticHandlerCallBack(llvm_log_handler, 1020bf215546Sopenharmony_ci const_cast<clc_logger *>(logger)); 1021bf215546Sopenharmony_ci 1022bf215546Sopenharmony_ci auto mod = clc_compile_to_llvm_module(llvm_ctx, args, logger); 1023bf215546Sopenharmony_ci if (!mod) 1024bf215546Sopenharmony_ci return -1; 1025bf215546Sopenharmony_ci 1026bf215546Sopenharmony_ci ::llvm::SmallVector<char, 0> buffer; 1027bf215546Sopenharmony_ci ::llvm::BitcodeWriter writer(buffer); 1028bf215546Sopenharmony_ci writer.writeModule(*mod); 1029bf215546Sopenharmony_ci 1030bf215546Sopenharmony_ci out_spir->size = buffer.size_in_bytes(); 1031bf215546Sopenharmony_ci out_spir->data = malloc(out_spir->size); 1032bf215546Sopenharmony_ci memcpy(out_spir->data, buffer.data(), out_spir->size); 1033bf215546Sopenharmony_ci 1034bf215546Sopenharmony_ci return 0; 1035bf215546Sopenharmony_ci} 1036bf215546Sopenharmony_ci 1037bf215546Sopenharmony_ciint 1038bf215546Sopenharmony_ciclc_c_to_spirv(const struct clc_compile_args *args, 1039bf215546Sopenharmony_ci const struct clc_logger *logger, 1040bf215546Sopenharmony_ci struct clc_binary *out_spirv) 1041bf215546Sopenharmony_ci{ 1042bf215546Sopenharmony_ci clc_initialize_llvm(); 1043bf215546Sopenharmony_ci 1044bf215546Sopenharmony_ci LLVMContext llvm_ctx; 1045bf215546Sopenharmony_ci llvm_ctx.setDiagnosticHandlerCallBack(llvm_log_handler, 1046bf215546Sopenharmony_ci const_cast<clc_logger *>(logger)); 1047bf215546Sopenharmony_ci 1048bf215546Sopenharmony_ci auto mod = clc_compile_to_llvm_module(llvm_ctx, args, logger); 1049bf215546Sopenharmony_ci if (!mod) 1050bf215546Sopenharmony_ci return -1; 1051bf215546Sopenharmony_ci return llvm_mod_to_spirv(std::move(mod), llvm_ctx, args, logger, out_spirv); 1052bf215546Sopenharmony_ci} 1053bf215546Sopenharmony_ci 1054bf215546Sopenharmony_ciint 1055bf215546Sopenharmony_ciclc_spir_to_spirv(const struct clc_binary *in_spir, 1056bf215546Sopenharmony_ci const struct clc_logger *logger, 1057bf215546Sopenharmony_ci struct clc_binary *out_spirv) 1058bf215546Sopenharmony_ci{ 1059bf215546Sopenharmony_ci clc_initialize_llvm(); 1060bf215546Sopenharmony_ci 1061bf215546Sopenharmony_ci LLVMContext llvm_ctx; 1062bf215546Sopenharmony_ci llvm_ctx.setDiagnosticHandlerCallBack(llvm_log_handler, 1063bf215546Sopenharmony_ci const_cast<clc_logger *>(logger)); 1064bf215546Sopenharmony_ci 1065bf215546Sopenharmony_ci ::llvm::StringRef spir_ref(static_cast<const char*>(in_spir->data), in_spir->size); 1066bf215546Sopenharmony_ci auto mod = ::llvm::parseBitcodeFile(::llvm::MemoryBufferRef(spir_ref, "<spir>"), llvm_ctx); 1067bf215546Sopenharmony_ci if (!mod) 1068bf215546Sopenharmony_ci return -1; 1069bf215546Sopenharmony_ci 1070bf215546Sopenharmony_ci return llvm_mod_to_spirv(std::move(mod.get()), llvm_ctx, NULL, logger, out_spirv); 1071bf215546Sopenharmony_ci} 1072bf215546Sopenharmony_ci 1073bf215546Sopenharmony_ciclass SPIRVMessageConsumer { 1074bf215546Sopenharmony_cipublic: 1075bf215546Sopenharmony_ci SPIRVMessageConsumer(const struct clc_logger *logger): logger(logger) {} 1076bf215546Sopenharmony_ci 1077bf215546Sopenharmony_ci void operator()(spv_message_level_t level, const char *src, 1078bf215546Sopenharmony_ci const spv_position_t &pos, const char *msg) 1079bf215546Sopenharmony_ci { 1080bf215546Sopenharmony_ci if (level == SPV_MSG_INFO || level == SPV_MSG_DEBUG) 1081bf215546Sopenharmony_ci return; 1082bf215546Sopenharmony_ci 1083bf215546Sopenharmony_ci std::ostringstream message; 1084bf215546Sopenharmony_ci message << "(file=" << src 1085bf215546Sopenharmony_ci << ",line=" << pos.line 1086bf215546Sopenharmony_ci << ",column=" << pos.column 1087bf215546Sopenharmony_ci << ",index=" << pos.index 1088bf215546Sopenharmony_ci << "): " << msg << "\n"; 1089bf215546Sopenharmony_ci 1090bf215546Sopenharmony_ci if (level == SPV_MSG_WARNING) 1091bf215546Sopenharmony_ci clc_warning(logger, "%s", message.str().c_str()); 1092bf215546Sopenharmony_ci else 1093bf215546Sopenharmony_ci clc_error(logger, "%s", message.str().c_str()); 1094bf215546Sopenharmony_ci } 1095bf215546Sopenharmony_ci 1096bf215546Sopenharmony_ciprivate: 1097bf215546Sopenharmony_ci const struct clc_logger *logger; 1098bf215546Sopenharmony_ci}; 1099bf215546Sopenharmony_ci 1100bf215546Sopenharmony_ciint 1101bf215546Sopenharmony_ciclc_link_spirv_binaries(const struct clc_linker_args *args, 1102bf215546Sopenharmony_ci const struct clc_logger *logger, 1103bf215546Sopenharmony_ci struct clc_binary *out_spirv) 1104bf215546Sopenharmony_ci{ 1105bf215546Sopenharmony_ci std::vector<std::vector<uint32_t>> binaries; 1106bf215546Sopenharmony_ci 1107bf215546Sopenharmony_ci for (unsigned i = 0; i < args->num_in_objs; i++) { 1108bf215546Sopenharmony_ci const uint32_t *data = static_cast<const uint32_t *>(args->in_objs[i]->data); 1109bf215546Sopenharmony_ci std::vector<uint32_t> bin(data, data + (args->in_objs[i]->size / 4)); 1110bf215546Sopenharmony_ci binaries.push_back(bin); 1111bf215546Sopenharmony_ci } 1112bf215546Sopenharmony_ci 1113bf215546Sopenharmony_ci SPIRVMessageConsumer msgconsumer(logger); 1114bf215546Sopenharmony_ci spvtools::Context context(spirv_target); 1115bf215546Sopenharmony_ci context.SetMessageConsumer(msgconsumer); 1116bf215546Sopenharmony_ci spvtools::LinkerOptions options; 1117bf215546Sopenharmony_ci options.SetAllowPartialLinkage(args->create_library); 1118bf215546Sopenharmony_ci options.SetCreateLibrary(args->create_library); 1119bf215546Sopenharmony_ci std::vector<uint32_t> linkingResult; 1120bf215546Sopenharmony_ci spv_result_t status = spvtools::Link(context, binaries, &linkingResult, options); 1121bf215546Sopenharmony_ci if (status != SPV_SUCCESS) { 1122bf215546Sopenharmony_ci return -1; 1123bf215546Sopenharmony_ci } 1124bf215546Sopenharmony_ci 1125bf215546Sopenharmony_ci out_spirv->size = linkingResult.size() * 4; 1126bf215546Sopenharmony_ci out_spirv->data = static_cast<uint32_t *>(malloc(out_spirv->size)); 1127bf215546Sopenharmony_ci memcpy(out_spirv->data, linkingResult.data(), out_spirv->size); 1128bf215546Sopenharmony_ci 1129bf215546Sopenharmony_ci return 0; 1130bf215546Sopenharmony_ci} 1131bf215546Sopenharmony_ci 1132bf215546Sopenharmony_ciint 1133bf215546Sopenharmony_ciclc_spirv_specialize(const struct clc_binary *in_spirv, 1134bf215546Sopenharmony_ci const struct clc_parsed_spirv *parsed_data, 1135bf215546Sopenharmony_ci const struct clc_spirv_specialization_consts *consts, 1136bf215546Sopenharmony_ci struct clc_binary *out_spirv) 1137bf215546Sopenharmony_ci{ 1138bf215546Sopenharmony_ci std::unordered_map<uint32_t, std::vector<uint32_t>> spec_const_map; 1139bf215546Sopenharmony_ci for (unsigned i = 0; i < consts->num_specializations; ++i) { 1140bf215546Sopenharmony_ci unsigned id = consts->specializations[i].id; 1141bf215546Sopenharmony_ci auto parsed_spec_const = std::find_if(parsed_data->spec_constants, 1142bf215546Sopenharmony_ci parsed_data->spec_constants + parsed_data->num_spec_constants, 1143bf215546Sopenharmony_ci [id](const clc_parsed_spec_constant &c) { return c.id == id; }); 1144bf215546Sopenharmony_ci assert(parsed_spec_const != parsed_data->spec_constants + parsed_data->num_spec_constants); 1145bf215546Sopenharmony_ci 1146bf215546Sopenharmony_ci std::vector<uint32_t> words; 1147bf215546Sopenharmony_ci switch (parsed_spec_const->type) { 1148bf215546Sopenharmony_ci case CLC_SPEC_CONSTANT_BOOL: 1149bf215546Sopenharmony_ci words.push_back(consts->specializations[i].value.b); 1150bf215546Sopenharmony_ci break; 1151bf215546Sopenharmony_ci case CLC_SPEC_CONSTANT_INT32: 1152bf215546Sopenharmony_ci case CLC_SPEC_CONSTANT_UINT32: 1153bf215546Sopenharmony_ci case CLC_SPEC_CONSTANT_FLOAT: 1154bf215546Sopenharmony_ci words.push_back(consts->specializations[i].value.u32); 1155bf215546Sopenharmony_ci break; 1156bf215546Sopenharmony_ci case CLC_SPEC_CONSTANT_INT16: 1157bf215546Sopenharmony_ci words.push_back((uint32_t)(int32_t)consts->specializations[i].value.i16); 1158bf215546Sopenharmony_ci break; 1159bf215546Sopenharmony_ci case CLC_SPEC_CONSTANT_INT8: 1160bf215546Sopenharmony_ci words.push_back((uint32_t)(int32_t)consts->specializations[i].value.i8); 1161bf215546Sopenharmony_ci break; 1162bf215546Sopenharmony_ci case CLC_SPEC_CONSTANT_UINT16: 1163bf215546Sopenharmony_ci words.push_back((uint32_t)consts->specializations[i].value.u16); 1164bf215546Sopenharmony_ci break; 1165bf215546Sopenharmony_ci case CLC_SPEC_CONSTANT_UINT8: 1166bf215546Sopenharmony_ci words.push_back((uint32_t)consts->specializations[i].value.u8); 1167bf215546Sopenharmony_ci break; 1168bf215546Sopenharmony_ci case CLC_SPEC_CONSTANT_DOUBLE: 1169bf215546Sopenharmony_ci case CLC_SPEC_CONSTANT_INT64: 1170bf215546Sopenharmony_ci case CLC_SPEC_CONSTANT_UINT64: 1171bf215546Sopenharmony_ci words.resize(2); 1172bf215546Sopenharmony_ci memcpy(words.data(), &consts->specializations[i].value.u64, 8); 1173bf215546Sopenharmony_ci break; 1174bf215546Sopenharmony_ci case CLC_SPEC_CONSTANT_UNKNOWN: 1175bf215546Sopenharmony_ci assert(0); 1176bf215546Sopenharmony_ci break; 1177bf215546Sopenharmony_ci } 1178bf215546Sopenharmony_ci 1179bf215546Sopenharmony_ci ASSERTED auto ret = spec_const_map.emplace(id, std::move(words)); 1180bf215546Sopenharmony_ci assert(ret.second); 1181bf215546Sopenharmony_ci } 1182bf215546Sopenharmony_ci 1183bf215546Sopenharmony_ci spvtools::Optimizer opt(spirv_target); 1184bf215546Sopenharmony_ci opt.RegisterPass(spvtools::CreateSetSpecConstantDefaultValuePass(std::move(spec_const_map))); 1185bf215546Sopenharmony_ci 1186bf215546Sopenharmony_ci std::vector<uint32_t> result; 1187bf215546Sopenharmony_ci if (!opt.Run(static_cast<const uint32_t*>(in_spirv->data), in_spirv->size / 4, &result)) 1188bf215546Sopenharmony_ci return false; 1189bf215546Sopenharmony_ci 1190bf215546Sopenharmony_ci out_spirv->size = result.size() * 4; 1191bf215546Sopenharmony_ci out_spirv->data = malloc(out_spirv->size); 1192bf215546Sopenharmony_ci memcpy(out_spirv->data, result.data(), out_spirv->size); 1193bf215546Sopenharmony_ci return true; 1194bf215546Sopenharmony_ci} 1195bf215546Sopenharmony_ci 1196bf215546Sopenharmony_civoid 1197bf215546Sopenharmony_ciclc_dump_spirv(const struct clc_binary *spvbin, FILE *f) 1198bf215546Sopenharmony_ci{ 1199bf215546Sopenharmony_ci spvtools::SpirvTools tools(spirv_target); 1200bf215546Sopenharmony_ci const uint32_t *data = static_cast<const uint32_t *>(spvbin->data); 1201bf215546Sopenharmony_ci std::vector<uint32_t> bin(data, data + (spvbin->size / 4)); 1202bf215546Sopenharmony_ci std::string out; 1203bf215546Sopenharmony_ci tools.Disassemble(bin, &out, 1204bf215546Sopenharmony_ci SPV_BINARY_TO_TEXT_OPTION_INDENT | 1205bf215546Sopenharmony_ci SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); 1206bf215546Sopenharmony_ci fwrite(out.c_str(), out.size(), 1, f); 1207bf215546Sopenharmony_ci} 1208bf215546Sopenharmony_ci 1209bf215546Sopenharmony_civoid 1210bf215546Sopenharmony_ciclc_free_spir_binary(struct clc_binary *spir) 1211bf215546Sopenharmony_ci{ 1212bf215546Sopenharmony_ci free(spir->data); 1213bf215546Sopenharmony_ci} 1214bf215546Sopenharmony_ci 1215bf215546Sopenharmony_civoid 1216bf215546Sopenharmony_ciclc_free_spirv_binary(struct clc_binary *spvbin) 1217bf215546Sopenharmony_ci{ 1218bf215546Sopenharmony_ci free(spvbin->data); 1219bf215546Sopenharmony_ci} 1220bf215546Sopenharmony_ci 1221bf215546Sopenharmony_civoid 1222bf215546Sopenharmony_ciinitialize_llvm_once(void) 1223bf215546Sopenharmony_ci{ 1224bf215546Sopenharmony_ci LLVMInitializeAllTargets(); 1225bf215546Sopenharmony_ci LLVMInitializeAllTargetInfos(); 1226bf215546Sopenharmony_ci LLVMInitializeAllTargetMCs(); 1227bf215546Sopenharmony_ci LLVMInitializeAllAsmParsers(); 1228bf215546Sopenharmony_ci LLVMInitializeAllAsmPrinters(); 1229bf215546Sopenharmony_ci} 1230bf215546Sopenharmony_ci 1231bf215546Sopenharmony_cistd::once_flag initialize_llvm_once_flag; 1232bf215546Sopenharmony_ci 1233bf215546Sopenharmony_civoid 1234bf215546Sopenharmony_ciclc_initialize_llvm(void) 1235bf215546Sopenharmony_ci{ 1236bf215546Sopenharmony_ci std::call_once(initialize_llvm_once_flag, 1237bf215546Sopenharmony_ci []() { initialize_llvm_once(); }); 1238bf215546Sopenharmony_ci} 1239