17ec681f3Smrg// 27ec681f3Smrg// Copyright 2012-2016 Francisco Jerez 37ec681f3Smrg// Copyright 2012-2016 Advanced Micro Devices, Inc. 47ec681f3Smrg// Copyright 2014-2016 Jan Vesely 57ec681f3Smrg// Copyright 2014-2015 Serge Martin 67ec681f3Smrg// Copyright 2015 Zoltan Gilian 77ec681f3Smrg// 87ec681f3Smrg// Permission is hereby granted, free of charge, to any person obtaining a 97ec681f3Smrg// copy of this software and associated documentation files (the "Software"), 107ec681f3Smrg// to deal in the Software without restriction, including without limitation 117ec681f3Smrg// the rights to use, copy, modify, merge, publish, distribute, sublicense, 127ec681f3Smrg// and/or sell copies of the Software, and to permit persons to whom the 137ec681f3Smrg// Software is furnished to do so, subject to the following conditions: 147ec681f3Smrg// 157ec681f3Smrg// The above copyright notice and this permission notice shall be included in 167ec681f3Smrg// all copies or substantial portions of the Software. 177ec681f3Smrg// 187ec681f3Smrg// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 197ec681f3Smrg// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 207ec681f3Smrg// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 217ec681f3Smrg// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 227ec681f3Smrg// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 237ec681f3Smrg// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 247ec681f3Smrg// OTHER DEALINGS IN THE SOFTWARE. 257ec681f3Smrg 267ec681f3Smrg#include <sstream> 277ec681f3Smrg 287ec681f3Smrg#include <llvm/ADT/ArrayRef.h> 297ec681f3Smrg#include <llvm/IR/DiagnosticPrinter.h> 307ec681f3Smrg#include <llvm/IR/DiagnosticInfo.h> 317ec681f3Smrg#include <llvm/IR/LLVMContext.h> 327ec681f3Smrg#include <llvm/IR/Type.h> 337ec681f3Smrg#include <llvm/Support/raw_ostream.h> 347ec681f3Smrg#include <llvm/Bitcode/BitcodeWriter.h> 357ec681f3Smrg#include <llvm/Bitcode/BitcodeReader.h> 367ec681f3Smrg#include <llvm-c/Core.h> 377ec681f3Smrg#include <llvm-c/Target.h> 387ec681f3Smrg#include <LLVMSPIRVLib/LLVMSPIRVLib.h> 397ec681f3Smrg 407ec681f3Smrg#include <clang/CodeGen/CodeGenAction.h> 417ec681f3Smrg#include <clang/Lex/PreprocessorOptions.h> 427ec681f3Smrg#include <clang/Frontend/CompilerInstance.h> 437ec681f3Smrg#include <clang/Frontend/TextDiagnosticBuffer.h> 447ec681f3Smrg#include <clang/Frontend/TextDiagnosticPrinter.h> 457ec681f3Smrg#include <clang/Basic/TargetInfo.h> 467ec681f3Smrg 477ec681f3Smrg#include <spirv-tools/libspirv.hpp> 487ec681f3Smrg#include <spirv-tools/linker.hpp> 497ec681f3Smrg#include <spirv-tools/optimizer.hpp> 507ec681f3Smrg 517ec681f3Smrg#include "util/macros.h" 527ec681f3Smrg#include "glsl_types.h" 537ec681f3Smrg 547ec681f3Smrg#include "spirv.h" 557ec681f3Smrg 567ec681f3Smrg#ifdef USE_STATIC_OPENCL_C_H 577ec681f3Smrg#include "opencl-c.h.h" 587ec681f3Smrg#include "opencl-c-base.h.h" 597ec681f3Smrg#endif 607ec681f3Smrg 617ec681f3Smrg#include "clc_helpers.h" 627ec681f3Smrg 637ec681f3Smrg/* Use the highest version of SPIRV supported by SPIRV-Tools. */ 647ec681f3Smrgconstexpr spv_target_env spirv_target = SPV_ENV_UNIVERSAL_1_5; 657ec681f3Smrg 667ec681f3Smrgconstexpr SPIRV::VersionNumber invalid_spirv_trans_version = static_cast<SPIRV::VersionNumber>(0); 677ec681f3Smrg 687ec681f3Smrgusing ::llvm::Function; 697ec681f3Smrgusing ::llvm::LLVMContext; 707ec681f3Smrgusing ::llvm::Module; 717ec681f3Smrgusing ::llvm::raw_string_ostream; 727ec681f3Smrg 737ec681f3Smrgstatic void 747ec681f3Smrgllvm_log_handler(const ::llvm::DiagnosticInfo &di, void *data) { 757ec681f3Smrg raw_string_ostream os { *reinterpret_cast<std::string *>(data) }; 767ec681f3Smrg ::llvm::DiagnosticPrinterRawOStream printer { os }; 777ec681f3Smrg di.print(printer); 787ec681f3Smrg} 797ec681f3Smrg 807ec681f3Smrgclass SPIRVKernelArg { 817ec681f3Smrgpublic: 827ec681f3Smrg SPIRVKernelArg(uint32_t id, uint32_t typeId) : id(id), typeId(typeId), 837ec681f3Smrg addrQualifier(CLC_KERNEL_ARG_ADDRESS_PRIVATE), 847ec681f3Smrg accessQualifier(0), 857ec681f3Smrg typeQualifier(0) { } 867ec681f3Smrg ~SPIRVKernelArg() { } 877ec681f3Smrg 887ec681f3Smrg uint32_t id; 897ec681f3Smrg uint32_t typeId; 907ec681f3Smrg std::string name; 917ec681f3Smrg std::string typeName; 927ec681f3Smrg enum clc_kernel_arg_address_qualifier addrQualifier; 937ec681f3Smrg unsigned accessQualifier; 947ec681f3Smrg unsigned typeQualifier; 957ec681f3Smrg}; 967ec681f3Smrg 977ec681f3Smrgclass SPIRVKernelInfo { 987ec681f3Smrgpublic: 997ec681f3Smrg SPIRVKernelInfo(uint32_t fid, const char *nm) : funcId(fid), name(nm), vecHint(0) { } 1007ec681f3Smrg ~SPIRVKernelInfo() { } 1017ec681f3Smrg 1027ec681f3Smrg uint32_t funcId; 1037ec681f3Smrg std::string name; 1047ec681f3Smrg std::vector<SPIRVKernelArg> args; 1057ec681f3Smrg unsigned vecHint; 1067ec681f3Smrg}; 1077ec681f3Smrg 1087ec681f3Smrgclass SPIRVKernelParser { 1097ec681f3Smrgpublic: 1107ec681f3Smrg SPIRVKernelParser() : curKernel(NULL) 1117ec681f3Smrg { 1127ec681f3Smrg ctx = spvContextCreate(spirv_target); 1137ec681f3Smrg } 1147ec681f3Smrg 1157ec681f3Smrg ~SPIRVKernelParser() 1167ec681f3Smrg { 1177ec681f3Smrg spvContextDestroy(ctx); 1187ec681f3Smrg } 1197ec681f3Smrg 1207ec681f3Smrg void parseEntryPoint(const spv_parsed_instruction_t *ins) 1217ec681f3Smrg { 1227ec681f3Smrg assert(ins->num_operands >= 3); 1237ec681f3Smrg 1247ec681f3Smrg const spv_parsed_operand_t *op = &ins->operands[1]; 1257ec681f3Smrg 1267ec681f3Smrg assert(op->type == SPV_OPERAND_TYPE_ID); 1277ec681f3Smrg 1287ec681f3Smrg uint32_t funcId = ins->words[op->offset]; 1297ec681f3Smrg 1307ec681f3Smrg for (auto &iter : kernels) { 1317ec681f3Smrg if (funcId == iter.funcId) 1327ec681f3Smrg return; 1337ec681f3Smrg } 1347ec681f3Smrg 1357ec681f3Smrg op = &ins->operands[2]; 1367ec681f3Smrg assert(op->type == SPV_OPERAND_TYPE_LITERAL_STRING); 1377ec681f3Smrg const char *name = reinterpret_cast<const char *>(ins->words + op->offset); 1387ec681f3Smrg 1397ec681f3Smrg kernels.push_back(SPIRVKernelInfo(funcId, name)); 1407ec681f3Smrg } 1417ec681f3Smrg 1427ec681f3Smrg void parseFunction(const spv_parsed_instruction_t *ins) 1437ec681f3Smrg { 1447ec681f3Smrg assert(ins->num_operands == 4); 1457ec681f3Smrg 1467ec681f3Smrg const spv_parsed_operand_t *op = &ins->operands[1]; 1477ec681f3Smrg 1487ec681f3Smrg assert(op->type == SPV_OPERAND_TYPE_RESULT_ID); 1497ec681f3Smrg 1507ec681f3Smrg uint32_t funcId = ins->words[op->offset]; 1517ec681f3Smrg 1527ec681f3Smrg for (auto &kernel : kernels) { 1537ec681f3Smrg if (funcId == kernel.funcId && !kernel.args.size()) { 1547ec681f3Smrg curKernel = &kernel; 1557ec681f3Smrg return; 1567ec681f3Smrg } 1577ec681f3Smrg } 1587ec681f3Smrg } 1597ec681f3Smrg 1607ec681f3Smrg void parseFunctionParam(const spv_parsed_instruction_t *ins) 1617ec681f3Smrg { 1627ec681f3Smrg const spv_parsed_operand_t *op; 1637ec681f3Smrg uint32_t id, typeId; 1647ec681f3Smrg 1657ec681f3Smrg if (!curKernel) 1667ec681f3Smrg return; 1677ec681f3Smrg 1687ec681f3Smrg assert(ins->num_operands == 2); 1697ec681f3Smrg op = &ins->operands[0]; 1707ec681f3Smrg assert(op->type == SPV_OPERAND_TYPE_TYPE_ID); 1717ec681f3Smrg typeId = ins->words[op->offset]; 1727ec681f3Smrg op = &ins->operands[1]; 1737ec681f3Smrg assert(op->type == SPV_OPERAND_TYPE_RESULT_ID); 1747ec681f3Smrg id = ins->words[op->offset]; 1757ec681f3Smrg curKernel->args.push_back(SPIRVKernelArg(id, typeId)); 1767ec681f3Smrg } 1777ec681f3Smrg 1787ec681f3Smrg void parseName(const spv_parsed_instruction_t *ins) 1797ec681f3Smrg { 1807ec681f3Smrg const spv_parsed_operand_t *op; 1817ec681f3Smrg const char *name; 1827ec681f3Smrg uint32_t id; 1837ec681f3Smrg 1847ec681f3Smrg assert(ins->num_operands == 2); 1857ec681f3Smrg 1867ec681f3Smrg op = &ins->operands[0]; 1877ec681f3Smrg assert(op->type == SPV_OPERAND_TYPE_ID); 1887ec681f3Smrg id = ins->words[op->offset]; 1897ec681f3Smrg op = &ins->operands[1]; 1907ec681f3Smrg assert(op->type == SPV_OPERAND_TYPE_LITERAL_STRING); 1917ec681f3Smrg name = reinterpret_cast<const char *>(ins->words + op->offset); 1927ec681f3Smrg 1937ec681f3Smrg for (auto &kernel : kernels) { 1947ec681f3Smrg for (auto &arg : kernel.args) { 1957ec681f3Smrg if (arg.id == id && arg.name.empty()) { 1967ec681f3Smrg arg.name = name; 1977ec681f3Smrg break; 1987ec681f3Smrg } 1997ec681f3Smrg } 2007ec681f3Smrg } 2017ec681f3Smrg } 2027ec681f3Smrg 2037ec681f3Smrg void parseTypePointer(const spv_parsed_instruction_t *ins) 2047ec681f3Smrg { 2057ec681f3Smrg enum clc_kernel_arg_address_qualifier addrQualifier; 2067ec681f3Smrg uint32_t typeId, storageClass; 2077ec681f3Smrg const spv_parsed_operand_t *op; 2087ec681f3Smrg 2097ec681f3Smrg assert(ins->num_operands == 3); 2107ec681f3Smrg 2117ec681f3Smrg op = &ins->operands[0]; 2127ec681f3Smrg assert(op->type == SPV_OPERAND_TYPE_RESULT_ID); 2137ec681f3Smrg typeId = ins->words[op->offset]; 2147ec681f3Smrg 2157ec681f3Smrg op = &ins->operands[1]; 2167ec681f3Smrg assert(op->type == SPV_OPERAND_TYPE_STORAGE_CLASS); 2177ec681f3Smrg storageClass = ins->words[op->offset]; 2187ec681f3Smrg switch (storageClass) { 2197ec681f3Smrg case SpvStorageClassCrossWorkgroup: 2207ec681f3Smrg addrQualifier = CLC_KERNEL_ARG_ADDRESS_GLOBAL; 2217ec681f3Smrg break; 2227ec681f3Smrg case SpvStorageClassWorkgroup: 2237ec681f3Smrg addrQualifier = CLC_KERNEL_ARG_ADDRESS_LOCAL; 2247ec681f3Smrg break; 2257ec681f3Smrg case SpvStorageClassUniformConstant: 2267ec681f3Smrg addrQualifier = CLC_KERNEL_ARG_ADDRESS_CONSTANT; 2277ec681f3Smrg break; 2287ec681f3Smrg default: 2297ec681f3Smrg addrQualifier = CLC_KERNEL_ARG_ADDRESS_PRIVATE; 2307ec681f3Smrg break; 2317ec681f3Smrg } 2327ec681f3Smrg 2337ec681f3Smrg for (auto &kernel : kernels) { 2347ec681f3Smrg for (auto &arg : kernel.args) { 2357ec681f3Smrg if (arg.typeId == typeId) 2367ec681f3Smrg arg.addrQualifier = addrQualifier; 2377ec681f3Smrg } 2387ec681f3Smrg } 2397ec681f3Smrg } 2407ec681f3Smrg 2417ec681f3Smrg void parseOpString(const spv_parsed_instruction_t *ins) 2427ec681f3Smrg { 2437ec681f3Smrg const spv_parsed_operand_t *op; 2447ec681f3Smrg std::string str; 2457ec681f3Smrg 2467ec681f3Smrg assert(ins->num_operands == 2); 2477ec681f3Smrg 2487ec681f3Smrg op = &ins->operands[1]; 2497ec681f3Smrg assert(op->type == SPV_OPERAND_TYPE_LITERAL_STRING); 2507ec681f3Smrg str = reinterpret_cast<const char *>(ins->words + op->offset); 2517ec681f3Smrg 2527ec681f3Smrg if (str.find("kernel_arg_type.") != 0) 2537ec681f3Smrg return; 2547ec681f3Smrg 2557ec681f3Smrg size_t start = sizeof("kernel_arg_type.") - 1; 2567ec681f3Smrg 2577ec681f3Smrg for (auto &kernel : kernels) { 2587ec681f3Smrg size_t pos; 2597ec681f3Smrg 2607ec681f3Smrg pos = str.find(kernel.name, start); 2617ec681f3Smrg if (pos == std::string::npos || 2627ec681f3Smrg pos != start || str[start + kernel.name.size()] != '.') 2637ec681f3Smrg continue; 2647ec681f3Smrg 2657ec681f3Smrg pos = start + kernel.name.size(); 2667ec681f3Smrg if (str[pos++] != '.') 2677ec681f3Smrg continue; 2687ec681f3Smrg 2697ec681f3Smrg for (auto &arg : kernel.args) { 2707ec681f3Smrg if (arg.name.empty()) 2717ec681f3Smrg break; 2727ec681f3Smrg 2737ec681f3Smrg size_t typeEnd = str.find(',', pos); 2747ec681f3Smrg if (typeEnd == std::string::npos) 2757ec681f3Smrg break; 2767ec681f3Smrg 2777ec681f3Smrg arg.typeName = str.substr(pos, typeEnd - pos); 2787ec681f3Smrg pos = typeEnd + 1; 2797ec681f3Smrg } 2807ec681f3Smrg } 2817ec681f3Smrg } 2827ec681f3Smrg 2837ec681f3Smrg void applyDecoration(uint32_t id, const spv_parsed_instruction_t *ins) 2847ec681f3Smrg { 2857ec681f3Smrg auto iter = decorationGroups.find(id); 2867ec681f3Smrg if (iter != decorationGroups.end()) { 2877ec681f3Smrg for (uint32_t entry : iter->second) 2887ec681f3Smrg applyDecoration(entry, ins); 2897ec681f3Smrg return; 2907ec681f3Smrg } 2917ec681f3Smrg 2927ec681f3Smrg const spv_parsed_operand_t *op; 2937ec681f3Smrg uint32_t decoration; 2947ec681f3Smrg 2957ec681f3Smrg assert(ins->num_operands >= 2); 2967ec681f3Smrg 2977ec681f3Smrg op = &ins->operands[1]; 2987ec681f3Smrg assert(op->type == SPV_OPERAND_TYPE_DECORATION); 2997ec681f3Smrg decoration = ins->words[op->offset]; 3007ec681f3Smrg 3017ec681f3Smrg if (decoration == SpvDecorationSpecId) { 3027ec681f3Smrg uint32_t spec_id = ins->words[ins->operands[2].offset]; 3037ec681f3Smrg for (auto &c : specConstants) { 3047ec681f3Smrg if (c.second.id == spec_id) { 3057ec681f3Smrg assert(c.first == id); 3067ec681f3Smrg return; 3077ec681f3Smrg } 3087ec681f3Smrg } 3097ec681f3Smrg specConstants.emplace_back(id, clc_parsed_spec_constant{ spec_id }); 3107ec681f3Smrg return; 3117ec681f3Smrg } 3127ec681f3Smrg 3137ec681f3Smrg for (auto &kernel : kernels) { 3147ec681f3Smrg for (auto &arg : kernel.args) { 3157ec681f3Smrg if (arg.id == id) { 3167ec681f3Smrg switch (decoration) { 3177ec681f3Smrg case SpvDecorationVolatile: 3187ec681f3Smrg arg.typeQualifier |= CLC_KERNEL_ARG_TYPE_VOLATILE; 3197ec681f3Smrg break; 3207ec681f3Smrg case SpvDecorationConstant: 3217ec681f3Smrg arg.typeQualifier |= CLC_KERNEL_ARG_TYPE_CONST; 3227ec681f3Smrg break; 3237ec681f3Smrg case SpvDecorationRestrict: 3247ec681f3Smrg arg.typeQualifier |= CLC_KERNEL_ARG_TYPE_RESTRICT; 3257ec681f3Smrg break; 3267ec681f3Smrg case SpvDecorationFuncParamAttr: 3277ec681f3Smrg op = &ins->operands[2]; 3287ec681f3Smrg assert(op->type == SPV_OPERAND_TYPE_FUNCTION_PARAMETER_ATTRIBUTE); 3297ec681f3Smrg switch (ins->words[op->offset]) { 3307ec681f3Smrg case SpvFunctionParameterAttributeNoAlias: 3317ec681f3Smrg arg.typeQualifier |= CLC_KERNEL_ARG_TYPE_RESTRICT; 3327ec681f3Smrg break; 3337ec681f3Smrg case SpvFunctionParameterAttributeNoWrite: 3347ec681f3Smrg arg.typeQualifier |= CLC_KERNEL_ARG_TYPE_CONST; 3357ec681f3Smrg break; 3367ec681f3Smrg } 3377ec681f3Smrg break; 3387ec681f3Smrg } 3397ec681f3Smrg } 3407ec681f3Smrg 3417ec681f3Smrg } 3427ec681f3Smrg } 3437ec681f3Smrg } 3447ec681f3Smrg 3457ec681f3Smrg void parseOpDecorate(const spv_parsed_instruction_t *ins) 3467ec681f3Smrg { 3477ec681f3Smrg const spv_parsed_operand_t *op; 3487ec681f3Smrg uint32_t id; 3497ec681f3Smrg 3507ec681f3Smrg assert(ins->num_operands >= 2); 3517ec681f3Smrg 3527ec681f3Smrg op = &ins->operands[0]; 3537ec681f3Smrg assert(op->type == SPV_OPERAND_TYPE_ID); 3547ec681f3Smrg id = ins->words[op->offset]; 3557ec681f3Smrg 3567ec681f3Smrg applyDecoration(id, ins); 3577ec681f3Smrg } 3587ec681f3Smrg 3597ec681f3Smrg void parseOpGroupDecorate(const spv_parsed_instruction_t *ins) 3607ec681f3Smrg { 3617ec681f3Smrg assert(ins->num_operands >= 2); 3627ec681f3Smrg 3637ec681f3Smrg const spv_parsed_operand_t *op = &ins->operands[0]; 3647ec681f3Smrg assert(op->type == SPV_OPERAND_TYPE_ID); 3657ec681f3Smrg uint32_t groupId = ins->words[op->offset]; 3667ec681f3Smrg 3677ec681f3Smrg auto lowerBound = decorationGroups.lower_bound(groupId); 3687ec681f3Smrg if (lowerBound != decorationGroups.end() && 3697ec681f3Smrg lowerBound->first == groupId) 3707ec681f3Smrg // Group already filled out 3717ec681f3Smrg return; 3727ec681f3Smrg 3737ec681f3Smrg auto iter = decorationGroups.emplace_hint(lowerBound, groupId, std::vector<uint32_t>{}); 3747ec681f3Smrg auto& vec = iter->second; 3757ec681f3Smrg vec.reserve(ins->num_operands - 1); 3767ec681f3Smrg for (uint32_t i = 1; i < ins->num_operands; ++i) { 3777ec681f3Smrg op = &ins->operands[i]; 3787ec681f3Smrg assert(op->type == SPV_OPERAND_TYPE_ID); 3797ec681f3Smrg vec.push_back(ins->words[op->offset]); 3807ec681f3Smrg } 3817ec681f3Smrg } 3827ec681f3Smrg 3837ec681f3Smrg void parseOpTypeImage(const spv_parsed_instruction_t *ins) 3847ec681f3Smrg { 3857ec681f3Smrg const spv_parsed_operand_t *op; 3867ec681f3Smrg uint32_t typeId; 3877ec681f3Smrg unsigned accessQualifier = CLC_KERNEL_ARG_ACCESS_READ; 3887ec681f3Smrg 3897ec681f3Smrg op = &ins->operands[0]; 3907ec681f3Smrg assert(op->type == SPV_OPERAND_TYPE_RESULT_ID); 3917ec681f3Smrg typeId = ins->words[op->offset]; 3927ec681f3Smrg 3937ec681f3Smrg if (ins->num_operands >= 9) { 3947ec681f3Smrg op = &ins->operands[8]; 3957ec681f3Smrg assert(op->type == SPV_OPERAND_TYPE_ACCESS_QUALIFIER); 3967ec681f3Smrg switch (ins->words[op->offset]) { 3977ec681f3Smrg case SpvAccessQualifierReadOnly: 3987ec681f3Smrg accessQualifier = CLC_KERNEL_ARG_ACCESS_READ; 3997ec681f3Smrg break; 4007ec681f3Smrg case SpvAccessQualifierWriteOnly: 4017ec681f3Smrg accessQualifier = CLC_KERNEL_ARG_ACCESS_WRITE; 4027ec681f3Smrg break; 4037ec681f3Smrg case SpvAccessQualifierReadWrite: 4047ec681f3Smrg accessQualifier = CLC_KERNEL_ARG_ACCESS_WRITE | 4057ec681f3Smrg CLC_KERNEL_ARG_ACCESS_READ; 4067ec681f3Smrg break; 4077ec681f3Smrg } 4087ec681f3Smrg } 4097ec681f3Smrg 4107ec681f3Smrg for (auto &kernel : kernels) { 4117ec681f3Smrg for (auto &arg : kernel.args) { 4127ec681f3Smrg if (arg.typeId == typeId) { 4137ec681f3Smrg arg.accessQualifier = accessQualifier; 4147ec681f3Smrg arg.addrQualifier = CLC_KERNEL_ARG_ADDRESS_GLOBAL; 4157ec681f3Smrg } 4167ec681f3Smrg } 4177ec681f3Smrg } 4187ec681f3Smrg } 4197ec681f3Smrg 4207ec681f3Smrg void parseExecutionMode(const spv_parsed_instruction_t *ins) 4217ec681f3Smrg { 4227ec681f3Smrg uint32_t executionMode = ins->words[ins->operands[1].offset]; 4237ec681f3Smrg if (executionMode != SpvExecutionModeVecTypeHint) 4247ec681f3Smrg return; 4257ec681f3Smrg 4267ec681f3Smrg uint32_t funcId = ins->words[ins->operands[0].offset]; 4277ec681f3Smrg uint32_t vecHint = ins->words[ins->operands[2].offset]; 4287ec681f3Smrg for (auto& kernel : kernels) { 4297ec681f3Smrg if (kernel.funcId == funcId) 4307ec681f3Smrg kernel.vecHint = vecHint; 4317ec681f3Smrg } 4327ec681f3Smrg } 4337ec681f3Smrg 4347ec681f3Smrg void parseLiteralType(const spv_parsed_instruction_t *ins) 4357ec681f3Smrg { 4367ec681f3Smrg uint32_t typeId = ins->words[ins->operands[0].offset]; 4377ec681f3Smrg auto& literalType = literalTypes[typeId]; 4387ec681f3Smrg switch (ins->opcode) { 4397ec681f3Smrg case SpvOpTypeBool: 4407ec681f3Smrg literalType = CLC_SPEC_CONSTANT_BOOL; 4417ec681f3Smrg break; 4427ec681f3Smrg case SpvOpTypeFloat: { 4437ec681f3Smrg uint32_t sizeInBits = ins->words[ins->operands[1].offset]; 4447ec681f3Smrg switch (sizeInBits) { 4457ec681f3Smrg case 32: 4467ec681f3Smrg literalType = CLC_SPEC_CONSTANT_FLOAT; 4477ec681f3Smrg break; 4487ec681f3Smrg case 64: 4497ec681f3Smrg literalType = CLC_SPEC_CONSTANT_DOUBLE; 4507ec681f3Smrg break; 4517ec681f3Smrg case 16: 4527ec681f3Smrg /* Can't be used for a spec constant */ 4537ec681f3Smrg break; 4547ec681f3Smrg default: 4557ec681f3Smrg unreachable("Unexpected float bit size"); 4567ec681f3Smrg } 4577ec681f3Smrg break; 4587ec681f3Smrg } 4597ec681f3Smrg case SpvOpTypeInt: { 4607ec681f3Smrg uint32_t sizeInBits = ins->words[ins->operands[1].offset]; 4617ec681f3Smrg bool isSigned = ins->words[ins->operands[2].offset]; 4627ec681f3Smrg if (isSigned) { 4637ec681f3Smrg switch (sizeInBits) { 4647ec681f3Smrg case 8: 4657ec681f3Smrg literalType = CLC_SPEC_CONSTANT_INT8; 4667ec681f3Smrg break; 4677ec681f3Smrg case 16: 4687ec681f3Smrg literalType = CLC_SPEC_CONSTANT_INT16; 4697ec681f3Smrg break; 4707ec681f3Smrg case 32: 4717ec681f3Smrg literalType = CLC_SPEC_CONSTANT_INT32; 4727ec681f3Smrg break; 4737ec681f3Smrg case 64: 4747ec681f3Smrg literalType = CLC_SPEC_CONSTANT_INT64; 4757ec681f3Smrg break; 4767ec681f3Smrg default: 4777ec681f3Smrg unreachable("Unexpected int bit size"); 4787ec681f3Smrg } 4797ec681f3Smrg } else { 4807ec681f3Smrg switch (sizeInBits) { 4817ec681f3Smrg case 8: 4827ec681f3Smrg literalType = CLC_SPEC_CONSTANT_UINT8; 4837ec681f3Smrg break; 4847ec681f3Smrg case 16: 4857ec681f3Smrg literalType = CLC_SPEC_CONSTANT_UINT16; 4867ec681f3Smrg break; 4877ec681f3Smrg case 32: 4887ec681f3Smrg literalType = CLC_SPEC_CONSTANT_UINT32; 4897ec681f3Smrg break; 4907ec681f3Smrg case 64: 4917ec681f3Smrg literalType = CLC_SPEC_CONSTANT_UINT64; 4927ec681f3Smrg break; 4937ec681f3Smrg default: 4947ec681f3Smrg unreachable("Unexpected uint bit size"); 4957ec681f3Smrg } 4967ec681f3Smrg } 4977ec681f3Smrg break; 4987ec681f3Smrg } 4997ec681f3Smrg default: 5007ec681f3Smrg unreachable("Unexpected type opcode"); 5017ec681f3Smrg } 5027ec681f3Smrg } 5037ec681f3Smrg 5047ec681f3Smrg void parseSpecConstant(const spv_parsed_instruction_t *ins) 5057ec681f3Smrg { 5067ec681f3Smrg uint32_t id = ins->result_id; 5077ec681f3Smrg for (auto& c : specConstants) { 5087ec681f3Smrg if (c.first == id) { 5097ec681f3Smrg auto& data = c.second; 5107ec681f3Smrg switch (ins->opcode) { 5117ec681f3Smrg case SpvOpSpecConstant: { 5127ec681f3Smrg uint32_t typeId = ins->words[ins->operands[0].offset]; 5137ec681f3Smrg 5147ec681f3Smrg // This better be an integer or float type 5157ec681f3Smrg auto typeIter = literalTypes.find(typeId); 5167ec681f3Smrg assert(typeIter != literalTypes.end()); 5177ec681f3Smrg 5187ec681f3Smrg data.type = typeIter->second; 5197ec681f3Smrg break; 5207ec681f3Smrg } 5217ec681f3Smrg case SpvOpSpecConstantFalse: 5227ec681f3Smrg case SpvOpSpecConstantTrue: 5237ec681f3Smrg data.type = CLC_SPEC_CONSTANT_BOOL; 5247ec681f3Smrg break; 5257ec681f3Smrg default: 5267ec681f3Smrg unreachable("Composites and Ops are not directly specializable."); 5277ec681f3Smrg } 5287ec681f3Smrg } 5297ec681f3Smrg } 5307ec681f3Smrg } 5317ec681f3Smrg 5327ec681f3Smrg static spv_result_t 5337ec681f3Smrg parseInstruction(void *data, const spv_parsed_instruction_t *ins) 5347ec681f3Smrg { 5357ec681f3Smrg SPIRVKernelParser *parser = reinterpret_cast<SPIRVKernelParser *>(data); 5367ec681f3Smrg 5377ec681f3Smrg switch (ins->opcode) { 5387ec681f3Smrg case SpvOpName: 5397ec681f3Smrg parser->parseName(ins); 5407ec681f3Smrg break; 5417ec681f3Smrg case SpvOpEntryPoint: 5427ec681f3Smrg parser->parseEntryPoint(ins); 5437ec681f3Smrg break; 5447ec681f3Smrg case SpvOpFunction: 5457ec681f3Smrg parser->parseFunction(ins); 5467ec681f3Smrg break; 5477ec681f3Smrg case SpvOpFunctionParameter: 5487ec681f3Smrg parser->parseFunctionParam(ins); 5497ec681f3Smrg break; 5507ec681f3Smrg case SpvOpFunctionEnd: 5517ec681f3Smrg case SpvOpLabel: 5527ec681f3Smrg parser->curKernel = NULL; 5537ec681f3Smrg break; 5547ec681f3Smrg case SpvOpTypePointer: 5557ec681f3Smrg parser->parseTypePointer(ins); 5567ec681f3Smrg break; 5577ec681f3Smrg case SpvOpTypeImage: 5587ec681f3Smrg parser->parseOpTypeImage(ins); 5597ec681f3Smrg break; 5607ec681f3Smrg case SpvOpString: 5617ec681f3Smrg parser->parseOpString(ins); 5627ec681f3Smrg break; 5637ec681f3Smrg case SpvOpDecorate: 5647ec681f3Smrg parser->parseOpDecorate(ins); 5657ec681f3Smrg break; 5667ec681f3Smrg case SpvOpGroupDecorate: 5677ec681f3Smrg parser->parseOpGroupDecorate(ins); 5687ec681f3Smrg break; 5697ec681f3Smrg case SpvOpExecutionMode: 5707ec681f3Smrg parser->parseExecutionMode(ins); 5717ec681f3Smrg break; 5727ec681f3Smrg case SpvOpTypeBool: 5737ec681f3Smrg case SpvOpTypeInt: 5747ec681f3Smrg case SpvOpTypeFloat: 5757ec681f3Smrg parser->parseLiteralType(ins); 5767ec681f3Smrg break; 5777ec681f3Smrg case SpvOpSpecConstant: 5787ec681f3Smrg case SpvOpSpecConstantFalse: 5797ec681f3Smrg case SpvOpSpecConstantTrue: 5807ec681f3Smrg parser->parseSpecConstant(ins); 5817ec681f3Smrg break; 5827ec681f3Smrg default: 5837ec681f3Smrg break; 5847ec681f3Smrg } 5857ec681f3Smrg 5867ec681f3Smrg return SPV_SUCCESS; 5877ec681f3Smrg } 5887ec681f3Smrg 5897ec681f3Smrg bool parsingComplete() 5907ec681f3Smrg { 5917ec681f3Smrg for (auto &kernel : kernels) { 5927ec681f3Smrg if (kernel.name.empty()) 5937ec681f3Smrg return false; 5947ec681f3Smrg 5957ec681f3Smrg for (auto &arg : kernel.args) { 5967ec681f3Smrg if (arg.name.empty() || arg.typeName.empty()) 5977ec681f3Smrg return false; 5987ec681f3Smrg } 5997ec681f3Smrg } 6007ec681f3Smrg 6017ec681f3Smrg return true; 6027ec681f3Smrg } 6037ec681f3Smrg 6047ec681f3Smrg bool parseBinary(const struct clc_binary &spvbin, const struct clc_logger *logger) 6057ec681f3Smrg { 6067ec681f3Smrg /* 3 passes should be enough to retrieve all kernel information: 6077ec681f3Smrg * 1st pass: all entry point name and number of args 6087ec681f3Smrg * 2nd pass: argument names and type names 6097ec681f3Smrg * 3rd pass: pointer type names 6107ec681f3Smrg */ 6117ec681f3Smrg for (unsigned pass = 0; pass < 3; pass++) { 6127ec681f3Smrg spv_diagnostic diagnostic = NULL; 6137ec681f3Smrg auto result = spvBinaryParse(ctx, reinterpret_cast<void *>(this), 6147ec681f3Smrg static_cast<uint32_t*>(spvbin.data), spvbin.size / 4, 6157ec681f3Smrg NULL, parseInstruction, &diagnostic); 6167ec681f3Smrg 6177ec681f3Smrg if (result != SPV_SUCCESS) { 6187ec681f3Smrg if (diagnostic && logger) 6197ec681f3Smrg logger->error(logger->priv, diagnostic->error); 6207ec681f3Smrg return false; 6217ec681f3Smrg } 6227ec681f3Smrg 6237ec681f3Smrg if (parsingComplete()) 6247ec681f3Smrg return true; 6257ec681f3Smrg } 6267ec681f3Smrg 6277ec681f3Smrg assert(0); 6287ec681f3Smrg return false; 6297ec681f3Smrg } 6307ec681f3Smrg 6317ec681f3Smrg std::vector<SPIRVKernelInfo> kernels; 6327ec681f3Smrg std::vector<std::pair<uint32_t, clc_parsed_spec_constant>> specConstants; 6337ec681f3Smrg std::map<uint32_t, enum clc_spec_constant_type> literalTypes; 6347ec681f3Smrg std::map<uint32_t, std::vector<uint32_t>> decorationGroups; 6357ec681f3Smrg SPIRVKernelInfo *curKernel; 6367ec681f3Smrg spv_context ctx; 6377ec681f3Smrg}; 6387ec681f3Smrg 6397ec681f3Smrgbool 6407ec681f3Smrgclc_spirv_get_kernels_info(const struct clc_binary *spvbin, 6417ec681f3Smrg const struct clc_kernel_info **out_kernels, 6427ec681f3Smrg unsigned *num_kernels, 6437ec681f3Smrg const struct clc_parsed_spec_constant **out_spec_constants, 6447ec681f3Smrg unsigned *num_spec_constants, 6457ec681f3Smrg const struct clc_logger *logger) 6467ec681f3Smrg{ 6477ec681f3Smrg struct clc_kernel_info *kernels; 6487ec681f3Smrg struct clc_parsed_spec_constant *spec_constants = NULL; 6497ec681f3Smrg 6507ec681f3Smrg SPIRVKernelParser parser; 6517ec681f3Smrg 6527ec681f3Smrg if (!parser.parseBinary(*spvbin, logger)) 6537ec681f3Smrg return false; 6547ec681f3Smrg 6557ec681f3Smrg *num_kernels = parser.kernels.size(); 6567ec681f3Smrg *num_spec_constants = parser.specConstants.size(); 6577ec681f3Smrg if (!*num_kernels) 6587ec681f3Smrg return false; 6597ec681f3Smrg 6607ec681f3Smrg kernels = reinterpret_cast<struct clc_kernel_info *>(calloc(*num_kernels, 6617ec681f3Smrg sizeof(*kernels))); 6627ec681f3Smrg assert(kernels); 6637ec681f3Smrg for (unsigned i = 0; i < parser.kernels.size(); i++) { 6647ec681f3Smrg kernels[i].name = strdup(parser.kernels[i].name.c_str()); 6657ec681f3Smrg kernels[i].num_args = parser.kernels[i].args.size(); 6667ec681f3Smrg kernels[i].vec_hint_size = parser.kernels[i].vecHint >> 16; 6677ec681f3Smrg kernels[i].vec_hint_type = (enum clc_vec_hint_type)(parser.kernels[i].vecHint & 0xFFFF); 6687ec681f3Smrg if (!kernels[i].num_args) 6697ec681f3Smrg continue; 6707ec681f3Smrg 6717ec681f3Smrg struct clc_kernel_arg *args; 6727ec681f3Smrg 6737ec681f3Smrg args = reinterpret_cast<struct clc_kernel_arg *>(calloc(kernels[i].num_args, 6747ec681f3Smrg sizeof(*kernels->args))); 6757ec681f3Smrg kernels[i].args = args; 6767ec681f3Smrg assert(args); 6777ec681f3Smrg for (unsigned j = 0; j < kernels[i].num_args; j++) { 6787ec681f3Smrg if (!parser.kernels[i].args[j].name.empty()) 6797ec681f3Smrg args[j].name = strdup(parser.kernels[i].args[j].name.c_str()); 6807ec681f3Smrg args[j].type_name = strdup(parser.kernels[i].args[j].typeName.c_str()); 6817ec681f3Smrg args[j].address_qualifier = parser.kernels[i].args[j].addrQualifier; 6827ec681f3Smrg args[j].type_qualifier = parser.kernels[i].args[j].typeQualifier; 6837ec681f3Smrg args[j].access_qualifier = parser.kernels[i].args[j].accessQualifier; 6847ec681f3Smrg } 6857ec681f3Smrg } 6867ec681f3Smrg 6877ec681f3Smrg if (*num_spec_constants) { 6887ec681f3Smrg spec_constants = reinterpret_cast<struct clc_parsed_spec_constant *>(calloc(*num_spec_constants, 6897ec681f3Smrg sizeof(*spec_constants))); 6907ec681f3Smrg assert(spec_constants); 6917ec681f3Smrg 6927ec681f3Smrg for (unsigned i = 0; i < parser.specConstants.size(); ++i) { 6937ec681f3Smrg spec_constants[i] = parser.specConstants[i].second; 6947ec681f3Smrg } 6957ec681f3Smrg } 6967ec681f3Smrg 6977ec681f3Smrg *out_kernels = kernels; 6987ec681f3Smrg *out_spec_constants = spec_constants; 6997ec681f3Smrg 7007ec681f3Smrg return true; 7017ec681f3Smrg} 7027ec681f3Smrg 7037ec681f3Smrgvoid 7047ec681f3Smrgclc_free_kernels_info(const struct clc_kernel_info *kernels, 7057ec681f3Smrg unsigned num_kernels) 7067ec681f3Smrg{ 7077ec681f3Smrg if (!kernels) 7087ec681f3Smrg return; 7097ec681f3Smrg 7107ec681f3Smrg for (unsigned i = 0; i < num_kernels; i++) { 7117ec681f3Smrg if (kernels[i].args) { 7127ec681f3Smrg for (unsigned j = 0; j < kernels[i].num_args; j++) { 7137ec681f3Smrg free((void *)kernels[i].args[j].name); 7147ec681f3Smrg free((void *)kernels[i].args[j].type_name); 7157ec681f3Smrg } 7167ec681f3Smrg } 7177ec681f3Smrg free((void *)kernels[i].name); 7187ec681f3Smrg } 7197ec681f3Smrg 7207ec681f3Smrg free((void *)kernels); 7217ec681f3Smrg} 7227ec681f3Smrg 7237ec681f3Smrgstatic std::pair<std::unique_ptr<::llvm::Module>, std::unique_ptr<LLVMContext>> 7247ec681f3Smrgclc_compile_to_llvm_module(const struct clc_compile_args *args, 7257ec681f3Smrg const struct clc_logger *logger) 7267ec681f3Smrg{ 7277ec681f3Smrg LLVMInitializeAllTargets(); 7287ec681f3Smrg LLVMInitializeAllTargetInfos(); 7297ec681f3Smrg LLVMInitializeAllTargetMCs(); 7307ec681f3Smrg LLVMInitializeAllAsmPrinters(); 7317ec681f3Smrg 7327ec681f3Smrg std::string log; 7337ec681f3Smrg std::unique_ptr<LLVMContext> llvm_ctx { new LLVMContext }; 7347ec681f3Smrg llvm_ctx->setDiagnosticHandlerCallBack(llvm_log_handler, &log); 7357ec681f3Smrg 7367ec681f3Smrg std::unique_ptr<clang::CompilerInstance> c { new clang::CompilerInstance }; 7377ec681f3Smrg clang::DiagnosticsEngine diag { new clang::DiagnosticIDs, 7387ec681f3Smrg new clang::DiagnosticOptions, 7397ec681f3Smrg new clang::TextDiagnosticPrinter(*new raw_string_ostream(log), 7407ec681f3Smrg &c->getDiagnosticOpts(), true)}; 7417ec681f3Smrg 7427ec681f3Smrg std::vector<const char *> clang_opts = { 7437ec681f3Smrg args->source.name, 7447ec681f3Smrg "-triple", "spir64-unknown-unknown", 7457ec681f3Smrg // By default, clang prefers to use modules to pull in the default headers, 7467ec681f3Smrg // which doesn't work with our technique of embedding the headers in our binary 7477ec681f3Smrg "-finclude-default-header", 7487ec681f3Smrg // Add a default CL compiler version. Clang will pick the last one specified 7497ec681f3Smrg // on the command line, so the app can override this one. 7507ec681f3Smrg "-cl-std=cl1.2", 7517ec681f3Smrg // The LLVM-SPIRV-Translator doesn't support memset with variable size 7527ec681f3Smrg "-fno-builtin-memset", 7537ec681f3Smrg // LLVM's optimizations can produce code that the translator can't translate 7547ec681f3Smrg "-O0", 7557ec681f3Smrg // Ensure inline functions are actually emitted 7567ec681f3Smrg "-fgnu89-inline" 7577ec681f3Smrg }; 7587ec681f3Smrg // We assume there's appropriate defines for __OPENCL_VERSION__ and __IMAGE_SUPPORT__ 7597ec681f3Smrg // being provided by the caller here. 7607ec681f3Smrg clang_opts.insert(clang_opts.end(), args->args, args->args + args->num_args); 7617ec681f3Smrg 7627ec681f3Smrg if (!clang::CompilerInvocation::CreateFromArgs(c->getInvocation(), 7637ec681f3Smrg#if LLVM_VERSION_MAJOR >= 10 7647ec681f3Smrg clang_opts, 7657ec681f3Smrg#else 7667ec681f3Smrg clang_opts.data(), 7677ec681f3Smrg clang_opts.data() + clang_opts.size(), 7687ec681f3Smrg#endif 7697ec681f3Smrg diag)) { 7707ec681f3Smrg clc_error(logger, "%sCouldn't create Clang invocation.\n", log.c_str()); 7717ec681f3Smrg return {}; 7727ec681f3Smrg } 7737ec681f3Smrg 7747ec681f3Smrg if (diag.hasErrorOccurred()) { 7757ec681f3Smrg clc_error(logger, "%sErrors occurred during Clang invocation.\n", 7767ec681f3Smrg log.c_str()); 7777ec681f3Smrg return {}; 7787ec681f3Smrg } 7797ec681f3Smrg 7807ec681f3Smrg // This is a workaround for a Clang bug which causes the number 7817ec681f3Smrg // of warnings and errors to be printed to stderr. 7827ec681f3Smrg // http://www.llvm.org/bugs/show_bug.cgi?id=19735 7837ec681f3Smrg c->getDiagnosticOpts().ShowCarets = false; 7847ec681f3Smrg 7857ec681f3Smrg c->createDiagnostics(new clang::TextDiagnosticPrinter( 7867ec681f3Smrg *new raw_string_ostream(log), 7877ec681f3Smrg &c->getDiagnosticOpts(), true)); 7887ec681f3Smrg 7897ec681f3Smrg c->setTarget(clang::TargetInfo::CreateTargetInfo( 7907ec681f3Smrg c->getDiagnostics(), c->getInvocation().TargetOpts)); 7917ec681f3Smrg 7927ec681f3Smrg c->getFrontendOpts().ProgramAction = clang::frontend::EmitLLVMOnly; 7937ec681f3Smrg 7947ec681f3Smrg#ifdef USE_STATIC_OPENCL_C_H 7957ec681f3Smrg c->getHeaderSearchOpts().UseBuiltinIncludes = false; 7967ec681f3Smrg c->getHeaderSearchOpts().UseStandardSystemIncludes = false; 7977ec681f3Smrg 7987ec681f3Smrg // Add opencl-c generic search path 7997ec681f3Smrg { 8007ec681f3Smrg ::llvm::SmallString<128> system_header_path; 8017ec681f3Smrg ::llvm::sys::path::system_temp_directory(true, system_header_path); 8027ec681f3Smrg ::llvm::sys::path::append(system_header_path, "openclon12"); 8037ec681f3Smrg c->getHeaderSearchOpts().AddPath(system_header_path.str(), 8047ec681f3Smrg clang::frontend::Angled, 8057ec681f3Smrg false, false); 8067ec681f3Smrg 8077ec681f3Smrg ::llvm::sys::path::append(system_header_path, "opencl-c.h"); 8087ec681f3Smrg c->getPreprocessorOpts().addRemappedFile(system_header_path.str(), 8097ec681f3Smrg ::llvm::MemoryBuffer::getMemBuffer(llvm::StringRef(opencl_c_source, ARRAY_SIZE(opencl_c_source) - 1)).release()); 8107ec681f3Smrg 8117ec681f3Smrg ::llvm::sys::path::remove_filename(system_header_path); 8127ec681f3Smrg ::llvm::sys::path::append(system_header_path, "opencl-c-base.h"); 8137ec681f3Smrg c->getPreprocessorOpts().addRemappedFile(system_header_path.str(), 8147ec681f3Smrg ::llvm::MemoryBuffer::getMemBuffer(llvm::StringRef(opencl_c_base_source, ARRAY_SIZE(opencl_c_base_source) - 1)).release()); 8157ec681f3Smrg } 8167ec681f3Smrg#else 8177ec681f3Smrg c->getHeaderSearchOpts().UseBuiltinIncludes = true; 8187ec681f3Smrg c->getHeaderSearchOpts().UseStandardSystemIncludes = true; 8197ec681f3Smrg c->getHeaderSearchOpts().ResourceDir = CLANG_RESOURCE_DIR; 8207ec681f3Smrg 8217ec681f3Smrg // Add opencl-c generic search path 8227ec681f3Smrg c->getHeaderSearchOpts().AddPath(CLANG_RESOURCE_DIR, 8237ec681f3Smrg clang::frontend::Angled, 8247ec681f3Smrg false, false); 8257ec681f3Smrg // Add opencl include 8267ec681f3Smrg c->getPreprocessorOpts().Includes.push_back("opencl-c.h"); 8277ec681f3Smrg#endif 8287ec681f3Smrg 8297ec681f3Smrg if (args->num_headers) { 8307ec681f3Smrg ::llvm::SmallString<128> tmp_header_path; 8317ec681f3Smrg ::llvm::sys::path::system_temp_directory(true, tmp_header_path); 8327ec681f3Smrg ::llvm::sys::path::append(tmp_header_path, "openclon12"); 8337ec681f3Smrg 8347ec681f3Smrg c->getHeaderSearchOpts().AddPath(tmp_header_path.str(), 8357ec681f3Smrg clang::frontend::Quoted, 8367ec681f3Smrg false, false); 8377ec681f3Smrg 8387ec681f3Smrg for (size_t i = 0; i < args->num_headers; i++) { 8397ec681f3Smrg auto path_copy = tmp_header_path; 8407ec681f3Smrg ::llvm::sys::path::append(path_copy, ::llvm::sys::path::convert_to_slash(args->headers[i].name)); 8417ec681f3Smrg c->getPreprocessorOpts().addRemappedFile(path_copy.str(), 8427ec681f3Smrg ::llvm::MemoryBuffer::getMemBufferCopy(args->headers[i].value).release()); 8437ec681f3Smrg } 8447ec681f3Smrg } 8457ec681f3Smrg 8467ec681f3Smrg c->getPreprocessorOpts().addRemappedFile( 8477ec681f3Smrg args->source.name, 8487ec681f3Smrg ::llvm::MemoryBuffer::getMemBufferCopy(std::string(args->source.value)).release()); 8497ec681f3Smrg 8507ec681f3Smrg // Compile the code 8517ec681f3Smrg clang::EmitLLVMOnlyAction act(llvm_ctx.get()); 8527ec681f3Smrg if (!c->ExecuteAction(act)) { 8537ec681f3Smrg clc_error(logger, "%sError executing LLVM compilation action.\n", 8547ec681f3Smrg log.c_str()); 8557ec681f3Smrg return {}; 8567ec681f3Smrg } 8577ec681f3Smrg 8587ec681f3Smrg return { act.takeModule(), std::move(llvm_ctx) }; 8597ec681f3Smrg} 8607ec681f3Smrg 8617ec681f3Smrgstatic SPIRV::VersionNumber 8627ec681f3Smrgspirv_version_to_llvm_spirv_translator_version(enum clc_spirv_version version) 8637ec681f3Smrg{ 8647ec681f3Smrg switch (version) { 8657ec681f3Smrg case CLC_SPIRV_VERSION_MAX: return SPIRV::VersionNumber::MaximumVersion; 8667ec681f3Smrg case CLC_SPIRV_VERSION_1_0: return SPIRV::VersionNumber::SPIRV_1_0; 8677ec681f3Smrg case CLC_SPIRV_VERSION_1_1: return SPIRV::VersionNumber::SPIRV_1_1; 8687ec681f3Smrg case CLC_SPIRV_VERSION_1_2: return SPIRV::VersionNumber::SPIRV_1_2; 8697ec681f3Smrg case CLC_SPIRV_VERSION_1_3: return SPIRV::VersionNumber::SPIRV_1_3; 8707ec681f3Smrg#ifdef HAS_SPIRV_1_4 8717ec681f3Smrg case CLC_SPIRV_VERSION_1_4: return SPIRV::VersionNumber::SPIRV_1_4; 8727ec681f3Smrg#endif 8737ec681f3Smrg default: return invalid_spirv_trans_version; 8747ec681f3Smrg } 8757ec681f3Smrg} 8767ec681f3Smrg 8777ec681f3Smrgstatic int 8787ec681f3Smrgllvm_mod_to_spirv(std::unique_ptr<::llvm::Module> mod, 8797ec681f3Smrg std::unique_ptr<LLVMContext> context, 8807ec681f3Smrg const struct clc_compile_args *args, 8817ec681f3Smrg const struct clc_logger *logger, 8827ec681f3Smrg struct clc_binary *out_spirv) 8837ec681f3Smrg{ 8847ec681f3Smrg std::string log; 8857ec681f3Smrg 8867ec681f3Smrg SPIRV::VersionNumber version = 8877ec681f3Smrg spirv_version_to_llvm_spirv_translator_version(args->spirv_version); 8887ec681f3Smrg if (version == invalid_spirv_trans_version) { 8897ec681f3Smrg clc_error(logger, "Invalid/unsupported SPIRV specified.\n"); 8907ec681f3Smrg return -1; 8917ec681f3Smrg } 8927ec681f3Smrg 8937ec681f3Smrg const char *const *extensions = NULL; 8947ec681f3Smrg if (args) 8957ec681f3Smrg extensions = args->allowed_spirv_extensions; 8967ec681f3Smrg if (!extensions) { 8977ec681f3Smrg /* The SPIR-V parser doesn't handle all extensions */ 8987ec681f3Smrg static const char *default_extensions[] = { 8997ec681f3Smrg "SPV_EXT_shader_atomic_float_add", 9007ec681f3Smrg "SPV_EXT_shader_atomic_float_min_max", 9017ec681f3Smrg "SPV_KHR_float_controls", 9027ec681f3Smrg NULL, 9037ec681f3Smrg }; 9047ec681f3Smrg extensions = default_extensions; 9057ec681f3Smrg } 9067ec681f3Smrg 9077ec681f3Smrg SPIRV::TranslatorOpts::ExtensionsStatusMap ext_map; 9087ec681f3Smrg for (int i = 0; extensions[i]; i++) { 9097ec681f3Smrg#define EXT(X) \ 9107ec681f3Smrg if (strcmp(#X, extensions[i]) == 0) \ 9117ec681f3Smrg ext_map.insert(std::make_pair(SPIRV::ExtensionID::X, true)); 9127ec681f3Smrg#include "LLVMSPIRVLib/LLVMSPIRVExtensions.inc" 9137ec681f3Smrg#undef EXT 9147ec681f3Smrg } 9157ec681f3Smrg SPIRV::TranslatorOpts spirv_opts = SPIRV::TranslatorOpts(version, ext_map); 9167ec681f3Smrg 9177ec681f3Smrg#if LLVM_VERSION_MAJOR >= 13 9187ec681f3Smrg /* This was the default in 12.0 and older, but currently we'll fail to parse without this */ 9197ec681f3Smrg spirv_opts.setPreserveOCLKernelArgTypeMetadataThroughString(true); 9207ec681f3Smrg#endif 9217ec681f3Smrg 9227ec681f3Smrg std::ostringstream spv_stream; 9237ec681f3Smrg if (!::llvm::writeSpirv(mod.get(), spirv_opts, spv_stream, log)) { 9247ec681f3Smrg clc_error(logger, "%sTranslation from LLVM IR to SPIR-V failed.\n", 9257ec681f3Smrg log.c_str()); 9267ec681f3Smrg return -1; 9277ec681f3Smrg } 9287ec681f3Smrg 9297ec681f3Smrg const std::string spv_out = spv_stream.str(); 9307ec681f3Smrg out_spirv->size = spv_out.size(); 9317ec681f3Smrg out_spirv->data = malloc(out_spirv->size); 9327ec681f3Smrg memcpy(out_spirv->data, spv_out.data(), out_spirv->size); 9337ec681f3Smrg 9347ec681f3Smrg return 0; 9357ec681f3Smrg} 9367ec681f3Smrg 9377ec681f3Smrgint 9387ec681f3Smrgclc_c_to_spir(const struct clc_compile_args *args, 9397ec681f3Smrg const struct clc_logger *logger, 9407ec681f3Smrg struct clc_binary *out_spir) 9417ec681f3Smrg{ 9427ec681f3Smrg auto pair = clc_compile_to_llvm_module(args, logger); 9437ec681f3Smrg if (!pair.first) 9447ec681f3Smrg return -1; 9457ec681f3Smrg 9467ec681f3Smrg ::llvm::SmallVector<char, 0> buffer; 9477ec681f3Smrg ::llvm::BitcodeWriter writer(buffer); 9487ec681f3Smrg writer.writeModule(*pair.first); 9497ec681f3Smrg 9507ec681f3Smrg out_spir->size = buffer.size_in_bytes(); 9517ec681f3Smrg out_spir->data = malloc(out_spir->size); 9527ec681f3Smrg memcpy(out_spir->data, buffer.data(), out_spir->size); 9537ec681f3Smrg 9547ec681f3Smrg return 0; 9557ec681f3Smrg} 9567ec681f3Smrg 9577ec681f3Smrgint 9587ec681f3Smrgclc_c_to_spirv(const struct clc_compile_args *args, 9597ec681f3Smrg const struct clc_logger *logger, 9607ec681f3Smrg struct clc_binary *out_spirv) 9617ec681f3Smrg{ 9627ec681f3Smrg auto pair = clc_compile_to_llvm_module(args, logger); 9637ec681f3Smrg if (!pair.first) 9647ec681f3Smrg return -1; 9657ec681f3Smrg return llvm_mod_to_spirv(std::move(pair.first), std::move(pair.second), args, logger, out_spirv); 9667ec681f3Smrg} 9677ec681f3Smrg 9687ec681f3Smrgint 9697ec681f3Smrgclc_spir_to_spirv(const struct clc_binary *in_spir, 9707ec681f3Smrg const struct clc_logger *logger, 9717ec681f3Smrg struct clc_binary *out_spirv) 9727ec681f3Smrg{ 9737ec681f3Smrg LLVMInitializeAllTargets(); 9747ec681f3Smrg LLVMInitializeAllTargetInfos(); 9757ec681f3Smrg LLVMInitializeAllTargetMCs(); 9767ec681f3Smrg LLVMInitializeAllAsmPrinters(); 9777ec681f3Smrg 9787ec681f3Smrg std::unique_ptr<LLVMContext> llvm_ctx{ new LLVMContext }; 9797ec681f3Smrg ::llvm::StringRef spir_ref(static_cast<const char*>(in_spir->data), in_spir->size); 9807ec681f3Smrg auto mod = ::llvm::parseBitcodeFile(::llvm::MemoryBufferRef(spir_ref, "<spir>"), *llvm_ctx); 9817ec681f3Smrg if (!mod) 9827ec681f3Smrg return -1; 9837ec681f3Smrg 9847ec681f3Smrg return llvm_mod_to_spirv(std::move(mod.get()), std::move(llvm_ctx), NULL, logger, out_spirv); 9857ec681f3Smrg} 9867ec681f3Smrg 9877ec681f3Smrgclass SPIRVMessageConsumer { 9887ec681f3Smrgpublic: 9897ec681f3Smrg SPIRVMessageConsumer(const struct clc_logger *logger): logger(logger) {} 9907ec681f3Smrg 9917ec681f3Smrg void operator()(spv_message_level_t level, const char *src, 9927ec681f3Smrg const spv_position_t &pos, const char *msg) 9937ec681f3Smrg { 9947ec681f3Smrg switch(level) { 9957ec681f3Smrg case SPV_MSG_FATAL: 9967ec681f3Smrg case SPV_MSG_INTERNAL_ERROR: 9977ec681f3Smrg case SPV_MSG_ERROR: 9987ec681f3Smrg clc_error(logger, "(file=%s,line=%ld,column=%ld,index=%ld): %s\n", 9997ec681f3Smrg src, pos.line, pos.column, pos.index, msg); 10007ec681f3Smrg break; 10017ec681f3Smrg 10027ec681f3Smrg case SPV_MSG_WARNING: 10037ec681f3Smrg clc_warning(logger, "(file=%s,line=%ld,column=%ld,index=%ld): %s\n", 10047ec681f3Smrg src, pos.line, pos.column, pos.index, msg); 10057ec681f3Smrg break; 10067ec681f3Smrg 10077ec681f3Smrg default: 10087ec681f3Smrg break; 10097ec681f3Smrg } 10107ec681f3Smrg } 10117ec681f3Smrg 10127ec681f3Smrgprivate: 10137ec681f3Smrg const struct clc_logger *logger; 10147ec681f3Smrg}; 10157ec681f3Smrg 10167ec681f3Smrgint 10177ec681f3Smrgclc_link_spirv_binaries(const struct clc_linker_args *args, 10187ec681f3Smrg const struct clc_logger *logger, 10197ec681f3Smrg struct clc_binary *out_spirv) 10207ec681f3Smrg{ 10217ec681f3Smrg std::vector<std::vector<uint32_t>> binaries; 10227ec681f3Smrg 10237ec681f3Smrg for (unsigned i = 0; i < args->num_in_objs; i++) { 10247ec681f3Smrg const uint32_t *data = static_cast<const uint32_t *>(args->in_objs[i]->data); 10257ec681f3Smrg std::vector<uint32_t> bin(data, data + (args->in_objs[i]->size / 4)); 10267ec681f3Smrg binaries.push_back(bin); 10277ec681f3Smrg } 10287ec681f3Smrg 10297ec681f3Smrg SPIRVMessageConsumer msgconsumer(logger); 10307ec681f3Smrg spvtools::Context context(spirv_target); 10317ec681f3Smrg context.SetMessageConsumer(msgconsumer); 10327ec681f3Smrg spvtools::LinkerOptions options; 10337ec681f3Smrg options.SetAllowPartialLinkage(args->create_library); 10347ec681f3Smrg options.SetCreateLibrary(args->create_library); 10357ec681f3Smrg std::vector<uint32_t> linkingResult; 10367ec681f3Smrg spv_result_t status = spvtools::Link(context, binaries, &linkingResult, options); 10377ec681f3Smrg if (status != SPV_SUCCESS) { 10387ec681f3Smrg return -1; 10397ec681f3Smrg } 10407ec681f3Smrg 10417ec681f3Smrg out_spirv->size = linkingResult.size() * 4; 10427ec681f3Smrg out_spirv->data = static_cast<uint32_t *>(malloc(out_spirv->size)); 10437ec681f3Smrg memcpy(out_spirv->data, linkingResult.data(), out_spirv->size); 10447ec681f3Smrg 10457ec681f3Smrg return 0; 10467ec681f3Smrg} 10477ec681f3Smrg 10487ec681f3Smrgint 10497ec681f3Smrgclc_spirv_specialize(const struct clc_binary *in_spirv, 10507ec681f3Smrg const struct clc_parsed_spirv *parsed_data, 10517ec681f3Smrg const struct clc_spirv_specialization_consts *consts, 10527ec681f3Smrg struct clc_binary *out_spirv) 10537ec681f3Smrg{ 10547ec681f3Smrg std::unordered_map<uint32_t, std::vector<uint32_t>> spec_const_map; 10557ec681f3Smrg for (unsigned i = 0; i < consts->num_specializations; ++i) { 10567ec681f3Smrg unsigned id = consts->specializations[i].id; 10577ec681f3Smrg auto parsed_spec_const = std::find_if(parsed_data->spec_constants, 10587ec681f3Smrg parsed_data->spec_constants + parsed_data->num_spec_constants, 10597ec681f3Smrg [id](const clc_parsed_spec_constant &c) { return c.id == id; }); 10607ec681f3Smrg assert(parsed_spec_const != parsed_data->spec_constants + parsed_data->num_spec_constants); 10617ec681f3Smrg 10627ec681f3Smrg std::vector<uint32_t> words; 10637ec681f3Smrg switch (parsed_spec_const->type) { 10647ec681f3Smrg case CLC_SPEC_CONSTANT_BOOL: 10657ec681f3Smrg words.push_back(consts->specializations[i].value.b); 10667ec681f3Smrg break; 10677ec681f3Smrg case CLC_SPEC_CONSTANT_INT32: 10687ec681f3Smrg case CLC_SPEC_CONSTANT_UINT32: 10697ec681f3Smrg case CLC_SPEC_CONSTANT_FLOAT: 10707ec681f3Smrg words.push_back(consts->specializations[i].value.u32); 10717ec681f3Smrg break; 10727ec681f3Smrg case CLC_SPEC_CONSTANT_INT16: 10737ec681f3Smrg words.push_back((uint32_t)(int32_t)consts->specializations[i].value.i16); 10747ec681f3Smrg break; 10757ec681f3Smrg case CLC_SPEC_CONSTANT_INT8: 10767ec681f3Smrg words.push_back((uint32_t)(int32_t)consts->specializations[i].value.i8); 10777ec681f3Smrg break; 10787ec681f3Smrg case CLC_SPEC_CONSTANT_UINT16: 10797ec681f3Smrg words.push_back((uint32_t)consts->specializations[i].value.u16); 10807ec681f3Smrg break; 10817ec681f3Smrg case CLC_SPEC_CONSTANT_UINT8: 10827ec681f3Smrg words.push_back((uint32_t)consts->specializations[i].value.u8); 10837ec681f3Smrg break; 10847ec681f3Smrg case CLC_SPEC_CONSTANT_DOUBLE: 10857ec681f3Smrg case CLC_SPEC_CONSTANT_INT64: 10867ec681f3Smrg case CLC_SPEC_CONSTANT_UINT64: 10877ec681f3Smrg words.resize(2); 10887ec681f3Smrg memcpy(words.data(), &consts->specializations[i].value.u64, 8); 10897ec681f3Smrg break; 10907ec681f3Smrg case CLC_SPEC_CONSTANT_UNKNOWN: 10917ec681f3Smrg assert(0); 10927ec681f3Smrg break; 10937ec681f3Smrg } 10947ec681f3Smrg 10957ec681f3Smrg ASSERTED auto ret = spec_const_map.emplace(id, std::move(words)); 10967ec681f3Smrg assert(ret.second); 10977ec681f3Smrg } 10987ec681f3Smrg 10997ec681f3Smrg spvtools::Optimizer opt(spirv_target); 11007ec681f3Smrg opt.RegisterPass(spvtools::CreateSetSpecConstantDefaultValuePass(std::move(spec_const_map))); 11017ec681f3Smrg 11027ec681f3Smrg std::vector<uint32_t> result; 11037ec681f3Smrg if (!opt.Run(static_cast<const uint32_t*>(in_spirv->data), in_spirv->size / 4, &result)) 11047ec681f3Smrg return false; 11057ec681f3Smrg 11067ec681f3Smrg out_spirv->size = result.size() * 4; 11077ec681f3Smrg out_spirv->data = malloc(out_spirv->size); 11087ec681f3Smrg memcpy(out_spirv->data, result.data(), out_spirv->size); 11097ec681f3Smrg return true; 11107ec681f3Smrg} 11117ec681f3Smrg 11127ec681f3Smrgvoid 11137ec681f3Smrgclc_dump_spirv(const struct clc_binary *spvbin, FILE *f) 11147ec681f3Smrg{ 11157ec681f3Smrg spvtools::SpirvTools tools(spirv_target); 11167ec681f3Smrg const uint32_t *data = static_cast<const uint32_t *>(spvbin->data); 11177ec681f3Smrg std::vector<uint32_t> bin(data, data + (spvbin->size / 4)); 11187ec681f3Smrg std::string out; 11197ec681f3Smrg tools.Disassemble(bin, &out, 11207ec681f3Smrg SPV_BINARY_TO_TEXT_OPTION_INDENT | 11217ec681f3Smrg SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES); 11227ec681f3Smrg fwrite(out.c_str(), out.size(), 1, f); 11237ec681f3Smrg} 11247ec681f3Smrg 11257ec681f3Smrgvoid 11267ec681f3Smrgclc_free_spir_binary(struct clc_binary *spir) 11277ec681f3Smrg{ 11287ec681f3Smrg free(spir->data); 11297ec681f3Smrg} 11307ec681f3Smrg 11317ec681f3Smrgvoid 11327ec681f3Smrgclc_free_spirv_binary(struct clc_binary *spvbin) 11337ec681f3Smrg{ 11347ec681f3Smrg free(spvbin->data); 11357ec681f3Smrg} 1136