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 // TODO: add support for switch cases.
895 llvm_unreachable("Unhandled terminator type.");
896}
897
899 MachineInstr *MaybeDef = MRI.getVRegDef(Reg);
900 if (MaybeDef && MaybeDef->getOpcode() == SPIRV::ASSIGN_TYPE)
901 MaybeDef = MRI.getVRegDef(MaybeDef->getOperand(1).getReg());
902 return MaybeDef;
903}
904
905static bool getVacantFunctionName(Module &M, std::string &Name) {
906 // It's a bit of paranoia, but still we don't want to have even a chance that
907 // the loop will work for too long.
908 constexpr unsigned MaxIters = 1024;
909 for (unsigned I = 0; I < MaxIters; ++I) {
910 std::string OrdName = Name + Twine(I).str();
911 if (!M.getFunction(OrdName)) {
912 Name = std::move(OrdName);
913 return true;
914 }
915 }
916 return false;
917}
918
919// Assign SPIR-V type to the register. If the register has no valid assigned
920// class, set register LLT type and class according to the SPIR-V type.
923 const MachineFunction &MF, bool Force) {
924 GR->assignSPIRVTypeToVReg(SpvType, Reg, MF);
925 if (!MRI->getRegClassOrNull(Reg) || Force) {
926 MRI->setRegClass(Reg, GR->getRegClass(SpvType));
927 LLT RegType = GR->getRegType(SpvType);
928 if (Force || !MRI->getType(Reg).isValid())
929 MRI->setType(Reg, RegType);
930 }
931}
932
933// Create a SPIR-V type, assign SPIR-V type to the register. If the register has
934// no valid assigned class, set register LLT type and class according to the
935// SPIR-V type.
937 MachineIRBuilder &MIRBuilder,
938 SPIRV::AccessQualifier::AccessQualifier AccessQual,
939 bool EmitIR, bool Force) {
941 GR->getOrCreateSPIRVType(Ty, MIRBuilder, AccessQual, EmitIR),
942 GR, MIRBuilder.getMRI(), MIRBuilder.getMF(), Force);
943}
944
945// Create a virtual register and assign SPIR-V type to the register. Set
946// register LLT type and class according to the SPIR-V type.
949 const MachineFunction &MF) {
950 Register Reg = MRI->createVirtualRegister(GR->getRegClass(SpvType));
951 MRI->setType(Reg, GR->getRegType(SpvType));
952 GR->assignSPIRVTypeToVReg(SpvType, Reg, MF);
953 return Reg;
954}
955
956// Create a virtual register and assign SPIR-V type to the register. Set
957// register LLT type and class according to the SPIR-V type.
959 MachineIRBuilder &MIRBuilder) {
960 return createVirtualRegister(SpvType, GR, MIRBuilder.getMRI(),
961 MIRBuilder.getMF());
962}
963
964// Create a SPIR-V type, virtual register and assign SPIR-V type to the
965// register. Set register LLT type and class according to the SPIR-V type.
967 const Type *Ty, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIRBuilder,
968 SPIRV::AccessQualifier::AccessQualifier AccessQual, bool EmitIR) {
970 GR->getOrCreateSPIRVType(Ty, MIRBuilder, AccessQual, EmitIR), GR,
971 MIRBuilder);
972}
973
975 Value *Arg, Value *Arg2, ArrayRef<Constant *> Imms,
976 IRBuilder<> &B) {
978 Args.push_back(Arg2);
979 Args.push_back(buildMD(Arg));
980 llvm::append_range(Args, Imms);
981 return B.CreateIntrinsicWithoutFolding(IntrID, {Types}, Args);
982}
983
984// Return true if there is an opaque pointer type nested in the argument.
985bool isNestedPointer(const Type *Ty) {
986 if (Ty->isPtrOrPtrVectorTy())
987 return true;
988 if (const FunctionType *RefTy = dyn_cast<FunctionType>(Ty)) {
989 if (isNestedPointer(RefTy->getReturnType()))
990 return true;
991 for (const Type *ArgTy : RefTy->params())
992 if (isNestedPointer(ArgTy))
993 return true;
994 return false;
995 }
996 if (const ArrayType *RefTy = dyn_cast<ArrayType>(Ty))
997 return isNestedPointer(RefTy->getElementType());
998 return false;
999}
1000
1001bool isSpvIntrinsic(const Value *Arg) {
1002 if (const auto *II = dyn_cast<IntrinsicInst>(Arg))
1003 if (Function *F = II->getCalledFunction())
1004 if (F->getName().starts_with("llvm.spv."))
1005 return true;
1006 return false;
1007}
1008
1009// Function to create continued instructions for SPV_INTEL_long_composites
1010// extension
1011SmallVector<MachineInstr *, 4>
1013 unsigned MinWC, unsigned ContinuedOpcode,
1014 ArrayRef<Register> Args, Register ReturnRegister,
1015 Register TypeID) {
1016
1017 SmallVector<MachineInstr *, 4> Instructions;
1018 constexpr unsigned MaxWordCount = UINT16_MAX;
1019 const size_t NumElements = Args.size();
1020 size_t MaxNumElements = MaxWordCount - MinWC;
1021 size_t SPIRVStructNumElements = NumElements;
1022
1023 if (NumElements > MaxNumElements) {
1024 // Do adjustments for continued instructions which always had only one
1025 // minumum word count.
1026 SPIRVStructNumElements = MaxNumElements;
1027 MaxNumElements = MaxWordCount - 1;
1028 }
1029
1030 auto MIB =
1031 MIRBuilder.buildInstr(Opcode).addDef(ReturnRegister).addUse(TypeID);
1032
1033 for (size_t I = 0; I < SPIRVStructNumElements; ++I)
1034 MIB.addUse(Args[I]);
1035
1036 Instructions.push_back(MIB.getInstr());
1037
1038 for (size_t I = SPIRVStructNumElements; I < NumElements;
1039 I += MaxNumElements) {
1040 auto MIB = MIRBuilder.buildInstr(ContinuedOpcode);
1041 for (size_t J = I; J < std::min(I + MaxNumElements, NumElements); ++J)
1042 MIB.addUse(Args[J]);
1043 Instructions.push_back(MIB.getInstr());
1044 }
1045 return Instructions;
1046}
1047
1048SmallVector<unsigned, 1>
1050 unsigned LC = SPIRV::LoopControl::None;
1051 // Currently used only to store PartialCount value. Later when other
1052 // LoopControls are added - this map should be sorted before making
1053 // them loop_merge operands to satisfy 3.23. Loop Control requirements.
1054 std::vector<std::pair<unsigned, unsigned>> MaskToValueMap;
1055 if (findOptionMDForLoopID(LoopMD, "llvm.loop.unroll.disable")) {
1056 LC |= SPIRV::LoopControl::DontUnroll;
1057 } else {
1058 if (findOptionMDForLoopID(LoopMD, "llvm.loop.unroll.enable") ||
1059 findOptionMDForLoopID(LoopMD, "llvm.loop.unroll.full")) {
1060 LC |= SPIRV::LoopControl::Unroll;
1061 }
1062 if (MDNode *CountMD =
1063 findOptionMDForLoopID(LoopMD, "llvm.loop.unroll.count")) {
1064 if (auto *CI =
1065 mdconst::extract_or_null<ConstantInt>(CountMD->getOperand(1))) {
1066 unsigned Count = CI->getZExtValue();
1067 if (Count != 1) {
1068 LC |= SPIRV::LoopControl::PartialCount;
1069 MaskToValueMap.emplace_back(
1070 std::make_pair(SPIRV::LoopControl::PartialCount, Count));
1071 }
1072 }
1073 }
1074 }
1075 SmallVector<unsigned, 1> Result = {LC};
1076 for (auto &[Mask, Val] : MaskToValueMap)
1077 Result.push_back(Val);
1078 return Result;
1079}
1080
1084
1085const std::set<unsigned> &getTypeFoldingSupportedOpcodes() {
1086 // clang-format off
1087 static const std::set<unsigned> TypeFoldingSupportingOpcs = {
1088 TargetOpcode::G_ADD,
1089 TargetOpcode::G_FADD,
1090 TargetOpcode::G_STRICT_FADD,
1091 TargetOpcode::G_SUB,
1092 TargetOpcode::G_FSUB,
1093 TargetOpcode::G_STRICT_FSUB,
1094 TargetOpcode::G_MUL,
1095 TargetOpcode::G_FMUL,
1096 TargetOpcode::G_STRICT_FMUL,
1097 TargetOpcode::G_SDIV,
1098 TargetOpcode::G_UDIV,
1099 TargetOpcode::G_FDIV,
1100 TargetOpcode::G_STRICT_FDIV,
1101 TargetOpcode::G_SREM,
1102 TargetOpcode::G_UREM,
1103 TargetOpcode::G_FREM,
1104 TargetOpcode::G_STRICT_FREM,
1105 TargetOpcode::G_FNEG,
1106 TargetOpcode::G_CONSTANT,
1107 TargetOpcode::G_FCONSTANT,
1108 TargetOpcode::G_AND,
1109 TargetOpcode::G_OR,
1110 TargetOpcode::G_XOR,
1111 TargetOpcode::G_SHL,
1112 TargetOpcode::G_ASHR,
1113 TargetOpcode::G_LSHR,
1114 TargetOpcode::G_SELECT,
1115 TargetOpcode::G_EXTRACT_VECTOR_ELT,
1116 };
1117 // clang-format on
1118 return TypeFoldingSupportingOpcs;
1119}
1120
1121bool isTypeFoldingSupported(unsigned Opcode) {
1122 return getTypeFoldingSupportedOpcodes().count(Opcode) > 0;
1123}
1124
1125// Traversing [g]MIR accounting for pseudo-instructions.
1127 return (Def->getOpcode() == SPIRV::ASSIGN_TYPE ||
1128 Def->getOpcode() == TargetOpcode::COPY)
1129 ? MRI->getVRegDef(Def->getOperand(1).getReg())
1130 : Def;
1131}
1132
1134 if (MachineInstr *Def = MRI->getVRegDef(MO.getReg()))
1135 return passCopy(Def, MRI);
1136 return nullptr;
1137}
1138
1140 if (MachineInstr *Def = getDef(MO, MRI)) {
1141 if (Def->getOpcode() == TargetOpcode::G_CONSTANT ||
1142 Def->getOpcode() == SPIRV::OpConstantI)
1143 return Def;
1144 }
1145 return nullptr;
1146}
1147
1148int64_t foldImm(const MachineOperand &MO, const MachineRegisterInfo *MRI) {
1149 if (MachineInstr *Def = getImm(MO, MRI)) {
1150 if (Def->getOpcode() == SPIRV::OpConstantI)
1151 return Def->getOperand(2).getImm();
1152 if (Def->getOpcode() == TargetOpcode::G_CONSTANT)
1153 return Def->getOperand(1).getCImm()->getZExtValue();
1154 }
1155 llvm_unreachable("Unexpected integer constant pattern");
1156}
1157
1159 const MachineInstr *ResType) {
1160 return foldImm(ResType->getOperand(2), MRI);
1161}
1162
1163bool matchPeeledArrayPattern(const StructType *Ty, Type *&OriginalElementType,
1164 uint64_t &TotalSize) {
1165 // An array of N padded structs is represented as {[N-1 x <{T, pad}>], T}.
1166 if (Ty->getStructNumElements() != 2)
1167 return false;
1168
1169 Type *FirstElement = Ty->getStructElementType(0);
1170 Type *SecondElement = Ty->getStructElementType(1);
1171
1172 if (!FirstElement->isArrayTy())
1173 return false;
1174
1175 Type *ArrayElementType = FirstElement->getArrayElementType();
1176 if (!ArrayElementType->isStructTy() ||
1177 ArrayElementType->getStructNumElements() != 2)
1178 return false;
1179
1180 Type *T_in_struct = ArrayElementType->getStructElementType(0);
1181 if (T_in_struct != SecondElement)
1182 return false;
1183
1184 auto *Padding_in_struct =
1185 dyn_cast<TargetExtType>(ArrayElementType->getStructElementType(1));
1186 if (!Padding_in_struct || Padding_in_struct->getName() != "spirv.Padding")
1187 return false;
1188
1189 const uint64_t ArraySize = FirstElement->getArrayNumElements();
1190 TotalSize = ArraySize + 1;
1191 OriginalElementType = ArrayElementType;
1192 return true;
1193}
1194
1196 if (!Ty->isStructTy())
1197 return Ty;
1198
1199 auto *STy = cast<StructType>(Ty);
1200 Type *OriginalElementType = nullptr;
1201 uint64_t TotalSize = 0;
1202 if (matchPeeledArrayPattern(STy, OriginalElementType, TotalSize)) {
1203 Type *ResultTy = ArrayType::get(
1204 reconstitutePeeledArrayType(OriginalElementType), TotalSize);
1205 return ResultTy;
1206 }
1207
1208 SmallVector<Type *, 4> NewElementTypes;
1209 bool Changed = false;
1210 for (Type *ElementTy : STy->elements()) {
1211 Type *NewElementTy = reconstitutePeeledArrayType(ElementTy);
1212 if (NewElementTy != ElementTy)
1213 Changed = true;
1214 NewElementTypes.push_back(NewElementTy);
1215 }
1216
1217 if (!Changed)
1218 return Ty;
1219
1220 Type *ResultTy;
1221 if (STy->isLiteral())
1222 ResultTy =
1223 StructType::get(STy->getContext(), NewElementTypes, STy->isPacked());
1224 else {
1225 auto *NewTy = StructType::create(STy->getContext(), STy->getName());
1226 NewTy->setBody(NewElementTypes, STy->isPacked());
1227 ResultTy = NewTy;
1228 }
1229 return ResultTy;
1230}
1231
1232std::optional<SPIRV::LinkageType::LinkageType>
1234 if (GV.hasLocalLinkage())
1235 return std::nullopt;
1236
1237 if (GV.isDeclarationForLinker()) {
1238 // Interface variables must not get Import linkage.
1239 if (const auto *GVar = dyn_cast<GlobalVariable>(&GV)) {
1240 auto SC = addressSpaceToStorageClass(GVar->getAddressSpace(), ST);
1241 if (SC == SPIRV::StorageClass::Input ||
1242 SC == SPIRV::StorageClass::Output ||
1243 SC == SPIRV::StorageClass::PushConstant)
1244 return std::nullopt;
1245 }
1246 return SPIRV::LinkageType::Import;
1247 }
1248
1249 if (GV.hasHiddenVisibility())
1250 return std::nullopt;
1251
1252 if (GV.hasLinkOnceODRLinkage() &&
1253 ST.canUseExtension(SPIRV::Extension::SPV_KHR_linkonce_odr))
1254 return SPIRV::LinkageType::LinkOnceODR;
1255
1256 if (GV.hasWeakLinkage() &&
1257 ST.canUseExtension(SPIRV::Extension::SPV_AMD_weak_linkage))
1258 return SPIRV::LinkageType::WeakAMD;
1259
1260 return SPIRV::LinkageType::Export;
1261}
1262
1264 std::string ServiceFunName = SPIRV_BACKEND_SERVICE_FUN_NAME;
1265 if (!getVacantFunctionName(M, ServiceFunName))
1267 "cannot allocate a name for the internal service function");
1268 if (Function *SF = M.getFunction(ServiceFunName)) {
1269 if (SF->getInstructionCount() > 0)
1271 "Unexpected combination of global variables and function pointers");
1272 return SF;
1273 }
1275 FunctionType::get(Type::getVoidTy(M.getContext()), {}, false),
1276 GlobalValue::PrivateLinkage, ServiceFunName, M);
1278 return SF;
1279}
1280
1281} // 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:537
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:633
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:1753
op_iterator op_end()
Definition Metadata.h:1842
iterator_range< op_iterator > operands()
Definition Metadata.h:1849
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:415
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:525
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:470
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:150
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:189
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:155
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:394
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