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