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