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