1//
2// Copyright 2018 Pierre Moreau
3//
4// Permission is hereby granted, free of charge, to any person obtaining a
5// copy of this software and associated documentation files (the "Software"),
6// to deal in the Software without restriction, including without limitation
7// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8// and/or sell copies of the Software, and to permit persons to whom the
9// Software is furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20// OTHER DEALINGS IN THE SOFTWARE.
21//
22
23#include "invocation.hpp"
24
25#include <limits>
26#include <unordered_map>
27#include <unordered_set>
28#include <vector>
29
30#ifdef HAVE_CLOVER_SPIRV
31#include <spirv-tools/libspirv.hpp>
32#include <spirv-tools/linker.hpp>
33#endif
34
35#include "core/error.hpp"
36#include "core/platform.hpp"
37#include "invocation.hpp"
38#include "llvm/util.hpp"
39#include "pipe/p_state.h"
40#include "util/algorithm.hpp"
41#include "util/functional.hpp"
42#include "util/u_math.h"
43
44#include "compiler/spirv/spirv.h"
45
46#define SPIRV_HEADER_WORD_SIZE 5
47
48using namespace clover;
49
50using clover::detokenize;
51
52#ifdef HAVE_CLOVER_SPIRV
53namespace {
54
55   static const std::array<std::string,7> type_strs = {
56      "uchar", "ushort", "uint", "ulong", "half", "float", "double"
57   };
58
59   template<typename T>
60   T get(const char *source, size_t index) {
61      const uint32_t *word_ptr = reinterpret_cast<const uint32_t *>(source);
62      return static_cast<T>(word_ptr[index]);
63   }
64
65   enum binary::argument::type
66   convert_storage_class(SpvStorageClass storage_class, std::string &err) {
67      switch (storage_class) {
68      case SpvStorageClassFunction:
69         return binary::argument::scalar;
70      case SpvStorageClassUniformConstant:
71         return binary::argument::global;
72      case SpvStorageClassWorkgroup:
73         return binary::argument::local;
74      case SpvStorageClassCrossWorkgroup:
75         return binary::argument::global;
76      default:
77         err += "Invalid storage type " + std::to_string(storage_class) + "\n";
78         throw build_error();
79      }
80   }
81
82   cl_kernel_arg_address_qualifier
83   convert_storage_class_to_cl(SpvStorageClass storage_class) {
84      switch (storage_class) {
85      case SpvStorageClassUniformConstant:
86         return CL_KERNEL_ARG_ADDRESS_CONSTANT;
87      case SpvStorageClassWorkgroup:
88         return CL_KERNEL_ARG_ADDRESS_LOCAL;
89      case SpvStorageClassCrossWorkgroup:
90         return CL_KERNEL_ARG_ADDRESS_GLOBAL;
91      case SpvStorageClassFunction:
92      default:
93         return CL_KERNEL_ARG_ADDRESS_PRIVATE;
94      }
95   }
96
97   enum binary::argument::type
98   convert_image_type(SpvId id, SpvDim dim, SpvAccessQualifier access,
99                      std::string &err) {
100      switch (dim) {
101      case SpvDim1D:
102      case SpvDim2D:
103      case SpvDim3D:
104      case SpvDimBuffer:
105         switch (access) {
106         case SpvAccessQualifierReadOnly:
107            return binary::argument::image_rd;
108         case SpvAccessQualifierWriteOnly:
109            return binary::argument::image_wr;
110         default:
111            err += "Unknown access qualifier " + std::to_string(access) + " for image "
112                +  std::to_string(id) + ".\n";
113            throw build_error();
114         }
115      default:
116         err += "Unknown dimension " + std::to_string(dim) + " for image "
117             +  std::to_string(id) + ".\n";
118         throw build_error();
119      }
120   }
121
122   binary::section
123   make_text_section(const std::string &code,
124                     enum binary::section::type section_type) {
125      const pipe_binary_program_header header { uint32_t(code.size()) };
126      binary::section text { 0, section_type, header.num_bytes, {} };
127
128      text.data.insert(text.data.end(), reinterpret_cast<const char *>(&header),
129                       reinterpret_cast<const char *>(&header) + sizeof(header));
130      text.data.insert(text.data.end(), code.begin(), code.end());
131
132      return text;
133   }
134
135   binary
136   create_binary_from_spirv(const std::string &source,
137                            size_t pointer_byte_size,
138                            std::string &err) {
139      const size_t length = source.size() / sizeof(uint32_t);
140      size_t i = SPIRV_HEADER_WORD_SIZE; // Skip header
141
142      std::string kernel_name;
143      size_t kernel_nb = 0u;
144      std::vector<binary::argument> args;
145      std::vector<size_t> req_local_size;
146
147      binary b;
148
149      std::vector<std::string> attributes;
150      std::unordered_map<SpvId, std::vector<size_t> > req_local_sizes;
151      std::unordered_map<SpvId, std::string> kernels;
152      std::unordered_map<SpvId, binary::argument> types;
153      std::unordered_map<SpvId, SpvId> pointer_types;
154      std::unordered_map<SpvId, unsigned int> constants;
155      std::unordered_set<SpvId> packed_structures;
156      std::unordered_map<SpvId, std::vector<SpvFunctionParameterAttribute>>
157         func_param_attr_map;
158      std::unordered_map<SpvId, std::string> names;
159      std::unordered_map<SpvId, cl_kernel_arg_type_qualifier> qualifiers;
160      std::unordered_map<std::string, std::vector<std::string> > param_type_names;
161
162      while (i < length) {
163         const auto inst = &source[i * sizeof(uint32_t)];
164         const auto desc_word = get<uint32_t>(inst, 0);
165         const auto opcode = static_cast<SpvOp>(desc_word & SpvOpCodeMask);
166         const unsigned int num_operands = desc_word >> SpvWordCountShift;
167
168         switch (opcode) {
169         case SpvOpName: {
170            names.emplace(get<SpvId>(inst, 1),
171                          source.data() + (i + 2u) * sizeof(uint32_t));
172            break;
173         }
174
175         case SpvOpString: {
176            // SPIRV-LLVM-Translator stores param type names as OpStrings
177            std::string str(source.data() + (i + 2u) * sizeof(uint32_t));
178            if (str.find("kernel_arg_type.") != 0)
179               break;
180
181            std::string line;
182            std::istringstream istream(str.substr(16));
183
184            std::getline(istream, line, '.');
185
186            std::string k = line;
187            while (std::getline(istream, line, ','))
188               param_type_names[k].push_back(line);
189            break;
190         }
191
192         case SpvOpEntryPoint:
193            if (get<SpvExecutionModel>(inst, 1) == SpvExecutionModelKernel)
194               kernels.emplace(get<SpvId>(inst, 2),
195                               source.data() + (i + 3u) * sizeof(uint32_t));
196            break;
197
198         case SpvOpExecutionMode:
199            switch (get<SpvExecutionMode>(inst, 2)) {
200            case SpvExecutionModeLocalSize: {
201               req_local_sizes[get<SpvId>(inst, 1)] = {
202                  get<uint32_t>(inst, 3),
203                  get<uint32_t>(inst, 4),
204                  get<uint32_t>(inst, 5)
205               };
206               std::string s = "reqd_work_group_size(";
207               s += std::to_string(get<uint32_t>(inst, 3));
208               s += ",";
209               s += std::to_string(get<uint32_t>(inst, 4));
210               s += ",";
211               s += std::to_string(get<uint32_t>(inst, 5));
212               s += ")";
213               attributes.emplace_back(s);
214               break;
215            }
216            case SpvExecutionModeLocalSizeHint: {
217               std::string s = "work_group_size_hint(";
218               s += std::to_string(get<uint32_t>(inst, 3));
219               s += ",";
220               s += std::to_string(get<uint32_t>(inst, 4));
221               s += ",";
222               s += std::to_string(get<uint32_t>(inst, 5));
223               s += ")";
224               attributes.emplace_back(s);
225               break;
226            }
227	    case SpvExecutionModeVecTypeHint: {
228               uint32_t val = get<uint32_t>(inst, 3);
229               uint32_t size = val >> 16;
230
231               val &= 0xf;
232               if (val > 6)
233                  val = 0;
234               std::string s = "vec_type_hint(";
235               s += type_strs[val];
236               s += std::to_string(size);
237               s += ")";
238               attributes.emplace_back(s);
239	       break;
240            }
241            default:
242               break;
243            }
244            break;
245
246         case SpvOpDecorate: {
247            const auto id = get<SpvId>(inst, 1);
248            const auto decoration = get<SpvDecoration>(inst, 2);
249            switch (decoration) {
250            case SpvDecorationCPacked:
251               packed_structures.emplace(id);
252               break;
253            case SpvDecorationFuncParamAttr: {
254               const auto attribute =
255                  get<SpvFunctionParameterAttribute>(inst, 3u);
256               func_param_attr_map[id].push_back(attribute);
257               break;
258            }
259            case SpvDecorationVolatile:
260               qualifiers[id] |= CL_KERNEL_ARG_TYPE_VOLATILE;
261               break;
262            default:
263               break;
264            }
265            break;
266         }
267
268         case SpvOpGroupDecorate: {
269            const auto group_id = get<SpvId>(inst, 1);
270            if (packed_structures.count(group_id)) {
271               for (unsigned int i = 2u; i < num_operands; ++i)
272                  packed_structures.emplace(get<SpvId>(inst, i));
273            }
274            const auto func_param_attr_iter =
275               func_param_attr_map.find(group_id);
276            if (func_param_attr_iter != func_param_attr_map.end()) {
277               for (unsigned int i = 2u; i < num_operands; ++i) {
278                  auto &attrs = func_param_attr_map[get<SpvId>(inst, i)];
279                  attrs.insert(attrs.begin(),
280                               func_param_attr_iter->second.begin(),
281                               func_param_attr_iter->second.end());
282               }
283            }
284            if (qualifiers.count(group_id)) {
285               for (unsigned int i = 2u; i < num_operands; ++i)
286                  qualifiers[get<SpvId>(inst, i)] |= qualifiers[group_id];
287            }
288            break;
289         }
290
291         case SpvOpConstant:
292            // We only care about constants that represent the size of arrays.
293            // If they are passed as argument, they will never be more than
294            // 4GB-wide, and even if they did, a clover::binary::argument size
295            // is represented by an int.
296            constants[get<SpvId>(inst, 2)] = get<unsigned int>(inst, 3u);
297            break;
298
299         case SpvOpTypeInt:
300         case SpvOpTypeFloat: {
301            const auto size = get<uint32_t>(inst, 2) / 8u;
302            const auto id = get<SpvId>(inst, 1);
303            types[id] = { binary::argument::scalar, size, size, size,
304                          binary::argument::zero_ext };
305            types[id].info.address_qualifier = CL_KERNEL_ARG_ADDRESS_PRIVATE;
306            break;
307         }
308
309         case SpvOpTypeArray: {
310            const auto id = get<SpvId>(inst, 1);
311            const auto type_id = get<SpvId>(inst, 2);
312            const auto types_iter = types.find(type_id);
313            if (types_iter == types.end())
314               break;
315
316            const auto constant_id = get<SpvId>(inst, 3);
317            const auto constants_iter = constants.find(constant_id);
318            if (constants_iter == constants.end()) {
319               err += "Constant " + std::to_string(constant_id) +
320                  " is missing\n";
321               throw build_error();
322            }
323            const auto elem_size = types_iter->second.size;
324            const auto elem_nbs = constants_iter->second;
325            const auto size = elem_size * elem_nbs;
326            types[id] = { binary::argument::scalar, size, size,
327                          types_iter->second.target_align,
328                          binary::argument::zero_ext };
329            break;
330         }
331
332         case SpvOpTypeStruct: {
333            const auto id = get<SpvId>(inst, 1);
334            const bool is_packed = packed_structures.count(id);
335
336            unsigned struct_size = 0u;
337            unsigned struct_align = 1u;
338            for (unsigned j = 2u; j < num_operands; ++j) {
339               const auto type_id = get<SpvId>(inst, j);
340               const auto types_iter = types.find(type_id);
341
342               // If a type was not found, that means it is not one of the
343               // types allowed as kernel arguments. And since the binary has
344               // been validated, this means this type is not used for kernel
345               // arguments, and therefore can be ignored.
346               if (types_iter == types.end())
347                  break;
348
349               const auto alignment = is_packed ? 1u
350                                                : types_iter->second.target_align;
351               const auto padding = (-struct_size) & (alignment - 1u);
352               struct_size += padding + types_iter->second.target_size;
353               struct_align = std::max(struct_align, alignment);
354            }
355            struct_size += (-struct_size) & (struct_align - 1u);
356            types[id] = { binary::argument::scalar, struct_size, struct_size,
357                          struct_align, binary::argument::zero_ext };
358            break;
359         }
360
361         case SpvOpTypeVector: {
362            const auto id = get<SpvId>(inst, 1);
363            const auto type_id = get<SpvId>(inst, 2);
364            const auto types_iter = types.find(type_id);
365
366            // If a type was not found, that means it is not one of the
367            // types allowed as kernel arguments. And since the binary has
368            // been validated, this means this type is not used for kernel
369            // arguments, and therefore can be ignored.
370            if (types_iter == types.end())
371               break;
372
373            const auto elem_size = types_iter->second.size;
374            const auto elem_nbs = get<uint32_t>(inst, 3);
375            const auto size = elem_size * (elem_nbs != 3 ? elem_nbs : 4);
376            types[id] = { binary::argument::scalar, size, size, size,
377                          binary::argument::zero_ext };
378            types[id].info.address_qualifier = CL_KERNEL_ARG_ADDRESS_PRIVATE;
379            break;
380         }
381
382         case SpvOpTypeForwardPointer: // FALLTHROUGH
383         case SpvOpTypePointer: {
384            const auto id = get<SpvId>(inst, 1);
385            const auto storage_class = get<SpvStorageClass>(inst, 2);
386            // Input means this is for a builtin variable, which can not be
387            // passed as an argument to a kernel.
388            if (storage_class == SpvStorageClassInput)
389               break;
390
391            if (opcode == SpvOpTypePointer)
392               pointer_types[id] = get<SpvId>(inst, 3);
393
394            binary::size_t alignment;
395            if (storage_class == SpvStorageClassWorkgroup)
396               alignment = opcode == SpvOpTypePointer ? types[pointer_types[id]].target_align : 0;
397            else
398               alignment = pointer_byte_size;
399
400            types[id] = { convert_storage_class(storage_class, err),
401                          sizeof(cl_mem),
402                          static_cast<binary::size_t>(pointer_byte_size),
403                          alignment,
404                          binary::argument::zero_ext };
405            types[id].info.address_qualifier = convert_storage_class_to_cl(storage_class);
406            break;
407         }
408
409         case SpvOpTypeSampler:
410            types[get<SpvId>(inst, 1)] = { binary::argument::sampler,
411                                             sizeof(cl_sampler) };
412            break;
413
414         case SpvOpTypeImage: {
415            const auto id = get<SpvId>(inst, 1);
416            const auto dim = get<SpvDim>(inst, 3);
417            const auto access = get<SpvAccessQualifier>(inst, 9);
418            types[id] = { convert_image_type(id, dim, access, err),
419                          sizeof(cl_mem), sizeof(cl_mem), sizeof(cl_mem),
420                          binary::argument::zero_ext };
421            break;
422         }
423
424         case SpvOpTypePipe: // FALLTHROUGH
425         case SpvOpTypeQueue: {
426            err += "TypePipe and TypeQueue are valid SPIR-V 1.0 types, but are "
427                   "not available in the currently supported OpenCL C version."
428                   "\n";
429            throw build_error();
430         }
431
432         case SpvOpFunction: {
433            auto id = get<SpvId>(inst, 2);
434            const auto kernels_iter = kernels.find(id);
435            if (kernels_iter != kernels.end())
436               kernel_name = kernels_iter->second;
437
438            const auto req_local_size_iter = req_local_sizes.find(id);
439            if (req_local_size_iter != req_local_sizes.end())
440               req_local_size =  (*req_local_size_iter).second;
441            else
442               req_local_size = { 0, 0, 0 };
443
444            break;
445         }
446
447         case SpvOpFunctionParameter: {
448            if (kernel_name.empty())
449               break;
450
451            const auto id = get<SpvId>(inst, 2);
452            const auto type_id = get<SpvId>(inst, 1);
453            auto arg = types.find(type_id)->second;
454            const auto &func_param_attr_iter =
455               func_param_attr_map.find(get<SpvId>(inst, 2));
456            if (func_param_attr_iter != func_param_attr_map.end()) {
457               for (auto &i : func_param_attr_iter->second) {
458                  switch (i) {
459                  case SpvFunctionParameterAttributeSext:
460                     arg.ext_type = binary::argument::sign_ext;
461                     break;
462                  case SpvFunctionParameterAttributeZext:
463                     arg.ext_type = binary::argument::zero_ext;
464                     break;
465                  case SpvFunctionParameterAttributeByVal: {
466                     const SpvId ptr_type_id =
467                        pointer_types.find(type_id)->second;
468                     arg = types.find(ptr_type_id)->second;
469                     break;
470                  }
471                  case SpvFunctionParameterAttributeNoAlias:
472                     arg.info.type_qualifier |= CL_KERNEL_ARG_TYPE_RESTRICT;
473                     break;
474                  case SpvFunctionParameterAttributeNoWrite:
475                     arg.info.type_qualifier |= CL_KERNEL_ARG_TYPE_CONST;
476                     break;
477                  default:
478                     break;
479                  }
480               }
481            }
482
483            auto name_it = names.find(id);
484            if (name_it != names.end())
485               arg.info.arg_name = (*name_it).second;
486
487            arg.info.type_qualifier |= qualifiers[id];
488            arg.info.address_qualifier = types[type_id].info.address_qualifier;
489            arg.info.access_qualifier = CL_KERNEL_ARG_ACCESS_NONE;
490            args.emplace_back(arg);
491            break;
492         }
493
494         case SpvOpFunctionEnd:
495            if (kernel_name.empty())
496               break;
497
498            for (size_t i = 0; i < param_type_names[kernel_name].size(); i++)
499               args[i].info.type_name = param_type_names[kernel_name][i];
500
501            b.syms.emplace_back(kernel_name, detokenize(attributes, " "),
502                                req_local_size, 0, kernel_nb, args);
503            ++kernel_nb;
504            kernel_name.clear();
505            args.clear();
506            attributes.clear();
507            break;
508
509         default:
510            break;
511         }
512
513         i += num_operands;
514      }
515
516      b.secs.push_back(make_text_section(source,
517                                         binary::section::text_intermediate));
518      return b;
519   }
520
521   bool
522   check_spirv_version(const device &dev, const char *binary,
523                       std::string &r_log) {
524      const auto spirv_version = get<uint32_t>(binary, 1u);
525      const auto supported_spirv_versions = clover::spirv::supported_versions();
526      const auto compare_versions =
527         [module_version =
528            clover::spirv::to_opencl_version_encoding(spirv_version)](const cl_name_version &supported){
529         return supported.version == module_version;
530      };
531
532      if (std::find_if(supported_spirv_versions.cbegin(),
533                       supported_spirv_versions.cend(),
534                       compare_versions) != supported_spirv_versions.cend())
535         return true;
536
537      r_log += "SPIR-V version " +
538               clover::spirv::version_to_string(spirv_version) +
539               " is not supported; supported versions:";
540      for (const auto &version : supported_spirv_versions) {
541         r_log += " " + clover::spirv::version_to_string(version.version);
542      }
543      r_log += "\n";
544      return false;
545   }
546
547   bool
548   check_capabilities(const device &dev, const std::string &source,
549                      std::string &r_log) {
550      const size_t length = source.size() / sizeof(uint32_t);
551      size_t i = SPIRV_HEADER_WORD_SIZE; // Skip header
552
553      while (i < length) {
554         const auto desc_word = get<uint32_t>(source.data(), i);
555         const auto opcode = static_cast<SpvOp>(desc_word & SpvOpCodeMask);
556         const unsigned int num_operands = desc_word >> SpvWordCountShift;
557
558         if (opcode != SpvOpCapability)
559            break;
560
561         const auto capability = get<SpvCapability>(source.data(), i + 1u);
562         switch (capability) {
563         // Mandatory capabilities
564         case SpvCapabilityAddresses:
565         case SpvCapabilityFloat16Buffer:
566         case SpvCapabilityGroups:
567         case SpvCapabilityInt64:
568         case SpvCapabilityInt16:
569         case SpvCapabilityInt8:
570         case SpvCapabilityKernel:
571         case SpvCapabilityLinkage:
572         case SpvCapabilityVector16:
573            break;
574         // Optional capabilities
575         case SpvCapabilityImageBasic:
576         case SpvCapabilityLiteralSampler:
577         case SpvCapabilitySampled1D:
578         case SpvCapabilityImage1D:
579         case SpvCapabilitySampledBuffer:
580         case SpvCapabilityImageBuffer:
581            if (!dev.image_support()) {
582               r_log += "Capability 'ImageBasic' is not supported.\n";
583               return false;
584            }
585            break;
586         case SpvCapabilityFloat64:
587            if (!dev.has_doubles()) {
588               r_log += "Capability 'Float64' is not supported.\n";
589               return false;
590            }
591            break;
592         // Enabled through extensions
593         case SpvCapabilityFloat16:
594            if (!dev.has_halves()) {
595               r_log += "Capability 'Float16' is not supported.\n";
596               return false;
597            }
598            break;
599         case SpvCapabilityInt64Atomics:
600            if (!dev.has_int64_atomics()) {
601               r_log += "Capability 'Int64Atomics' is not supported.\n";
602               return false;
603            }
604            break;
605         default:
606            r_log += "Capability '" + std::to_string(capability) +
607                     "' is not supported.\n";
608            return false;
609         }
610
611         i += num_operands;
612      }
613
614      return true;
615   }
616
617   bool
618   check_extensions(const device &dev, const std::string &source,
619                    std::string &r_log) {
620      const size_t length = source.size() / sizeof(uint32_t);
621      size_t i = SPIRV_HEADER_WORD_SIZE; // Skip header
622      const auto spirv_extensions = spirv::supported_extensions();
623
624      while (i < length) {
625         const auto desc_word = get<uint32_t>(source.data(), i);
626         const auto opcode = static_cast<SpvOp>(desc_word & SpvOpCodeMask);
627         const unsigned int num_operands = desc_word >> SpvWordCountShift;
628
629         if (opcode == SpvOpCapability) {
630            i += num_operands;
631            continue;
632         }
633         if (opcode != SpvOpExtension)
634            break;
635
636         const std::string extension = source.data() + (i + 1u) * sizeof(uint32_t);
637         if (spirv_extensions.count(extension) == 0) {
638            r_log += "Extension '" + extension + "' is not supported.\n";
639            return false;
640         }
641
642         i += num_operands;
643      }
644
645      return true;
646   }
647
648   bool
649   check_memory_model(const device &dev, const std::string &source,
650                      std::string &r_log) {
651      const size_t length = source.size() / sizeof(uint32_t);
652      size_t i = SPIRV_HEADER_WORD_SIZE; // Skip header
653
654      while (i < length) {
655         const auto desc_word = get<uint32_t>(source.data(), i);
656         const auto opcode = static_cast<SpvOp>(desc_word & SpvOpCodeMask);
657         const unsigned int num_operands = desc_word >> SpvWordCountShift;
658
659         switch (opcode) {
660         case SpvOpMemoryModel:
661            switch (get<SpvAddressingModel>(source.data(), i + 1u)) {
662            case SpvAddressingModelPhysical32:
663               return dev.address_bits() == 32;
664            case SpvAddressingModelPhysical64:
665               return dev.address_bits() == 64;
666            default:
667               unreachable("Only Physical32 and Physical64 are valid for OpenCL, and the binary was already validated");
668               return false;
669            }
670            break;
671         default:
672            break;
673         }
674
675         i += num_operands;
676      }
677
678      return false;
679   }
680
681   // Copies the input binary and convert it to the endianness of the host CPU.
682   std::string
683   spirv_to_cpu(const std::string &binary)
684   {
685      const uint32_t first_word = get<uint32_t>(binary.data(), 0u);
686      if (first_word == SpvMagicNumber)
687         return binary;
688
689      std::vector<char> cpu_endianness_binary(binary.size());
690      for (size_t i = 0; i < (binary.size() / 4u); ++i) {
691         const uint32_t word = get<uint32_t>(binary.data(), i);
692         reinterpret_cast<uint32_t *>(cpu_endianness_binary.data())[i] =
693            util_bswap32(word);
694      }
695
696      return std::string(cpu_endianness_binary.begin(),
697                         cpu_endianness_binary.end());
698   }
699
700#ifdef HAVE_CLOVER_SPIRV
701   std::string
702   format_validator_msg(spv_message_level_t level, const char * /* source */,
703                        const spv_position_t &position, const char *message) {
704      std::string level_str;
705      switch (level) {
706      case SPV_MSG_FATAL:
707         level_str = "Fatal";
708         break;
709      case SPV_MSG_INTERNAL_ERROR:
710         level_str = "Internal error";
711         break;
712      case SPV_MSG_ERROR:
713         level_str = "Error";
714         break;
715      case SPV_MSG_WARNING:
716         level_str = "Warning";
717         break;
718      case SPV_MSG_INFO:
719         level_str = "Info";
720         break;
721      case SPV_MSG_DEBUG:
722         level_str = "Debug";
723         break;
724      }
725      return "[" + level_str + "] At word No." +
726             std::to_string(position.index) + ": \"" + message + "\"\n";
727   }
728
729   spv_target_env
730   convert_opencl_version_to_target_env(const cl_version opencl_version) {
731      // Pick 1.2 for 3.0 for now
732      if (opencl_version == CL_MAKE_VERSION(3, 0, 0)) {
733         return SPV_ENV_OPENCL_1_2;
734      } else if (opencl_version == CL_MAKE_VERSION(2, 2, 0)) {
735         return SPV_ENV_OPENCL_2_2;
736      } else if (opencl_version == CL_MAKE_VERSION(2, 1, 0)) {
737         return SPV_ENV_OPENCL_2_1;
738      } else if (opencl_version == CL_MAKE_VERSION(2, 0, 0)) {
739         return SPV_ENV_OPENCL_2_0;
740      } else if (opencl_version == CL_MAKE_VERSION(1, 2, 0) ||
741                 opencl_version == CL_MAKE_VERSION(1, 1, 0) ||
742                 opencl_version == CL_MAKE_VERSION(1, 0, 0)) {
743         // SPIR-V is only defined for OpenCL >= 1.2, however some drivers
744         // might use it with OpenCL 1.0 and 1.1.
745         return SPV_ENV_OPENCL_1_2;
746      } else {
747         throw build_error("Invalid OpenCL version");
748      }
749   }
750#endif
751
752}
753
754bool
755clover::spirv::is_binary_spirv(const std::string &binary)
756{
757   // A SPIR-V binary is at the very least 5 32-bit words, which represent the
758   // SPIR-V header.
759   if (binary.size() < 20u)
760      return false;
761
762   const uint32_t first_word =
763      reinterpret_cast<const uint32_t *>(binary.data())[0u];
764   return (first_word == SpvMagicNumber) ||
765          (util_bswap32(first_word) == SpvMagicNumber);
766}
767
768std::string
769clover::spirv::version_to_string(uint32_t version) {
770   const uint32_t major_version = (version >> 16) & 0xff;
771   const uint32_t minor_version = (version >> 8) & 0xff;
772   return std::to_string(major_version) + '.' +
773      std::to_string(minor_version);
774}
775
776binary
777clover::spirv::compile_program(const std::string &binary,
778                               const device &dev, std::string &r_log,
779                               bool validate) {
780   std::string source = spirv_to_cpu(binary);
781
782   if (validate && !is_valid_spirv(source, dev.device_version(), r_log))
783      throw build_error();
784
785   if (!check_spirv_version(dev, source.data(), r_log))
786      throw build_error();
787   if (!check_capabilities(dev, source, r_log))
788      throw build_error();
789   if (!check_extensions(dev, source, r_log))
790      throw build_error();
791   if (!check_memory_model(dev, source, r_log))
792      throw build_error();
793
794   return create_binary_from_spirv(source,
795                                   dev.address_bits() == 32 ? 4u : 8u, r_log);
796}
797
798binary
799clover::spirv::link_program(const std::vector<binary> &binaries,
800                            const device &dev, const std::string &opts,
801                            std::string &r_log) {
802   std::vector<std::string> options = tokenize(opts);
803
804   bool create_library = false;
805
806   std::string ignored_options;
807   for (const std::string &option : options) {
808      if (option == "-create-library") {
809         create_library = true;
810      } else {
811         ignored_options += "'" + option + "' ";
812      }
813   }
814   if (!ignored_options.empty()) {
815      r_log += "Ignoring the following link options: " + ignored_options
816            + "\n";
817   }
818
819   spvtools::LinkerOptions linker_options;
820   linker_options.SetCreateLibrary(create_library);
821
822   binary b;
823
824   const auto section_type = create_library ? binary::section::text_library :
825                                              binary::section::text_executable;
826
827   std::vector<const uint32_t *> sections;
828   sections.reserve(binaries.size());
829   std::vector<size_t> lengths;
830   lengths.reserve(binaries.size());
831
832   auto const validator_consumer = [&r_log](spv_message_level_t level,
833                                            const char *source,
834                                            const spv_position_t &position,
835                                            const char *message) {
836      r_log += format_validator_msg(level, source, position, message);
837   };
838
839   for (const auto &bin : binaries) {
840      const auto &bsec = find([](const binary::section &sec) {
841                  return sec.type == binary::section::text_intermediate ||
842                         sec.type == binary::section::text_library;
843               }, bin.secs);
844
845      const auto c_il = ((struct pipe_binary_program_header*)bsec.data.data())->blob;
846      const auto length = bsec.size;
847
848      if (!check_spirv_version(dev, c_il, r_log))
849         throw error(CL_LINK_PROGRAM_FAILURE);
850
851      sections.push_back(reinterpret_cast<const uint32_t *>(c_il));
852      lengths.push_back(length / sizeof(uint32_t));
853   }
854
855   std::vector<uint32_t> linked_binary;
856
857   const cl_version opencl_version = dev.device_version();
858   const spv_target_env target_env =
859      convert_opencl_version_to_target_env(opencl_version);
860
861   const spvtools::MessageConsumer consumer = validator_consumer;
862   spvtools::Context context(target_env);
863   context.SetMessageConsumer(std::move(consumer));
864
865   if (Link(context, sections.data(), lengths.data(), sections.size(),
866            &linked_binary, linker_options) != SPV_SUCCESS)
867      throw error(CL_LINK_PROGRAM_FAILURE);
868
869   std::string final_binary{
870         reinterpret_cast<char *>(linked_binary.data()),
871         reinterpret_cast<char *>(linked_binary.data() +
872               linked_binary.size()) };
873   if (!is_valid_spirv(final_binary, opencl_version, r_log))
874      throw error(CL_LINK_PROGRAM_FAILURE);
875
876   if (has_flag(llvm::debug::spirv))
877      llvm::debug::log(".spvasm", spirv::print_module(final_binary, dev.device_version()));
878
879   for (const auto &bin : binaries)
880      b.syms.insert(b.syms.end(), bin.syms.begin(), bin.syms.end());
881
882   b.secs.emplace_back(make_text_section(final_binary, section_type));
883
884   return b;
885}
886
887bool
888clover::spirv::is_valid_spirv(const std::string &binary,
889                              const cl_version opencl_version,
890                              std::string &r_log) {
891   auto const validator_consumer =
892      [&r_log](spv_message_level_t level, const char *source,
893               const spv_position_t &position, const char *message) {
894      r_log += format_validator_msg(level, source, position, message);
895   };
896
897   const spv_target_env target_env =
898      convert_opencl_version_to_target_env(opencl_version);
899   spvtools::SpirvTools spvTool(target_env);
900   spvTool.SetMessageConsumer(validator_consumer);
901
902   spvtools::ValidatorOptions validator_options;
903   validator_options.SetUniversalLimit(spv_validator_limit_max_function_args,
904                                       std::numeric_limits<uint32_t>::max());
905
906   return spvTool.Validate(reinterpret_cast<const uint32_t *>(binary.data()),
907                           binary.size() / 4u, validator_options);
908}
909
910std::string
911clover::spirv::print_module(const std::string &binary,
912                            const cl_version opencl_version) {
913   const spv_target_env target_env =
914      convert_opencl_version_to_target_env(opencl_version);
915   spvtools::SpirvTools spvTool(target_env);
916   spv_context spvContext = spvContextCreate(target_env);
917   if (!spvContext)
918      return "Failed to create an spv_context for disassembling the binary.";
919
920   spv_text disassembly;
921   spvBinaryToText(spvContext,
922                   reinterpret_cast<const uint32_t *>(binary.data()),
923                   binary.size() / 4u, SPV_BINARY_TO_TEXT_OPTION_NONE,
924                   &disassembly, nullptr);
925   spvContextDestroy(spvContext);
926
927   const std::string disassemblyStr = disassembly->str;
928   spvTextDestroy(disassembly);
929
930   return disassemblyStr;
931}
932
933std::unordered_set<std::string>
934clover::spirv::supported_extensions() {
935   return {
936      /* this is only a hint so all devices support that */
937      "SPV_KHR_no_integer_wrap_decoration"
938   };
939}
940
941std::vector<cl_name_version>
942clover::spirv::supported_versions() {
943   return { cl_name_version { CL_MAKE_VERSION(1u, 0u, 0u), "SPIR-V" } };
944}
945
946cl_version
947clover::spirv::to_opencl_version_encoding(uint32_t version) {
948      return CL_MAKE_VERSION((version >> 16u) & 0xff,
949                             (version >> 8u) & 0xff, 0u);
950}
951
952uint32_t
953clover::spirv::to_spirv_version_encoding(cl_version version) {
954   return ((CL_VERSION_MAJOR(version) & 0xff) << 16u) |
955          ((CL_VERSION_MINOR(version) & 0xff) << 8u);
956}
957
958#else
959bool
960clover::spirv::is_binary_spirv(const std::string &binary)
961{
962   return false;
963}
964
965bool
966clover::spirv::is_valid_spirv(const std::string &/*binary*/,
967                              const cl_version opencl_version,
968                              std::string &/*r_log*/) {
969   return false;
970}
971
972std::string
973clover::spirv::version_to_string(uint32_t version) {
974   return "";
975}
976
977binary
978clover::spirv::compile_program(const std::string &binary,
979                               const device &dev, std::string &r_log,
980                               bool validate) {
981   r_log += "SPIR-V support in clover is not enabled.\n";
982   throw build_error();
983}
984
985binary
986clover::spirv::link_program(const std::vector<binary> &/*binaries*/,
987                            const device &/*dev*/, const std::string &/*opts*/,
988                            std::string &r_log) {
989   r_log += "SPIR-V support in clover is not enabled.\n";
990   throw error(CL_LINKER_NOT_AVAILABLE);
991}
992
993std::string
994clover::spirv::print_module(const std::string &binary,
995                            const cl_version opencl_version) {
996   return std::string();
997}
998
999std::unordered_set<std::string>
1000clover::spirv::supported_extensions() {
1001   return {};
1002}
1003
1004std::vector<cl_name_version>
1005clover::spirv::supported_versions() {
1006   return {};
1007}
1008
1009cl_version
1010clover::spirv::to_opencl_version_encoding(uint32_t version) {
1011   return CL_MAKE_VERSION(0u, 0u, 0u);
1012}
1013
1014uint32_t
1015clover::spirv::to_spirv_version_encoding(cl_version version) {
1016   return 0u;
1017}
1018#endif
1019