LLVM 24.0.0git
SPIRVUtils.cpp
Go to the documentation of this file.
1//===--- SPIRVUtils.cpp ---- SPIR-V Utility 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 contains miscellaneous utility functions.
10//
11//===----------------------------------------------------------------------===//
12
13#include "SPIRVUtils.h"
15#include "SPIRV.h"
16#include "SPIRVBuiltins.h"
17#include "SPIRVGlobalRegistry.h"
18#include "SPIRVInstrInfo.h"
19#include "SPIRVSubtarget.h"
20#include "llvm/ADT/STLExtras.h"
21#include "llvm/ADT/StringRef.h"
28#include "llvm/IR/IntrinsicsSPIRV.h"
31#include <queue>
32#include <vector>
33
34namespace llvm {
35namespace SPIRV {
37 auto It = find_if(NMD->operands(), [Name](MDNode *N) {
38 if (auto *MDS = dyn_cast_or_null<MDString>(N->getOperand(0)))
39 return MDS->getString() == Name;
40 return false;
41 });
42 return It == NMD->op_end() ? nullptr : *It;
43}
44
45// This code restores function args/retvalue types for composite cases
46// because the final types should still be aggregate whereas they're i32
47// during the translation to cope with aggregate flattening etc.
48// TODO: should these just return nullptr when there's no metadata?
50 FunctionType *FTy,
51 StringRef Name) {
52 if (!NMD)
53 return FTy;
54
55 MDNode *Match = findNamedMDOperand(NMD, Name);
56 if (!Match)
57 return FTy;
58
59 Type *RetTy = FTy->getReturnType();
60 SmallVector<Type *, 4> PTys(FTy->params());
61
62 for (unsigned I = 1; I != Match->getNumOperands(); ++I) {
63 MDNode *MD = dyn_cast<MDNode>(Match->getOperand(I));
64 assert(MD && "MDNode operand is expected");
65
66 if (auto *Const = getMDOperandAsConstInt(MD, 0)) {
67 auto *CMeta = dyn_cast<ConstantAsMetadata>(MD->getOperand(1));
68 assert(CMeta && "ConstantAsMetadata operand is expected");
69 int64_t Idx = Const->getSExtValue();
70 // Currently -1 indicates return value, greater values mean
71 // argument numbers.
72 if (Idx == -1) {
73 RetTy = CMeta->getType();
74 continue;
75 }
76 if (Idx >= 0 && static_cast<uint64_t>(Idx) < PTys.size()) {
77 PTys[Idx] = CMeta->getType();
78 continue;
79 }
80 report_fatal_error("invalid argument index in function type metadata");
81 }
82 }
83
84 return FunctionType::get(RetTy, PTys, FTy->isVarArg());
85}
86
88 StringRef Constraints,
89 StringRef Name) {
90 if (!NMD)
91 return Constraints;
92
93 MDNode *Match = findNamedMDOperand(NMD, Name);
94 if (!Match)
95 return Constraints;
96
97 // By convention, the constraints string is stored in the final MD operand.
98 MDNode *MD = dyn_cast<MDNode>(Match->getOperand(Match->getNumOperands() - 1));
99 assert(MD && "MDNode operand is expected");
100
101 if (auto *MDS = dyn_cast<MDString>(MD->getOperand(0)))
102 Constraints = MDS->getString();
103
104 return Constraints;
105}
106
109 F.getParent()->getNamedMetadata("spv.cloned_funcs"), F.getFunctionType(),
110 F.getName());
111}
112
113// Keyed via instruction metadata, not a name.
114static std::optional<StringRef> getMutatedCallsiteKey(const CallBase &CB) {
115 if (MDNode *MD = CB.getMetadata("spv.mutated_callsite"))
116 if (MD->getNumOperands() > 0)
117 if (auto *MDS = dyn_cast<MDString>(MD->getOperand(0)))
118 return MDS->getString();
119 return std::nullopt;
120}
121
123 std::optional<StringRef> Key = getMutatedCallsiteKey(CB);
124 if (!Key)
125 return CB.getFunctionType();
127 CB.getModule()->getNamedMetadata("spv.mutated_callsites"),
128 CB.getFunctionType(), *Key);
129}
130
132 StringRef Constraints =
133 cast<InlineAsm>(CB.getCalledOperand())->getConstraintString();
134 std::optional<StringRef> Key = getMutatedCallsiteKey(CB);
135 if (!Key)
136 return Constraints;
138 CB.getModule()->getNamedMetadata("spv.mutated_callsites"), Constraints,
139 *Key);
140}
141} // Namespace SPIRV
142
143// The following functions are used to add these string literals as a series of
144// 32-bit integer operands with the correct format, and unpack them if necessary
145// when making string comparisons in compiler passes.
146// SPIR-V requires null-terminated UTF-8 strings padded to 32-bit alignment.
147static uint32_t convertCharsToWord(StringRef Str, unsigned i) {
148 uint32_t Word = 0u; // Build up this 32-bit word from 4 8-bit chars.
149 for (unsigned WordIndex = 0; WordIndex < 4; ++WordIndex) {
150 unsigned StrIndex = i + WordIndex;
151 uint8_t CharToAdd = 0; // Initilize char as padding/null.
152 if (StrIndex < Str.size()) { // If it's within the string, get a real char.
153 CharToAdd = Str[StrIndex];
154 }
155 Word |= (CharToAdd << (WordIndex * 8));
156 }
157 return Word;
158}
159
160// Get length including padding and null terminator.
161static size_t getPaddedLen(StringRef Str) { return alignTo(Str.size() + 1, 4); }
162
163void addStringImm(StringRef Str, MCInst &Inst) {
164 const size_t PaddedLen = getPaddedLen(Str);
165 for (unsigned i = 0; i < PaddedLen; i += 4) {
166 // Add an operand for the 32-bits of chars or padding.
168 }
169}
170
172 const size_t PaddedLen = getPaddedLen(Str);
173 for (unsigned i = 0; i < PaddedLen; i += 4) {
174 // Add an operand for the 32-bits of chars or padding.
175 MIB.addImm(convertCharsToWord(Str, i));
176 }
177}
178
179std::string getStringImm(const MachineInstr &MI, unsigned StartIndex) {
180 return getSPIRVStringOperand(MI, StartIndex);
181}
182
184 MachineInstr *Def = getVRegDef(MRI, Reg);
185 assert(Def && Def->getOpcode() == TargetOpcode::G_GLOBAL_VALUE &&
186 "Expected G_GLOBAL_VALUE");
187 const GlobalValue *GV = Def->getOperand(1).getGlobal();
188 Value *V = GV->getOperand(0);
190 return CDA->getAsCString().str();
191}
192
193void addNumImm(const APInt &Imm, MachineInstrBuilder &MIB) {
194 const auto Bitwidth = Imm.getBitWidth();
195 if (Bitwidth == 1)
196 return; // Already handled
197 else if (Bitwidth <= 32) {
198 MIB.addImm(Imm.getZExtValue());
199 // Asm Printer needs this info to print floating-type correctly
200 if (Bitwidth == 16)
202 return;
203 } else if (Bitwidth <= 64) {
204 uint64_t FullImm = Imm.getZExtValue();
205 MIB.addImm(Lo_32(FullImm)).addImm(Hi_32(FullImm));
206 // Asm Printer needs this info to print 64-bit operands correctly
208 return;
209 } else {
210 // Emit ceil(Bitwidth / 32) words to conform SPIR-V spec.
211 unsigned NumWords = divideCeil(Bitwidth, 32);
212 for (unsigned I = 0; I < NumWords; ++I) {
213 unsigned LimbIdx = I / 2;
214 unsigned LimbShift = (I % 2) * 32;
215 uint32_t Word = (Imm.getRawData()[LimbIdx] >> LimbShift) & 0xffffffff;
216 MIB.addImm(Word);
217 }
218 return;
219 }
220}
221
223 MachineIRBuilder &MIRBuilder) {
224 if (!Name.empty()) {
225 auto MIB = MIRBuilder.buildInstr(SPIRV::OpName).addUse(Target);
226 addStringImm(Name, MIB);
227 }
228}
229
231 const SPIRVInstrInfo &TII) {
232 if (!Name.empty()) {
233 auto MIB =
234 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SPIRV::OpName))
235 .addUse(Target);
236 addStringImm(Name, MIB);
237 }
238}
239
241 ArrayRef<uint32_t> DecArgs,
242 StringRef StrImm) {
243 if (!StrImm.empty())
244 addStringImm(StrImm, MIB);
245 for (const auto &DecArg : DecArgs)
246 MIB.addImm(DecArg);
247}
248
250 SPIRV::Decoration::Decoration Dec,
251 ArrayRef<uint32_t> DecArgs, StringRef StrImm) {
252 auto MIB = MIRBuilder.buildInstr(SPIRV::OpDecorate)
253 .addUse(Reg)
254 .addImm(static_cast<uint32_t>(Dec));
255 finishBuildOpDecorate(MIB, DecArgs, StrImm);
256}
257
259 SPIRV::Decoration::Decoration Dec,
260 ArrayRef<uint32_t> DecArgs, StringRef StrImm) {
261 MachineBasicBlock &MBB = *I.getParent();
262 auto MIB = BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpDecorate))
263 .addUse(Reg)
264 .addImm(static_cast<uint32_t>(Dec));
265 finishBuildOpDecorate(MIB, DecArgs, StrImm);
266}
267
269 SPIRV::Decoration::Decoration Dec, uint32_t Member,
270 ArrayRef<uint32_t> DecArgs, StringRef StrImm) {
271 auto MIB = MIRBuilder.buildInstr(SPIRV::OpMemberDecorate)
272 .addUse(Reg)
273 .addImm(Member)
274 .addImm(static_cast<uint32_t>(Dec));
275 finishBuildOpDecorate(MIB, DecArgs, StrImm);
276}
277
279 const MDNode *GVarMD, const SPIRVSubtarget &ST) {
280 for (unsigned I = 0, E = GVarMD->getNumOperands(); I != E; ++I) {
281 auto *OpMD = dyn_cast<MDNode>(GVarMD->getOperand(I));
282 if (!OpMD)
283 report_fatal_error("Invalid decoration");
284 if (OpMD->getNumOperands() == 0)
285 report_fatal_error("Expect operand(s) of the decoration");
286 ConstantInt *DecorationId =
287 mdconst::dyn_extract<ConstantInt>(OpMD->getOperand(0));
288 if (!DecorationId)
289 report_fatal_error("Expect SPIR-V <Decoration> operand to be the first "
290 "element of the decoration");
291
292 // The goal of `spirv.Decorations` metadata is to provide a way to
293 // represent SPIR-V entities that do not map to LLVM in an obvious way.
294 // FP flags do have obvious matches between LLVM IR and SPIR-V.
295 // Additionally, we have no guarantee at this point that the flags passed
296 // through the decoration are not violated already in the optimizer passes.
297 // Therefore, we simply ignore FP flags, including NoContraction, and
298 // FPFastMathMode.
299 if (DecorationId->getZExtValue() ==
300 static_cast<uint32_t>(SPIRV::Decoration::NoContraction) ||
301 DecorationId->getZExtValue() ==
302 static_cast<uint32_t>(SPIRV::Decoration::FPFastMathMode)) {
303 continue; // Ignored.
304 }
305 uint32_t Dec = static_cast<uint32_t>(DecorationId->getZExtValue());
306 if (Dec == static_cast<uint32_t>(SPIRV::Decoration::UniformId)) {
307 ConstantInt *ScopeV =
308 OpMD->getNumOperands() == 2
309 ? mdconst::dyn_extract<ConstantInt>(OpMD->getOperand(1))
310 : nullptr;
311 assert(ScopeV && isUInt<32>(ScopeV->getZExtValue()) &&
312 "Expect Scope <id> operand of the UniformId decoration");
313 SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
314 SPIRVTypeInst SpvTypeInt32 =
315 GR->getOrCreateSPIRVIntegerType(32, MIRBuilder);
316 Register ScopeReg = GR->buildConstantInt(
317 ScopeV->getZExtValue(), MIRBuilder, SpvTypeInt32, /*EmitIR=*/false);
318 MIRBuilder.buildInstr(SPIRV::OpDecorateId)
319 .addUse(Reg)
320 .addImm(Dec)
321 .addUse(ScopeReg);
322 continue;
323 }
324 auto MIB = MIRBuilder.buildInstr(SPIRV::OpDecorate).addUse(Reg).addImm(Dec);
325 for (unsigned OpI = 1, OpE = OpMD->getNumOperands(); OpI != OpE; ++OpI) {
326 if (ConstantInt *OpV =
327 mdconst::dyn_extract<ConstantInt>(OpMD->getOperand(OpI)))
328 MIB.addImm(static_cast<uint32_t>(OpV->getZExtValue()));
329 else if (MDString *OpV = dyn_cast<MDString>(OpMD->getOperand(OpI)))
330 addStringImm(OpV->getString(), MIB);
331 else
332 report_fatal_error("Unexpected operand of the decoration");
333 }
334 }
335}
336
339 // Find the position to insert the OpVariable instruction.
340 // We will insert it after the last OpFunctionParameter, if any, or
341 // after OpFunction otherwise.
342 auto IsPreamble = [](const MachineInstr &MI) {
343 switch (MI.getOpcode()) {
344 case SPIRV::OpFunction:
345 case SPIRV::OpFunctionParameter:
346 case SPIRV::OpLabel:
347 case SPIRV::ASSIGN_TYPE:
348 return true;
349 default:
350 return false;
351 }
352 };
353 MachineBasicBlock::iterator VarPos = MBB.SkipPHIsAndLabels(MBB.begin());
354 while (VarPos != MBB.end() && VarPos->getOpcode() != SPIRV::OpFunction)
355 ++VarPos;
356 // Advance past the preamble.
357 while (VarPos != MBB.end() && IsPreamble(*VarPos))
358 ++VarPos;
359 return VarPos;
360}
361
364 if (I == MBB->begin())
365 return I;
366 --I;
367 while (I->isTerminator() || I->isDebugValue()) {
368 if (I == MBB->begin())
369 break;
370 --I;
371 }
372 return I;
373}
374
375SPIRV::StorageClass::StorageClass
376addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI) {
377 switch (AddrSpace) {
378 case 0:
379 return SPIRV::StorageClass::Function;
380 case 1:
381 return SPIRV::StorageClass::CrossWorkgroup;
382 case 2:
383 return SPIRV::StorageClass::UniformConstant;
384 case 3:
385 return SPIRV::StorageClass::Workgroup;
386 case 4:
387 return SPIRV::StorageClass::Generic;
388 case 5:
389 return STI.canUseExtension(SPIRV::Extension::SPV_INTEL_usm_storage_classes)
390 ? SPIRV::StorageClass::DeviceOnlyINTEL
391 : SPIRV::StorageClass::CrossWorkgroup;
392 case 6:
393 return STI.canUseExtension(SPIRV::Extension::SPV_INTEL_usm_storage_classes)
394 ? SPIRV::StorageClass::HostOnlyINTEL
395 : SPIRV::StorageClass::CrossWorkgroup;
396 case 7:
397 return SPIRV::StorageClass::Input;
398 case 8:
399 return SPIRV::StorageClass::Output;
400 case 9:
401 return SPIRV::StorageClass::CodeSectionINTEL;
402 case 10:
403 return SPIRV::StorageClass::Private;
404 case 11:
405 return SPIRV::StorageClass::StorageBuffer;
406 case 12:
407 return SPIRV::StorageClass::Uniform;
408 case 13:
409 return SPIRV::StorageClass::PushConstant;
410 default:
411 report_fatal_error("Unknown address space");
412 }
413}
414
415SPIRV::MemorySemantics::MemorySemantics
416getMemSemanticsForStorageClass(SPIRV::StorageClass::StorageClass SC) {
417 switch (SC) {
418 case SPIRV::StorageClass::StorageBuffer:
419 case SPIRV::StorageClass::Uniform:
420 return SPIRV::MemorySemantics::UniformMemory;
421 case SPIRV::StorageClass::Workgroup:
422 return SPIRV::MemorySemantics::WorkgroupMemory;
423 case SPIRV::StorageClass::CrossWorkgroup:
424 return SPIRV::MemorySemantics::CrossWorkgroupMemory;
425 case SPIRV::StorageClass::AtomicCounter:
426 return SPIRV::MemorySemantics::AtomicCounterMemory;
427 case SPIRV::StorageClass::Image:
428 return SPIRV::MemorySemantics::ImageMemory;
429 default:
430 return SPIRV::MemorySemantics::None;
431 }
432}
433
434SPIRV::MemorySemantics::MemorySemantics getMemSemantics(AtomicOrdering Ord) {
435 switch (Ord) {
437 return SPIRV::MemorySemantics::Acquire;
439 return SPIRV::MemorySemantics::Release;
441 return SPIRV::MemorySemantics::AcquireRelease;
443 return SPIRV::MemorySemantics::SequentiallyConsistent;
447 return SPIRV::MemorySemantics::None;
448 }
449 llvm_unreachable(nullptr);
450}
451
453 uint32_t StorageClassSem) {
454 bool DropStorageClass =
455 TT.isVulkanOS() &&
456 OrderSem == static_cast<uint32_t>(SPIRV::MemorySemantics::None);
457 return OrderSem | (DropStorageClass ? 0 : StorageClassSem);
458}
459
460SPIRV::Scope::Scope getMemScope(const Triple &TT, LLVMContext &Ctx,
461 SyncScope::ID Id) {
462 // Named by
463 // https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#_scope_id.
464 // We don't need aliases for Invocation and CrossDevice, as we already have
465 // them covered by "singlethread" and "" strings respectively (see
466 // implementation of LLVMContext::LLVMContext()).
467 auto ScopeID = [&](AtomicScope Scope) {
468 return Ctx.getOrInsertSyncScopeID(*getAtomicScopeIRString(TT, Scope));
469 };
470 static const llvm::SyncScope::ID SubGroup = ScopeID(AtomicScope::Wavefront);
471 static const llvm::SyncScope::ID WorkGroup = ScopeID(AtomicScope::Workgroup);
472 static const llvm::SyncScope::ID Device = ScopeID(AtomicScope::Device);
473
475 return SPIRV::Scope::Invocation;
476 else if (Id == llvm::SyncScope::System)
477 return SPIRV::Scope::CrossDevice;
478 else if (Id == SubGroup)
479 return SPIRV::Scope::Subgroup;
480 else if (Id == WorkGroup)
481 return SPIRV::Scope::Workgroup;
482 else if (Id == Device)
483 return SPIRV::Scope::Device;
484 return SPIRV::Scope::CrossDevice;
485}
486
488 const MachineRegisterInfo *MRI) {
489 MachineInstr *MI = MRI->getVRegDef(ConstReg);
490 MachineInstr *ConstInstr =
491 MI->getOpcode() == SPIRV::G_TRUNC || MI->getOpcode() == SPIRV::G_ZEXT
492 ? MRI->getVRegDef(MI->getOperand(1).getReg())
493 : MI;
494 if (auto *GI = dyn_cast<GIntrinsic>(ConstInstr)) {
495 if (GI->is(Intrinsic::spv_track_constant)) {
496 ConstReg = ConstInstr->getOperand(2).getReg();
497 return MRI->getVRegDef(ConstReg);
498 }
499 } else if (ConstInstr->getOpcode() == SPIRV::ASSIGN_TYPE) {
500 ConstReg = ConstInstr->getOperand(1).getReg();
501 return MRI->getVRegDef(ConstReg);
502 } else if (ConstInstr->getOpcode() == TargetOpcode::G_CONSTANT ||
503 ConstInstr->getOpcode() == TargetOpcode::G_FCONSTANT) {
504 ConstReg = ConstInstr->getOperand(0).getReg();
505 return ConstInstr;
506 }
507 return MRI->getVRegDef(ConstReg);
508}
509
511 const MachineInstr *MI = getDefInstrMaybeConstant(ConstReg, MRI);
512 assert(MI && MI->getOpcode() == TargetOpcode::G_CONSTANT);
513 return MI->getOperand(1).getCImm()->getValue().getZExtValue();
514}
515
516int64_t getIConstValSext(Register ConstReg, const MachineRegisterInfo *MRI) {
517 const MachineInstr *MI = getDefInstrMaybeConstant(ConstReg, MRI);
518 assert(MI && MI->getOpcode() == TargetOpcode::G_CONSTANT);
519 return MI->getOperand(1).getCImm()->getSExtValue();
520}
521
522bool isSpvIntrinsic(const MachineInstr &MI, Intrinsic::ID IntrinsicID) {
523 if (const auto *GI = dyn_cast<GIntrinsic>(&MI))
524 return GI->is(IntrinsicID);
525 return false;
526}
527
528Type *getMDOperandAsType(const MDNode *N, unsigned I) {
529 Type *ElementTy = cast<ValueAsMetadata>(N->getOperand(I))->getType();
530 return toTypedPointer(ElementTy);
531}
532
534 if (N->getNumOperands() <= I)
535 return nullptr;
536 if (auto *CMeta = dyn_cast<ConstantAsMetadata>(N->getOperand(I)))
537 return dyn_cast<ConstantInt>(CMeta->getValue());
538 return nullptr;
539}
540
541static bool isEnqueueKernelBI(StringRef MangledName) {
542 return MangledName == "__enqueue_kernel_basic" ||
543 MangledName == "__enqueue_kernel_basic_events" ||
544 MangledName == "__enqueue_kernel_varargs" ||
545 MangledName == "__enqueue_kernel_events_varargs";
546}
547
548static bool isKernelQueryBI(StringRef MangledName) {
549 return MangledName == "__get_kernel_work_group_size_impl" ||
550 MangledName == "__get_kernel_sub_group_count_for_ndrange_impl" ||
551 MangledName == "__get_kernel_max_sub_group_size_for_ndrange_impl" ||
552 MangledName == "__get_kernel_preferred_work_group_size_multiple_impl";
553}
554
556 if (!Name.starts_with("__"))
557 return false;
558
559 return isEnqueueKernelBI(Name) || isKernelQueryBI(Name) ||
561 Name == "__translate_sampler_initializer";
562}
563
565 bool IsNonMangledOCL = isNonMangledOCLBuiltin(Name);
566 bool IsNonMangledSPIRV = Name.starts_with("__spirv_");
567 bool IsNonMangledHLSL = Name.starts_with("__hlsl_");
568 bool IsMangled = Name.starts_with("_Z");
569
570 // Otherwise use simple demangling to return the function name.
571 if (IsNonMangledOCL || IsNonMangledSPIRV || IsNonMangledHLSL || !IsMangled)
572 return Name.str();
573
574 // Try to use the itanium demangler.
575 if (char *DemangledName = itaniumDemangle(Name.data())) {
576 std::string Result = DemangledName;
577 free(DemangledName);
578 return Result;
579 }
580
581 // Autocheck C++, maybe need to do explicit check of the source language.
582 // OpenCL C++ built-ins are declared in cl namespace.
583 // TODO: consider using 'St' abbriviation for cl namespace mangling.
584 // Similar to ::std:: in C++.
585 size_t Start, Len = 0;
586 size_t DemangledNameLenStart = 2;
587 if (Name.starts_with("_ZN")) {
588 // Skip CV and ref qualifiers.
589 size_t NameSpaceStart = Name.find_first_not_of("rVKRO", 3);
590 // All built-ins are in the ::cl:: namespace.
591 if (Name.substr(NameSpaceStart, 11) != "2cl7__spirv")
592 return std::string();
593 DemangledNameLenStart = NameSpaceStart + 11;
594 }
595 Start = Name.find_first_not_of("0123456789", DemangledNameLenStart);
596 bool Error = Name.substr(DemangledNameLenStart, Start - DemangledNameLenStart)
597 .getAsInteger(10, Len);
598 if (Error)
599 return std::string();
600 return Name.substr(Start, Len).str();
601}
602
604 if (Name.starts_with("opencl.") || Name.starts_with("ocl_") ||
605 Name.starts_with("spirv."))
606 return true;
607 return false;
608}
609
610bool isSpecialOpaqueType(const Type *Ty) {
611 if (const TargetExtType *ExtTy = dyn_cast<TargetExtType>(Ty))
612 return isTypedPointerWrapper(ExtTy)
613 ? false
614 : hasBuiltinTypePrefix(ExtTy->getName());
615
616 return false;
617}
618
619bool isEntryPoint(const Function &F) {
620 // OpenCL handling: any function with the SPIR_KERNEL
621 // calling convention will be a potential entry point.
622 if (F.getCallingConv() == CallingConv::SPIR_KERNEL)
623 return true;
624
625 // HLSL handling: special attribute are emitted from the
626 // front-end.
627 if (F.getFnAttribute("hlsl.shader").isValid())
628 return true;
629
630 return false;
631}
632
634 TypeName.consume_front("atomic_");
635 if (TypeName.consume_front("void"))
636 return Type::getVoidTy(Ctx);
637 else if (TypeName.consume_front("bool") || TypeName.consume_front("_Bool"))
638 return Type::getIntNTy(Ctx, 1);
639 else if (TypeName.consume_front("char") ||
640 TypeName.consume_front("signed char") ||
641 TypeName.consume_front("unsigned char") ||
642 TypeName.consume_front("uchar"))
643 return Type::getInt8Ty(Ctx);
644 else if (TypeName.consume_front("short") ||
645 TypeName.consume_front("signed short") ||
646 TypeName.consume_front("unsigned short") ||
647 TypeName.consume_front("ushort"))
648 return Type::getInt16Ty(Ctx);
649 else if (TypeName.consume_front("int") ||
650 TypeName.consume_front("signed int") ||
651 TypeName.consume_front("unsigned int") ||
652 TypeName.consume_front("uint"))
653 return Type::getInt32Ty(Ctx);
654 else if (TypeName.consume_front("long") ||
655 TypeName.consume_front("signed long") ||
656 TypeName.consume_front("unsigned long") ||
657 TypeName.consume_front("ulong"))
658 return Type::getInt64Ty(Ctx);
659 else if (TypeName.consume_front("half") ||
660 TypeName.consume_front("_Float16") ||
661 TypeName.consume_front("__fp16"))
662 return Type::getHalfTy(Ctx);
663 else if (TypeName.consume_front("float"))
664 return Type::getFloatTy(Ctx);
665 else if (TypeName.consume_front("double"))
666 return Type::getDoubleTy(Ctx);
667
668 // Unable to recognize SPIRV type name
669 return nullptr;
670}
671
672SmallPtrSet<BasicBlock *, 0>
673PartialOrderingVisitor::getReachableFrom(BasicBlock *Start) {
674 std::queue<BasicBlock *> ToVisit;
675 ToVisit.push(Start);
676
677 SmallPtrSet<BasicBlock *, 0> Output;
678 while (ToVisit.size() != 0) {
679 BasicBlock *BB = ToVisit.front();
680 ToVisit.pop();
681
682 if (Output.count(BB) != 0)
683 continue;
684 Output.insert(BB);
685
686 for (BasicBlock *Successor : successors(BB)) {
687 if (DT.dominates(Successor, BB))
688 continue;
689 ToVisit.push(Successor);
690 }
691 }
692
693 return Output;
694}
695
696bool PartialOrderingVisitor::CanBeVisited(BasicBlock *BB) const {
697 for (BasicBlock *P : predecessors(BB)) {
698 // Ignore back-edges.
699 if (DT.dominates(BB, P))
700 continue;
701
702 // One of the predecessor hasn't been visited. Not ready yet.
703 if (BlockToOrder.count(P) == 0)
704 return false;
705
706 // If the block is a loop exit, the loop must be finished before
707 // we can continue.
708 Loop *L = LI.getLoopFor(P);
709 if (L == nullptr || L->contains(BB))
710 continue;
711
712 // SPIR-V requires a single back-edge. And the backend first
713 // step transforms loops into the simplified format. If we have
714 // more than 1 back-edge, something is wrong.
715 assert(L->getNumBackEdges() <= 1);
716
717 // If the loop has no latch, loop's rank won't matter, so we can
718 // proceed.
719 BasicBlock *Latch = L->getLoopLatch();
720 assert(Latch);
721 if (Latch == nullptr)
722 continue;
723
724 // The latch is not ready yet, let's wait.
725 if (BlockToOrder.count(Latch) == 0)
726 return false;
727 }
728
729 return true;
730}
731
733 auto It = BlockToOrder.find(BB);
734 if (It != BlockToOrder.end())
735 return It->second.Rank;
736
737 size_t result = 0;
738 for (BasicBlock *P : predecessors(BB)) {
739 // Ignore back-edges.
740 if (DT.dominates(BB, P))
741 continue;
742
743 auto Iterator = BlockToOrder.end();
744 Loop *L = LI.getLoopFor(P);
745 BasicBlock *Latch = L ? L->getLoopLatch() : nullptr;
746
747 // If the predecessor is either outside a loop, or part of
748 // the same loop, simply take its rank + 1.
749 if (L == nullptr || L->contains(BB) || Latch == nullptr) {
750 Iterator = BlockToOrder.find(P);
751 } else {
752 // Otherwise, take the loop's rank (highest rank in the loop) as base.
753 // Since loops have a single latch, highest rank is easy to find.
754 // If the loop has no latch, then it doesn't matter.
755 Iterator = BlockToOrder.find(Latch);
756 }
757
758 assert(Iterator != BlockToOrder.end());
759 result = std::max(result, Iterator->second.Rank + 1);
760 }
761
762 return result;
763}
764
765size_t PartialOrderingVisitor::visit(BasicBlock *BB, size_t Unused) {
766 ToVisit.push(BB);
767 Queued.insert(BB);
768
769 size_t QueueIndex = 0;
770 while (ToVisit.size() != 0) {
771 BasicBlock *BB = ToVisit.front();
772 ToVisit.pop();
773
774 if (!CanBeVisited(BB)) {
775 ToVisit.push(BB);
776 if (QueueIndex >= ToVisit.size())
778 "No valid candidate in the queue. Is the graph reducible?");
779 QueueIndex++;
780 continue;
781 }
782
783 QueueIndex = 0;
784 size_t Rank = GetNodeRank(BB);
785 OrderInfo Info = {Rank, BlockToOrder.size()};
786 BlockToOrder.try_emplace(BB, Info);
787
788 for (BasicBlock *S : successors(BB)) {
789 if (Queued.count(S) != 0)
790 continue;
791 ToVisit.push(S);
792 Queued.insert(S);
793 }
794 }
795
796 return 0;
797}
798
800 DT.recalculate(F);
801 LI = LoopInfo(DT);
802
803 visit(&*F.begin(), 0);
804
805 Order.reserve(F.size());
806 for (auto &[BB, Info] : BlockToOrder)
807 Order.emplace_back(BB);
808
809 llvm::sort(Order, [&](const auto &LHS, const auto &RHS) {
810 return compare(LHS, RHS);
811 });
812}
813
815 const BasicBlock *RHS) const {
816 const OrderInfo &InfoLHS = BlockToOrder.at(const_cast<BasicBlock *>(LHS));
817 const OrderInfo &InfoRHS = BlockToOrder.at(const_cast<BasicBlock *>(RHS));
818 if (InfoLHS.Rank != InfoRHS.Rank)
819 return InfoLHS.Rank < InfoRHS.Rank;
820 return InfoLHS.TraversalIndex < InfoRHS.TraversalIndex;
821}
822
824 BasicBlock &Start, std::function<bool(BasicBlock *)> Op) {
825 SmallPtrSet<BasicBlock *, 0> Reachable = getReachableFrom(&Start);
826 assert(BlockToOrder.count(&Start) != 0);
827
828 // Skipping blocks with a rank inferior to |Start|'s rank.
829 auto It = Order.begin();
830 while (It != Order.end() && *It != &Start)
831 ++It;
832
833 // This is unexpected. Worst case |Start| is the last block,
834 // so It should point to the last block, not past-end.
835 assert(It != Order.end());
836
837 // By default, there is no rank limit. Setting it to the maximum value.
838 std::optional<size_t> EndRank = std::nullopt;
839 for (; It != Order.end(); ++It) {
840 if (EndRank.has_value() && BlockToOrder[*It].Rank > *EndRank)
841 break;
842
843 if (Reachable.count(*It) == 0) {
844 continue;
845 }
846
847 if (!Op(*It)) {
848 EndRank = BlockToOrder[*It].Rank;
849 }
850 }
851}
852
854 if (F.size() == 0)
855 return false;
856
857 bool Modified = false;
858 std::vector<BasicBlock *> Order;
859 Order.reserve(F.size());
860
862 llvm::append_range(Order, RPOT);
863
864 assert(&*F.begin() == Order[0]);
865 BasicBlock *LastBlock = &*F.begin();
866 for (BasicBlock *BB : Order) {
867 if (BB != LastBlock && &*LastBlock->getNextNode() != BB) {
868 Modified = true;
869 BB->moveAfter(LastBlock);
870 }
871 LastBlock = BB;
872 }
873
874 return Modified;
875}
876
878 const DataLayout &DL = F.getDataLayout();
879 return new AllocaInst(Type, DL.getAllocaAddrSpace(), nullptr, "reg",
880 F.begin()->getFirstInsertionPt());
881}
882
883Value *
885 const DenseMap<BasicBlock *, ConstantInt *> &TargetToValue) {
886 auto *T = BB->getTerminator();
887 if (isa<ReturnInst>(T))
888 return nullptr;
889 if (auto *BI = dyn_cast<UncondBrInst>(T))
890 return TargetToValue.lookup(BI->getSuccessor());
891
892 IRBuilder<> Builder(BB);
893 Builder.SetInsertPoint(T);
894
895 if (auto *BI = dyn_cast<CondBrInst>(T)) {
896 Value *LHS = TargetToValue.lookup(BI->getSuccessor(0));
897 Value *RHS = TargetToValue.lookup(BI->getSuccessor(1));
898
899 if (LHS == nullptr || RHS == nullptr)
900 return LHS == nullptr ? RHS : LHS;
901 return Builder.CreateSelect(BI->getCondition(), LHS, RHS);
902 }
903
904 if (auto *SI = dyn_cast<SwitchInst>(T)) {
905 Value *Condition = SI->getCondition();
906 // The default destination acts as the fallback value of the select chain.
907 Value *Result = TargetToValue.lookup(SI->getDefaultDest());
908 for (const auto &Case : SI->cases()) {
909 Value *CaseValue = TargetToValue.lookup(Case.getCaseSuccessor());
910 // Successors that are internal to the region have no exit value.
911 if (CaseValue == nullptr)
912 continue;
913 // The first known exit value becomes the base of the select chain.
914 if (Result == nullptr) {
915 Result = CaseValue;
916 continue;
917 }
918 Value *Cmp = Builder.CreateICmpEQ(Condition, Case.getCaseValue());
919 Result = Builder.CreateSelect(Cmp, CaseValue, Result);
920 }
921 return Result;
922 }
923
924 llvm_unreachable("Unhandled terminator type.");
925}
926
928 MachineInstr *MaybeDef = MRI.getVRegDef(Reg);
929 if (MaybeDef && MaybeDef->getOpcode() == SPIRV::ASSIGN_TYPE)
930 MaybeDef = MRI.getVRegDef(MaybeDef->getOperand(1).getReg());
931 return MaybeDef;
932}
933
934static bool getVacantFunctionName(Module &M, std::string &Name) {
935 // It's a bit of paranoia, but still we don't want to have even a chance that
936 // the loop will work for too long.
937 constexpr unsigned MaxIters = 1024;
938 for (unsigned I = 0; I < MaxIters; ++I) {
939 std::string OrdName = Name + Twine(I).str();
940 if (!M.getFunction(OrdName)) {
941 Name = std::move(OrdName);
942 return true;
943 }
944 }
945 return false;
946}
947
948// Assign SPIR-V type to the register. If the register has no valid assigned
949// class, set register LLT type and class according to the SPIR-V type.
952 const MachineFunction &MF, bool Force) {
953 GR->assignSPIRVTypeToVReg(SpvType, Reg, MF);
954 if (!MRI->getRegClassOrNull(Reg) || Force) {
955 MRI->setRegClass(Reg, GR->getRegClass(SpvType));
956 LLT RegType = GR->getRegType(SpvType);
957 if (Force || !MRI->getType(Reg).isValid())
958 MRI->setType(Reg, RegType);
959 }
960}
961
962// Create a SPIR-V type, assign SPIR-V type to the register. If the register has
963// no valid assigned class, set register LLT type and class according to the
964// SPIR-V type.
966 MachineIRBuilder &MIRBuilder,
967 SPIRV::AccessQualifier::AccessQualifier AccessQual,
968 bool EmitIR, bool Force) {
970 GR->getOrCreateSPIRVType(Ty, MIRBuilder, AccessQual, EmitIR),
971 GR, MIRBuilder.getMRI(), MIRBuilder.getMF(), Force);
972}
973
974// Create a virtual register and assign SPIR-V type to the register. Set
975// register LLT type and class according to the SPIR-V type.
978 const MachineFunction &MF) {
979 Register Reg = MRI->createVirtualRegister(GR->getRegClass(SpvType));
980 MRI->setType(Reg, GR->getRegType(SpvType));
981 GR->assignSPIRVTypeToVReg(SpvType, Reg, MF);
982 return Reg;
983}
984
985// Create a virtual register and assign SPIR-V type to the register. Set
986// register LLT type and class according to the SPIR-V type.
988 MachineIRBuilder &MIRBuilder) {
989 return createVirtualRegister(SpvType, GR, MIRBuilder.getMRI(),
990 MIRBuilder.getMF());
991}
992
993// Create a SPIR-V type, virtual register and assign SPIR-V type to the
994// register. Set register LLT type and class according to the SPIR-V type.
996 const Type *Ty, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIRBuilder,
997 SPIRV::AccessQualifier::AccessQualifier AccessQual, bool EmitIR) {
999 GR->getOrCreateSPIRVType(Ty, MIRBuilder, AccessQual, EmitIR), GR,
1000 MIRBuilder);
1001}
1002
1004 Value *Arg, Value *Arg2, ArrayRef<Constant *> Imms,
1005 IRBuilder<> &B) {
1007 Args.push_back(Arg2);
1008 Args.push_back(buildMD(Arg));
1009 llvm::append_range(Args, Imms);
1010 return B.CreateIntrinsicWithoutFolding(IntrID, {Types}, Args);
1011}
1012
1013// Return true if there is an opaque pointer type nested in the argument.
1014bool isNestedPointer(const Type *Ty) {
1015 if (Ty->isPtrOrPtrVectorTy())
1016 return true;
1017 if (const FunctionType *RefTy = dyn_cast<FunctionType>(Ty)) {
1018 if (isNestedPointer(RefTy->getReturnType()))
1019 return true;
1020 for (const Type *ArgTy : RefTy->params())
1021 if (isNestedPointer(ArgTy))
1022 return true;
1023 return false;
1024 }
1025 if (const ArrayType *RefTy = dyn_cast<ArrayType>(Ty))
1026 return isNestedPointer(RefTy->getElementType());
1027 return false;
1028}
1029
1030bool isSpvIntrinsic(const Value *Arg) {
1031 if (const auto *II = dyn_cast<IntrinsicInst>(Arg))
1032 if (Function *F = II->getCalledFunction())
1033 if (F->getName().starts_with("llvm.spv."))
1034 return true;
1035 return false;
1036}
1037
1038// Function to create continued instructions for SPV_INTEL_long_composites
1039// extension
1040SmallVector<MachineInstr *, 4>
1042 unsigned MinWC, unsigned ContinuedOpcode,
1043 ArrayRef<Register> Args, Register ReturnRegister,
1044 Register TypeID) {
1045
1046 SmallVector<MachineInstr *, 4> Instructions;
1047 constexpr unsigned MaxWordCount = UINT16_MAX;
1048 const size_t NumElements = Args.size();
1049 size_t MaxNumElements = MaxWordCount - MinWC;
1050 size_t SPIRVStructNumElements = NumElements;
1051
1052 if (NumElements > MaxNumElements) {
1053 // Do adjustments for continued instructions which always had only one
1054 // minumum word count.
1055 SPIRVStructNumElements = MaxNumElements;
1056 MaxNumElements = MaxWordCount - 1;
1057 }
1058
1059 auto MIB =
1060 MIRBuilder.buildInstr(Opcode).addDef(ReturnRegister).addUse(TypeID);
1061
1062 for (size_t I = 0; I < SPIRVStructNumElements; ++I)
1063 MIB.addUse(Args[I]);
1064
1065 Instructions.push_back(MIB.getInstr());
1066
1067 for (size_t I = SPIRVStructNumElements; I < NumElements;
1068 I += MaxNumElements) {
1069 auto MIB = MIRBuilder.buildInstr(ContinuedOpcode);
1070 for (size_t J = I; J < std::min(I + MaxNumElements, NumElements); ++J)
1071 MIB.addUse(Args[J]);
1072 Instructions.push_back(MIB.getInstr());
1073 }
1074 return Instructions;
1075}
1076
1077SmallVector<unsigned, 1>
1079 unsigned LC = SPIRV::LoopControl::None;
1080 // Currently used only to store PartialCount value. Later when other
1081 // LoopControls are added - this map should be sorted before making
1082 // them loop_merge operands to satisfy 3.23. Loop Control requirements.
1083 std::vector<std::pair<unsigned, unsigned>> MaskToValueMap;
1084 if (findOptionMDForLoopID(LoopMD, "llvm.loop.unroll.disable")) {
1085 LC |= SPIRV::LoopControl::DontUnroll;
1086 } else {
1087 if (findOptionMDForLoopID(LoopMD, "llvm.loop.unroll.enable") ||
1088 findOptionMDForLoopID(LoopMD, "llvm.loop.unroll.full")) {
1089 LC |= SPIRV::LoopControl::Unroll;
1090 }
1091 if (MDNode *CountMD =
1092 findOptionMDForLoopID(LoopMD, "llvm.loop.unroll.count")) {
1093 if (auto *CI =
1094 mdconst::extract_or_null<ConstantInt>(CountMD->getOperand(1))) {
1095 unsigned Count = CI->getZExtValue();
1096 if (Count != 1) {
1097 LC |= SPIRV::LoopControl::PartialCount;
1098 MaskToValueMap.emplace_back(
1099 std::make_pair(SPIRV::LoopControl::PartialCount, Count));
1100 }
1101 }
1102 }
1103 }
1104 SmallVector<unsigned, 1> Result = {LC};
1105 for (auto &[Mask, Val] : MaskToValueMap)
1106 Result.push_back(Val);
1107 return Result;
1108}
1109
1113
1114const std::set<unsigned> &getTypeFoldingSupportedOpcodes() {
1115 // clang-format off
1116 static const std::set<unsigned> TypeFoldingSupportingOpcs = {
1117 TargetOpcode::G_ADD,
1118 TargetOpcode::G_FADD,
1119 TargetOpcode::G_STRICT_FADD,
1120 TargetOpcode::G_SUB,
1121 TargetOpcode::G_FSUB,
1122 TargetOpcode::G_STRICT_FSUB,
1123 TargetOpcode::G_MUL,
1124 TargetOpcode::G_FMUL,
1125 TargetOpcode::G_STRICT_FMUL,
1126 TargetOpcode::G_SDIV,
1127 TargetOpcode::G_UDIV,
1128 TargetOpcode::G_FDIV,
1129 TargetOpcode::G_STRICT_FDIV,
1130 TargetOpcode::G_SREM,
1131 TargetOpcode::G_UREM,
1132 TargetOpcode::G_FREM,
1133 TargetOpcode::G_STRICT_FREM,
1134 TargetOpcode::G_FNEG,
1135 TargetOpcode::G_CONSTANT,
1136 TargetOpcode::G_FCONSTANT,
1137 TargetOpcode::G_AND,
1138 TargetOpcode::G_OR,
1139 TargetOpcode::G_XOR,
1140 TargetOpcode::G_SHL,
1141 TargetOpcode::G_ASHR,
1142 TargetOpcode::G_LSHR,
1143 TargetOpcode::G_SELECT,
1144 TargetOpcode::G_EXTRACT_VECTOR_ELT,
1145 };
1146 // clang-format on
1147 return TypeFoldingSupportingOpcs;
1148}
1149
1150bool isTypeFoldingSupported(unsigned Opcode) {
1151 return getTypeFoldingSupportedOpcodes().count(Opcode) > 0;
1152}
1153
1154// Traversing [g]MIR accounting for pseudo-instructions.
1156 return (Def->getOpcode() == SPIRV::ASSIGN_TYPE ||
1157 Def->getOpcode() == TargetOpcode::COPY)
1158 ? MRI->getVRegDef(Def->getOperand(1).getReg())
1159 : Def;
1160}
1161
1163 if (MachineInstr *Def = MRI->getVRegDef(MO.getReg()))
1164 return passCopy(Def, MRI);
1165 return nullptr;
1166}
1167
1169 if (MachineInstr *Def = getDef(MO, MRI)) {
1170 if (Def->getOpcode() == TargetOpcode::G_CONSTANT ||
1171 Def->getOpcode() == SPIRV::OpConstantI)
1172 return Def;
1173 }
1174 return nullptr;
1175}
1176
1177int64_t foldImm(const MachineOperand &MO, const MachineRegisterInfo *MRI) {
1178 if (MachineInstr *Def = getImm(MO, MRI)) {
1179 if (Def->getOpcode() == SPIRV::OpConstantI)
1180 return Def->getOperand(2).getImm();
1181 if (Def->getOpcode() == TargetOpcode::G_CONSTANT)
1182 return Def->getOperand(1).getCImm()->getZExtValue();
1183 }
1184 llvm_unreachable("Unexpected integer constant pattern");
1185}
1186
1188 const MachineInstr *ResType) {
1189 return foldImm(ResType->getOperand(2), MRI);
1190}
1191
1192bool matchPeeledArrayPattern(const StructType *Ty, Type *&OriginalElementType,
1193 uint64_t &TotalSize) {
1194 // An array of N padded structs is represented as {[N-1 x <{T, pad}>], T}.
1195 if (Ty->getStructNumElements() != 2)
1196 return false;
1197
1198 Type *FirstElement = Ty->getStructElementType(0);
1199 Type *SecondElement = Ty->getStructElementType(1);
1200
1201 if (!FirstElement->isArrayTy())
1202 return false;
1203
1204 Type *ArrayElementType = FirstElement->getArrayElementType();
1205 if (!ArrayElementType->isStructTy() ||
1206 ArrayElementType->getStructNumElements() != 2)
1207 return false;
1208
1209 Type *T_in_struct = ArrayElementType->getStructElementType(0);
1210 if (T_in_struct != SecondElement)
1211 return false;
1212
1213 auto *Padding_in_struct =
1214 dyn_cast<TargetExtType>(ArrayElementType->getStructElementType(1));
1215 if (!Padding_in_struct || Padding_in_struct->getName() != "spirv.Padding")
1216 return false;
1217
1218 const uint64_t ArraySize = FirstElement->getArrayNumElements();
1219 TotalSize = ArraySize + 1;
1220 OriginalElementType = ArrayElementType;
1221 return true;
1222}
1223
1225 if (!Ty->isStructTy())
1226 return Ty;
1227
1228 auto *STy = cast<StructType>(Ty);
1229 Type *OriginalElementType = nullptr;
1230 uint64_t TotalSize = 0;
1231 if (matchPeeledArrayPattern(STy, OriginalElementType, TotalSize)) {
1232 Type *ResultTy = ArrayType::get(
1233 reconstitutePeeledArrayType(OriginalElementType), TotalSize);
1234 return ResultTy;
1235 }
1236
1237 SmallVector<Type *, 4> NewElementTypes;
1238 bool Changed = false;
1239 for (Type *ElementTy : STy->elements()) {
1240 Type *NewElementTy = reconstitutePeeledArrayType(ElementTy);
1241 if (NewElementTy != ElementTy)
1242 Changed = true;
1243 NewElementTypes.push_back(NewElementTy);
1244 }
1245
1246 if (!Changed)
1247 return Ty;
1248
1249 Type *ResultTy;
1250 if (STy->isLiteral())
1251 ResultTy =
1252 StructType::get(STy->getContext(), NewElementTypes, STy->isPacked());
1253 else {
1254 auto *NewTy = StructType::create(STy->getContext(), STy->getName());
1255 NewTy->setBody(NewElementTypes, STy->isPacked());
1256 ResultTy = NewTy;
1257 }
1258 return ResultTy;
1259}
1260
1261std::optional<SPIRV::LinkageType::LinkageType>
1263 if (GV.hasLocalLinkage())
1264 return std::nullopt;
1265
1266 if (GV.isDeclarationForLinker()) {
1267 if (const auto *GVar = dyn_cast<GlobalVariable>(&GV)) {
1268 auto SC = addressSpaceToStorageClass(GVar->getAddressSpace(), ST);
1269 // Interface variables must not get Import linkage.
1270 if (SC == SPIRV::StorageClass::Input ||
1271 SC == SPIRV::StorageClass::Output ||
1272 SC == SPIRV::StorageClass::PushConstant)
1273 return std::nullopt;
1274 // Shaders have no linker, so module-internal storage
1275 // (e.g. HLSL groupshared) can't be imported
1276 if (ST.isShader() && (SC == SPIRV::StorageClass::Workgroup ||
1277 SC == SPIRV::StorageClass::Private))
1278 return std::nullopt;
1279 }
1280 return SPIRV::LinkageType::Import;
1281 }
1282
1283 if (GV.hasHiddenVisibility())
1284 return std::nullopt;
1285
1286 if (GV.hasLinkOnceODRLinkage() &&
1287 ST.canUseExtension(SPIRV::Extension::SPV_KHR_linkonce_odr))
1288 return SPIRV::LinkageType::LinkOnceODR;
1289
1290 if (GV.hasWeakLinkage() &&
1291 ST.canUseExtension(SPIRV::Extension::SPV_AMD_weak_linkage))
1292 return SPIRV::LinkageType::WeakAMD;
1293
1294 return SPIRV::LinkageType::Export;
1295}
1296
1298 std::string ServiceFunName = SPIRV_BACKEND_SERVICE_FUN_NAME;
1299 if (!getVacantFunctionName(M, ServiceFunName))
1301 "cannot allocate a name for the internal service function");
1302 if (Function *SF = M.getFunction(ServiceFunName)) {
1303 if (SF->getInstructionCount() > 0)
1305 "Unexpected combination of global variables and function pointers");
1306 return SF;
1307 }
1309 FunctionType::get(Type::getVoidTy(M.getContext()), {}, false),
1310 GlobalValue::PrivateLinkage, ServiceFunName, M);
1312 return SF;
1313}
1314
1315} // namespace llvm
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
This file declares the MachineIRBuilder class.
Register Reg
Type::TypeID TypeID
#define T
uint64_t IntrinsicInst * II
#define P(N)
#define SPIRV_BACKEND_SERVICE_FUN_NAME
Definition SPIRVUtils.h:546
This file contains some templates that are useful if you are working with the STL at all.
Value * RHS
Value * LHS
Class for arbitrary precision integers.
Definition APInt.h:78
an instruction to allocate memory on the stack
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
Class to represent array types.
static LLVM_ABI ArrayType * get(Type *ElementType, uint64_t NumElements)
This static method is the primary way to construct an ArrayType.
LLVM Basic Block Representation.
Definition BasicBlock.h:62
LLVM_ABI void moveAfter(BasicBlock *MovePos)
Unlink this basic block from its current function and insert it right after MovePos in the function M...
const Instruction & front() const
Definition BasicBlock.h:469
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
Definition BasicBlock.h:237
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
Value * getCalledOperand() const
FunctionType * getFunctionType() const
This class represents a function call, abstracting a target machine's calling convention.
An array constant whose element type is a simple 1/2/4/8-byte integer, bytes or float/double,...
Definition Constants.h:865
StringRef getAsCString() const
If this array is isCString(), then this method returns the array (without the trailing null byte) as ...
Definition Constants.h:838
This is the shared class of boolean and integer constants.
Definition Constants.h:87
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
Definition Constants.h:168
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:64
ValueT lookup(const_arg_type_t< KeyT > Val) const
Return the entry for the specified key, or a default constructed value if no such entry exists.
Definition DenseMap.h:250
unsigned size() const
Definition DenseMap.h:172
bool dominates(const DomTreeNodeBase< NodeT > *A, const DomTreeNodeBase< NodeT > *B) const
dominates - Returns true iff A dominates B.
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
Class to represent function types.
ArrayRef< Type * > params() const
bool isVarArg() const
Type * getReturnType() const
static LLVM_ABI FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
void addFnAttr(Attribute::AttrKind Kind)
Add function attributes to this function.
Definition Function.cpp:637
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
Definition Function.h:168
const Function & getFunction() const
Definition Function.h:166
bool hasLocalLinkage() const
bool hasHiddenVisibility() const
bool isDeclarationForLinker() const
bool hasWeakLinkage() const
bool hasLinkOnceODRLinkage() const
@ PrivateLinkage
Like Internal, but omit from symbol table.
Definition GlobalValue.h:61
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2893
LLVM_ABI const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
MDNode * getMetadata(unsigned KindID) const
Get the metadata of given kind attached to this Instruction.
constexpr bool isValid() const
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:68
Represents a single loop in the control flow graph.
Definition LoopInfo.h:40
Instances of this class represent a single low-level machine instruction.
Definition MCInst.h:188
void addOperand(const MCOperand Op)
Definition MCInst.h:215
static MCOperand createImm(int64_t Val)
Definition MCInst.h:145
Metadata node.
Definition Metadata.h:1069
const MDOperand & getOperand(unsigned I) const
Definition Metadata.h:1426
unsigned getNumOperands() const
Return number of MDNode operands.
Definition Metadata.h:1432
A single uniqued string.
Definition Metadata.h:722
MachineInstrBundleIterator< MachineInstr > iterator
const MachineBasicBlock & front() const
Helper class to build MachineInstr.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineFunction & getMF()
Getter for the function we currently build.
MachineRegisterInfo * getMRI()
Getter for MRI.
const MachineInstrBuilder & addUse(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
MachineInstr * getInstr() const
If conversion operators fail, use this method to get the MachineInstr explicitly.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
void setAsmPrinterFlag(AsmPrinterFlagTy Flag)
Set a flag for the AsmPrinter.
const MachineOperand & getOperand(unsigned i) const
MachineOperand class - Representation of each machine instruction operand.
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI LLVM_READONLY MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
LLVM_ABI Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
LLVM_ABI void setType(Register VReg, LLT Ty)
Set the low-level type of VReg to Ty.
LLVM_ABI void setRegClass(Register Reg, const TargetRegisterClass *RC)
setRegClass - Set the register class of the specified virtual register.
const TargetRegisterClass * getRegClassOrNull(Register Reg) const
Return the register class of Reg, or null if Reg has not been assigned a register class yet.
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
NamedMDNode * getNamedMetadata(StringRef Name) const
Return the first NamedMDNode in the module with the specified name.
Definition Module.cpp:301
A tuple of MDNodes.
Definition Metadata.h:1755
op_iterator op_end()
Definition Metadata.h:1844
iterator_range< op_iterator > operands()
Definition Metadata.h:1851
size_t GetNodeRank(BasicBlock *BB) const
void partialOrderVisit(BasicBlock &Start, std::function< bool(BasicBlock *)> Op)
bool compare(const BasicBlock *LHS, const BasicBlock *RHS) const
Wrapper class representing virtual and physical registers.
Definition Register.h:20
void assignSPIRVTypeToVReg(SPIRVTypeInst Type, Register VReg, const MachineFunction &MF)
const TargetRegisterClass * getRegClass(SPIRVTypeInst SpvType) const
SPIRVTypeInst getOrCreateSPIRVIntegerType(unsigned BitWidth, MachineIRBuilder &MIRBuilder)
LLT getRegType(SPIRVTypeInst SpvType) const
SPIRVTypeInst getOrCreateSPIRVType(const Type *Type, MachineInstr &I, SPIRV::AccessQualifier::AccessQualifier AQ, bool EmitIR)
Register buildConstantInt(uint64_t Val, MachineIRBuilder &MIRBuilder, SPIRVTypeInst SpvType, bool EmitIR, bool ZeroAsNull=true)
bool canUseExtension(SPIRV::Extension::Extension E) const
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
std::string str() const
Get the contents as an std::string.
Definition StringRef.h:222
constexpr bool empty() const
Check if the string is empty.
Definition StringRef.h:141
Class to represent struct types.
static LLVM_ABI StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)
This static method is the primary way to create a literal StructType.
Definition Type.cpp:477
static LLVM_ABI StructType * create(LLVMContext &Context, StringRef Name)
This creates an identified struct.
Definition Type.cpp:683
Class to represent target extensions types, which are generally unintrospectable from target-independ...
Target - Wrapper for Target specific information.
Triple - Helper class for working with autoconf configuration names.
Definition Triple.h:48
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
LLVM_ABI std::string str() const
Return the twine contents as a std::string.
Definition Twine.cpp:17
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
static LLVM_ABI IntegerType * getInt64Ty(LLVMContext &C)
Definition Type.cpp:310
LLVM_ABI Type * getStructElementType(unsigned N) const
bool isArrayTy() const
True if this is an instance of ArrayType.
Definition Type.h:279
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
Definition Type.cpp:309
Type * getArrayElementType() const
Definition Type.h:425
LLVM_ABI unsigned getStructNumElements() const
LLVM_ABI uint64_t getArrayNumElements() const
static LLVM_ABI Type * getVoidTy(LLVMContext &C)
Definition Type.cpp:282
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
Definition Type.cpp:307
bool isStructTy() const
True if this is an instance of StructType.
Definition Type.h:276
static LLVM_ABI IntegerType * getInt16Ty(LLVMContext &C)
Definition Type.cpp:308
static LLVM_ABI IntegerType * getIntNTy(LLVMContext &C, unsigned N)
Definition Type.cpp:313
static LLVM_ABI Type * getDoubleTy(LLVMContext &C)
Definition Type.cpp:287
static LLVM_ABI Type * getFloatTy(LLVMContext &C)
Definition Type.cpp:286
static LLVM_ABI Type * getHalfTy(LLVMContext &C)
Definition Type.cpp:284
Value * getOperand(unsigned i) const
Definition User.h:207
unsigned getNumOperands() const
Definition User.h:229
LLVM Value Representation.
Definition Value.h:75
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
Definition ilist_node.h:348
Changed
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ SPIR_KERNEL
Used for SPIR kernel functions.
@ BasicBlock
Various leaf nodes.
Definition ISDOpcodes.h:81
static StringRef extractAsmConstraintsFromMetadata(NamedMDNode *NMD, StringRef Constraints, StringRef Name)
bool isPipeOrAddressSpaceCastBuiltin(StringRef Name)
Returns true if Name is a pipe or address-space-cast OpenCL builtin.
static MDNode * findNamedMDOperand(NamedMDNode *NMD, StringRef Name)
FunctionType * getOriginalFunctionType(const Function &F)
static std::optional< StringRef > getMutatedCallsiteKey(const CallBase &CB)
static FunctionType * extractFunctionTypeFromMetadata(NamedMDNode *NMD, FunctionType *FTy, StringRef Name)
StringRef getOriginalAsmConstraints(const CallBase &CB)
@ SingleThread
Synchronized with respect to signal handlers executing in the same thread.
Definition LLVMContext.h:55
@ System
Synchronized with respect to all concurrently executing threads.
Definition LLVMContext.h:58
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > extract_or_null(Y &&MD)
Extract a Value from Metadata, allowing null.
Definition Metadata.h:683
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > dyn_extract(Y &&MD)
Extract a Value from Metadata, if any.
Definition Metadata.h:696
This is an optimization pass for GlobalISel generic memory operations.
std::string getStringImm(const MachineInstr &MI, unsigned StartIndex)
void addStringImm(StringRef Str, MCInst &Inst)
MachineBasicBlock::iterator getOpVariableMBBIt(MachineFunction &MF)
int64_t getIConstValSext(Register ConstReg, const MachineRegisterInfo *MRI)
bool isTypedPointerWrapper(const TargetExtType *ExtTy)
Definition SPIRVUtils.h:424
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
AtomicScope
Target-neutral memory synchronization scopes.
Definition AtomicScope.h:23
bool isTypeFoldingSupported(unsigned Opcode)
uint32_t getMemSemanticsWithStorageClass(const Triple &TT, uint32_t OrderSem, uint32_t StorageClassSem)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
MachineInstr * getDef(const MachineOperand &MO, const MachineRegisterInfo *MRI)
void addNumImm(const APInt &Imm, MachineInstrBuilder &MIB)
auto successors(const MachineBasicBlock *BB)
CallInst * buildIntrWithMD(Intrinsic::ID IntrID, ArrayRef< Type * > Types, Value *Arg, Value *Arg2, ArrayRef< Constant * > Imms, IRBuilder<> &B)
bool matchPeeledArrayPattern(const StructType *Ty, Type *&OriginalElementType, uint64_t &TotalSize)
Register createVirtualRegister(SPIRVTypeInst SpvType, SPIRVGlobalRegistry *GR, MachineRegisterInfo *MRI, const MachineFunction &MF)
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Definition STLExtras.h:2208
unsigned getArrayComponentCount(const MachineRegisterInfo *MRI, const MachineInstr *ResType)
bool sortBlocks(Function &F)
AllocaInst * createVariable(Function &F, Type *Type)
static bool getVacantFunctionName(Module &M, std::string &Name)
void buildOpDecorate(Register Reg, MachineIRBuilder &MIRBuilder, SPIRV::Decoration::Decoration Dec, ArrayRef< uint32_t > DecArgs, StringRef StrImm)
SPIRV::Scope::Scope getMemScope(const Triple &TT, LLVMContext &Ctx, SyncScope::ID Id)
uint64_t getIConstVal(Register ConstReg, const MachineRegisterInfo *MRI)
SmallVector< MachineInstr *, 4 > createContinuedInstructions(MachineIRBuilder &MIRBuilder, unsigned Opcode, unsigned MinWC, unsigned ContinuedOpcode, ArrayRef< Register > Args, Register ReturnRegister, Register TypeID)
SPIRV::MemorySemantics::MemorySemantics getMemSemanticsForStorageClass(SPIRV::StorageClass::StorageClass SC)
bool isNestedPointer(const Type *Ty)
Function * getOrCreateBackendServiceFunction(Module &M)
MetadataAsValue * buildMD(Value *Arg)
Definition SPIRVUtils.h:534
std::string getOclOrSpirvBuiltinDemangledName(StringRef Name)
void buildOpName(Register Target, StringRef Name, MachineIRBuilder &MIRBuilder)
static void finishBuildOpDecorate(MachineInstrBuilder &MIB, ArrayRef< uint32_t > DecArgs, StringRef StrImm)
SmallVector< unsigned, 1 > getSpirvLoopControlOperandsFromLoopMetadata(MDNode *LoopMD)
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
static uint32_t convertCharsToWord(StringRef Str, unsigned i)
void sort(IteratorTy Start, IteratorTy End)
Definition STLExtras.h:1636
std::string getSPIRVStringOperand(const InstType &MI, unsigned StartIndex)
Type * toTypedPointer(Type *Ty)
Definition SPIRVUtils.h:479
ConstantInt * getMDOperandAsConstInt(const MDNode *N, unsigned I)
DEMANGLE_ABI char * itaniumDemangle(std::string_view mangled_name, bool ParseParams=true)
Returns a non-NULL pointer to a NUL-terminated C style string that should be explicitly freed,...
constexpr uint32_t Hi_32(uint64_t Value)
Return the high 32 bits of a 64 bit value.
Definition MathExtras.h:151
bool isSpecialOpaqueType(const Type *Ty)
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
constexpr uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition Alignment.h:144
void setRegClassType(Register Reg, SPIRVTypeInst SpvType, SPIRVGlobalRegistry *GR, MachineRegisterInfo *MRI, const MachineFunction &MF, bool Force)
MachineBasicBlock::iterator getInsertPtValidEnd(MachineBasicBlock *MBB)
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
Definition MathExtras.h:190
static bool isNonMangledOCLBuiltin(StringRef Name)
constexpr uint32_t Lo_32(uint64_t Value)
Return the low 32 bits of a 64 bit value.
Definition MathExtras.h:156
MachineInstr * passCopy(MachineInstr *Def, const MachineRegisterInfo *MRI)
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
std::optional< SPIRV::LinkageType::LinkageType > getSpirvLinkageTypeFor(const SPIRVSubtarget &ST, const GlobalValue &GV)
bool isEntryPoint(const Function &F)
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
const std::set< unsigned > & getTypeFoldingSupportedOpcodes()
SPIRV::StorageClass::StorageClass addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI)
AtomicOrdering
Atomic ordering for LLVM's memory model.
constexpr T divideCeil(U Numerator, V Denominator)
Returns the integer ceil(Numerator / Denominator).
Definition MathExtras.h:395
static bool isEnqueueKernelBI(StringRef MangledName)
static bool isKernelQueryBI(StringRef MangledName)
void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder, const MDNode *GVarMD, const SPIRVSubtarget &ST)
std::string getStringValueFromReg(Register Reg, MachineRegisterInfo &MRI)
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
Definition InstrProf.h:145
int64_t foldImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
Type * parseBasicTypeName(StringRef &TypeName, LLVMContext &Ctx)
DWARFExpression::Operation Op
MachineInstr * getDefInstrMaybeConstant(Register &ConstReg, const MachineRegisterInfo *MRI)
Value * createExitVariable(BasicBlock *BB, const DenseMap< BasicBlock *, ConstantInt * > &TargetToValue)
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
bool hasBuiltinTypePrefix(StringRef Name)
Type * getMDOperandAsType(const MDNode *N, unsigned I)
void buildOpMemberDecorate(Register Reg, MachineIRBuilder &MIRBuilder, SPIRV::Decoration::Decoration Dec, uint32_t Member, ArrayRef< uint32_t > DecArgs, StringRef StrImm)
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1772
std::optional< StringRef > getAtomicScopeIRString(const Triple &T, AtomicScope S, bool IsSingleAddressSpace=false)
Returns the LLVM IR syncscope string that T uses to spell S.
Definition AtomicScope.h:34
auto predecessors(const MachineBasicBlock *BB)
static size_t getPaddedLen(StringRef Str)
bool isSpvIntrinsic(const MachineInstr &MI, Intrinsic::ID IntrinsicID)
MachineInstr * getVRegDef(MachineRegisterInfo &MRI, Register Reg)
Type * reconstitutePeeledArrayType(Type *Ty)
SPIRV::MemorySemantics::MemorySemantics getMemSemantics(AtomicOrdering Ord)
LLVM_ABI MDNode * findOptionMDForLoopID(MDNode *LoopID, StringRef Name)
Find and return the loop attribute node for the attribute Name in LoopID.
#define N