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
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
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 ArrayRef<uint32_t> DecArgs,
232 StringRef StrImm) {
233 if (!StrImm.empty())
234 addStringImm(StrImm, MIB);
235 for (const auto &DecArg : DecArgs)
236 MIB.addImm(DecArg);
237}
238
240 SPIRV::Decoration::Decoration Dec,
241 ArrayRef<uint32_t> DecArgs, StringRef StrImm) {
242 auto MIB = MIRBuilder.buildInstr(SPIRV::OpDecorate)
243 .addUse(Reg)
244 .addImm(static_cast<uint32_t>(Dec));
245 finishBuildOpDecorate(MIB, DecArgs, StrImm);
246}
247
249 SPIRV::Decoration::Decoration Dec,
250 ArrayRef<uint32_t> DecArgs, StringRef StrImm) {
251 MachineBasicBlock &MBB = *I.getParent();
252 auto MIB = BuildMI(MBB, I, I.getDebugLoc(), TII.get(SPIRV::OpDecorate))
253 .addUse(Reg)
254 .addImm(static_cast<uint32_t>(Dec));
255 finishBuildOpDecorate(MIB, DecArgs, StrImm);
256}
257
259 SPIRV::Decoration::Decoration Dec, uint32_t Member,
260 ArrayRef<uint32_t> DecArgs, StringRef StrImm) {
261 auto MIB = MIRBuilder.buildInstr(SPIRV::OpMemberDecorate)
262 .addUse(Reg)
263 .addImm(Member)
264 .addImm(static_cast<uint32_t>(Dec));
265 finishBuildOpDecorate(MIB, DecArgs, StrImm);
266}
267
269 const MDNode *GVarMD, const SPIRVSubtarget &ST) {
270 for (unsigned I = 0, E = GVarMD->getNumOperands(); I != E; ++I) {
271 auto *OpMD = dyn_cast<MDNode>(GVarMD->getOperand(I));
272 if (!OpMD)
273 report_fatal_error("Invalid decoration");
274 if (OpMD->getNumOperands() == 0)
275 report_fatal_error("Expect operand(s) of the decoration");
276 ConstantInt *DecorationId =
277 mdconst::dyn_extract<ConstantInt>(OpMD->getOperand(0));
278 if (!DecorationId)
279 report_fatal_error("Expect SPIR-V <Decoration> operand to be the first "
280 "element of the decoration");
281
282 // The goal of `spirv.Decorations` metadata is to provide a way to
283 // represent SPIR-V entities that do not map to LLVM in an obvious way.
284 // FP flags do have obvious matches between LLVM IR and SPIR-V.
285 // Additionally, we have no guarantee at this point that the flags passed
286 // through the decoration are not violated already in the optimizer passes.
287 // Therefore, we simply ignore FP flags, including NoContraction, and
288 // FPFastMathMode.
289 if (DecorationId->getZExtValue() ==
290 static_cast<uint32_t>(SPIRV::Decoration::NoContraction) ||
291 DecorationId->getZExtValue() ==
292 static_cast<uint32_t>(SPIRV::Decoration::FPFastMathMode)) {
293 continue; // Ignored.
294 }
295 uint32_t Dec = static_cast<uint32_t>(DecorationId->getZExtValue());
296 if (Dec == static_cast<uint32_t>(SPIRV::Decoration::UniformId) ||
297 Dec == static_cast<uint32_t>(SPIRV::Decoration::AlignmentId) ||
298 Dec == static_cast<uint32_t>(SPIRV::Decoration::MaxByteOffsetId)) {
299 ConstantInt *IdV =
300 OpMD->getNumOperands() == 2
301 ? mdconst::dyn_extract<ConstantInt>(OpMD->getOperand(1))
302 : nullptr;
303 if (!IdV || !isUInt<32>(IdV->getZExtValue()))
304 report_fatal_error("Expect a single integer <id> operand of the "
305 "decoration");
306 SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
307 SPIRVTypeInst SpvTypeInt32 =
308 GR->getOrCreateSPIRVIntegerType(32, MIRBuilder);
309 Register IdReg = GR->buildConstantInt(IdV->getZExtValue(), MIRBuilder,
310 SpvTypeInt32, /*EmitIR=*/false);
311 MIRBuilder.buildInstr(SPIRV::OpDecorateId)
312 .addUse(Reg)
313 .addImm(Dec)
314 .addUse(IdReg);
315 continue;
316 }
317 auto MIB = MIRBuilder.buildInstr(SPIRV::OpDecorate).addUse(Reg).addImm(Dec);
318 for (unsigned OpI = 1, OpE = OpMD->getNumOperands(); OpI != OpE; ++OpI) {
319 if (ConstantInt *OpV =
320 mdconst::dyn_extract<ConstantInt>(OpMD->getOperand(OpI)))
321 MIB.addImm(static_cast<uint32_t>(OpV->getZExtValue()));
322 else if (MDString *OpV = dyn_cast<MDString>(OpMD->getOperand(OpI)))
323 addStringImm(OpV->getString(), MIB);
324 else
325 report_fatal_error("Unexpected operand of the decoration");
326 }
327 }
328}
329
332 // Find the position to insert the OpVariable instruction.
333 // We will insert it after the last OpFunctionParameter, if any, or
334 // after OpFunction otherwise.
335 auto IsPreamble = [](const MachineInstr &MI) {
336 switch (MI.getOpcode()) {
337 case SPIRV::OpFunction:
338 case SPIRV::OpFunctionParameter:
339 case SPIRV::OpLabel:
340 case SPIRV::ASSIGN_TYPE:
341 return true;
342 default:
343 return false;
344 }
345 };
346 MachineBasicBlock::iterator VarPos = MBB.SkipPHIsAndLabels(MBB.begin());
347 while (VarPos != MBB.end() && VarPos->getOpcode() != SPIRV::OpFunction)
348 ++VarPos;
349 // Advance past the preamble.
350 while (VarPos != MBB.end() && IsPreamble(*VarPos))
351 ++VarPos;
352 return VarPos;
353}
354
357 if (I == MBB->begin())
358 return I;
359 --I;
360 while (I->isTerminator() || I->isDebugValue()) {
361 if (I == MBB->begin())
362 break;
363 --I;
364 }
365 return I;
366}
367
368SPIRV::StorageClass::StorageClass
369addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI) {
370 switch (AddrSpace) {
372 return SPIRV::StorageClass::Function;
374 return SPIRV::StorageClass::CrossWorkgroup;
376 return SPIRV::StorageClass::UniformConstant;
378 return SPIRV::StorageClass::Workgroup;
379 case SPIRVAS::Generic:
380 return SPIRV::StorageClass::Generic;
382 return STI.canUseExtension(SPIRV::Extension::SPV_INTEL_usm_storage_classes)
383 ? SPIRV::StorageClass::DeviceOnlyINTEL
384 : SPIRV::StorageClass::CrossWorkgroup;
386 return STI.canUseExtension(SPIRV::Extension::SPV_INTEL_usm_storage_classes)
387 ? SPIRV::StorageClass::HostOnlyINTEL
388 : SPIRV::StorageClass::CrossWorkgroup;
389 case SPIRVAS::Input:
390 return SPIRV::StorageClass::Input;
391 case SPIRVAS::Output:
392 return SPIRV::StorageClass::Output;
394 return SPIRV::StorageClass::CodeSectionINTEL;
395 case SPIRVAS::Private:
396 return SPIRV::StorageClass::Private;
398 return SPIRV::StorageClass::StorageBuffer;
399 case SPIRVAS::Uniform:
400 return SPIRV::StorageClass::Uniform;
402 return SPIRV::StorageClass::PushConstant;
403 default:
404 report_fatal_error("Unknown address space");
405 }
406}
407
408SPIRV::MemorySemantics::MemorySemantics
409getMemSemanticsForStorageClass(SPIRV::StorageClass::StorageClass SC) {
410 switch (SC) {
411 case SPIRV::StorageClass::StorageBuffer:
412 case SPIRV::StorageClass::Uniform:
413 return SPIRV::MemorySemantics::UniformMemory;
414 case SPIRV::StorageClass::Workgroup:
415 return SPIRV::MemorySemantics::WorkgroupMemory;
416 case SPIRV::StorageClass::CrossWorkgroup:
417 return SPIRV::MemorySemantics::CrossWorkgroupMemory;
418 case SPIRV::StorageClass::Generic:
419 return SPIRV::MemorySemantics::MemorySemantics(
420 SPIRV::MemorySemantics::WorkgroupMemory |
421 SPIRV::MemorySemantics::CrossWorkgroupMemory);
422 case SPIRV::StorageClass::AtomicCounter:
423 return SPIRV::MemorySemantics::AtomicCounterMemory;
424 case SPIRV::StorageClass::Image:
425 return SPIRV::MemorySemantics::ImageMemory;
426 default:
427 return SPIRV::MemorySemantics::None;
428 }
429}
430
431SPIRV::MemorySemantics::MemorySemantics getMemSemantics(AtomicOrdering Ord) {
432 switch (Ord) {
434 return SPIRV::MemorySemantics::Acquire;
436 return SPIRV::MemorySemantics::Release;
438 return SPIRV::MemorySemantics::AcquireRelease;
440 return SPIRV::MemorySemantics::SequentiallyConsistent;
444 return SPIRV::MemorySemantics::None;
445 }
446 llvm_unreachable(nullptr);
447}
448
450 uint32_t StorageClassSem) {
451 bool DropStorageClass =
452 TT.isVulkanOS() &&
453 OrderSem == static_cast<uint32_t>(SPIRV::MemorySemantics::None);
454 return OrderSem | (DropStorageClass ? 0 : StorageClassSem);
455}
456
457SPIRV::Scope::Scope getMemScope(const Triple &TT, LLVMContext &Ctx,
458 SyncScope::ID Id) {
459 // Named by
460 // https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#_scope_id.
461 // We don't need aliases for Invocation and CrossDevice, as we already have
462 // them covered by "singlethread" and "" strings respectively (see
463 // implementation of LLVMContext::LLVMContext()).
464 auto ScopeID = [&](AtomicScope Scope) {
465 return Ctx.getOrInsertSyncScopeID(*getAtomicScopeIRString(TT, Scope));
466 };
467 const llvm::SyncScope::ID SubGroup = ScopeID(AtomicScope::Wavefront);
468 const llvm::SyncScope::ID WorkGroup = ScopeID(AtomicScope::Workgroup);
470
472 return SPIRV::Scope::Invocation;
473 else if (Id == llvm::SyncScope::System)
474 return SPIRV::Scope::CrossDevice;
475 else if (Id == SubGroup)
476 return SPIRV::Scope::Subgroup;
477 else if (Id == WorkGroup)
478 return SPIRV::Scope::Workgroup;
479 else if (Id == Device)
480 return SPIRV::Scope::Device;
481 return SPIRV::Scope::CrossDevice;
482}
483
485 const MachineRegisterInfo *MRI) {
486 MachineInstr *MI = MRI->getVRegDef(ConstReg);
487 MachineInstr *ConstInstr =
488 MI->getOpcode() == SPIRV::G_TRUNC || MI->getOpcode() == SPIRV::G_ZEXT
489 ? MRI->getVRegDef(MI->getOperand(1).getReg())
490 : MI;
491 if (auto *GI = dyn_cast<GIntrinsic>(ConstInstr)) {
492 if (GI->is(Intrinsic::spv_track_constant)) {
493 ConstReg = ConstInstr->getOperand(2).getReg();
494 return MRI->getVRegDef(ConstReg);
495 }
496 } else if (ConstInstr->getOpcode() == SPIRV::ASSIGN_TYPE) {
497 ConstReg = ConstInstr->getOperand(1).getReg();
498 return MRI->getVRegDef(ConstReg);
499 } else if (ConstInstr->getOpcode() == TargetOpcode::G_CONSTANT ||
500 ConstInstr->getOpcode() == TargetOpcode::G_FCONSTANT) {
501 ConstReg = ConstInstr->getOperand(0).getReg();
502 return ConstInstr;
503 }
504 return MRI->getVRegDef(ConstReg);
505}
506
508 const MachineInstr *MI = getDefInstrMaybeConstant(ConstReg, MRI);
509 assert(MI && MI->getOpcode() == TargetOpcode::G_CONSTANT);
510 return MI->getOperand(1).getCImm()->getValue().getZExtValue();
511}
512
513bool isSpvIntrinsic(const MachineInstr &MI, Intrinsic::ID IntrinsicID) {
514 if (const auto *GI = dyn_cast<GIntrinsic>(&MI))
515 return GI->is(IntrinsicID);
516 return false;
517}
518
519Type *getMDOperandAsType(const MDNode *N, unsigned I) {
520 Type *ElementTy = cast<ValueAsMetadata>(N->getOperand(I))->getType();
521 return toTypedPointer(ElementTy);
522}
523
525 if (N->getNumOperands() <= I)
526 return nullptr;
527 if (auto *CMeta = dyn_cast<ConstantAsMetadata>(N->getOperand(I)))
528 return dyn_cast<ConstantInt>(CMeta->getValue());
529 return nullptr;
530}
531
532static bool isEnqueueKernelBI(StringRef MangledName) {
533 return MangledName == "__enqueue_kernel_basic" ||
534 MangledName == "__enqueue_kernel_basic_events" ||
535 MangledName == "__enqueue_kernel_varargs" ||
536 MangledName == "__enqueue_kernel_events_varargs";
537}
538
539static bool isKernelQueryBI(StringRef MangledName) {
540 return MangledName == "__get_kernel_work_group_size_impl" ||
541 MangledName == "__get_kernel_sub_group_count_for_ndrange_impl" ||
542 MangledName == "__get_kernel_max_sub_group_size_for_ndrange_impl" ||
543 MangledName == "__get_kernel_preferred_work_group_size_multiple_impl";
544}
545
547 if (!Name.starts_with("__"))
548 return false;
549
550 return isEnqueueKernelBI(Name) || isKernelQueryBI(Name) ||
552 Name == "__translate_sampler_initializer";
553}
554
556 bool IsNonMangledOCL = isNonMangledOCLBuiltin(Name);
557 bool IsNonMangledSPIRV = Name.starts_with("__spirv_");
558 bool IsNonMangledHLSL = Name.starts_with("__hlsl_");
559 bool IsMangled = Name.starts_with("_Z");
560
561 // Otherwise use simple demangling to return the function name.
562 if (IsNonMangledOCL || IsNonMangledSPIRV || IsNonMangledHLSL || !IsMangled)
563 return Name.str();
564
565 // Try to use the itanium demangler.
566 if (char *DemangledName = itaniumDemangle(Name.data())) {
567 std::string Result = DemangledName;
568 free(DemangledName);
569 return Result;
570 }
571
572 // Autocheck C++, maybe need to do explicit check of the source language.
573 // OpenCL C++ built-ins are declared in cl namespace.
574 // TODO: consider using 'St' abbriviation for cl namespace mangling.
575 // Similar to ::std:: in C++.
576 size_t Start, Len = 0;
577 size_t DemangledNameLenStart = 2;
578 if (Name.starts_with("_ZN")) {
579 // Skip CV and ref qualifiers.
580 size_t NameSpaceStart = Name.find_first_not_of("rVKRO", 3);
581 // All built-ins are in the ::cl:: namespace.
582 if (Name.substr(NameSpaceStart, 11) != "2cl7__spirv")
583 return std::string();
584 DemangledNameLenStart = NameSpaceStart + 11;
585 }
586 Start = Name.find_first_not_of("0123456789", DemangledNameLenStart);
587 bool Error = Name.substr(DemangledNameLenStart, Start - DemangledNameLenStart)
588 .getAsInteger(10, Len);
589 if (Error)
590 return std::string();
591 return Name.substr(Start, Len).str();
592}
593
595 if (Name.starts_with("opencl.") || Name.starts_with("ocl_") ||
596 Name.starts_with("spirv."))
597 return true;
598 return false;
599}
600
601bool isSpecialOpaqueType(const Type *Ty) {
602 if (const TargetExtType *ExtTy = dyn_cast<TargetExtType>(Ty))
603 return isTypedPointerWrapper(ExtTy)
604 ? false
605 : hasBuiltinTypePrefix(ExtTy->getName());
606
607 return false;
608}
609
610bool isEntryPoint(const Function &F) {
611 // OpenCL handling: any function with the SPIR_KERNEL
612 // calling convention will be a potential entry point.
613 if (F.getCallingConv() == CallingConv::SPIR_KERNEL)
614 return true;
615
616 // HLSL handling: special attribute are emitted from the
617 // front-end.
618 if (F.getFnAttribute("hlsl.shader").isValid())
619 return true;
620
621 return false;
622}
623
625 TypeName.consume_front("atomic_");
626 if (TypeName.consume_front("void"))
627 return Type::getVoidTy(Ctx);
628 else if (TypeName.consume_front("bool") || TypeName.consume_front("_Bool"))
629 return Type::getIntNTy(Ctx, 1);
630 else if (TypeName.consume_front("char") ||
631 TypeName.consume_front("signed char") ||
632 TypeName.consume_front("unsigned char") ||
633 TypeName.consume_front("uchar"))
634 return Type::getInt8Ty(Ctx);
635 else if (TypeName.consume_front("short") ||
636 TypeName.consume_front("signed short") ||
637 TypeName.consume_front("unsigned short") ||
638 TypeName.consume_front("ushort"))
639 return Type::getInt16Ty(Ctx);
640 else if (TypeName.consume_front("int") ||
641 TypeName.consume_front("signed int") ||
642 TypeName.consume_front("unsigned int") ||
643 TypeName.consume_front("uint"))
644 return Type::getInt32Ty(Ctx);
645 else if (TypeName.consume_front("long") ||
646 TypeName.consume_front("signed long") ||
647 TypeName.consume_front("unsigned long") ||
648 TypeName.consume_front("ulong"))
649 return Type::getInt64Ty(Ctx);
650 else if (TypeName.consume_front("half") ||
651 TypeName.consume_front("_Float16") ||
652 TypeName.consume_front("__fp16"))
653 return Type::getHalfTy(Ctx);
654 else if (TypeName.consume_front("float"))
655 return Type::getFloatTy(Ctx);
656 else if (TypeName.consume_front("double"))
657 return Type::getDoubleTy(Ctx);
658
659 // Unable to recognize SPIRV type name
660 return nullptr;
661}
662
663SmallPtrSet<BasicBlock *, 0>
664PartialOrderingVisitor::getReachableFrom(BasicBlock *Start) {
665 std::queue<BasicBlock *> ToVisit;
666 ToVisit.push(Start);
667
668 SmallPtrSet<BasicBlock *, 0> Output;
669 while (ToVisit.size() != 0) {
670 BasicBlock *BB = ToVisit.front();
671 ToVisit.pop();
672
673 if (Output.count(BB) != 0)
674 continue;
675 Output.insert(BB);
676
677 for (BasicBlock *Successor : successors(BB)) {
678 if (DT.dominates(Successor, BB))
679 continue;
680 ToVisit.push(Successor);
681 }
682 }
683
684 return Output;
685}
686
687bool PartialOrderingVisitor::CanBeVisited(BasicBlock *BB) const {
688 for (BasicBlock *P : predecessors(BB)) {
689 // Ignore back-edges.
690 if (DT.dominates(BB, P))
691 continue;
692
693 // One of the predecessor hasn't been visited. Not ready yet.
694 if (BlockToOrder.count(P) == 0)
695 return false;
696
697 // If the block is a loop exit, the loop must be finished before
698 // we can continue.
699 Loop *L = LI.getLoopFor(P);
700 if (L == nullptr || L->contains(BB))
701 continue;
702
703 // SPIR-V requires a single back-edge. And the backend first
704 // step transforms loops into the simplified format. If we have
705 // more than 1 back-edge, something is wrong.
706 assert(L->getNumBackEdges() <= 1);
707
708 // If the loop has no latch, loop's rank won't matter, so we can
709 // proceed.
710 BasicBlock *Latch = L->getLoopLatch();
711 assert(Latch);
712 if (Latch == nullptr)
713 continue;
714
715 // The latch is not ready yet, let's wait.
716 if (BlockToOrder.count(Latch) == 0)
717 return false;
718 }
719
720 return true;
721}
722
724 auto It = BlockToOrder.find(BB);
725 if (It != BlockToOrder.end())
726 return It->second.Rank;
727
728 size_t result = 0;
729 for (BasicBlock *P : predecessors(BB)) {
730 // Ignore back-edges.
731 if (DT.dominates(BB, P))
732 continue;
733
734 auto Iterator = BlockToOrder.end();
735 Loop *L = LI.getLoopFor(P);
736 BasicBlock *Latch = L ? L->getLoopLatch() : nullptr;
737
738 // If the predecessor is either outside a loop, or part of
739 // the same loop, simply take its rank + 1.
740 if (L == nullptr || L->contains(BB) || Latch == nullptr) {
741 Iterator = BlockToOrder.find(P);
742 } else {
743 // Otherwise, take the loop's rank (highest rank in the loop) as base.
744 // Since loops have a single latch, highest rank is easy to find.
745 // If the loop has no latch, then it doesn't matter.
746 Iterator = BlockToOrder.find(Latch);
747 }
748
749 assert(Iterator != BlockToOrder.end());
750 result = std::max(result, Iterator->second.Rank + 1);
751 }
752
753 return result;
754}
755
756size_t PartialOrderingVisitor::visit(BasicBlock *BB, size_t Unused) {
757 ToVisit.push(BB);
758 Queued.insert(BB);
759
760 size_t QueueIndex = 0;
761 while (ToVisit.size() != 0) {
762 BasicBlock *BB = ToVisit.front();
763 ToVisit.pop();
764
765 if (!CanBeVisited(BB)) {
766 ToVisit.push(BB);
767 if (QueueIndex >= ToVisit.size())
769 "No valid candidate in the queue. Is the graph reducible?");
770 QueueIndex++;
771 continue;
772 }
773
774 QueueIndex = 0;
775 size_t Rank = GetNodeRank(BB);
776 OrderInfo Info = {Rank, BlockToOrder.size()};
777 BlockToOrder.try_emplace(BB, Info);
778
779 for (BasicBlock *S : successors(BB)) {
780 if (Queued.count(S) != 0)
781 continue;
782 ToVisit.push(S);
783 Queued.insert(S);
784 }
785 }
786
787 return 0;
788}
789
791 DT.recalculate(F);
792 LI = LoopInfo(DT);
793
794 visit(&*F.begin(), 0);
795
796 Order.reserve(F.size());
797 for (auto &[BB, Info] : BlockToOrder)
798 Order.emplace_back(BB);
799
800 llvm::sort(Order, [&](const auto &LHS, const auto &RHS) {
801 return compare(LHS, RHS);
802 });
803}
804
806 const BasicBlock *RHS) const {
807 const OrderInfo &InfoLHS = BlockToOrder.at(const_cast<BasicBlock *>(LHS));
808 const OrderInfo &InfoRHS = BlockToOrder.at(const_cast<BasicBlock *>(RHS));
809 if (InfoLHS.Rank != InfoRHS.Rank)
810 return InfoLHS.Rank < InfoRHS.Rank;
811 return InfoLHS.TraversalIndex < InfoRHS.TraversalIndex;
812}
813
815 BasicBlock &Start, std::function<bool(BasicBlock *)> Op) {
816 SmallPtrSet<BasicBlock *, 0> Reachable = getReachableFrom(&Start);
817 assert(BlockToOrder.count(&Start) != 0);
818
819 // Skipping blocks with a rank inferior to |Start|'s rank.
820 auto It = Order.begin();
821 while (It != Order.end() && *It != &Start)
822 ++It;
823
824 // This is unexpected. Worst case |Start| is the last block,
825 // so It should point to the last block, not past-end.
826 assert(It != Order.end());
827
828 // By default, there is no rank limit. Setting it to the maximum value.
829 std::optional<size_t> EndRank = std::nullopt;
830 for (; It != Order.end(); ++It) {
831 if (EndRank.has_value() && BlockToOrder[*It].Rank > *EndRank)
832 break;
833
834 if (Reachable.count(*It) == 0) {
835 continue;
836 }
837
838 if (!Op(*It)) {
839 EndRank = BlockToOrder[*It].Rank;
840 }
841 }
842}
843
845 if (F.size() == 0)
846 return false;
847
848 bool Modified = false;
849 std::vector<BasicBlock *> Order;
850 Order.reserve(F.size());
851
853 llvm::append_range(Order, RPOT);
854
855 assert(&*F.begin() == Order[0]);
856 BasicBlock *LastBlock = &*F.begin();
857 for (BasicBlock *BB : Order) {
858 if (BB != LastBlock && &*LastBlock->getNextNode() != BB) {
859 Modified = true;
860 BB->moveAfter(LastBlock);
861 }
862 LastBlock = BB;
863 }
864
865 return Modified;
866}
867
869 const DataLayout &DL = F.getDataLayout();
870 return new AllocaInst(Type, DL.getAllocaAddrSpace(), nullptr, "reg",
871 F.begin()->getFirstInsertionPt());
872}
873
874Value *
876 const DenseMap<BasicBlock *, ConstantInt *> &TargetToValue) {
877 auto *T = BB->getTerminator();
878 if (isa<ReturnInst>(T))
879 return nullptr;
880 if (auto *BI = dyn_cast<UncondBrInst>(T))
881 return TargetToValue.lookup(BI->getSuccessor());
882
883 IRBuilder<> Builder(BB);
884 Builder.SetInsertPoint(T);
885
886 if (auto *BI = dyn_cast<CondBrInst>(T)) {
887 Value *LHS = TargetToValue.lookup(BI->getSuccessor(0));
888 Value *RHS = TargetToValue.lookup(BI->getSuccessor(1));
889
890 if (LHS == nullptr || RHS == nullptr)
891 return LHS == nullptr ? RHS : LHS;
892 return Builder.CreateSelect(BI->getCondition(), LHS, RHS);
893 }
894
895 if (auto *SI = dyn_cast<SwitchInst>(T)) {
896 Value *Condition = SI->getCondition();
897 // The default destination acts as the fallback value of the select chain.
898 Value *Result = TargetToValue.lookup(SI->getDefaultDest());
899 for (const auto &Case : SI->cases()) {
900 Value *CaseValue = TargetToValue.lookup(Case.getCaseSuccessor());
901 // Successors that are internal to the region have no exit value.
902 if (CaseValue == nullptr)
903 continue;
904 // The first known exit value becomes the base of the select chain.
905 if (Result == nullptr) {
906 Result = CaseValue;
907 continue;
908 }
909 Value *Cmp = Builder.CreateICmpEQ(Condition, Case.getCaseValue());
910 Result = Builder.CreateSelect(Cmp, CaseValue, Result);
911 }
912 return Result;
913 }
914
915 llvm_unreachable("Unhandled terminator type.");
916}
917
919 MachineInstr *MaybeDef = MRI.getVRegDef(Reg);
920 if (MaybeDef && MaybeDef->getOpcode() == SPIRV::ASSIGN_TYPE)
921 MaybeDef = MRI.getVRegDef(MaybeDef->getOperand(1).getReg());
922 return MaybeDef;
923}
924
925static bool getVacantFunctionName(Module &M, std::string &Name) {
926 // It's a bit of paranoia, but still we don't want to have even a chance that
927 // the loop will work for too long.
928 constexpr unsigned MaxIters = 1024;
929 for (unsigned I = 0; I < MaxIters; ++I) {
930 std::string OrdName = Name + Twine(I).str();
931 if (!M.getFunction(OrdName)) {
932 Name = std::move(OrdName);
933 return true;
934 }
935 }
936 return false;
937}
938
939// Assign SPIR-V type to the register. If the register has no valid assigned
940// class, set register LLT type and class according to the SPIR-V type.
943 const MachineFunction &MF, bool Force) {
944 GR->assignSPIRVTypeToVReg(SpvType, Reg, MF);
945 if (!MRI->getRegClassOrNull(Reg) || Force) {
946 MRI->setRegClass(Reg, GR->getRegClass(SpvType));
947 LLT RegType = GR->getRegType(SpvType);
948 if (Force || !MRI->getType(Reg).isValid())
949 MRI->setType(Reg, RegType);
950 }
951}
952
953// Create a SPIR-V type, assign SPIR-V type to the register. If the register has
954// no valid assigned class, set register LLT type and class according to the
955// SPIR-V type.
957 MachineIRBuilder &MIRBuilder,
958 SPIRV::AccessQualifier::AccessQualifier AccessQual,
959 bool EmitIR, bool Force) {
961 GR->getOrCreateSPIRVType(Ty, MIRBuilder, AccessQual, EmitIR),
962 GR, MIRBuilder.getMRI(), MIRBuilder.getMF(), Force);
963}
964
965// Create a virtual register and assign SPIR-V type to the register. Set
966// register LLT type and class according to the SPIR-V type.
969 const MachineFunction &MF) {
970 Register Reg = MRI->createVirtualRegister(GR->getRegClass(SpvType));
971 MRI->setType(Reg, GR->getRegType(SpvType));
972 GR->assignSPIRVTypeToVReg(SpvType, Reg, MF);
973 return Reg;
974}
975
976// Create a virtual register and assign SPIR-V type to the register. Set
977// register LLT type and class according to the SPIR-V type.
979 MachineIRBuilder &MIRBuilder) {
980 return createVirtualRegister(SpvType, GR, MIRBuilder.getMRI(),
981 MIRBuilder.getMF());
982}
983
984// Create a SPIR-V type, virtual register and assign SPIR-V type to the
985// register. Set register LLT type and class according to the SPIR-V type.
987 const Type *Ty, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIRBuilder,
988 SPIRV::AccessQualifier::AccessQualifier AccessQual, bool EmitIR) {
990 GR->getOrCreateSPIRVType(Ty, MIRBuilder, AccessQual, EmitIR), GR,
991 MIRBuilder);
992}
993
995 return SPVTy->getOpcode() == SPIRV::OpTypeVector ||
996 SPVTy->getOpcode() == SPIRV::OpTypeVectorIdEXT;
997}
998
1000 Value *Arg, Value *Arg2, ArrayRef<Constant *> Imms,
1001 IRBuilder<> &B) {
1003 Args.push_back(Arg2);
1004 Args.push_back(buildMD(Arg));
1005 llvm::append_range(Args, Imms);
1006 return B.CreateIntrinsicWithoutFolding(IntrID, {Types}, Args);
1007}
1008
1009// Return true if there is an opaque pointer type nested in the argument.
1010bool isNestedPointer(const Type *Ty) {
1011 if (Ty->isPtrOrPtrVectorTy())
1012 return true;
1013 if (const FunctionType *RefTy = dyn_cast<FunctionType>(Ty)) {
1014 if (isNestedPointer(RefTy->getReturnType()))
1015 return true;
1016 for (const Type *ArgTy : RefTy->params())
1017 if (isNestedPointer(ArgTy))
1018 return true;
1019 return false;
1020 }
1021 if (const ArrayType *RefTy = dyn_cast<ArrayType>(Ty))
1022 return isNestedPointer(RefTy->getElementType());
1023 return false;
1024}
1025
1026bool isSpvIntrinsic(const Value *Arg) {
1027 if (const auto *II = dyn_cast<IntrinsicInst>(Arg))
1028 if (Function *F = II->getCalledFunction())
1029 if (F->getName().starts_with("llvm.spv."))
1030 return true;
1031 return false;
1032}
1033
1034// Function to create continued instructions for SPV_INTEL_long_composites
1035// extension
1036SmallVector<MachineInstr *, 4>
1038 unsigned MinWC, unsigned ContinuedOpcode,
1039 ArrayRef<Register> Args, Register ReturnRegister,
1040 Register TypeID) {
1041
1042 SmallVector<MachineInstr *, 4> Instructions;
1043 constexpr unsigned MaxWordCount = UINT16_MAX;
1044 const size_t NumElements = Args.size();
1045 size_t MaxNumElements = MaxWordCount - MinWC;
1046 size_t SPIRVStructNumElements = NumElements;
1047
1048 if (NumElements > MaxNumElements) {
1049 // Do adjustments for continued instructions which always had only one
1050 // minumum word count.
1051 SPIRVStructNumElements = MaxNumElements;
1052 MaxNumElements = MaxWordCount - 1;
1053 }
1054
1055 auto MIB =
1056 MIRBuilder.buildInstr(Opcode).addDef(ReturnRegister).addUse(TypeID);
1057
1058 for (size_t I = 0; I < SPIRVStructNumElements; ++I)
1059 MIB.addUse(Args[I]);
1060
1061 Instructions.push_back(MIB.getInstr());
1062
1063 for (size_t I = SPIRVStructNumElements; I < NumElements;
1064 I += MaxNumElements) {
1065 auto MIB = MIRBuilder.buildInstr(ContinuedOpcode);
1066 for (size_t J = I; J < std::min(I + MaxNumElements, NumElements); ++J)
1067 MIB.addUse(Args[J]);
1068 Instructions.push_back(MIB.getInstr());
1069 }
1070 return Instructions;
1071}
1072
1073SmallVector<unsigned, 1>
1075 unsigned LC = SPIRV::LoopControl::None;
1076 // Currently used only to store PartialCount value. Later when other
1077 // LoopControls are added - this map should be sorted before making
1078 // them loop_merge operands to satisfy 3.23. Loop Control requirements.
1079 std::vector<std::pair<unsigned, unsigned>> MaskToValueMap;
1080 if (findOptionMDForLoopID(LoopMD, "llvm.loop.unroll.disable")) {
1081 LC |= SPIRV::LoopControl::DontUnroll;
1082 } else {
1083 if (findOptionMDForLoopID(LoopMD, "llvm.loop.unroll.enable") ||
1084 findOptionMDForLoopID(LoopMD, "llvm.loop.unroll.full")) {
1085 LC |= SPIRV::LoopControl::Unroll;
1086 }
1087 if (MDNode *CountMD =
1088 findOptionMDForLoopID(LoopMD, "llvm.loop.unroll.count")) {
1089 if (auto *CI =
1090 mdconst::extract_or_null<ConstantInt>(CountMD->getOperand(1))) {
1091 unsigned Count = CI->getZExtValue();
1092 if (Count != 1) {
1093 LC |= SPIRV::LoopControl::PartialCount;
1094 MaskToValueMap.emplace_back(
1095 std::make_pair(SPIRV::LoopControl::PartialCount, Count));
1096 }
1097 }
1098 }
1099 }
1100 SmallVector<unsigned, 1> Result = {LC};
1101 for (auto &[Mask, Val] : MaskToValueMap)
1102 Result.push_back(Val);
1103 return Result;
1104}
1105
1109
1110const std::set<unsigned> &getTypeFoldingSupportedOpcodes() {
1111 // clang-format off
1112 static const std::set<unsigned> TypeFoldingSupportingOpcs = {
1113 TargetOpcode::G_ADD,
1114 TargetOpcode::G_FADD,
1115 TargetOpcode::G_STRICT_FADD,
1116 TargetOpcode::G_SUB,
1117 TargetOpcode::G_FSUB,
1118 TargetOpcode::G_STRICT_FSUB,
1119 TargetOpcode::G_MUL,
1120 TargetOpcode::G_FMUL,
1121 TargetOpcode::G_STRICT_FMUL,
1122 TargetOpcode::G_SDIV,
1123 TargetOpcode::G_UDIV,
1124 TargetOpcode::G_FDIV,
1125 TargetOpcode::G_STRICT_FDIV,
1126 TargetOpcode::G_SREM,
1127 TargetOpcode::G_UREM,
1128 TargetOpcode::G_FREM,
1129 TargetOpcode::G_STRICT_FREM,
1130 TargetOpcode::G_FNEG,
1131 TargetOpcode::G_CONSTANT,
1132 TargetOpcode::G_FCONSTANT,
1133 TargetOpcode::G_AND,
1134 TargetOpcode::G_OR,
1135 TargetOpcode::G_XOR,
1136 TargetOpcode::G_SHL,
1137 TargetOpcode::G_ASHR,
1138 TargetOpcode::G_LSHR,
1139 TargetOpcode::G_SELECT,
1140 TargetOpcode::G_EXTRACT_VECTOR_ELT,
1141 };
1142 // clang-format on
1143 return TypeFoldingSupportingOpcs;
1144}
1145
1146bool isTypeFoldingSupported(unsigned Opcode) {
1147 return getTypeFoldingSupportedOpcodes().count(Opcode) > 0;
1148}
1149
1150// Traversing [g]MIR accounting for pseudo-instructions.
1152 return (Def->getOpcode() == SPIRV::ASSIGN_TYPE ||
1153 Def->getOpcode() == TargetOpcode::COPY)
1154 ? MRI->getVRegDef(Def->getOperand(1).getReg())
1155 : Def;
1156}
1157
1159 if (MachineInstr *Def = MRI->getVRegDef(MO.getReg()))
1160 return passCopy(Def, MRI);
1161 return nullptr;
1162}
1163
1165 if (MachineInstr *Def = getDef(MO, MRI)) {
1166 if (Def->getOpcode() == TargetOpcode::G_CONSTANT ||
1167 Def->getOpcode() == SPIRV::OpConstantI)
1168 return Def;
1169 }
1170 return nullptr;
1171}
1172
1173int64_t foldImm(const MachineOperand &MO, const MachineRegisterInfo *MRI) {
1174 if (MachineInstr *Def = getImm(MO, MRI)) {
1175 if (Def->getOpcode() == SPIRV::OpConstantI)
1176 return Def->getOperand(2).getImm();
1177 if (Def->getOpcode() == TargetOpcode::G_CONSTANT)
1178 return Def->getOperand(1).getCImm()->getZExtValue();
1179 }
1180 llvm_unreachable("Unexpected integer constant pattern");
1181}
1182
1184 const MachineInstr *ResType) {
1185 return foldImm(ResType->getOperand(2), MRI);
1186}
1187
1188bool matchPeeledArrayPattern(const StructType *Ty, Type *&OriginalElementType,
1189 uint64_t &TotalSize) {
1190 // An array of N padded structs is represented as {[N-1 x <{T, pad}>], T}.
1191 if (Ty->getStructNumElements() != 2)
1192 return false;
1193
1194 Type *FirstElement = Ty->getStructElementType(0);
1195 Type *SecondElement = Ty->getStructElementType(1);
1196
1197 if (!FirstElement->isArrayTy())
1198 return false;
1199
1200 Type *ArrayElementType = FirstElement->getArrayElementType();
1201 if (!ArrayElementType->isStructTy() ||
1202 ArrayElementType->getStructNumElements() != 2)
1203 return false;
1204
1205 Type *T_in_struct = ArrayElementType->getStructElementType(0);
1206 if (T_in_struct != SecondElement)
1207 return false;
1208
1209 auto *Padding_in_struct =
1210 dyn_cast<TargetExtType>(ArrayElementType->getStructElementType(1));
1211 if (!Padding_in_struct || Padding_in_struct->getName() != "spirv.Padding")
1212 return false;
1213
1214 const uint64_t ArraySize = FirstElement->getArrayNumElements();
1215 TotalSize = ArraySize + 1;
1216 OriginalElementType = ArrayElementType;
1217 return true;
1218}
1219
1221 if (!Ty->isStructTy())
1222 return Ty;
1223
1224 auto *STy = cast<StructType>(Ty);
1225 Type *OriginalElementType = nullptr;
1226 uint64_t TotalSize = 0;
1227 if (matchPeeledArrayPattern(STy, OriginalElementType, TotalSize)) {
1228 Type *ResultTy = ArrayType::get(
1229 reconstitutePeeledArrayType(OriginalElementType), TotalSize);
1230 return ResultTy;
1231 }
1232
1233 SmallVector<Type *, 4> NewElementTypes;
1234 bool Changed = false;
1235 for (Type *ElementTy : STy->elements()) {
1236 Type *NewElementTy = reconstitutePeeledArrayType(ElementTy);
1237 if (NewElementTy != ElementTy)
1238 Changed = true;
1239 NewElementTypes.push_back(NewElementTy);
1240 }
1241
1242 if (!Changed)
1243 return Ty;
1244
1245 Type *ResultTy;
1246 if (STy->isLiteral()) {
1247 ResultTy =
1248 StructType::get(STy->getContext(), NewElementTypes, STy->isPacked());
1249 } else {
1250 ResultTy = StructType::create(STy->getContext(), NewElementTypes,
1251 STy->getName(), STy->isPacked());
1252 }
1253 return ResultTy;
1254}
1255
1256std::optional<SPIRV::LinkageType::LinkageType>
1258 if (GV.hasLocalLinkage())
1259 return std::nullopt;
1260
1261 if (GV.isDeclarationForLinker()) {
1262 if (const auto *GVar = dyn_cast<GlobalVariable>(&GV)) {
1263 auto SC = addressSpaceToStorageClass(GVar->getAddressSpace(), ST);
1264 // Interface variables must not get Import linkage.
1265 if (SC == SPIRV::StorageClass::Input ||
1266 SC == SPIRV::StorageClass::Output ||
1267 SC == SPIRV::StorageClass::PushConstant)
1268 return std::nullopt;
1269 // Shaders have no linker, so module-internal storage
1270 // (e.g. HLSL groupshared) can't be imported
1271 if (ST.isShader() && (SC == SPIRV::StorageClass::Workgroup ||
1272 SC == SPIRV::StorageClass::Private))
1273 return std::nullopt;
1274 }
1275 return SPIRV::LinkageType::Import;
1276 }
1277
1278 if (GV.hasHiddenVisibility())
1279 return std::nullopt;
1280
1281 if (GV.hasLinkOnceODRLinkage() &&
1282 ST.canUseExtension(SPIRV::Extension::SPV_KHR_linkonce_odr))
1283 return SPIRV::LinkageType::LinkOnceODR;
1284
1285 if (GV.hasWeakLinkage() &&
1286 ST.canUseExtension(SPIRV::Extension::SPV_AMD_weak_linkage))
1287 return SPIRV::LinkageType::WeakAMD;
1288
1289 return SPIRV::LinkageType::Export;
1290}
1291
1293 std::string ServiceFunName = SPIRV_BACKEND_SERVICE_FUN_NAME;
1294 if (!getVacantFunctionName(M, ServiceFunName))
1296 "cannot allocate a name for the internal service function");
1297 if (Function *SF = M.getFunction(ServiceFunName)) {
1298 if (SF->getInstructionCount() > 0)
1300 "Unexpected combination of global variables and function pointers");
1301 return SF;
1302 }
1304 FunctionType::get(Type::getVoidTy(M.getContext()), {}, false),
1305 GlobalValue::PrivateLinkage, ServiceFunName, M);
1307 return SF;
1308}
1309
1310} // namespace llvm
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
uint64_t uint64_t
uint64_t Imm
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)
MachineRegisterInfo & MRI
#define SPIRV_BACKEND_SERVICE_FUN_NAME
Definition SPIRVUtils.h:558
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:463
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
unsigned size() const
Definition DenseMap.h:717
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:793
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:641
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
Definition Function.h:169
const Function & getFunction() const
Definition Function.h:167
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:2949
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.
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:76
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:1081
const MDOperand & getOperand(unsigned I) const
Definition Metadata.h:1437
unsigned getNumOperands() const
Return number of MDNode operands.
Definition Metadata.h:1443
A single uniqued string.
Definition Metadata.h:733
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,...
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:68
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:1797
op_iterator op_end()
Definition Metadata.h:1886
iterator_range< op_iterator > operands()
Definition Metadata.h:1893
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:467
static LLVM_ABI StructType * create(LLVMContext &Context, StringRef Name)
This creates an identified struct.
Definition Type.cpp:662
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:300
LLVM_ABI Type * getStructElementType(unsigned N) const
bool isArrayTy() const
True if this is an instance of ArrayType.
Definition Type.h:274
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
Definition Type.cpp:299
Type * getArrayElementType() const
Definition Type.h:420
LLVM_ABI unsigned getStructNumElements() const
LLVM_ABI uint64_t getArrayNumElements() const
static LLVM_ABI Type * getVoidTy(LLVMContext &C)
Definition Type.cpp:272
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
Definition Type.cpp:297
bool isStructTy() const
True if this is an instance of StructType.
Definition Type.h:271
static LLVM_ABI IntegerType * getInt16Ty(LLVMContext &C)
Definition Type.cpp:298
static LLVM_ABI IntegerType * getIntNTy(LLVMContext &C, unsigned N)
Definition Type.cpp:303
static LLVM_ABI Type * getDoubleTy(LLVMContext &C)
Definition Type.cpp:277
static LLVM_ABI Type * getFloatTy(LLVMContext &C)
Definition Type.cpp:276
static LLVM_ABI Type * getHalfTy(LLVMContext &C)
Definition Type.cpp:274
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
#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:83
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:63
@ System
Synchronized with respect to all concurrently executing threads.
Definition LLVMContext.h:66
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:694
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > dyn_extract(Y &&MD)
Extract a Value from Metadata, if any.
Definition Metadata.h:707
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)
bool isTypedPointerWrapper(const TargetExtType *ExtTy)
Definition SPIRVUtils.h:414
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:2224
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 isVectorType(SPIRVTypeInst SPVTy)
bool isNestedPointer(const Type *Ty)
Function * getOrCreateBackendServiceFunction(Module &M)
MetadataAsValue * buildMD(Value *Arg)
Definition SPIRVUtils.h:546
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:1652
std::string getSPIRVStringOperand(const InstType &MI, unsigned StartIndex)
Type * toTypedPointer(Type *Ty)
Definition SPIRVUtils.h:469
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:149
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:389
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:1788
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