xref: /freebsd/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp (revision 7a6dacaca14b62ca4b74406814becb87a3fefac0)
1 //===- SPIRVBuiltins.cpp - SPIR-V Built-in Functions ------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements lowering builtin function calls and types using their
10 // demangled names and TableGen records.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "SPIRVBuiltins.h"
15 #include "SPIRV.h"
16 #include "SPIRVUtils.h"
17 #include "llvm/ADT/StringExtras.h"
18 #include "llvm/Analysis/ValueTracking.h"
19 #include "llvm/IR/IntrinsicsSPIRV.h"
20 #include <string>
21 #include <tuple>
22 
23 #define DEBUG_TYPE "spirv-builtins"
24 
25 namespace llvm {
26 namespace SPIRV {
27 #define GET_BuiltinGroup_DECL
28 #include "SPIRVGenTables.inc"
29 
30 struct DemangledBuiltin {
31   StringRef Name;
32   InstructionSet::InstructionSet Set;
33   BuiltinGroup Group;
34   uint8_t MinNumArgs;
35   uint8_t MaxNumArgs;
36 };
37 
38 #define GET_DemangledBuiltins_DECL
39 #define GET_DemangledBuiltins_IMPL
40 
41 struct IncomingCall {
42   const std::string BuiltinName;
43   const DemangledBuiltin *Builtin;
44 
45   const Register ReturnRegister;
46   const SPIRVType *ReturnType;
47   const SmallVectorImpl<Register> &Arguments;
48 
49   IncomingCall(const std::string BuiltinName, const DemangledBuiltin *Builtin,
50                const Register ReturnRegister, const SPIRVType *ReturnType,
51                const SmallVectorImpl<Register> &Arguments)
52       : BuiltinName(BuiltinName), Builtin(Builtin),
53         ReturnRegister(ReturnRegister), ReturnType(ReturnType),
54         Arguments(Arguments) {}
55 };
56 
57 struct NativeBuiltin {
58   StringRef Name;
59   InstructionSet::InstructionSet Set;
60   uint32_t Opcode;
61 };
62 
63 #define GET_NativeBuiltins_DECL
64 #define GET_NativeBuiltins_IMPL
65 
66 struct GroupBuiltin {
67   StringRef Name;
68   uint32_t Opcode;
69   uint32_t GroupOperation;
70   bool IsElect;
71   bool IsAllOrAny;
72   bool IsAllEqual;
73   bool IsBallot;
74   bool IsInverseBallot;
75   bool IsBallotBitExtract;
76   bool IsBallotFindBit;
77   bool IsLogical;
78   bool NoGroupOperation;
79   bool HasBoolArg;
80 };
81 
82 #define GET_GroupBuiltins_DECL
83 #define GET_GroupBuiltins_IMPL
84 
85 struct GetBuiltin {
86   StringRef Name;
87   InstructionSet::InstructionSet Set;
88   BuiltIn::BuiltIn Value;
89 };
90 
91 using namespace BuiltIn;
92 #define GET_GetBuiltins_DECL
93 #define GET_GetBuiltins_IMPL
94 
95 struct ImageQueryBuiltin {
96   StringRef Name;
97   InstructionSet::InstructionSet Set;
98   uint32_t Component;
99 };
100 
101 #define GET_ImageQueryBuiltins_DECL
102 #define GET_ImageQueryBuiltins_IMPL
103 
104 struct ConvertBuiltin {
105   StringRef Name;
106   InstructionSet::InstructionSet Set;
107   bool IsDestinationSigned;
108   bool IsSaturated;
109   bool IsRounded;
110   FPRoundingMode::FPRoundingMode RoundingMode;
111 };
112 
113 struct VectorLoadStoreBuiltin {
114   StringRef Name;
115   InstructionSet::InstructionSet Set;
116   uint32_t Number;
117   bool IsRounded;
118   FPRoundingMode::FPRoundingMode RoundingMode;
119 };
120 
121 using namespace FPRoundingMode;
122 #define GET_ConvertBuiltins_DECL
123 #define GET_ConvertBuiltins_IMPL
124 
125 using namespace InstructionSet;
126 #define GET_VectorLoadStoreBuiltins_DECL
127 #define GET_VectorLoadStoreBuiltins_IMPL
128 
129 #define GET_CLMemoryScope_DECL
130 #define GET_CLSamplerAddressingMode_DECL
131 #define GET_CLMemoryFenceFlags_DECL
132 #define GET_ExtendedBuiltins_DECL
133 #include "SPIRVGenTables.inc"
134 } // namespace SPIRV
135 
136 //===----------------------------------------------------------------------===//
137 // Misc functions for looking up builtins and veryfying requirements using
138 // TableGen records
139 //===----------------------------------------------------------------------===//
140 
141 /// Looks up the demangled builtin call in the SPIRVBuiltins.td records using
142 /// the provided \p DemangledCall and specified \p Set.
143 ///
144 /// The lookup follows the following algorithm, returning the first successful
145 /// match:
146 /// 1. Search with the plain demangled name (expecting a 1:1 match).
147 /// 2. Search with the prefix before or suffix after the demangled name
148 /// signyfying the type of the first argument.
149 ///
150 /// \returns Wrapper around the demangled call and found builtin definition.
151 static std::unique_ptr<const SPIRV::IncomingCall>
152 lookupBuiltin(StringRef DemangledCall,
153               SPIRV::InstructionSet::InstructionSet Set,
154               Register ReturnRegister, const SPIRVType *ReturnType,
155               const SmallVectorImpl<Register> &Arguments) {
156   // Extract the builtin function name and types of arguments from the call
157   // skeleton.
158   std::string BuiltinName =
159       DemangledCall.substr(0, DemangledCall.find('(')).str();
160 
161   // Check if the extracted name contains type information between angle
162   // brackets. If so, the builtin is an instantiated template - needs to have
163   // the information after angle brackets and return type removed.
164   if (BuiltinName.find('<') && BuiltinName.back() == '>') {
165     BuiltinName = BuiltinName.substr(0, BuiltinName.find('<'));
166     BuiltinName = BuiltinName.substr(BuiltinName.find_last_of(' ') + 1);
167   }
168 
169   // Check if the extracted name begins with "__spirv_ImageSampleExplicitLod"
170   // contains return type information at the end "_R<type>", if so extract the
171   // plain builtin name without the type information.
172   if (StringRef(BuiltinName).contains("__spirv_ImageSampleExplicitLod") &&
173       StringRef(BuiltinName).contains("_R")) {
174     BuiltinName = BuiltinName.substr(0, BuiltinName.find("_R"));
175   }
176 
177   SmallVector<StringRef, 10> BuiltinArgumentTypes;
178   StringRef BuiltinArgs =
179       DemangledCall.slice(DemangledCall.find('(') + 1, DemangledCall.find(')'));
180   BuiltinArgs.split(BuiltinArgumentTypes, ',', -1, false);
181 
182   // Look up the builtin in the defined set. Start with the plain demangled
183   // name, expecting a 1:1 match in the defined builtin set.
184   const SPIRV::DemangledBuiltin *Builtin;
185   if ((Builtin = SPIRV::lookupBuiltin(BuiltinName, Set)))
186     return std::make_unique<SPIRV::IncomingCall>(
187         BuiltinName, Builtin, ReturnRegister, ReturnType, Arguments);
188 
189   // If the initial look up was unsuccessful and the demangled call takes at
190   // least 1 argument, add a prefix or suffix signifying the type of the first
191   // argument and repeat the search.
192   if (BuiltinArgumentTypes.size() >= 1) {
193     char FirstArgumentType = BuiltinArgumentTypes[0][0];
194     // Prefix to be added to the builtin's name for lookup.
195     // For example, OpenCL "abs" taking an unsigned value has a prefix "u_".
196     std::string Prefix;
197 
198     switch (FirstArgumentType) {
199     // Unsigned:
200     case 'u':
201       if (Set == SPIRV::InstructionSet::OpenCL_std)
202         Prefix = "u_";
203       else if (Set == SPIRV::InstructionSet::GLSL_std_450)
204         Prefix = "u";
205       break;
206     // Signed:
207     case 'c':
208     case 's':
209     case 'i':
210     case 'l':
211       if (Set == SPIRV::InstructionSet::OpenCL_std)
212         Prefix = "s_";
213       else if (Set == SPIRV::InstructionSet::GLSL_std_450)
214         Prefix = "s";
215       break;
216     // Floating-point:
217     case 'f':
218     case 'd':
219     case 'h':
220       if (Set == SPIRV::InstructionSet::OpenCL_std ||
221           Set == SPIRV::InstructionSet::GLSL_std_450)
222         Prefix = "f";
223       break;
224     }
225 
226     // If argument-type name prefix was added, look up the builtin again.
227     if (!Prefix.empty() &&
228         (Builtin = SPIRV::lookupBuiltin(Prefix + BuiltinName, Set)))
229       return std::make_unique<SPIRV::IncomingCall>(
230           BuiltinName, Builtin, ReturnRegister, ReturnType, Arguments);
231 
232     // If lookup with a prefix failed, find a suffix to be added to the
233     // builtin's name for lookup. For example, OpenCL "group_reduce_max" taking
234     // an unsigned value has a suffix "u".
235     std::string Suffix;
236 
237     switch (FirstArgumentType) {
238     // Unsigned:
239     case 'u':
240       Suffix = "u";
241       break;
242     // Signed:
243     case 'c':
244     case 's':
245     case 'i':
246     case 'l':
247       Suffix = "s";
248       break;
249     // Floating-point:
250     case 'f':
251     case 'd':
252     case 'h':
253       Suffix = "f";
254       break;
255     }
256 
257     // If argument-type name suffix was added, look up the builtin again.
258     if (!Suffix.empty() &&
259         (Builtin = SPIRV::lookupBuiltin(BuiltinName + Suffix, Set)))
260       return std::make_unique<SPIRV::IncomingCall>(
261           BuiltinName, Builtin, ReturnRegister, ReturnType, Arguments);
262   }
263 
264   // No builtin with such name was found in the set.
265   return nullptr;
266 }
267 
268 //===----------------------------------------------------------------------===//
269 // Helper functions for building misc instructions
270 //===----------------------------------------------------------------------===//
271 
272 /// Helper function building either a resulting scalar or vector bool register
273 /// depending on the expected \p ResultType.
274 ///
275 /// \returns Tuple of the resulting register and its type.
276 static std::tuple<Register, SPIRVType *>
277 buildBoolRegister(MachineIRBuilder &MIRBuilder, const SPIRVType *ResultType,
278                   SPIRVGlobalRegistry *GR) {
279   LLT Type;
280   SPIRVType *BoolType = GR->getOrCreateSPIRVBoolType(MIRBuilder);
281 
282   if (ResultType->getOpcode() == SPIRV::OpTypeVector) {
283     unsigned VectorElements = ResultType->getOperand(2).getImm();
284     BoolType =
285         GR->getOrCreateSPIRVVectorType(BoolType, VectorElements, MIRBuilder);
286     const FixedVectorType *LLVMVectorType =
287         cast<FixedVectorType>(GR->getTypeForSPIRVType(BoolType));
288     Type = LLT::vector(LLVMVectorType->getElementCount(), 1);
289   } else {
290     Type = LLT::scalar(1);
291   }
292 
293   Register ResultRegister =
294       MIRBuilder.getMRI()->createGenericVirtualRegister(Type);
295   MIRBuilder.getMRI()->setRegClass(ResultRegister, &SPIRV::IDRegClass);
296   GR->assignSPIRVTypeToVReg(BoolType, ResultRegister, MIRBuilder.getMF());
297   return std::make_tuple(ResultRegister, BoolType);
298 }
299 
300 /// Helper function for building either a vector or scalar select instruction
301 /// depending on the expected \p ResultType.
302 static bool buildSelectInst(MachineIRBuilder &MIRBuilder,
303                             Register ReturnRegister, Register SourceRegister,
304                             const SPIRVType *ReturnType,
305                             SPIRVGlobalRegistry *GR) {
306   Register TrueConst, FalseConst;
307 
308   if (ReturnType->getOpcode() == SPIRV::OpTypeVector) {
309     unsigned Bits = GR->getScalarOrVectorBitWidth(ReturnType);
310     uint64_t AllOnes = APInt::getAllOnes(Bits).getZExtValue();
311     TrueConst = GR->getOrCreateConsIntVector(AllOnes, MIRBuilder, ReturnType);
312     FalseConst = GR->getOrCreateConsIntVector(0, MIRBuilder, ReturnType);
313   } else {
314     TrueConst = GR->buildConstantInt(1, MIRBuilder, ReturnType);
315     FalseConst = GR->buildConstantInt(0, MIRBuilder, ReturnType);
316   }
317   return MIRBuilder.buildSelect(ReturnRegister, SourceRegister, TrueConst,
318                                 FalseConst);
319 }
320 
321 /// Helper function for building a load instruction loading into the
322 /// \p DestinationReg.
323 static Register buildLoadInst(SPIRVType *BaseType, Register PtrRegister,
324                               MachineIRBuilder &MIRBuilder,
325                               SPIRVGlobalRegistry *GR, LLT LowLevelType,
326                               Register DestinationReg = Register(0)) {
327   MachineRegisterInfo *MRI = MIRBuilder.getMRI();
328   if (!DestinationReg.isValid()) {
329     DestinationReg = MRI->createVirtualRegister(&SPIRV::IDRegClass);
330     MRI->setType(DestinationReg, LLT::scalar(32));
331     GR->assignSPIRVTypeToVReg(BaseType, DestinationReg, MIRBuilder.getMF());
332   }
333   // TODO: consider using correct address space and alignment (p0 is canonical
334   // type for selection though).
335   MachinePointerInfo PtrInfo = MachinePointerInfo();
336   MIRBuilder.buildLoad(DestinationReg, PtrRegister, PtrInfo, Align());
337   return DestinationReg;
338 }
339 
340 /// Helper function for building a load instruction for loading a builtin global
341 /// variable of \p BuiltinValue value.
342 static Register buildBuiltinVariableLoad(MachineIRBuilder &MIRBuilder,
343                                          SPIRVType *VariableType,
344                                          SPIRVGlobalRegistry *GR,
345                                          SPIRV::BuiltIn::BuiltIn BuiltinValue,
346                                          LLT LLType,
347                                          Register Reg = Register(0)) {
348   Register NewRegister =
349       MIRBuilder.getMRI()->createVirtualRegister(&SPIRV::IDRegClass);
350   MIRBuilder.getMRI()->setType(NewRegister,
351                                LLT::pointer(0, GR->getPointerSize()));
352   SPIRVType *PtrType = GR->getOrCreateSPIRVPointerType(
353       VariableType, MIRBuilder, SPIRV::StorageClass::Input);
354   GR->assignSPIRVTypeToVReg(PtrType, NewRegister, MIRBuilder.getMF());
355 
356   // Set up the global OpVariable with the necessary builtin decorations.
357   Register Variable = GR->buildGlobalVariable(
358       NewRegister, PtrType, getLinkStringForBuiltIn(BuiltinValue), nullptr,
359       SPIRV::StorageClass::Input, nullptr, true, true,
360       SPIRV::LinkageType::Import, MIRBuilder, false);
361 
362   // Load the value from the global variable.
363   Register LoadedRegister =
364       buildLoadInst(VariableType, Variable, MIRBuilder, GR, LLType, Reg);
365   MIRBuilder.getMRI()->setType(LoadedRegister, LLType);
366   return LoadedRegister;
367 }
368 
369 /// Helper external function for inserting ASSIGN_TYPE instuction between \p Reg
370 /// and its definition, set the new register as a destination of the definition,
371 /// assign SPIRVType to both registers. If SpirvTy is provided, use it as
372 /// SPIRVType in ASSIGN_TYPE, otherwise create it from \p Ty. Defined in
373 /// SPIRVPreLegalizer.cpp.
374 extern Register insertAssignInstr(Register Reg, Type *Ty, SPIRVType *SpirvTy,
375                                   SPIRVGlobalRegistry *GR,
376                                   MachineIRBuilder &MIB,
377                                   MachineRegisterInfo &MRI);
378 
379 // TODO: Move to TableGen.
380 static SPIRV::MemorySemantics::MemorySemantics
381 getSPIRVMemSemantics(std::memory_order MemOrder) {
382   switch (MemOrder) {
383   case std::memory_order::memory_order_relaxed:
384     return SPIRV::MemorySemantics::None;
385   case std::memory_order::memory_order_acquire:
386     return SPIRV::MemorySemantics::Acquire;
387   case std::memory_order::memory_order_release:
388     return SPIRV::MemorySemantics::Release;
389   case std::memory_order::memory_order_acq_rel:
390     return SPIRV::MemorySemantics::AcquireRelease;
391   case std::memory_order::memory_order_seq_cst:
392     return SPIRV::MemorySemantics::SequentiallyConsistent;
393   default:
394     llvm_unreachable("Unknown CL memory scope");
395   }
396 }
397 
398 static SPIRV::Scope::Scope getSPIRVScope(SPIRV::CLMemoryScope ClScope) {
399   switch (ClScope) {
400   case SPIRV::CLMemoryScope::memory_scope_work_item:
401     return SPIRV::Scope::Invocation;
402   case SPIRV::CLMemoryScope::memory_scope_work_group:
403     return SPIRV::Scope::Workgroup;
404   case SPIRV::CLMemoryScope::memory_scope_device:
405     return SPIRV::Scope::Device;
406   case SPIRV::CLMemoryScope::memory_scope_all_svm_devices:
407     return SPIRV::Scope::CrossDevice;
408   case SPIRV::CLMemoryScope::memory_scope_sub_group:
409     return SPIRV::Scope::Subgroup;
410   }
411   llvm_unreachable("Unknown CL memory scope");
412 }
413 
414 static Register buildConstantIntReg(uint64_t Val, MachineIRBuilder &MIRBuilder,
415                                     SPIRVGlobalRegistry *GR,
416                                     unsigned BitWidth = 32) {
417   SPIRVType *IntType = GR->getOrCreateSPIRVIntegerType(BitWidth, MIRBuilder);
418   return GR->buildConstantInt(Val, MIRBuilder, IntType);
419 }
420 
421 static Register buildScopeReg(Register CLScopeRegister,
422                               SPIRV::Scope::Scope Scope,
423                               MachineIRBuilder &MIRBuilder,
424                               SPIRVGlobalRegistry *GR,
425                               MachineRegisterInfo *MRI) {
426   if (CLScopeRegister.isValid()) {
427     auto CLScope =
428         static_cast<SPIRV::CLMemoryScope>(getIConstVal(CLScopeRegister, MRI));
429     Scope = getSPIRVScope(CLScope);
430 
431     if (CLScope == static_cast<unsigned>(Scope)) {
432       MRI->setRegClass(CLScopeRegister, &SPIRV::IDRegClass);
433       return CLScopeRegister;
434     }
435   }
436   return buildConstantIntReg(Scope, MIRBuilder, GR);
437 }
438 
439 static Register buildMemSemanticsReg(Register SemanticsRegister,
440                                      Register PtrRegister, unsigned &Semantics,
441                                      MachineIRBuilder &MIRBuilder,
442                                      SPIRVGlobalRegistry *GR) {
443   if (SemanticsRegister.isValid()) {
444     MachineRegisterInfo *MRI = MIRBuilder.getMRI();
445     std::memory_order Order =
446         static_cast<std::memory_order>(getIConstVal(SemanticsRegister, MRI));
447     Semantics =
448         getSPIRVMemSemantics(Order) |
449         getMemSemanticsForStorageClass(GR->getPointerStorageClass(PtrRegister));
450 
451     if (Order == Semantics) {
452       MRI->setRegClass(SemanticsRegister, &SPIRV::IDRegClass);
453       return SemanticsRegister;
454     }
455   }
456   return buildConstantIntReg(Semantics, MIRBuilder, GR);
457 }
458 
459 /// Helper function for translating atomic init to OpStore.
460 static bool buildAtomicInitInst(const SPIRV::IncomingCall *Call,
461                                 MachineIRBuilder &MIRBuilder) {
462   assert(Call->Arguments.size() == 2 &&
463          "Need 2 arguments for atomic init translation");
464   MIRBuilder.getMRI()->setRegClass(Call->Arguments[0], &SPIRV::IDRegClass);
465   MIRBuilder.getMRI()->setRegClass(Call->Arguments[1], &SPIRV::IDRegClass);
466   MIRBuilder.buildInstr(SPIRV::OpStore)
467       .addUse(Call->Arguments[0])
468       .addUse(Call->Arguments[1]);
469   return true;
470 }
471 
472 /// Helper function for building an atomic load instruction.
473 static bool buildAtomicLoadInst(const SPIRV::IncomingCall *Call,
474                                 MachineIRBuilder &MIRBuilder,
475                                 SPIRVGlobalRegistry *GR) {
476   Register PtrRegister = Call->Arguments[0];
477   MIRBuilder.getMRI()->setRegClass(PtrRegister, &SPIRV::IDRegClass);
478   // TODO: if true insert call to __translate_ocl_memory_sccope before
479   // OpAtomicLoad and the function implementation. We can use Translator's
480   // output for transcoding/atomic_explicit_arguments.cl as an example.
481   Register ScopeRegister;
482   if (Call->Arguments.size() > 1) {
483     ScopeRegister = Call->Arguments[1];
484     MIRBuilder.getMRI()->setRegClass(ScopeRegister, &SPIRV::IDRegClass);
485   } else
486     ScopeRegister = buildConstantIntReg(SPIRV::Scope::Device, MIRBuilder, GR);
487 
488   Register MemSemanticsReg;
489   if (Call->Arguments.size() > 2) {
490     // TODO: Insert call to __translate_ocl_memory_order before OpAtomicLoad.
491     MemSemanticsReg = Call->Arguments[2];
492     MIRBuilder.getMRI()->setRegClass(MemSemanticsReg, &SPIRV::IDRegClass);
493   } else {
494     int Semantics =
495         SPIRV::MemorySemantics::SequentiallyConsistent |
496         getMemSemanticsForStorageClass(GR->getPointerStorageClass(PtrRegister));
497     MemSemanticsReg = buildConstantIntReg(Semantics, MIRBuilder, GR);
498   }
499 
500   MIRBuilder.buildInstr(SPIRV::OpAtomicLoad)
501       .addDef(Call->ReturnRegister)
502       .addUse(GR->getSPIRVTypeID(Call->ReturnType))
503       .addUse(PtrRegister)
504       .addUse(ScopeRegister)
505       .addUse(MemSemanticsReg);
506   return true;
507 }
508 
509 /// Helper function for building an atomic store instruction.
510 static bool buildAtomicStoreInst(const SPIRV::IncomingCall *Call,
511                                  MachineIRBuilder &MIRBuilder,
512                                  SPIRVGlobalRegistry *GR) {
513   Register ScopeRegister =
514       buildConstantIntReg(SPIRV::Scope::Device, MIRBuilder, GR);
515   Register PtrRegister = Call->Arguments[0];
516   MIRBuilder.getMRI()->setRegClass(PtrRegister, &SPIRV::IDRegClass);
517   int Semantics =
518       SPIRV::MemorySemantics::SequentiallyConsistent |
519       getMemSemanticsForStorageClass(GR->getPointerStorageClass(PtrRegister));
520   Register MemSemanticsReg = buildConstantIntReg(Semantics, MIRBuilder, GR);
521   MIRBuilder.getMRI()->setRegClass(Call->Arguments[1], &SPIRV::IDRegClass);
522   MIRBuilder.buildInstr(SPIRV::OpAtomicStore)
523       .addUse(PtrRegister)
524       .addUse(ScopeRegister)
525       .addUse(MemSemanticsReg)
526       .addUse(Call->Arguments[1]);
527   return true;
528 }
529 
530 /// Helper function for building an atomic compare-exchange instruction.
531 static bool buildAtomicCompareExchangeInst(const SPIRV::IncomingCall *Call,
532                                            MachineIRBuilder &MIRBuilder,
533                                            SPIRVGlobalRegistry *GR) {
534   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
535   unsigned Opcode =
536       SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
537   bool IsCmpxchg = Call->Builtin->Name.contains("cmpxchg");
538   MachineRegisterInfo *MRI = MIRBuilder.getMRI();
539 
540   Register ObjectPtr = Call->Arguments[0];   // Pointer (volatile A *object.)
541   Register ExpectedArg = Call->Arguments[1]; // Comparator (C* expected).
542   Register Desired = Call->Arguments[2];     // Value (C Desired).
543   MRI->setRegClass(ObjectPtr, &SPIRV::IDRegClass);
544   MRI->setRegClass(ExpectedArg, &SPIRV::IDRegClass);
545   MRI->setRegClass(Desired, &SPIRV::IDRegClass);
546   SPIRVType *SpvDesiredTy = GR->getSPIRVTypeForVReg(Desired);
547   LLT DesiredLLT = MRI->getType(Desired);
548 
549   assert(GR->getSPIRVTypeForVReg(ObjectPtr)->getOpcode() ==
550          SPIRV::OpTypePointer);
551   unsigned ExpectedType = GR->getSPIRVTypeForVReg(ExpectedArg)->getOpcode();
552   assert(IsCmpxchg ? ExpectedType == SPIRV::OpTypeInt
553                    : ExpectedType == SPIRV::OpTypePointer);
554   assert(GR->isScalarOfType(Desired, SPIRV::OpTypeInt));
555 
556   SPIRVType *SpvObjectPtrTy = GR->getSPIRVTypeForVReg(ObjectPtr);
557   assert(SpvObjectPtrTy->getOperand(2).isReg() && "SPIRV type is expected");
558   auto StorageClass = static_cast<SPIRV::StorageClass::StorageClass>(
559       SpvObjectPtrTy->getOperand(1).getImm());
560   auto MemSemStorage = getMemSemanticsForStorageClass(StorageClass);
561 
562   Register MemSemEqualReg;
563   Register MemSemUnequalReg;
564   uint64_t MemSemEqual =
565       IsCmpxchg
566           ? SPIRV::MemorySemantics::None
567           : SPIRV::MemorySemantics::SequentiallyConsistent | MemSemStorage;
568   uint64_t MemSemUnequal =
569       IsCmpxchg
570           ? SPIRV::MemorySemantics::None
571           : SPIRV::MemorySemantics::SequentiallyConsistent | MemSemStorage;
572   if (Call->Arguments.size() >= 4) {
573     assert(Call->Arguments.size() >= 5 &&
574            "Need 5+ args for explicit atomic cmpxchg");
575     auto MemOrdEq =
576         static_cast<std::memory_order>(getIConstVal(Call->Arguments[3], MRI));
577     auto MemOrdNeq =
578         static_cast<std::memory_order>(getIConstVal(Call->Arguments[4], MRI));
579     MemSemEqual = getSPIRVMemSemantics(MemOrdEq) | MemSemStorage;
580     MemSemUnequal = getSPIRVMemSemantics(MemOrdNeq) | MemSemStorage;
581     if (MemOrdEq == MemSemEqual)
582       MemSemEqualReg = Call->Arguments[3];
583     if (MemOrdNeq == MemSemEqual)
584       MemSemUnequalReg = Call->Arguments[4];
585     MRI->setRegClass(Call->Arguments[3], &SPIRV::IDRegClass);
586     MRI->setRegClass(Call->Arguments[4], &SPIRV::IDRegClass);
587   }
588   if (!MemSemEqualReg.isValid())
589     MemSemEqualReg = buildConstantIntReg(MemSemEqual, MIRBuilder, GR);
590   if (!MemSemUnequalReg.isValid())
591     MemSemUnequalReg = buildConstantIntReg(MemSemUnequal, MIRBuilder, GR);
592 
593   Register ScopeReg;
594   auto Scope = IsCmpxchg ? SPIRV::Scope::Workgroup : SPIRV::Scope::Device;
595   if (Call->Arguments.size() >= 6) {
596     assert(Call->Arguments.size() == 6 &&
597            "Extra args for explicit atomic cmpxchg");
598     auto ClScope = static_cast<SPIRV::CLMemoryScope>(
599         getIConstVal(Call->Arguments[5], MRI));
600     Scope = getSPIRVScope(ClScope);
601     if (ClScope == static_cast<unsigned>(Scope))
602       ScopeReg = Call->Arguments[5];
603     MRI->setRegClass(Call->Arguments[5], &SPIRV::IDRegClass);
604   }
605   if (!ScopeReg.isValid())
606     ScopeReg = buildConstantIntReg(Scope, MIRBuilder, GR);
607 
608   Register Expected = IsCmpxchg
609                           ? ExpectedArg
610                           : buildLoadInst(SpvDesiredTy, ExpectedArg, MIRBuilder,
611                                           GR, LLT::scalar(32));
612   MRI->setType(Expected, DesiredLLT);
613   Register Tmp = !IsCmpxchg ? MRI->createGenericVirtualRegister(DesiredLLT)
614                             : Call->ReturnRegister;
615   if (!MRI->getRegClassOrNull(Tmp))
616     MRI->setRegClass(Tmp, &SPIRV::IDRegClass);
617   GR->assignSPIRVTypeToVReg(SpvDesiredTy, Tmp, MIRBuilder.getMF());
618 
619   SPIRVType *IntTy = GR->getOrCreateSPIRVIntegerType(32, MIRBuilder);
620   MIRBuilder.buildInstr(Opcode)
621       .addDef(Tmp)
622       .addUse(GR->getSPIRVTypeID(IntTy))
623       .addUse(ObjectPtr)
624       .addUse(ScopeReg)
625       .addUse(MemSemEqualReg)
626       .addUse(MemSemUnequalReg)
627       .addUse(Desired)
628       .addUse(Expected);
629   if (!IsCmpxchg) {
630     MIRBuilder.buildInstr(SPIRV::OpStore).addUse(ExpectedArg).addUse(Tmp);
631     MIRBuilder.buildICmp(CmpInst::ICMP_EQ, Call->ReturnRegister, Tmp, Expected);
632   }
633   return true;
634 }
635 
636 /// Helper function for building an atomic load instruction.
637 static bool buildAtomicRMWInst(const SPIRV::IncomingCall *Call, unsigned Opcode,
638                                MachineIRBuilder &MIRBuilder,
639                                SPIRVGlobalRegistry *GR) {
640   MachineRegisterInfo *MRI = MIRBuilder.getMRI();
641   Register ScopeRegister =
642       Call->Arguments.size() >= 4 ? Call->Arguments[3] : Register();
643 
644   assert(Call->Arguments.size() <= 4 &&
645          "Too many args for explicit atomic RMW");
646   ScopeRegister = buildScopeReg(ScopeRegister, SPIRV::Scope::Workgroup,
647                                 MIRBuilder, GR, MRI);
648 
649   Register PtrRegister = Call->Arguments[0];
650   unsigned Semantics = SPIRV::MemorySemantics::None;
651   MRI->setRegClass(PtrRegister, &SPIRV::IDRegClass);
652   Register MemSemanticsReg =
653       Call->Arguments.size() >= 3 ? Call->Arguments[2] : Register();
654   MemSemanticsReg = buildMemSemanticsReg(MemSemanticsReg, PtrRegister,
655                                          Semantics, MIRBuilder, GR);
656   MRI->setRegClass(Call->Arguments[1], &SPIRV::IDRegClass);
657   MIRBuilder.buildInstr(Opcode)
658       .addDef(Call->ReturnRegister)
659       .addUse(GR->getSPIRVTypeID(Call->ReturnType))
660       .addUse(PtrRegister)
661       .addUse(ScopeRegister)
662       .addUse(MemSemanticsReg)
663       .addUse(Call->Arguments[1]);
664   return true;
665 }
666 
667 /// Helper function for building atomic flag instructions (e.g.
668 /// OpAtomicFlagTestAndSet).
669 static bool buildAtomicFlagInst(const SPIRV::IncomingCall *Call,
670                                 unsigned Opcode, MachineIRBuilder &MIRBuilder,
671                                 SPIRVGlobalRegistry *GR) {
672   MachineRegisterInfo *MRI = MIRBuilder.getMRI();
673   Register PtrRegister = Call->Arguments[0];
674   unsigned Semantics = SPIRV::MemorySemantics::SequentiallyConsistent;
675   Register MemSemanticsReg =
676       Call->Arguments.size() >= 2 ? Call->Arguments[1] : Register();
677   MemSemanticsReg = buildMemSemanticsReg(MemSemanticsReg, PtrRegister,
678                                          Semantics, MIRBuilder, GR);
679 
680   assert((Opcode != SPIRV::OpAtomicFlagClear ||
681           (Semantics != SPIRV::MemorySemantics::Acquire &&
682            Semantics != SPIRV::MemorySemantics::AcquireRelease)) &&
683          "Invalid memory order argument!");
684 
685   Register ScopeRegister =
686       Call->Arguments.size() >= 3 ? Call->Arguments[2] : Register();
687   ScopeRegister =
688       buildScopeReg(ScopeRegister, SPIRV::Scope::Device, MIRBuilder, GR, MRI);
689 
690   auto MIB = MIRBuilder.buildInstr(Opcode);
691   if (Opcode == SPIRV::OpAtomicFlagTestAndSet)
692     MIB.addDef(Call->ReturnRegister)
693         .addUse(GR->getSPIRVTypeID(Call->ReturnType));
694 
695   MIB.addUse(PtrRegister).addUse(ScopeRegister).addUse(MemSemanticsReg);
696   return true;
697 }
698 
699 /// Helper function for building barriers, i.e., memory/control ordering
700 /// operations.
701 static bool buildBarrierInst(const SPIRV::IncomingCall *Call, unsigned Opcode,
702                              MachineIRBuilder &MIRBuilder,
703                              SPIRVGlobalRegistry *GR) {
704   MachineRegisterInfo *MRI = MIRBuilder.getMRI();
705   unsigned MemFlags = getIConstVal(Call->Arguments[0], MRI);
706   unsigned MemSemantics = SPIRV::MemorySemantics::None;
707 
708   if (MemFlags & SPIRV::CLK_LOCAL_MEM_FENCE)
709     MemSemantics |= SPIRV::MemorySemantics::WorkgroupMemory;
710 
711   if (MemFlags & SPIRV::CLK_GLOBAL_MEM_FENCE)
712     MemSemantics |= SPIRV::MemorySemantics::CrossWorkgroupMemory;
713 
714   if (MemFlags & SPIRV::CLK_IMAGE_MEM_FENCE)
715     MemSemantics |= SPIRV::MemorySemantics::ImageMemory;
716 
717   if (Opcode == SPIRV::OpMemoryBarrier) {
718     std::memory_order MemOrder =
719         static_cast<std::memory_order>(getIConstVal(Call->Arguments[1], MRI));
720     MemSemantics = getSPIRVMemSemantics(MemOrder) | MemSemantics;
721   } else {
722     MemSemantics |= SPIRV::MemorySemantics::SequentiallyConsistent;
723   }
724 
725   Register MemSemanticsReg;
726   if (MemFlags == MemSemantics) {
727     MemSemanticsReg = Call->Arguments[0];
728     MRI->setRegClass(MemSemanticsReg, &SPIRV::IDRegClass);
729   } else
730     MemSemanticsReg = buildConstantIntReg(MemSemantics, MIRBuilder, GR);
731 
732   Register ScopeReg;
733   SPIRV::Scope::Scope Scope = SPIRV::Scope::Workgroup;
734   SPIRV::Scope::Scope MemScope = Scope;
735   if (Call->Arguments.size() >= 2) {
736     assert(
737         ((Opcode != SPIRV::OpMemoryBarrier && Call->Arguments.size() == 2) ||
738          (Opcode == SPIRV::OpMemoryBarrier && Call->Arguments.size() == 3)) &&
739         "Extra args for explicitly scoped barrier");
740     Register ScopeArg = (Opcode == SPIRV::OpMemoryBarrier) ? Call->Arguments[2]
741                                                            : Call->Arguments[1];
742     SPIRV::CLMemoryScope CLScope =
743         static_cast<SPIRV::CLMemoryScope>(getIConstVal(ScopeArg, MRI));
744     MemScope = getSPIRVScope(CLScope);
745     if (!(MemFlags & SPIRV::CLK_LOCAL_MEM_FENCE) ||
746         (Opcode == SPIRV::OpMemoryBarrier))
747       Scope = MemScope;
748 
749     if (CLScope == static_cast<unsigned>(Scope)) {
750       ScopeReg = Call->Arguments[1];
751       MRI->setRegClass(ScopeReg, &SPIRV::IDRegClass);
752     }
753   }
754 
755   if (!ScopeReg.isValid())
756     ScopeReg = buildConstantIntReg(Scope, MIRBuilder, GR);
757 
758   auto MIB = MIRBuilder.buildInstr(Opcode).addUse(ScopeReg);
759   if (Opcode != SPIRV::OpMemoryBarrier)
760     MIB.addUse(buildConstantIntReg(MemScope, MIRBuilder, GR));
761   MIB.addUse(MemSemanticsReg);
762   return true;
763 }
764 
765 static unsigned getNumComponentsForDim(SPIRV::Dim::Dim dim) {
766   switch (dim) {
767   case SPIRV::Dim::DIM_1D:
768   case SPIRV::Dim::DIM_Buffer:
769     return 1;
770   case SPIRV::Dim::DIM_2D:
771   case SPIRV::Dim::DIM_Cube:
772   case SPIRV::Dim::DIM_Rect:
773     return 2;
774   case SPIRV::Dim::DIM_3D:
775     return 3;
776   default:
777     llvm_unreachable("Cannot get num components for given Dim");
778   }
779 }
780 
781 /// Helper function for obtaining the number of size components.
782 static unsigned getNumSizeComponents(SPIRVType *imgType) {
783   assert(imgType->getOpcode() == SPIRV::OpTypeImage);
784   auto dim = static_cast<SPIRV::Dim::Dim>(imgType->getOperand(2).getImm());
785   unsigned numComps = getNumComponentsForDim(dim);
786   bool arrayed = imgType->getOperand(4).getImm() == 1;
787   return arrayed ? numComps + 1 : numComps;
788 }
789 
790 //===----------------------------------------------------------------------===//
791 // Implementation functions for each builtin group
792 //===----------------------------------------------------------------------===//
793 
794 static bool generateExtInst(const SPIRV::IncomingCall *Call,
795                             MachineIRBuilder &MIRBuilder,
796                             SPIRVGlobalRegistry *GR) {
797   // Lookup the extended instruction number in the TableGen records.
798   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
799   uint32_t Number =
800       SPIRV::lookupExtendedBuiltin(Builtin->Name, Builtin->Set)->Number;
801 
802   // Build extended instruction.
803   auto MIB =
804       MIRBuilder.buildInstr(SPIRV::OpExtInst)
805           .addDef(Call->ReturnRegister)
806           .addUse(GR->getSPIRVTypeID(Call->ReturnType))
807           .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::OpenCL_std))
808           .addImm(Number);
809 
810   for (auto Argument : Call->Arguments)
811     MIB.addUse(Argument);
812   return true;
813 }
814 
815 static bool generateRelationalInst(const SPIRV::IncomingCall *Call,
816                                    MachineIRBuilder &MIRBuilder,
817                                    SPIRVGlobalRegistry *GR) {
818   // Lookup the instruction opcode in the TableGen records.
819   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
820   unsigned Opcode =
821       SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
822 
823   Register CompareRegister;
824   SPIRVType *RelationType;
825   std::tie(CompareRegister, RelationType) =
826       buildBoolRegister(MIRBuilder, Call->ReturnType, GR);
827 
828   // Build relational instruction.
829   auto MIB = MIRBuilder.buildInstr(Opcode)
830                  .addDef(CompareRegister)
831                  .addUse(GR->getSPIRVTypeID(RelationType));
832 
833   for (auto Argument : Call->Arguments)
834     MIB.addUse(Argument);
835 
836   // Build select instruction.
837   return buildSelectInst(MIRBuilder, Call->ReturnRegister, CompareRegister,
838                          Call->ReturnType, GR);
839 }
840 
841 static bool generateGroupInst(const SPIRV::IncomingCall *Call,
842                               MachineIRBuilder &MIRBuilder,
843                               SPIRVGlobalRegistry *GR) {
844   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
845   const SPIRV::GroupBuiltin *GroupBuiltin =
846       SPIRV::lookupGroupBuiltin(Builtin->Name);
847   MachineRegisterInfo *MRI = MIRBuilder.getMRI();
848   Register Arg0;
849   if (GroupBuiltin->HasBoolArg) {
850     Register ConstRegister = Call->Arguments[0];
851     auto ArgInstruction = getDefInstrMaybeConstant(ConstRegister, MRI);
852     // TODO: support non-constant bool values.
853     assert(ArgInstruction->getOpcode() == TargetOpcode::G_CONSTANT &&
854            "Only constant bool value args are supported");
855     if (GR->getSPIRVTypeForVReg(Call->Arguments[0])->getOpcode() !=
856         SPIRV::OpTypeBool)
857       Arg0 = GR->buildConstantInt(getIConstVal(ConstRegister, MRI), MIRBuilder,
858                                   GR->getOrCreateSPIRVBoolType(MIRBuilder));
859   }
860 
861   Register GroupResultRegister = Call->ReturnRegister;
862   SPIRVType *GroupResultType = Call->ReturnType;
863 
864   // TODO: maybe we need to check whether the result type is already boolean
865   // and in this case do not insert select instruction.
866   const bool HasBoolReturnTy =
867       GroupBuiltin->IsElect || GroupBuiltin->IsAllOrAny ||
868       GroupBuiltin->IsAllEqual || GroupBuiltin->IsLogical ||
869       GroupBuiltin->IsInverseBallot || GroupBuiltin->IsBallotBitExtract;
870 
871   if (HasBoolReturnTy)
872     std::tie(GroupResultRegister, GroupResultType) =
873         buildBoolRegister(MIRBuilder, Call->ReturnType, GR);
874 
875   auto Scope = Builtin->Name.starts_with("sub_group") ? SPIRV::Scope::Subgroup
876                                                       : SPIRV::Scope::Workgroup;
877   Register ScopeRegister = buildConstantIntReg(Scope, MIRBuilder, GR);
878 
879   // Build work/sub group instruction.
880   auto MIB = MIRBuilder.buildInstr(GroupBuiltin->Opcode)
881                  .addDef(GroupResultRegister)
882                  .addUse(GR->getSPIRVTypeID(GroupResultType))
883                  .addUse(ScopeRegister);
884 
885   if (!GroupBuiltin->NoGroupOperation)
886     MIB.addImm(GroupBuiltin->GroupOperation);
887   if (Call->Arguments.size() > 0) {
888     MIB.addUse(Arg0.isValid() ? Arg0 : Call->Arguments[0]);
889     MRI->setRegClass(Call->Arguments[0], &SPIRV::IDRegClass);
890     for (unsigned i = 1; i < Call->Arguments.size(); i++) {
891       MIB.addUse(Call->Arguments[i]);
892       MRI->setRegClass(Call->Arguments[i], &SPIRV::IDRegClass);
893     }
894   }
895 
896   // Build select instruction.
897   if (HasBoolReturnTy)
898     buildSelectInst(MIRBuilder, Call->ReturnRegister, GroupResultRegister,
899                     Call->ReturnType, GR);
900   return true;
901 }
902 
903 // These queries ask for a single size_t result for a given dimension index, e.g
904 // size_t get_global_id(uint dimindex). In SPIR-V, the builtins corresonding to
905 // these values are all vec3 types, so we need to extract the correct index or
906 // return defaultVal (0 or 1 depending on the query). We also handle extending
907 // or tuncating in case size_t does not match the expected result type's
908 // bitwidth.
909 //
910 // For a constant index >= 3 we generate:
911 //  %res = OpConstant %SizeT 0
912 //
913 // For other indices we generate:
914 //  %g = OpVariable %ptr_V3_SizeT Input
915 //  OpDecorate %g BuiltIn XXX
916 //  OpDecorate %g LinkageAttributes "__spirv_BuiltInXXX"
917 //  OpDecorate %g Constant
918 //  %loadedVec = OpLoad %V3_SizeT %g
919 //
920 //  Then, if the index is constant < 3, we generate:
921 //    %res = OpCompositeExtract %SizeT %loadedVec idx
922 //  If the index is dynamic, we generate:
923 //    %tmp = OpVectorExtractDynamic %SizeT %loadedVec %idx
924 //    %cmp = OpULessThan %bool %idx %const_3
925 //    %res = OpSelect %SizeT %cmp %tmp %const_0
926 //
927 //  If the bitwidth of %res does not match the expected return type, we add an
928 //  extend or truncate.
929 static bool genWorkgroupQuery(const SPIRV::IncomingCall *Call,
930                               MachineIRBuilder &MIRBuilder,
931                               SPIRVGlobalRegistry *GR,
932                               SPIRV::BuiltIn::BuiltIn BuiltinValue,
933                               uint64_t DefaultValue) {
934   Register IndexRegister = Call->Arguments[0];
935   const unsigned ResultWidth = Call->ReturnType->getOperand(1).getImm();
936   const unsigned PointerSize = GR->getPointerSize();
937   const SPIRVType *PointerSizeType =
938       GR->getOrCreateSPIRVIntegerType(PointerSize, MIRBuilder);
939   MachineRegisterInfo *MRI = MIRBuilder.getMRI();
940   auto IndexInstruction = getDefInstrMaybeConstant(IndexRegister, MRI);
941 
942   // Set up the final register to do truncation or extension on at the end.
943   Register ToTruncate = Call->ReturnRegister;
944 
945   // If the index is constant, we can statically determine if it is in range.
946   bool IsConstantIndex =
947       IndexInstruction->getOpcode() == TargetOpcode::G_CONSTANT;
948 
949   // If it's out of range (max dimension is 3), we can just return the constant
950   // default value (0 or 1 depending on which query function).
951   if (IsConstantIndex && getIConstVal(IndexRegister, MRI) >= 3) {
952     Register DefaultReg = Call->ReturnRegister;
953     if (PointerSize != ResultWidth) {
954       DefaultReg = MRI->createGenericVirtualRegister(LLT::scalar(PointerSize));
955       MRI->setRegClass(DefaultReg, &SPIRV::IDRegClass);
956       GR->assignSPIRVTypeToVReg(PointerSizeType, DefaultReg,
957                                 MIRBuilder.getMF());
958       ToTruncate = DefaultReg;
959     }
960     auto NewRegister =
961         GR->buildConstantInt(DefaultValue, MIRBuilder, PointerSizeType);
962     MIRBuilder.buildCopy(DefaultReg, NewRegister);
963   } else { // If it could be in range, we need to load from the given builtin.
964     auto Vec3Ty =
965         GR->getOrCreateSPIRVVectorType(PointerSizeType, 3, MIRBuilder);
966     Register LoadedVector =
967         buildBuiltinVariableLoad(MIRBuilder, Vec3Ty, GR, BuiltinValue,
968                                  LLT::fixed_vector(3, PointerSize));
969     // Set up the vreg to extract the result to (possibly a new temporary one).
970     Register Extracted = Call->ReturnRegister;
971     if (!IsConstantIndex || PointerSize != ResultWidth) {
972       Extracted = MRI->createGenericVirtualRegister(LLT::scalar(PointerSize));
973       MRI->setRegClass(Extracted, &SPIRV::IDRegClass);
974       GR->assignSPIRVTypeToVReg(PointerSizeType, Extracted, MIRBuilder.getMF());
975     }
976     // Use Intrinsic::spv_extractelt so dynamic vs static extraction is
977     // handled later: extr = spv_extractelt LoadedVector, IndexRegister.
978     MachineInstrBuilder ExtractInst = MIRBuilder.buildIntrinsic(
979         Intrinsic::spv_extractelt, ArrayRef<Register>{Extracted}, true, false);
980     ExtractInst.addUse(LoadedVector).addUse(IndexRegister);
981 
982     // If the index is dynamic, need check if it's < 3, and then use a select.
983     if (!IsConstantIndex) {
984       insertAssignInstr(Extracted, nullptr, PointerSizeType, GR, MIRBuilder,
985                         *MRI);
986 
987       auto IndexType = GR->getSPIRVTypeForVReg(IndexRegister);
988       auto BoolType = GR->getOrCreateSPIRVBoolType(MIRBuilder);
989 
990       Register CompareRegister =
991           MRI->createGenericVirtualRegister(LLT::scalar(1));
992       MRI->setRegClass(CompareRegister, &SPIRV::IDRegClass);
993       GR->assignSPIRVTypeToVReg(BoolType, CompareRegister, MIRBuilder.getMF());
994 
995       // Use G_ICMP to check if idxVReg < 3.
996       MIRBuilder.buildICmp(CmpInst::ICMP_ULT, CompareRegister, IndexRegister,
997                            GR->buildConstantInt(3, MIRBuilder, IndexType));
998 
999       // Get constant for the default value (0 or 1 depending on which
1000       // function).
1001       Register DefaultRegister =
1002           GR->buildConstantInt(DefaultValue, MIRBuilder, PointerSizeType);
1003 
1004       // Get a register for the selection result (possibly a new temporary one).
1005       Register SelectionResult = Call->ReturnRegister;
1006       if (PointerSize != ResultWidth) {
1007         SelectionResult =
1008             MRI->createGenericVirtualRegister(LLT::scalar(PointerSize));
1009         MRI->setRegClass(SelectionResult, &SPIRV::IDRegClass);
1010         GR->assignSPIRVTypeToVReg(PointerSizeType, SelectionResult,
1011                                   MIRBuilder.getMF());
1012       }
1013       // Create the final G_SELECT to return the extracted value or the default.
1014       MIRBuilder.buildSelect(SelectionResult, CompareRegister, Extracted,
1015                              DefaultRegister);
1016       ToTruncate = SelectionResult;
1017     } else {
1018       ToTruncate = Extracted;
1019     }
1020   }
1021   // Alter the result's bitwidth if it does not match the SizeT value extracted.
1022   if (PointerSize != ResultWidth)
1023     MIRBuilder.buildZExtOrTrunc(Call->ReturnRegister, ToTruncate);
1024   return true;
1025 }
1026 
1027 static bool generateBuiltinVar(const SPIRV::IncomingCall *Call,
1028                                MachineIRBuilder &MIRBuilder,
1029                                SPIRVGlobalRegistry *GR) {
1030   // Lookup the builtin variable record.
1031   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
1032   SPIRV::BuiltIn::BuiltIn Value =
1033       SPIRV::lookupGetBuiltin(Builtin->Name, Builtin->Set)->Value;
1034 
1035   if (Value == SPIRV::BuiltIn::GlobalInvocationId)
1036     return genWorkgroupQuery(Call, MIRBuilder, GR, Value, 0);
1037 
1038   // Build a load instruction for the builtin variable.
1039   unsigned BitWidth = GR->getScalarOrVectorBitWidth(Call->ReturnType);
1040   LLT LLType;
1041   if (Call->ReturnType->getOpcode() == SPIRV::OpTypeVector)
1042     LLType =
1043         LLT::fixed_vector(Call->ReturnType->getOperand(2).getImm(), BitWidth);
1044   else
1045     LLType = LLT::scalar(BitWidth);
1046 
1047   return buildBuiltinVariableLoad(MIRBuilder, Call->ReturnType, GR, Value,
1048                                   LLType, Call->ReturnRegister);
1049 }
1050 
1051 static bool generateAtomicInst(const SPIRV::IncomingCall *Call,
1052                                MachineIRBuilder &MIRBuilder,
1053                                SPIRVGlobalRegistry *GR) {
1054   // Lookup the instruction opcode in the TableGen records.
1055   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
1056   unsigned Opcode =
1057       SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
1058 
1059   switch (Opcode) {
1060   case SPIRV::OpStore:
1061     return buildAtomicInitInst(Call, MIRBuilder);
1062   case SPIRV::OpAtomicLoad:
1063     return buildAtomicLoadInst(Call, MIRBuilder, GR);
1064   case SPIRV::OpAtomicStore:
1065     return buildAtomicStoreInst(Call, MIRBuilder, GR);
1066   case SPIRV::OpAtomicCompareExchange:
1067   case SPIRV::OpAtomicCompareExchangeWeak:
1068     return buildAtomicCompareExchangeInst(Call, MIRBuilder, GR);
1069   case SPIRV::OpAtomicIAdd:
1070   case SPIRV::OpAtomicISub:
1071   case SPIRV::OpAtomicOr:
1072   case SPIRV::OpAtomicXor:
1073   case SPIRV::OpAtomicAnd:
1074   case SPIRV::OpAtomicExchange:
1075     return buildAtomicRMWInst(Call, Opcode, MIRBuilder, GR);
1076   case SPIRV::OpMemoryBarrier:
1077     return buildBarrierInst(Call, SPIRV::OpMemoryBarrier, MIRBuilder, GR);
1078   case SPIRV::OpAtomicFlagTestAndSet:
1079   case SPIRV::OpAtomicFlagClear:
1080     return buildAtomicFlagInst(Call, Opcode, MIRBuilder, GR);
1081   default:
1082     return false;
1083   }
1084 }
1085 
1086 static bool generateBarrierInst(const SPIRV::IncomingCall *Call,
1087                                 MachineIRBuilder &MIRBuilder,
1088                                 SPIRVGlobalRegistry *GR) {
1089   // Lookup the instruction opcode in the TableGen records.
1090   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
1091   unsigned Opcode =
1092       SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
1093 
1094   return buildBarrierInst(Call, Opcode, MIRBuilder, GR);
1095 }
1096 
1097 static bool generateDotOrFMulInst(const SPIRV::IncomingCall *Call,
1098                                   MachineIRBuilder &MIRBuilder,
1099                                   SPIRVGlobalRegistry *GR) {
1100   unsigned Opcode = GR->getSPIRVTypeForVReg(Call->Arguments[0])->getOpcode();
1101   bool IsVec = Opcode == SPIRV::OpTypeVector;
1102   // Use OpDot only in case of vector args and OpFMul in case of scalar args.
1103   MIRBuilder.buildInstr(IsVec ? SPIRV::OpDot : SPIRV::OpFMulS)
1104       .addDef(Call->ReturnRegister)
1105       .addUse(GR->getSPIRVTypeID(Call->ReturnType))
1106       .addUse(Call->Arguments[0])
1107       .addUse(Call->Arguments[1]);
1108   return true;
1109 }
1110 
1111 static bool generateGetQueryInst(const SPIRV::IncomingCall *Call,
1112                                  MachineIRBuilder &MIRBuilder,
1113                                  SPIRVGlobalRegistry *GR) {
1114   // Lookup the builtin record.
1115   SPIRV::BuiltIn::BuiltIn Value =
1116       SPIRV::lookupGetBuiltin(Call->Builtin->Name, Call->Builtin->Set)->Value;
1117   uint64_t IsDefault = (Value == SPIRV::BuiltIn::GlobalSize ||
1118                         Value == SPIRV::BuiltIn::WorkgroupSize ||
1119                         Value == SPIRV::BuiltIn::EnqueuedWorkgroupSize);
1120   return genWorkgroupQuery(Call, MIRBuilder, GR, Value, IsDefault ? 1 : 0);
1121 }
1122 
1123 static bool generateImageSizeQueryInst(const SPIRV::IncomingCall *Call,
1124                                        MachineIRBuilder &MIRBuilder,
1125                                        SPIRVGlobalRegistry *GR) {
1126   // Lookup the image size query component number in the TableGen records.
1127   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
1128   uint32_t Component =
1129       SPIRV::lookupImageQueryBuiltin(Builtin->Name, Builtin->Set)->Component;
1130   // Query result may either be a vector or a scalar. If return type is not a
1131   // vector, expect only a single size component. Otherwise get the number of
1132   // expected components.
1133   SPIRVType *RetTy = Call->ReturnType;
1134   unsigned NumExpectedRetComponents = RetTy->getOpcode() == SPIRV::OpTypeVector
1135                                           ? RetTy->getOperand(2).getImm()
1136                                           : 1;
1137   // Get the actual number of query result/size components.
1138   SPIRVType *ImgType = GR->getSPIRVTypeForVReg(Call->Arguments[0]);
1139   unsigned NumActualRetComponents = getNumSizeComponents(ImgType);
1140   Register QueryResult = Call->ReturnRegister;
1141   SPIRVType *QueryResultType = Call->ReturnType;
1142   if (NumExpectedRetComponents != NumActualRetComponents) {
1143     QueryResult = MIRBuilder.getMRI()->createGenericVirtualRegister(
1144         LLT::fixed_vector(NumActualRetComponents, 32));
1145     MIRBuilder.getMRI()->setRegClass(QueryResult, &SPIRV::IDRegClass);
1146     SPIRVType *IntTy = GR->getOrCreateSPIRVIntegerType(32, MIRBuilder);
1147     QueryResultType = GR->getOrCreateSPIRVVectorType(
1148         IntTy, NumActualRetComponents, MIRBuilder);
1149     GR->assignSPIRVTypeToVReg(QueryResultType, QueryResult, MIRBuilder.getMF());
1150   }
1151   bool IsDimBuf = ImgType->getOperand(2).getImm() == SPIRV::Dim::DIM_Buffer;
1152   unsigned Opcode =
1153       IsDimBuf ? SPIRV::OpImageQuerySize : SPIRV::OpImageQuerySizeLod;
1154   MIRBuilder.getMRI()->setRegClass(Call->Arguments[0], &SPIRV::IDRegClass);
1155   auto MIB = MIRBuilder.buildInstr(Opcode)
1156                  .addDef(QueryResult)
1157                  .addUse(GR->getSPIRVTypeID(QueryResultType))
1158                  .addUse(Call->Arguments[0]);
1159   if (!IsDimBuf)
1160     MIB.addUse(buildConstantIntReg(0, MIRBuilder, GR)); // Lod id.
1161   if (NumExpectedRetComponents == NumActualRetComponents)
1162     return true;
1163   if (NumExpectedRetComponents == 1) {
1164     // Only 1 component is expected, build OpCompositeExtract instruction.
1165     unsigned ExtractedComposite =
1166         Component == 3 ? NumActualRetComponents - 1 : Component;
1167     assert(ExtractedComposite < NumActualRetComponents &&
1168            "Invalid composite index!");
1169     MIRBuilder.buildInstr(SPIRV::OpCompositeExtract)
1170         .addDef(Call->ReturnRegister)
1171         .addUse(GR->getSPIRVTypeID(Call->ReturnType))
1172         .addUse(QueryResult)
1173         .addImm(ExtractedComposite);
1174   } else {
1175     // More than 1 component is expected, fill a new vector.
1176     auto MIB = MIRBuilder.buildInstr(SPIRV::OpVectorShuffle)
1177                    .addDef(Call->ReturnRegister)
1178                    .addUse(GR->getSPIRVTypeID(Call->ReturnType))
1179                    .addUse(QueryResult)
1180                    .addUse(QueryResult);
1181     for (unsigned i = 0; i < NumExpectedRetComponents; ++i)
1182       MIB.addImm(i < NumActualRetComponents ? i : 0xffffffff);
1183   }
1184   return true;
1185 }
1186 
1187 static bool generateImageMiscQueryInst(const SPIRV::IncomingCall *Call,
1188                                        MachineIRBuilder &MIRBuilder,
1189                                        SPIRVGlobalRegistry *GR) {
1190   assert(Call->ReturnType->getOpcode() == SPIRV::OpTypeInt &&
1191          "Image samples query result must be of int type!");
1192 
1193   // Lookup the instruction opcode in the TableGen records.
1194   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
1195   unsigned Opcode =
1196       SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
1197 
1198   Register Image = Call->Arguments[0];
1199   MIRBuilder.getMRI()->setRegClass(Image, &SPIRV::IDRegClass);
1200   SPIRV::Dim::Dim ImageDimensionality = static_cast<SPIRV::Dim::Dim>(
1201       GR->getSPIRVTypeForVReg(Image)->getOperand(2).getImm());
1202 
1203   switch (Opcode) {
1204   case SPIRV::OpImageQuerySamples:
1205     assert(ImageDimensionality == SPIRV::Dim::DIM_2D &&
1206            "Image must be of 2D dimensionality");
1207     break;
1208   case SPIRV::OpImageQueryLevels:
1209     assert((ImageDimensionality == SPIRV::Dim::DIM_1D ||
1210             ImageDimensionality == SPIRV::Dim::DIM_2D ||
1211             ImageDimensionality == SPIRV::Dim::DIM_3D ||
1212             ImageDimensionality == SPIRV::Dim::DIM_Cube) &&
1213            "Image must be of 1D/2D/3D/Cube dimensionality");
1214     break;
1215   }
1216 
1217   MIRBuilder.buildInstr(Opcode)
1218       .addDef(Call->ReturnRegister)
1219       .addUse(GR->getSPIRVTypeID(Call->ReturnType))
1220       .addUse(Image);
1221   return true;
1222 }
1223 
1224 // TODO: Move to TableGen.
1225 static SPIRV::SamplerAddressingMode::SamplerAddressingMode
1226 getSamplerAddressingModeFromBitmask(unsigned Bitmask) {
1227   switch (Bitmask & SPIRV::CLK_ADDRESS_MODE_MASK) {
1228   case SPIRV::CLK_ADDRESS_CLAMP:
1229     return SPIRV::SamplerAddressingMode::Clamp;
1230   case SPIRV::CLK_ADDRESS_CLAMP_TO_EDGE:
1231     return SPIRV::SamplerAddressingMode::ClampToEdge;
1232   case SPIRV::CLK_ADDRESS_REPEAT:
1233     return SPIRV::SamplerAddressingMode::Repeat;
1234   case SPIRV::CLK_ADDRESS_MIRRORED_REPEAT:
1235     return SPIRV::SamplerAddressingMode::RepeatMirrored;
1236   case SPIRV::CLK_ADDRESS_NONE:
1237     return SPIRV::SamplerAddressingMode::None;
1238   default:
1239     llvm_unreachable("Unknown CL address mode");
1240   }
1241 }
1242 
1243 static unsigned getSamplerParamFromBitmask(unsigned Bitmask) {
1244   return (Bitmask & SPIRV::CLK_NORMALIZED_COORDS_TRUE) ? 1 : 0;
1245 }
1246 
1247 static SPIRV::SamplerFilterMode::SamplerFilterMode
1248 getSamplerFilterModeFromBitmask(unsigned Bitmask) {
1249   if (Bitmask & SPIRV::CLK_FILTER_LINEAR)
1250     return SPIRV::SamplerFilterMode::Linear;
1251   if (Bitmask & SPIRV::CLK_FILTER_NEAREST)
1252     return SPIRV::SamplerFilterMode::Nearest;
1253   return SPIRV::SamplerFilterMode::Nearest;
1254 }
1255 
1256 static bool generateReadImageInst(const StringRef DemangledCall,
1257                                   const SPIRV::IncomingCall *Call,
1258                                   MachineIRBuilder &MIRBuilder,
1259                                   SPIRVGlobalRegistry *GR) {
1260   Register Image = Call->Arguments[0];
1261   MachineRegisterInfo *MRI = MIRBuilder.getMRI();
1262   MRI->setRegClass(Image, &SPIRV::IDRegClass);
1263   MRI->setRegClass(Call->Arguments[1], &SPIRV::IDRegClass);
1264   bool HasOclSampler = DemangledCall.contains_insensitive("ocl_sampler");
1265   bool HasMsaa = DemangledCall.contains_insensitive("msaa");
1266   if (HasOclSampler || HasMsaa)
1267     MRI->setRegClass(Call->Arguments[2], &SPIRV::IDRegClass);
1268   if (HasOclSampler) {
1269     Register Sampler = Call->Arguments[1];
1270 
1271     if (!GR->isScalarOfType(Sampler, SPIRV::OpTypeSampler) &&
1272         getDefInstrMaybeConstant(Sampler, MRI)->getOperand(1).isCImm()) {
1273       uint64_t SamplerMask = getIConstVal(Sampler, MRI);
1274       Sampler = GR->buildConstantSampler(
1275           Register(), getSamplerAddressingModeFromBitmask(SamplerMask),
1276           getSamplerParamFromBitmask(SamplerMask),
1277           getSamplerFilterModeFromBitmask(SamplerMask), MIRBuilder,
1278           GR->getSPIRVTypeForVReg(Sampler));
1279     }
1280     SPIRVType *ImageType = GR->getSPIRVTypeForVReg(Image);
1281     SPIRVType *SampledImageType =
1282         GR->getOrCreateOpTypeSampledImage(ImageType, MIRBuilder);
1283     Register SampledImage = MRI->createVirtualRegister(&SPIRV::IDRegClass);
1284 
1285     MIRBuilder.buildInstr(SPIRV::OpSampledImage)
1286         .addDef(SampledImage)
1287         .addUse(GR->getSPIRVTypeID(SampledImageType))
1288         .addUse(Image)
1289         .addUse(Sampler);
1290 
1291     Register Lod = GR->buildConstantFP(APFloat::getZero(APFloat::IEEEsingle()),
1292                                        MIRBuilder);
1293     SPIRVType *TempType = Call->ReturnType;
1294     bool NeedsExtraction = false;
1295     if (TempType->getOpcode() != SPIRV::OpTypeVector) {
1296       TempType =
1297           GR->getOrCreateSPIRVVectorType(Call->ReturnType, 4, MIRBuilder);
1298       NeedsExtraction = true;
1299     }
1300     LLT LLType = LLT::scalar(GR->getScalarOrVectorBitWidth(TempType));
1301     Register TempRegister = MRI->createGenericVirtualRegister(LLType);
1302     MRI->setRegClass(TempRegister, &SPIRV::IDRegClass);
1303     GR->assignSPIRVTypeToVReg(TempType, TempRegister, MIRBuilder.getMF());
1304 
1305     MIRBuilder.buildInstr(SPIRV::OpImageSampleExplicitLod)
1306         .addDef(NeedsExtraction ? TempRegister : Call->ReturnRegister)
1307         .addUse(GR->getSPIRVTypeID(TempType))
1308         .addUse(SampledImage)
1309         .addUse(Call->Arguments[2]) // Coordinate.
1310         .addImm(SPIRV::ImageOperand::Lod)
1311         .addUse(Lod);
1312 
1313     if (NeedsExtraction)
1314       MIRBuilder.buildInstr(SPIRV::OpCompositeExtract)
1315           .addDef(Call->ReturnRegister)
1316           .addUse(GR->getSPIRVTypeID(Call->ReturnType))
1317           .addUse(TempRegister)
1318           .addImm(0);
1319   } else if (HasMsaa) {
1320     MIRBuilder.buildInstr(SPIRV::OpImageRead)
1321         .addDef(Call->ReturnRegister)
1322         .addUse(GR->getSPIRVTypeID(Call->ReturnType))
1323         .addUse(Image)
1324         .addUse(Call->Arguments[1]) // Coordinate.
1325         .addImm(SPIRV::ImageOperand::Sample)
1326         .addUse(Call->Arguments[2]);
1327   } else {
1328     MIRBuilder.buildInstr(SPIRV::OpImageRead)
1329         .addDef(Call->ReturnRegister)
1330         .addUse(GR->getSPIRVTypeID(Call->ReturnType))
1331         .addUse(Image)
1332         .addUse(Call->Arguments[1]); // Coordinate.
1333   }
1334   return true;
1335 }
1336 
1337 static bool generateWriteImageInst(const SPIRV::IncomingCall *Call,
1338                                    MachineIRBuilder &MIRBuilder,
1339                                    SPIRVGlobalRegistry *GR) {
1340   MIRBuilder.getMRI()->setRegClass(Call->Arguments[0], &SPIRV::IDRegClass);
1341   MIRBuilder.getMRI()->setRegClass(Call->Arguments[1], &SPIRV::IDRegClass);
1342   MIRBuilder.getMRI()->setRegClass(Call->Arguments[2], &SPIRV::IDRegClass);
1343   MIRBuilder.buildInstr(SPIRV::OpImageWrite)
1344       .addUse(Call->Arguments[0])  // Image.
1345       .addUse(Call->Arguments[1])  // Coordinate.
1346       .addUse(Call->Arguments[2]); // Texel.
1347   return true;
1348 }
1349 
1350 static bool generateSampleImageInst(const StringRef DemangledCall,
1351                                     const SPIRV::IncomingCall *Call,
1352                                     MachineIRBuilder &MIRBuilder,
1353                                     SPIRVGlobalRegistry *GR) {
1354   MachineRegisterInfo *MRI = MIRBuilder.getMRI();
1355   if (Call->Builtin->Name.contains_insensitive(
1356           "__translate_sampler_initializer")) {
1357     // Build sampler literal.
1358     uint64_t Bitmask = getIConstVal(Call->Arguments[0], MRI);
1359     Register Sampler = GR->buildConstantSampler(
1360         Call->ReturnRegister, getSamplerAddressingModeFromBitmask(Bitmask),
1361         getSamplerParamFromBitmask(Bitmask),
1362         getSamplerFilterModeFromBitmask(Bitmask), MIRBuilder, Call->ReturnType);
1363     return Sampler.isValid();
1364   } else if (Call->Builtin->Name.contains_insensitive("__spirv_SampledImage")) {
1365     // Create OpSampledImage.
1366     Register Image = Call->Arguments[0];
1367     SPIRVType *ImageType = GR->getSPIRVTypeForVReg(Image);
1368     SPIRVType *SampledImageType =
1369         GR->getOrCreateOpTypeSampledImage(ImageType, MIRBuilder);
1370     Register SampledImage =
1371         Call->ReturnRegister.isValid()
1372             ? Call->ReturnRegister
1373             : MRI->createVirtualRegister(&SPIRV::IDRegClass);
1374     MIRBuilder.buildInstr(SPIRV::OpSampledImage)
1375         .addDef(SampledImage)
1376         .addUse(GR->getSPIRVTypeID(SampledImageType))
1377         .addUse(Image)
1378         .addUse(Call->Arguments[1]); // Sampler.
1379     return true;
1380   } else if (Call->Builtin->Name.contains_insensitive(
1381                  "__spirv_ImageSampleExplicitLod")) {
1382     // Sample an image using an explicit level of detail.
1383     std::string ReturnType = DemangledCall.str();
1384     if (DemangledCall.contains("_R")) {
1385       ReturnType = ReturnType.substr(ReturnType.find("_R") + 2);
1386       ReturnType = ReturnType.substr(0, ReturnType.find('('));
1387     }
1388     SPIRVType *Type = GR->getOrCreateSPIRVTypeByName(ReturnType, MIRBuilder);
1389     MRI->setRegClass(Call->Arguments[0], &SPIRV::IDRegClass);
1390     MRI->setRegClass(Call->Arguments[1], &SPIRV::IDRegClass);
1391     MRI->setRegClass(Call->Arguments[3], &SPIRV::IDRegClass);
1392 
1393     MIRBuilder.buildInstr(SPIRV::OpImageSampleExplicitLod)
1394         .addDef(Call->ReturnRegister)
1395         .addUse(GR->getSPIRVTypeID(Type))
1396         .addUse(Call->Arguments[0]) // Image.
1397         .addUse(Call->Arguments[1]) // Coordinate.
1398         .addImm(SPIRV::ImageOperand::Lod)
1399         .addUse(Call->Arguments[3]);
1400     return true;
1401   }
1402   return false;
1403 }
1404 
1405 static bool generateSelectInst(const SPIRV::IncomingCall *Call,
1406                                MachineIRBuilder &MIRBuilder) {
1407   MIRBuilder.buildSelect(Call->ReturnRegister, Call->Arguments[0],
1408                          Call->Arguments[1], Call->Arguments[2]);
1409   return true;
1410 }
1411 
1412 static bool generateSpecConstantInst(const SPIRV::IncomingCall *Call,
1413                                      MachineIRBuilder &MIRBuilder,
1414                                      SPIRVGlobalRegistry *GR) {
1415   // Lookup the instruction opcode in the TableGen records.
1416   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
1417   unsigned Opcode =
1418       SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
1419   const MachineRegisterInfo *MRI = MIRBuilder.getMRI();
1420 
1421   switch (Opcode) {
1422   case SPIRV::OpSpecConstant: {
1423     // Build the SpecID decoration.
1424     unsigned SpecId =
1425         static_cast<unsigned>(getIConstVal(Call->Arguments[0], MRI));
1426     buildOpDecorate(Call->ReturnRegister, MIRBuilder, SPIRV::Decoration::SpecId,
1427                     {SpecId});
1428     // Determine the constant MI.
1429     Register ConstRegister = Call->Arguments[1];
1430     const MachineInstr *Const = getDefInstrMaybeConstant(ConstRegister, MRI);
1431     assert(Const &&
1432            (Const->getOpcode() == TargetOpcode::G_CONSTANT ||
1433             Const->getOpcode() == TargetOpcode::G_FCONSTANT) &&
1434            "Argument should be either an int or floating-point constant");
1435     // Determine the opcode and built the OpSpec MI.
1436     const MachineOperand &ConstOperand = Const->getOperand(1);
1437     if (Call->ReturnType->getOpcode() == SPIRV::OpTypeBool) {
1438       assert(ConstOperand.isCImm() && "Int constant operand is expected");
1439       Opcode = ConstOperand.getCImm()->getValue().getZExtValue()
1440                    ? SPIRV::OpSpecConstantTrue
1441                    : SPIRV::OpSpecConstantFalse;
1442     }
1443     auto MIB = MIRBuilder.buildInstr(Opcode)
1444                    .addDef(Call->ReturnRegister)
1445                    .addUse(GR->getSPIRVTypeID(Call->ReturnType));
1446 
1447     if (Call->ReturnType->getOpcode() != SPIRV::OpTypeBool) {
1448       if (Const->getOpcode() == TargetOpcode::G_CONSTANT)
1449         addNumImm(ConstOperand.getCImm()->getValue(), MIB);
1450       else
1451         addNumImm(ConstOperand.getFPImm()->getValueAPF().bitcastToAPInt(), MIB);
1452     }
1453     return true;
1454   }
1455   case SPIRV::OpSpecConstantComposite: {
1456     auto MIB = MIRBuilder.buildInstr(Opcode)
1457                    .addDef(Call->ReturnRegister)
1458                    .addUse(GR->getSPIRVTypeID(Call->ReturnType));
1459     for (unsigned i = 0; i < Call->Arguments.size(); i++)
1460       MIB.addUse(Call->Arguments[i]);
1461     return true;
1462   }
1463   default:
1464     return false;
1465   }
1466 }
1467 
1468 static bool buildNDRange(const SPIRV::IncomingCall *Call,
1469                          MachineIRBuilder &MIRBuilder,
1470                          SPIRVGlobalRegistry *GR) {
1471   MachineRegisterInfo *MRI = MIRBuilder.getMRI();
1472   MRI->setRegClass(Call->Arguments[0], &SPIRV::IDRegClass);
1473   SPIRVType *PtrType = GR->getSPIRVTypeForVReg(Call->Arguments[0]);
1474   assert(PtrType->getOpcode() == SPIRV::OpTypePointer &&
1475          PtrType->getOperand(2).isReg());
1476   Register TypeReg = PtrType->getOperand(2).getReg();
1477   SPIRVType *StructType = GR->getSPIRVTypeForVReg(TypeReg);
1478   MachineFunction &MF = MIRBuilder.getMF();
1479   Register TmpReg = MRI->createVirtualRegister(&SPIRV::IDRegClass);
1480   GR->assignSPIRVTypeToVReg(StructType, TmpReg, MF);
1481   // Skip the first arg, it's the destination pointer. OpBuildNDRange takes
1482   // three other arguments, so pass zero constant on absence.
1483   unsigned NumArgs = Call->Arguments.size();
1484   assert(NumArgs >= 2);
1485   Register GlobalWorkSize = Call->Arguments[NumArgs < 4 ? 1 : 2];
1486   MRI->setRegClass(GlobalWorkSize, &SPIRV::IDRegClass);
1487   Register LocalWorkSize =
1488       NumArgs == 2 ? Register(0) : Call->Arguments[NumArgs < 4 ? 2 : 3];
1489   if (LocalWorkSize.isValid())
1490     MRI->setRegClass(LocalWorkSize, &SPIRV::IDRegClass);
1491   Register GlobalWorkOffset = NumArgs <= 3 ? Register(0) : Call->Arguments[1];
1492   if (GlobalWorkOffset.isValid())
1493     MRI->setRegClass(GlobalWorkOffset, &SPIRV::IDRegClass);
1494   if (NumArgs < 4) {
1495     Register Const;
1496     SPIRVType *SpvTy = GR->getSPIRVTypeForVReg(GlobalWorkSize);
1497     if (SpvTy->getOpcode() == SPIRV::OpTypePointer) {
1498       MachineInstr *DefInstr = MRI->getUniqueVRegDef(GlobalWorkSize);
1499       assert(DefInstr && isSpvIntrinsic(*DefInstr, Intrinsic::spv_gep) &&
1500              DefInstr->getOperand(3).isReg());
1501       Register GWSPtr = DefInstr->getOperand(3).getReg();
1502       if (!MRI->getRegClassOrNull(GWSPtr))
1503         MRI->setRegClass(GWSPtr, &SPIRV::IDRegClass);
1504       // TODO: Maybe simplify generation of the type of the fields.
1505       unsigned Size = Call->Builtin->Name.equals("ndrange_3D") ? 3 : 2;
1506       unsigned BitWidth = GR->getPointerSize() == 64 ? 64 : 32;
1507       Type *BaseTy = IntegerType::get(MF.getFunction().getContext(), BitWidth);
1508       Type *FieldTy = ArrayType::get(BaseTy, Size);
1509       SPIRVType *SpvFieldTy = GR->getOrCreateSPIRVType(FieldTy, MIRBuilder);
1510       GlobalWorkSize = MRI->createVirtualRegister(&SPIRV::IDRegClass);
1511       GR->assignSPIRVTypeToVReg(SpvFieldTy, GlobalWorkSize, MF);
1512       MIRBuilder.buildInstr(SPIRV::OpLoad)
1513           .addDef(GlobalWorkSize)
1514           .addUse(GR->getSPIRVTypeID(SpvFieldTy))
1515           .addUse(GWSPtr);
1516       Const = GR->getOrCreateConsIntArray(0, MIRBuilder, SpvFieldTy);
1517     } else {
1518       Const = GR->buildConstantInt(0, MIRBuilder, SpvTy);
1519     }
1520     if (!LocalWorkSize.isValid())
1521       LocalWorkSize = Const;
1522     if (!GlobalWorkOffset.isValid())
1523       GlobalWorkOffset = Const;
1524   }
1525   assert(LocalWorkSize.isValid() && GlobalWorkOffset.isValid());
1526   MIRBuilder.buildInstr(SPIRV::OpBuildNDRange)
1527       .addDef(TmpReg)
1528       .addUse(TypeReg)
1529       .addUse(GlobalWorkSize)
1530       .addUse(LocalWorkSize)
1531       .addUse(GlobalWorkOffset);
1532   return MIRBuilder.buildInstr(SPIRV::OpStore)
1533       .addUse(Call->Arguments[0])
1534       .addUse(TmpReg);
1535 }
1536 
1537 static MachineInstr *getBlockStructInstr(Register ParamReg,
1538                                          MachineRegisterInfo *MRI) {
1539   // We expect the following sequence of instructions:
1540   //   %0:_(pN) = G_INTRINSIC_W_SIDE_EFFECTS intrinsic(@llvm.spv.alloca)
1541   //   or       = G_GLOBAL_VALUE @block_literal_global
1542   //   %1:_(pN) = G_INTRINSIC_W_SIDE_EFFECTS intrinsic(@llvm.spv.bitcast), %0
1543   //   %2:_(p4) = G_ADDRSPACE_CAST %1:_(pN)
1544   MachineInstr *MI = MRI->getUniqueVRegDef(ParamReg);
1545   assert(MI->getOpcode() == TargetOpcode::G_ADDRSPACE_CAST &&
1546          MI->getOperand(1).isReg());
1547   Register BitcastReg = MI->getOperand(1).getReg();
1548   MachineInstr *BitcastMI = MRI->getUniqueVRegDef(BitcastReg);
1549   assert(isSpvIntrinsic(*BitcastMI, Intrinsic::spv_bitcast) &&
1550          BitcastMI->getOperand(2).isReg());
1551   Register ValueReg = BitcastMI->getOperand(2).getReg();
1552   MachineInstr *ValueMI = MRI->getUniqueVRegDef(ValueReg);
1553   return ValueMI;
1554 }
1555 
1556 // Return an integer constant corresponding to the given register and
1557 // defined in spv_track_constant.
1558 // TODO: maybe unify with prelegalizer pass.
1559 static unsigned getConstFromIntrinsic(Register Reg, MachineRegisterInfo *MRI) {
1560   MachineInstr *DefMI = MRI->getUniqueVRegDef(Reg);
1561   assert(isSpvIntrinsic(*DefMI, Intrinsic::spv_track_constant) &&
1562          DefMI->getOperand(2).isReg());
1563   MachineInstr *DefMI2 = MRI->getUniqueVRegDef(DefMI->getOperand(2).getReg());
1564   assert(DefMI2->getOpcode() == TargetOpcode::G_CONSTANT &&
1565          DefMI2->getOperand(1).isCImm());
1566   return DefMI2->getOperand(1).getCImm()->getValue().getZExtValue();
1567 }
1568 
1569 // Return type of the instruction result from spv_assign_type intrinsic.
1570 // TODO: maybe unify with prelegalizer pass.
1571 static const Type *getMachineInstrType(MachineInstr *MI) {
1572   MachineInstr *NextMI = MI->getNextNode();
1573   if (isSpvIntrinsic(*NextMI, Intrinsic::spv_assign_name))
1574     NextMI = NextMI->getNextNode();
1575   Register ValueReg = MI->getOperand(0).getReg();
1576   if (!isSpvIntrinsic(*NextMI, Intrinsic::spv_assign_type) ||
1577       NextMI->getOperand(1).getReg() != ValueReg)
1578     return nullptr;
1579   Type *Ty = getMDOperandAsType(NextMI->getOperand(2).getMetadata(), 0);
1580   assert(Ty && "Type is expected");
1581   return getTypedPtrEltType(Ty);
1582 }
1583 
1584 static const Type *getBlockStructType(Register ParamReg,
1585                                       MachineRegisterInfo *MRI) {
1586   // In principle, this information should be passed to us from Clang via
1587   // an elementtype attribute. However, said attribute requires that
1588   // the function call be an intrinsic, which is not. Instead, we rely on being
1589   // able to trace this to the declaration of a variable: OpenCL C specification
1590   // section 6.12.5 should guarantee that we can do this.
1591   MachineInstr *MI = getBlockStructInstr(ParamReg, MRI);
1592   if (MI->getOpcode() == TargetOpcode::G_GLOBAL_VALUE)
1593     return getTypedPtrEltType(MI->getOperand(1).getGlobal()->getType());
1594   assert(isSpvIntrinsic(*MI, Intrinsic::spv_alloca) &&
1595          "Blocks in OpenCL C must be traceable to allocation site");
1596   return getMachineInstrType(MI);
1597 }
1598 
1599 // TODO: maybe move to the global register.
1600 static SPIRVType *
1601 getOrCreateSPIRVDeviceEventPointer(MachineIRBuilder &MIRBuilder,
1602                                    SPIRVGlobalRegistry *GR) {
1603   LLVMContext &Context = MIRBuilder.getMF().getFunction().getContext();
1604   Type *OpaqueType = StructType::getTypeByName(Context, "spirv.DeviceEvent");
1605   if (!OpaqueType)
1606     OpaqueType = StructType::getTypeByName(Context, "opencl.clk_event_t");
1607   if (!OpaqueType)
1608     OpaqueType = StructType::create(Context, "spirv.DeviceEvent");
1609   unsigned SC0 = storageClassToAddressSpace(SPIRV::StorageClass::Function);
1610   unsigned SC1 = storageClassToAddressSpace(SPIRV::StorageClass::Generic);
1611   Type *PtrType = PointerType::get(PointerType::get(OpaqueType, SC0), SC1);
1612   return GR->getOrCreateSPIRVType(PtrType, MIRBuilder);
1613 }
1614 
1615 static bool buildEnqueueKernel(const SPIRV::IncomingCall *Call,
1616                                MachineIRBuilder &MIRBuilder,
1617                                SPIRVGlobalRegistry *GR) {
1618   MachineRegisterInfo *MRI = MIRBuilder.getMRI();
1619   const DataLayout &DL = MIRBuilder.getDataLayout();
1620   bool HasEvents = Call->Builtin->Name.contains("events");
1621   const SPIRVType *Int32Ty = GR->getOrCreateSPIRVIntegerType(32, MIRBuilder);
1622 
1623   // Make vararg instructions before OpEnqueueKernel.
1624   // Local sizes arguments: Sizes of block invoke arguments. Clang generates
1625   // local size operands as an array, so we need to unpack them.
1626   SmallVector<Register, 16> LocalSizes;
1627   if (Call->Builtin->Name.find("_varargs") != StringRef::npos) {
1628     const unsigned LocalSizeArrayIdx = HasEvents ? 9 : 6;
1629     Register GepReg = Call->Arguments[LocalSizeArrayIdx];
1630     MachineInstr *GepMI = MRI->getUniqueVRegDef(GepReg);
1631     assert(isSpvIntrinsic(*GepMI, Intrinsic::spv_gep) &&
1632            GepMI->getOperand(3).isReg());
1633     Register ArrayReg = GepMI->getOperand(3).getReg();
1634     MachineInstr *ArrayMI = MRI->getUniqueVRegDef(ArrayReg);
1635     const Type *LocalSizeTy = getMachineInstrType(ArrayMI);
1636     assert(LocalSizeTy && "Local size type is expected");
1637     const uint64_t LocalSizeNum =
1638         cast<ArrayType>(LocalSizeTy)->getNumElements();
1639     unsigned SC = storageClassToAddressSpace(SPIRV::StorageClass::Generic);
1640     const LLT LLType = LLT::pointer(SC, GR->getPointerSize());
1641     const SPIRVType *PointerSizeTy = GR->getOrCreateSPIRVPointerType(
1642         Int32Ty, MIRBuilder, SPIRV::StorageClass::Function);
1643     for (unsigned I = 0; I < LocalSizeNum; ++I) {
1644       Register Reg = MRI->createVirtualRegister(&SPIRV::IDRegClass);
1645       MRI->setType(Reg, LLType);
1646       GR->assignSPIRVTypeToVReg(PointerSizeTy, Reg, MIRBuilder.getMF());
1647       auto GEPInst = MIRBuilder.buildIntrinsic(
1648           Intrinsic::spv_gep, ArrayRef<Register>{Reg}, true, false);
1649       GEPInst
1650           .addImm(GepMI->getOperand(2).getImm())          // In bound.
1651           .addUse(ArrayMI->getOperand(0).getReg())        // Alloca.
1652           .addUse(buildConstantIntReg(0, MIRBuilder, GR)) // Indices.
1653           .addUse(buildConstantIntReg(I, MIRBuilder, GR));
1654       LocalSizes.push_back(Reg);
1655     }
1656   }
1657 
1658   // SPIRV OpEnqueueKernel instruction has 10+ arguments.
1659   auto MIB = MIRBuilder.buildInstr(SPIRV::OpEnqueueKernel)
1660                  .addDef(Call->ReturnRegister)
1661                  .addUse(GR->getSPIRVTypeID(Int32Ty));
1662 
1663   // Copy all arguments before block invoke function pointer.
1664   const unsigned BlockFIdx = HasEvents ? 6 : 3;
1665   for (unsigned i = 0; i < BlockFIdx; i++)
1666     MIB.addUse(Call->Arguments[i]);
1667 
1668   // If there are no event arguments in the original call, add dummy ones.
1669   if (!HasEvents) {
1670     MIB.addUse(buildConstantIntReg(0, MIRBuilder, GR)); // Dummy num events.
1671     Register NullPtr = GR->getOrCreateConstNullPtr(
1672         MIRBuilder, getOrCreateSPIRVDeviceEventPointer(MIRBuilder, GR));
1673     MIB.addUse(NullPtr); // Dummy wait events.
1674     MIB.addUse(NullPtr); // Dummy ret event.
1675   }
1676 
1677   MachineInstr *BlockMI = getBlockStructInstr(Call->Arguments[BlockFIdx], MRI);
1678   assert(BlockMI->getOpcode() == TargetOpcode::G_GLOBAL_VALUE);
1679   // Invoke: Pointer to invoke function.
1680   MIB.addGlobalAddress(BlockMI->getOperand(1).getGlobal());
1681 
1682   Register BlockLiteralReg = Call->Arguments[BlockFIdx + 1];
1683   // Param: Pointer to block literal.
1684   MIB.addUse(BlockLiteralReg);
1685 
1686   Type *PType = const_cast<Type *>(getBlockStructType(BlockLiteralReg, MRI));
1687   // TODO: these numbers should be obtained from block literal structure.
1688   // Param Size: Size of block literal structure.
1689   MIB.addUse(buildConstantIntReg(DL.getTypeStoreSize(PType), MIRBuilder, GR));
1690   // Param Aligment: Aligment of block literal structure.
1691   MIB.addUse(
1692       buildConstantIntReg(DL.getPrefTypeAlign(PType).value(), MIRBuilder, GR));
1693 
1694   for (unsigned i = 0; i < LocalSizes.size(); i++)
1695     MIB.addUse(LocalSizes[i]);
1696   return true;
1697 }
1698 
1699 static bool generateEnqueueInst(const SPIRV::IncomingCall *Call,
1700                                 MachineIRBuilder &MIRBuilder,
1701                                 SPIRVGlobalRegistry *GR) {
1702   // Lookup the instruction opcode in the TableGen records.
1703   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
1704   unsigned Opcode =
1705       SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
1706 
1707   switch (Opcode) {
1708   case SPIRV::OpRetainEvent:
1709   case SPIRV::OpReleaseEvent:
1710     MIRBuilder.getMRI()->setRegClass(Call->Arguments[0], &SPIRV::IDRegClass);
1711     return MIRBuilder.buildInstr(Opcode).addUse(Call->Arguments[0]);
1712   case SPIRV::OpCreateUserEvent:
1713   case SPIRV::OpGetDefaultQueue:
1714     return MIRBuilder.buildInstr(Opcode)
1715         .addDef(Call->ReturnRegister)
1716         .addUse(GR->getSPIRVTypeID(Call->ReturnType));
1717   case SPIRV::OpIsValidEvent:
1718     MIRBuilder.getMRI()->setRegClass(Call->Arguments[0], &SPIRV::IDRegClass);
1719     return MIRBuilder.buildInstr(Opcode)
1720         .addDef(Call->ReturnRegister)
1721         .addUse(GR->getSPIRVTypeID(Call->ReturnType))
1722         .addUse(Call->Arguments[0]);
1723   case SPIRV::OpSetUserEventStatus:
1724     MIRBuilder.getMRI()->setRegClass(Call->Arguments[0], &SPIRV::IDRegClass);
1725     MIRBuilder.getMRI()->setRegClass(Call->Arguments[1], &SPIRV::IDRegClass);
1726     return MIRBuilder.buildInstr(Opcode)
1727         .addUse(Call->Arguments[0])
1728         .addUse(Call->Arguments[1]);
1729   case SPIRV::OpCaptureEventProfilingInfo:
1730     MIRBuilder.getMRI()->setRegClass(Call->Arguments[0], &SPIRV::IDRegClass);
1731     MIRBuilder.getMRI()->setRegClass(Call->Arguments[1], &SPIRV::IDRegClass);
1732     MIRBuilder.getMRI()->setRegClass(Call->Arguments[2], &SPIRV::IDRegClass);
1733     return MIRBuilder.buildInstr(Opcode)
1734         .addUse(Call->Arguments[0])
1735         .addUse(Call->Arguments[1])
1736         .addUse(Call->Arguments[2]);
1737   case SPIRV::OpBuildNDRange:
1738     return buildNDRange(Call, MIRBuilder, GR);
1739   case SPIRV::OpEnqueueKernel:
1740     return buildEnqueueKernel(Call, MIRBuilder, GR);
1741   default:
1742     return false;
1743   }
1744 }
1745 
1746 static bool generateAsyncCopy(const SPIRV::IncomingCall *Call,
1747                               MachineIRBuilder &MIRBuilder,
1748                               SPIRVGlobalRegistry *GR) {
1749   // Lookup the instruction opcode in the TableGen records.
1750   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
1751   unsigned Opcode =
1752       SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
1753   auto Scope = buildConstantIntReg(SPIRV::Scope::Workgroup, MIRBuilder, GR);
1754 
1755   switch (Opcode) {
1756   case SPIRV::OpGroupAsyncCopy:
1757     return MIRBuilder.buildInstr(Opcode)
1758         .addDef(Call->ReturnRegister)
1759         .addUse(GR->getSPIRVTypeID(Call->ReturnType))
1760         .addUse(Scope)
1761         .addUse(Call->Arguments[0])
1762         .addUse(Call->Arguments[1])
1763         .addUse(Call->Arguments[2])
1764         .addUse(buildConstantIntReg(1, MIRBuilder, GR))
1765         .addUse(Call->Arguments[3]);
1766   case SPIRV::OpGroupWaitEvents:
1767     return MIRBuilder.buildInstr(Opcode)
1768         .addUse(Scope)
1769         .addUse(Call->Arguments[0])
1770         .addUse(Call->Arguments[1]);
1771   default:
1772     return false;
1773   }
1774 }
1775 
1776 static bool generateConvertInst(const StringRef DemangledCall,
1777                                 const SPIRV::IncomingCall *Call,
1778                                 MachineIRBuilder &MIRBuilder,
1779                                 SPIRVGlobalRegistry *GR) {
1780   // Lookup the conversion builtin in the TableGen records.
1781   const SPIRV::ConvertBuiltin *Builtin =
1782       SPIRV::lookupConvertBuiltin(Call->Builtin->Name, Call->Builtin->Set);
1783 
1784   if (Builtin->IsSaturated)
1785     buildOpDecorate(Call->ReturnRegister, MIRBuilder,
1786                     SPIRV::Decoration::SaturatedConversion, {});
1787   if (Builtin->IsRounded)
1788     buildOpDecorate(Call->ReturnRegister, MIRBuilder,
1789                     SPIRV::Decoration::FPRoundingMode,
1790                     {(unsigned)Builtin->RoundingMode});
1791 
1792   unsigned Opcode = SPIRV::OpNop;
1793   if (GR->isScalarOrVectorOfType(Call->Arguments[0], SPIRV::OpTypeInt)) {
1794     // Int -> ...
1795     if (GR->isScalarOrVectorOfType(Call->ReturnRegister, SPIRV::OpTypeInt)) {
1796       // Int -> Int
1797       if (Builtin->IsSaturated)
1798         Opcode = Builtin->IsDestinationSigned ? SPIRV::OpSatConvertUToS
1799                                               : SPIRV::OpSatConvertSToU;
1800       else
1801         Opcode = Builtin->IsDestinationSigned ? SPIRV::OpUConvert
1802                                               : SPIRV::OpSConvert;
1803     } else if (GR->isScalarOrVectorOfType(Call->ReturnRegister,
1804                                           SPIRV::OpTypeFloat)) {
1805       // Int -> Float
1806       bool IsSourceSigned =
1807           DemangledCall[DemangledCall.find_first_of('(') + 1] != 'u';
1808       Opcode = IsSourceSigned ? SPIRV::OpConvertSToF : SPIRV::OpConvertUToF;
1809     }
1810   } else if (GR->isScalarOrVectorOfType(Call->Arguments[0],
1811                                         SPIRV::OpTypeFloat)) {
1812     // Float -> ...
1813     if (GR->isScalarOrVectorOfType(Call->ReturnRegister, SPIRV::OpTypeInt))
1814       // Float -> Int
1815       Opcode = Builtin->IsDestinationSigned ? SPIRV::OpConvertFToS
1816                                             : SPIRV::OpConvertFToU;
1817     else if (GR->isScalarOrVectorOfType(Call->ReturnRegister,
1818                                         SPIRV::OpTypeFloat))
1819       // Float -> Float
1820       Opcode = SPIRV::OpFConvert;
1821   }
1822 
1823   assert(Opcode != SPIRV::OpNop &&
1824          "Conversion between the types not implemented!");
1825 
1826   MIRBuilder.buildInstr(Opcode)
1827       .addDef(Call->ReturnRegister)
1828       .addUse(GR->getSPIRVTypeID(Call->ReturnType))
1829       .addUse(Call->Arguments[0]);
1830   return true;
1831 }
1832 
1833 static bool generateVectorLoadStoreInst(const SPIRV::IncomingCall *Call,
1834                                         MachineIRBuilder &MIRBuilder,
1835                                         SPIRVGlobalRegistry *GR) {
1836   // Lookup the vector load/store builtin in the TableGen records.
1837   const SPIRV::VectorLoadStoreBuiltin *Builtin =
1838       SPIRV::lookupVectorLoadStoreBuiltin(Call->Builtin->Name,
1839                                           Call->Builtin->Set);
1840   // Build extended instruction.
1841   auto MIB =
1842       MIRBuilder.buildInstr(SPIRV::OpExtInst)
1843           .addDef(Call->ReturnRegister)
1844           .addUse(GR->getSPIRVTypeID(Call->ReturnType))
1845           .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::OpenCL_std))
1846           .addImm(Builtin->Number);
1847   for (auto Argument : Call->Arguments)
1848     MIB.addUse(Argument);
1849 
1850   // Rounding mode should be passed as a last argument in the MI for builtins
1851   // like "vstorea_halfn_r".
1852   if (Builtin->IsRounded)
1853     MIB.addImm(static_cast<uint32_t>(Builtin->RoundingMode));
1854   return true;
1855 }
1856 
1857 static bool generateLoadStoreInst(const SPIRV::IncomingCall *Call,
1858                                   MachineIRBuilder &MIRBuilder,
1859                                   SPIRVGlobalRegistry *GR) {
1860   // Lookup the instruction opcode in the TableGen records.
1861   const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
1862   unsigned Opcode =
1863       SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
1864   bool IsLoad = Opcode == SPIRV::OpLoad;
1865   // Build the instruction.
1866   auto MIB = MIRBuilder.buildInstr(Opcode);
1867   if (IsLoad) {
1868     MIB.addDef(Call->ReturnRegister);
1869     MIB.addUse(GR->getSPIRVTypeID(Call->ReturnType));
1870   }
1871   // Add a pointer to the value to load/store.
1872   MIB.addUse(Call->Arguments[0]);
1873   MachineRegisterInfo *MRI = MIRBuilder.getMRI();
1874   MRI->setRegClass(Call->Arguments[0], &SPIRV::IDRegClass);
1875   // Add a value to store.
1876   if (!IsLoad) {
1877     MIB.addUse(Call->Arguments[1]);
1878     MRI->setRegClass(Call->Arguments[1], &SPIRV::IDRegClass);
1879   }
1880   // Add optional memory attributes and an alignment.
1881   unsigned NumArgs = Call->Arguments.size();
1882   if ((IsLoad && NumArgs >= 2) || NumArgs >= 3) {
1883     MIB.addImm(getConstFromIntrinsic(Call->Arguments[IsLoad ? 1 : 2], MRI));
1884     MRI->setRegClass(Call->Arguments[IsLoad ? 1 : 2], &SPIRV::IDRegClass);
1885   }
1886   if ((IsLoad && NumArgs >= 3) || NumArgs >= 4) {
1887     MIB.addImm(getConstFromIntrinsic(Call->Arguments[IsLoad ? 2 : 3], MRI));
1888     MRI->setRegClass(Call->Arguments[IsLoad ? 2 : 3], &SPIRV::IDRegClass);
1889   }
1890   return true;
1891 }
1892 
1893 /// Lowers a builtin funtion call using the provided \p DemangledCall skeleton
1894 /// and external instruction \p Set.
1895 namespace SPIRV {
1896 std::optional<bool> lowerBuiltin(const StringRef DemangledCall,
1897                                  SPIRV::InstructionSet::InstructionSet Set,
1898                                  MachineIRBuilder &MIRBuilder,
1899                                  const Register OrigRet, const Type *OrigRetTy,
1900                                  const SmallVectorImpl<Register> &Args,
1901                                  SPIRVGlobalRegistry *GR) {
1902   LLVM_DEBUG(dbgs() << "Lowering builtin call: " << DemangledCall << "\n");
1903 
1904   // SPIR-V type and return register.
1905   Register ReturnRegister = OrigRet;
1906   SPIRVType *ReturnType = nullptr;
1907   if (OrigRetTy && !OrigRetTy->isVoidTy()) {
1908     ReturnType = GR->assignTypeToVReg(OrigRetTy, OrigRet, MIRBuilder);
1909     if (!MIRBuilder.getMRI()->getRegClassOrNull(ReturnRegister))
1910       MIRBuilder.getMRI()->setRegClass(ReturnRegister, &SPIRV::IDRegClass);
1911   } else if (OrigRetTy && OrigRetTy->isVoidTy()) {
1912     ReturnRegister = MIRBuilder.getMRI()->createVirtualRegister(&IDRegClass);
1913     MIRBuilder.getMRI()->setType(ReturnRegister, LLT::scalar(32));
1914     ReturnType = GR->assignTypeToVReg(OrigRetTy, ReturnRegister, MIRBuilder);
1915   }
1916 
1917   // Lookup the builtin in the TableGen records.
1918   std::unique_ptr<const IncomingCall> Call =
1919       lookupBuiltin(DemangledCall, Set, ReturnRegister, ReturnType, Args);
1920 
1921   if (!Call) {
1922     LLVM_DEBUG(dbgs() << "Builtin record was not found!\n");
1923     return std::nullopt;
1924   }
1925 
1926   // TODO: check if the provided args meet the builtin requirments.
1927   assert(Args.size() >= Call->Builtin->MinNumArgs &&
1928          "Too few arguments to generate the builtin");
1929   if (Call->Builtin->MaxNumArgs && Args.size() > Call->Builtin->MaxNumArgs)
1930     LLVM_DEBUG(dbgs() << "More arguments provided than required!\n");
1931 
1932   // Match the builtin with implementation based on the grouping.
1933   switch (Call->Builtin->Group) {
1934   case SPIRV::Extended:
1935     return generateExtInst(Call.get(), MIRBuilder, GR);
1936   case SPIRV::Relational:
1937     return generateRelationalInst(Call.get(), MIRBuilder, GR);
1938   case SPIRV::Group:
1939     return generateGroupInst(Call.get(), MIRBuilder, GR);
1940   case SPIRV::Variable:
1941     return generateBuiltinVar(Call.get(), MIRBuilder, GR);
1942   case SPIRV::Atomic:
1943     return generateAtomicInst(Call.get(), MIRBuilder, GR);
1944   case SPIRV::Barrier:
1945     return generateBarrierInst(Call.get(), MIRBuilder, GR);
1946   case SPIRV::Dot:
1947     return generateDotOrFMulInst(Call.get(), MIRBuilder, GR);
1948   case SPIRV::GetQuery:
1949     return generateGetQueryInst(Call.get(), MIRBuilder, GR);
1950   case SPIRV::ImageSizeQuery:
1951     return generateImageSizeQueryInst(Call.get(), MIRBuilder, GR);
1952   case SPIRV::ImageMiscQuery:
1953     return generateImageMiscQueryInst(Call.get(), MIRBuilder, GR);
1954   case SPIRV::ReadImage:
1955     return generateReadImageInst(DemangledCall, Call.get(), MIRBuilder, GR);
1956   case SPIRV::WriteImage:
1957     return generateWriteImageInst(Call.get(), MIRBuilder, GR);
1958   case SPIRV::SampleImage:
1959     return generateSampleImageInst(DemangledCall, Call.get(), MIRBuilder, GR);
1960   case SPIRV::Select:
1961     return generateSelectInst(Call.get(), MIRBuilder);
1962   case SPIRV::SpecConstant:
1963     return generateSpecConstantInst(Call.get(), MIRBuilder, GR);
1964   case SPIRV::Enqueue:
1965     return generateEnqueueInst(Call.get(), MIRBuilder, GR);
1966   case SPIRV::AsyncCopy:
1967     return generateAsyncCopy(Call.get(), MIRBuilder, GR);
1968   case SPIRV::Convert:
1969     return generateConvertInst(DemangledCall, Call.get(), MIRBuilder, GR);
1970   case SPIRV::VectorLoadStore:
1971     return generateVectorLoadStoreInst(Call.get(), MIRBuilder, GR);
1972   case SPIRV::LoadStore:
1973     return generateLoadStoreInst(Call.get(), MIRBuilder, GR);
1974   }
1975   return false;
1976 }
1977 
1978 struct BuiltinType {
1979   StringRef Name;
1980   uint32_t Opcode;
1981 };
1982 
1983 #define GET_BuiltinTypes_DECL
1984 #define GET_BuiltinTypes_IMPL
1985 
1986 struct OpenCLType {
1987   StringRef Name;
1988   StringRef SpirvTypeLiteral;
1989 };
1990 
1991 #define GET_OpenCLTypes_DECL
1992 #define GET_OpenCLTypes_IMPL
1993 
1994 #include "SPIRVGenTables.inc"
1995 } // namespace SPIRV
1996 
1997 //===----------------------------------------------------------------------===//
1998 // Misc functions for parsing builtin types.
1999 //===----------------------------------------------------------------------===//
2000 
2001 static Type *parseTypeString(const StringRef Name, LLVMContext &Context) {
2002   if (Name.starts_with("void"))
2003     return Type::getVoidTy(Context);
2004   else if (Name.starts_with("int") || Name.starts_with("uint"))
2005     return Type::getInt32Ty(Context);
2006   else if (Name.starts_with("float"))
2007     return Type::getFloatTy(Context);
2008   else if (Name.starts_with("half"))
2009     return Type::getHalfTy(Context);
2010   llvm_unreachable("Unable to recognize type!");
2011 }
2012 
2013 //===----------------------------------------------------------------------===//
2014 // Implementation functions for builtin types.
2015 //===----------------------------------------------------------------------===//
2016 
2017 static SPIRVType *getNonParameterizedType(const TargetExtType *ExtensionType,
2018                                           const SPIRV::BuiltinType *TypeRecord,
2019                                           MachineIRBuilder &MIRBuilder,
2020                                           SPIRVGlobalRegistry *GR) {
2021   unsigned Opcode = TypeRecord->Opcode;
2022   // Create or get an existing type from GlobalRegistry.
2023   return GR->getOrCreateOpTypeByOpcode(ExtensionType, MIRBuilder, Opcode);
2024 }
2025 
2026 static SPIRVType *getSamplerType(MachineIRBuilder &MIRBuilder,
2027                                  SPIRVGlobalRegistry *GR) {
2028   // Create or get an existing type from GlobalRegistry.
2029   return GR->getOrCreateOpTypeSampler(MIRBuilder);
2030 }
2031 
2032 static SPIRVType *getPipeType(const TargetExtType *ExtensionType,
2033                               MachineIRBuilder &MIRBuilder,
2034                               SPIRVGlobalRegistry *GR) {
2035   assert(ExtensionType->getNumIntParameters() == 1 &&
2036          "Invalid number of parameters for SPIR-V pipe builtin!");
2037   // Create or get an existing type from GlobalRegistry.
2038   return GR->getOrCreateOpTypePipe(MIRBuilder,
2039                                    SPIRV::AccessQualifier::AccessQualifier(
2040                                        ExtensionType->getIntParameter(0)));
2041 }
2042 
2043 static SPIRVType *
2044 getImageType(const TargetExtType *ExtensionType,
2045              const SPIRV::AccessQualifier::AccessQualifier Qualifier,
2046              MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR) {
2047   assert(ExtensionType->getNumTypeParameters() == 1 &&
2048          "SPIR-V image builtin type must have sampled type parameter!");
2049   const SPIRVType *SampledType =
2050       GR->getOrCreateSPIRVType(ExtensionType->getTypeParameter(0), MIRBuilder);
2051   assert(ExtensionType->getNumIntParameters() == 7 &&
2052          "Invalid number of parameters for SPIR-V image builtin!");
2053   // Create or get an existing type from GlobalRegistry.
2054   return GR->getOrCreateOpTypeImage(
2055       MIRBuilder, SampledType,
2056       SPIRV::Dim::Dim(ExtensionType->getIntParameter(0)),
2057       ExtensionType->getIntParameter(1), ExtensionType->getIntParameter(2),
2058       ExtensionType->getIntParameter(3), ExtensionType->getIntParameter(4),
2059       SPIRV::ImageFormat::ImageFormat(ExtensionType->getIntParameter(5)),
2060       Qualifier == SPIRV::AccessQualifier::WriteOnly
2061           ? SPIRV::AccessQualifier::WriteOnly
2062           : SPIRV::AccessQualifier::AccessQualifier(
2063                 ExtensionType->getIntParameter(6)));
2064 }
2065 
2066 static SPIRVType *getSampledImageType(const TargetExtType *OpaqueType,
2067                                       MachineIRBuilder &MIRBuilder,
2068                                       SPIRVGlobalRegistry *GR) {
2069   SPIRVType *OpaqueImageType = getImageType(
2070       OpaqueType, SPIRV::AccessQualifier::ReadOnly, MIRBuilder, GR);
2071   // Create or get an existing type from GlobalRegistry.
2072   return GR->getOrCreateOpTypeSampledImage(OpaqueImageType, MIRBuilder);
2073 }
2074 
2075 namespace SPIRV {
2076 const TargetExtType *
2077 parseBuiltinTypeNameToTargetExtType(std::string TypeName,
2078                                     MachineIRBuilder &MIRBuilder) {
2079   StringRef NameWithParameters = TypeName;
2080 
2081   // Pointers-to-opaque-structs representing OpenCL types are first translated
2082   // to equivalent SPIR-V types. OpenCL builtin type names should have the
2083   // following format: e.g. %opencl.event_t
2084   if (NameWithParameters.starts_with("opencl.")) {
2085     const SPIRV::OpenCLType *OCLTypeRecord =
2086         SPIRV::lookupOpenCLType(NameWithParameters);
2087     if (!OCLTypeRecord)
2088       report_fatal_error("Missing TableGen record for OpenCL type: " +
2089                          NameWithParameters);
2090     NameWithParameters = OCLTypeRecord->SpirvTypeLiteral;
2091     // Continue with the SPIR-V builtin type...
2092   }
2093 
2094   // Names of the opaque structs representing a SPIR-V builtins without
2095   // parameters should have the following format: e.g. %spirv.Event
2096   assert(NameWithParameters.starts_with("spirv.") &&
2097          "Unknown builtin opaque type!");
2098 
2099   // Parameterized SPIR-V builtins names follow this format:
2100   // e.g. %spirv.Image._void_1_0_0_0_0_0_0, %spirv.Pipe._0
2101   if (!NameWithParameters.contains('_'))
2102     return TargetExtType::get(MIRBuilder.getContext(), NameWithParameters);
2103 
2104   SmallVector<StringRef> Parameters;
2105   unsigned BaseNameLength = NameWithParameters.find('_') - 1;
2106   SplitString(NameWithParameters.substr(BaseNameLength + 1), Parameters, "_");
2107 
2108   SmallVector<Type *, 1> TypeParameters;
2109   bool HasTypeParameter = !isDigit(Parameters[0][0]);
2110   if (HasTypeParameter)
2111     TypeParameters.push_back(parseTypeString(
2112         Parameters[0], MIRBuilder.getMF().getFunction().getContext()));
2113   SmallVector<unsigned> IntParameters;
2114   for (unsigned i = HasTypeParameter ? 1 : 0; i < Parameters.size(); i++) {
2115     unsigned IntParameter = 0;
2116     bool ValidLiteral = !Parameters[i].getAsInteger(10, IntParameter);
2117     assert(ValidLiteral &&
2118            "Invalid format of SPIR-V builtin parameter literal!");
2119     IntParameters.push_back(IntParameter);
2120   }
2121   return TargetExtType::get(MIRBuilder.getContext(),
2122                             NameWithParameters.substr(0, BaseNameLength),
2123                             TypeParameters, IntParameters);
2124 }
2125 
2126 SPIRVType *lowerBuiltinType(const Type *OpaqueType,
2127                             SPIRV::AccessQualifier::AccessQualifier AccessQual,
2128                             MachineIRBuilder &MIRBuilder,
2129                             SPIRVGlobalRegistry *GR) {
2130   // In LLVM IR, SPIR-V and OpenCL builtin types are represented as either
2131   // target(...) target extension types or pointers-to-opaque-structs. The
2132   // approach relying on structs is deprecated and works only in the non-opaque
2133   // pointer mode (-opaque-pointers=0).
2134   // In order to maintain compatibility with LLVM IR generated by older versions
2135   // of Clang and LLVM/SPIR-V Translator, the pointers-to-opaque-structs are
2136   // "translated" to target extension types. This translation is temporary and
2137   // will be removed in the future release of LLVM.
2138   const TargetExtType *BuiltinType = dyn_cast<TargetExtType>(OpaqueType);
2139   if (!BuiltinType)
2140     BuiltinType = parseBuiltinTypeNameToTargetExtType(
2141         OpaqueType->getStructName().str(), MIRBuilder);
2142 
2143   unsigned NumStartingVRegs = MIRBuilder.getMRI()->getNumVirtRegs();
2144 
2145   const StringRef Name = BuiltinType->getName();
2146   LLVM_DEBUG(dbgs() << "Lowering builtin type: " << Name << "\n");
2147 
2148   // Lookup the demangled builtin type in the TableGen records.
2149   const SPIRV::BuiltinType *TypeRecord = SPIRV::lookupBuiltinType(Name);
2150   if (!TypeRecord)
2151     report_fatal_error("Missing TableGen record for builtin type: " + Name);
2152 
2153   // "Lower" the BuiltinType into TargetType. The following get<...>Type methods
2154   // use the implementation details from TableGen records or TargetExtType
2155   // parameters to either create a new OpType<...> machine instruction or get an
2156   // existing equivalent SPIRVType from GlobalRegistry.
2157   SPIRVType *TargetType;
2158   switch (TypeRecord->Opcode) {
2159   case SPIRV::OpTypeImage:
2160     TargetType = getImageType(BuiltinType, AccessQual, MIRBuilder, GR);
2161     break;
2162   case SPIRV::OpTypePipe:
2163     TargetType = getPipeType(BuiltinType, MIRBuilder, GR);
2164     break;
2165   case SPIRV::OpTypeDeviceEvent:
2166     TargetType = GR->getOrCreateOpTypeDeviceEvent(MIRBuilder);
2167     break;
2168   case SPIRV::OpTypeSampler:
2169     TargetType = getSamplerType(MIRBuilder, GR);
2170     break;
2171   case SPIRV::OpTypeSampledImage:
2172     TargetType = getSampledImageType(BuiltinType, MIRBuilder, GR);
2173     break;
2174   default:
2175     TargetType =
2176         getNonParameterizedType(BuiltinType, TypeRecord, MIRBuilder, GR);
2177     break;
2178   }
2179 
2180   // Emit OpName instruction if a new OpType<...> instruction was added
2181   // (equivalent type was not found in GlobalRegistry).
2182   if (NumStartingVRegs < MIRBuilder.getMRI()->getNumVirtRegs())
2183     buildOpName(GR->getSPIRVTypeID(TargetType), Name, MIRBuilder);
2184 
2185   return TargetType;
2186 }
2187 } // namespace SPIRV
2188 } // namespace llvm
2189