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