LLVM 24.0.0git
AMDGPUTargetParser.cpp
Go to the documentation of this file.
1//===-- AMDGPUTargetParser - Parser for AMDGPU features ---------*- 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 implements a target parser to recognise AMDGPU hardware features.
10//
11//===----------------------------------------------------------------------===//
12
16#include "llvm/ADT/Twine.h"
19#include <algorithm>
20#include <array>
21#include <cassert>
22
23using namespace llvm;
24using namespace AMDGPU;
25
26namespace {
27constexpr unsigned NumAMDGPUSubArches =
29
30// A legacy GPU name (e.g. "tahiti") mapped to the GPUKind it aliases.
31struct GPUNameAlias {
32 StringTable::Offset AltName;
33 GPUKind Kind;
34};
35
36// Per-GPU data for the AMDGCN GPUKinds, from the generated table below.
37struct GPUInfo {
38 StringTable::Offset Name;
39 Triple::SubArchType SubArch;
40 AMDGPUFeatureBitset Features;
41 IsaVersion Version;
42 StringTable::Offset FamilyName;
43 uint8_t MaxWavesPerEU;
44 uint32_t MaxHWAddressableLocalMemorySize;
45 uint8_t LDSBankCount;
46 uint8_t BufferResourceNumRecordsWidth;
47};
48
49// Per-GPU data for the R600 GPUKinds.
50struct R600Info {
51 StringTable::Offset Name;
52 R600FeatureBitset Features;
53};
54
55#define GET_AMDGPU_NAME_TABLE
56#define GET_AMDGPU_GPU_TABLE
57#define GET_AMDGPU_GPU_ALIAS_TABLE
58#define GET_AMDGPU_MAJOR_SUBARCH
59#define GET_AMDGPU_SUBARCH_NAME
60#define GET_AMDGPU_FEATURE_NAME_TABLE
61#include "llvm/TargetParser/AMDGPUTargetParserDef.inc"
62
63#define GET_R600_NAME_TABLE
64#define GET_R600_GPU_TABLE
65#define GET_R600_GPU_ALIAS_TABLE
66#define GET_R600_FEATURE_NAME_TABLE
67#include "llvm/TargetParser/R600TargetParserDef.inc"
68
69// The string tables holding GPU-name-derived strings as offsets. R600 and
70// AMDGPU come from separate generated headers, each with its own pool.
71constexpr StringTable AMDGPUNameStrTab = AMDGPUNameTable;
72constexpr StringTable R600NameStrTab = R600NameTable;
73
74// Look up the GPUInfo row for an AMDGCN GPUKind, or nullptr for GK_NONE / a
75// non-AMDGCN (R600) kind.
76const GPUInfo *getAMDGPUInfo(GPUKind AK) {
77 if (AK < AMDGPUFirstGPUKind)
78 return nullptr;
79 unsigned Idx = AK - AMDGPUFirstGPUKind;
80 if (Idx >= std::size(AMDGPUGPUTable))
81 return nullptr;
82 return &AMDGPUGPUTable[Idx];
83}
84
85// Look up the R600Info row for an R600 GPUKind, or nullptr for a non-R600 kind.
86const R600Info *getR600Info(GPUKind AK) {
87 if (AK < R600FirstGPUKind)
88 return nullptr;
89 unsigned Idx = AK - R600FirstGPUKind;
90 if (Idx >= std::size(R600GPUTable))
91 return nullptr;
92 return &R600GPUTable[Idx];
93}
94
95// Scan a name -> GPUKind table (canonical names, then aliases) for \p CPU.
96template <typename InfoT, size_t N, size_t M>
97GPUKind parseArchImpl(StringRef CPU, const InfoT (&Table)[N], GPUKind FirstKind,
98 const StringTable &StrTab,
99 const GPUNameAlias (&Aliases)[M]) {
100 for (unsigned I = 0; I != N; ++I) {
101 if (CPU == StrTab[Table[I].Name])
102 return static_cast<GPUKind>(FirstKind + I);
103 }
104
105 for (const GPUNameAlias &A : Aliases) {
106 if (CPU == StrTab[A.AltName])
107 return A.Kind;
108 }
109
110 return GK_NONE;
111}
112
113// Reverse map: SubArch -> GPUKind, indexed by (SubArch - FirstAMDGPUSubArch).
114// Subarches with no GPU (incl. the NoSubArch pseudo targets) map to GK_NONE.
115constexpr std::array<GPUKind, NumAMDGPUSubArches> AMDGPUSubArchToGPUKind = [] {
116 std::array<GPUKind, NumAMDGPUSubArches> Map{};
117
118 for (unsigned I = 0; I < std::size(AMDGPUGPUTable); ++I) {
119 Triple::SubArchType SubArch = AMDGPUGPUTable[I].SubArch;
120 if (SubArch != Triple::NoSubArch) {
122 static_cast<GPUKind>(AMDGPUFirstGPUKind + I);
123 }
124 }
125 return Map;
126}();
127
128/// SubArch -> major-family, indexed by (SubArch - FirstAMDGPUSubArch).
129constexpr std::array<Triple::SubArchType, NumAMDGPUSubArches>
130 AMDGPUMajorFamilies = [] {
131 std::array<Triple::SubArchType, NumAMDGPUSubArches> Map{};
132
133 for (unsigned I = 0; I < NumAMDGPUSubArches; ++I) {
134 Map[I] =
136 }
137
138 for (const AMDGPUMajorSubArchEntry &Entry : AMDGPUMajorSubArch)
139 Map[Entry.SubArch - Triple::FirstAMDGPUSubArch] = Entry.Major;
140 return Map;
141 }();
142
143// SubArch -> name-offset, indexed by (SubArch - FirstAMDGPUSubArch). Unmapped
144// subarches keep offset 0 (the empty string).
145constexpr std::array<StringTable::Offset, NumAMDGPUSubArches>
146 AMDGPUSubArchNameOffsets = [] {
147 std::array<StringTable::Offset, NumAMDGPUSubArches> Map{};
148 for (const AMDGPUSubArchNameEntry &Entry : AMDGPUSubArchNames)
149 Map[Entry.SubArch - Triple::FirstAMDGPUSubArch] = Entry.NameOffset;
150 return Map;
151 }();
152
153// SubArch -> triple-name-offset (e.g. "amdgpu9.00"), like
154// AMDGPUSubArchNameOffsets.
155constexpr std::array<StringTable::Offset, NumAMDGPUSubArches>
156 AMDGPUSubArchTripleNameOffsets = [] {
157 std::array<StringTable::Offset, NumAMDGPUSubArches> Map{};
158 for (const AMDGPUSubArchNameEntry &Entry : AMDGPUSubArchNames)
159 Map[Entry.SubArch - Triple::FirstAMDGPUSubArch] =
160 Entry.TripleNameOffset;
161 return Map;
162 }();
163} // namespace
164
166 const GPUInfo *Info = getAMDGPUInfo(AK);
167 return Info ? AMDGPUNameStrTab[Info->FamilyName] : "";
168}
169
171 const GPUInfo *Info = getAMDGPUInfo(AK);
172 return Info ? Info->SubArch : Triple::SubArchType::NoSubArch;
173}
174
178
181 if (SubArch < Triple::FirstAMDGPUSubArch ||
183 return GK_NONE;
184 return AMDGPUSubArchToGPUKind[SubArch - Triple::FirstAMDGPUSubArch];
185}
186
192
194 if (A == B || A == Triple::NoSubArch || B == Triple::NoSubArch)
195 return true;
196
199
200 // One side is the major-family subarch covering the other's family.
201 if (A == MajorA)
202 return MajorA == MajorB;
203 if (B == MajorB)
204 return MajorA == MajorB;
205
206 return false;
207}
208
210 // An unrecognized GPU is never valid.
211 if (AK == GK_NONE)
212 return false;
213 // A legacy triple without a subarch accepts any known GPU.
214 if (SubArch == Triple::NoSubArch)
215 return true;
216
217 // Reject the dummy "generic" targets
218 Triple::SubArchType GPUSubArch = getSubArch(AK);
219 if (GPUSubArch == Triple::NoSubArch)
220 return false;
221
222 return isSubArchCompatible(GPUSubArch, SubArch);
223}
224
228
230 const GPUInfo *Info = getAMDGPUInfo(AK);
231 return Info && Info->SubArch == Triple::NoSubArch;
232}
233
237
239 // Tolerate subarch mismatch if one entry is none. This is a hack for bitcode
240 // libraries.
241 // There's a missing enum entry for an unknown subarch. Make sure the
242 // subarch is really empty.
243 if (A.getSubArch() == Triple::NoSubArch)
244 return A.getArchName().size() == 6;
245
246 if (B.getSubArch() == Triple::NoSubArch)
247 return B.getArchName().size() == 6;
248
249 return isSubArchCompatible(A.getSubArch(), B.getSubArch());
250}
251
252std::string AMDGPU::mergeSubArch(const Triple &A, const Triple &B) {
253 if (A.getSubArch() == Triple::NoSubArch)
254 return B.str();
255 if (B.getSubArch() == Triple::NoSubArch)
256 return A.str();
257
258 Triple::SubArchType MajorA = AMDGPU::getMajorSubArch(A.getSubArch());
259 Triple::SubArchType MajorB = AMDGPU::getMajorSubArch(B.getSubArch());
260
261 // With a compatible major arch, return the specific subarch.
262 if (A.getSubArch() == MajorA) {
263 if (MajorA == MajorB)
264 return B.str();
265 }
266
267 if (B.getSubArch() == MajorB) {
268 if (MajorA == MajorB)
269 return A.str();
270 }
271
272 // Invalid case.
273 return B.str();
274}
275
277 const GPUInfo *Info = getAMDGPUInfo(AK);
278 return Info ? AMDGPUNameStrTab[Info->Name] : "";
279}
280
282 if (SubArch < Triple::FirstAMDGPUSubArch ||
284 return "";
285 return AMDGPUNameStrTab[AMDGPUSubArchNameOffsets[SubArch -
287}
288
290 if (SubArch == Triple::NoSubArch)
291 return AMDGPUNameStrTab[AMDGPUNoSubArchNameOffset];
292
294 SubArch <= Triple::LastAMDGPUSubArch &&
295 "expected an AMDGPU subarch or NoSubArch");
296 return AMDGPUNameStrTab
297 [AMDGPUSubArchTripleNameOffsets[SubArch - Triple::FirstAMDGPUSubArch]];
298}
299
301 const R600Info *Info = getR600Info(AK);
302 return Info ? R600NameStrTab[Info->Name] : "";
303}
304
306 return parseArchImpl(CPU, AMDGPUGPUTable, AMDGPUFirstGPUKind,
307 AMDGPUNameStrTab, AMDGPUGPUAliases);
308}
309
311 return parseArchImpl(CPU, R600GPUTable, R600FirstGPUKind, R600NameStrTab,
312 R600GPUAliases);
313}
314
316 static constexpr AMDGPUFeatureBitset Empty{};
317 const GPUInfo *Info = getAMDGPUInfo(AK);
318 return Info ? Info->Features : Empty;
319}
320
322 static constexpr R600FeatureBitset Empty{};
323 const R600Info *Info = getR600Info(AK);
324 return Info ? Info->Features : Empty;
325}
326
329 for (unsigned I = 0; I != NUM_FEATURES; ++I) {
330 if (Features.test(I))
331 Names.push_back(AMDGPUNameStrTab[AMDGPUFeatureNames[I]]);
332 }
333}
334
336 Triple::SubArchType SubArch) {
337 // XXX: Should this only report unique canonical names?
338 // An alias shares its GPU's GPUKind, so it is filtered alongside it.
339 for (unsigned I = 0; I != std::size(AMDGPUGPUTable); ++I) {
340 GPUKind Kind = static_cast<GPUKind>(AMDGPUFirstGPUKind + I);
341 if (AMDGPUGPUTable[I].SubArch != Triple::NoSubArch &&
342 isCPUValidForSubArch(SubArch, Kind))
343 Values.push_back(AMDGPUNameStrTab[AMDGPUGPUTable[I].Name]);
344 }
345
346 for (const GPUNameAlias &A : AMDGPUGPUAliases) {
347 if (isCPUValidForSubArch(SubArch, A.Kind))
348 Values.push_back(AMDGPUNameStrTab[A.AltName]);
349 }
350}
351
353 for (const R600Info &Info : R600GPUTable)
354 Values.push_back(R600NameStrTab[Info.Name]);
355 for (const GPUNameAlias &A : R600GPUAliases)
356 Values.push_back(R600NameStrTab[A.AltName]);
357}
358
360 const GPUInfo *Info = getAMDGPUInfo(parseArchAMDGCN(GPU));
361 return Info ? Info->Version : IsaVersion{0, 0, 0};
362}
363
365 const GPUInfo *Info = getAMDGPUInfo(getGPUKindFromSubArch(SubArch));
366 return Info ? Info->Version : IsaVersion{0, 0, 0};
367}
368
371 if (Version.Major >= 8)
372 return 800;
373 return 512;
374}
375
378 if (Version.Major >= 8)
379 return 800;
380 return 512;
381}
382
384 if (getFeatureBitset(AK).test(FEAT_SGPR_INIT_BUG))
386
388 if (Version.Major >= 10)
389 return 106;
390 if (Version.Major >= 8)
391 return 102;
392 return 104;
393}
394
396 if (getFeatureBitset(getGPUKindFromSubArch(SubArch)).test(FEAT_SGPR_INIT_BUG))
398
400 if (Version.Major >= 10)
401 return 106;
402 if (Version.Major >= 8)
403 return 102;
404 return 104;
405}
406
409 if (Version.Major >= 10)
410 return getAddressableNumSGPRs(AK);
411 if (Version.Major >= 8)
412 return 16;
413 return 8;
414}
415
418 if (Version.Major >= 10)
419 return getAddressableNumSGPRs(SubArch);
420 if (Version.Major >= 8)
421 return 16;
422 return 8;
423}
424
425unsigned AMDGPU::getVGPRAllocGranule(GPUKind AK, bool IsWave32) {
426 const AMDGPUFeatureBitset &Features = getFeatureBitset(AK);
427 if (Features.test(FEAT_GFX90A_INSTS))
428 return 8;
429 if (Features.test(FEAT_1536_PHYSICAL_VGPRS))
430 return IsWave32 ? 24 : 12;
431 if (Features.test(FEAT_GFX10_3_INSTS))
432 return IsWave32 ? 16 : 8;
433 return IsWave32 ? 8 : 4;
434}
435
437 bool IsWave32) {
438 return getVGPRAllocGranule(getGPUKindFromSubArch(SubArch), IsWave32);
439}
440
441unsigned AMDGPU::getTotalNumVGPRs(GPUKind AK, bool IsWave32) {
442 const AMDGPUFeatureBitset &Features = getFeatureBitset(AK);
443 if (Features.test(FEAT_GFX90A_INSTS))
444 return 512;
445 if (!Features.test(FEAT_GFX10_INSTS))
446 return 256;
447 if (Features.test(FEAT_1536_PHYSICAL_VGPRS))
448 return IsWave32 ? 1536 : 768;
449 return IsWave32 ? 1024 : 512;
450}
451
452unsigned AMDGPU::getTotalNumVGPRs(Triple::SubArchType SubArch, bool IsWave32) {
453 return getTotalNumVGPRs(getGPUKindFromSubArch(SubArch), IsWave32);
454}
455
456unsigned AMDGPU::getAddressableNumVGPRs(GPUKind AK, bool IsWave32) {
457 const AMDGPUFeatureBitset &Features = getFeatureBitset(AK);
458 // The unified register file makes the AGPRs addressable as VGPRs.
459 if (Features.test(FEAT_GFX90A_INSTS))
460 return 512;
461
462 // VGPR operand fields are 8 bits; VGPR MSBs add 2 more per operand.
463 constexpr unsigned OperandBits = 8;
464 constexpr unsigned MSBBits = 2;
465 unsigned Bits = OperandBits;
466 if (Features.test(FEAT_VGPR_MSBS))
467 Bits += MSBBits;
468 return std::min(1u << Bits, getTotalNumVGPRs(AK, IsWave32));
469}
470
472 bool IsWave32) {
473 return getAddressableNumVGPRs(getGPUKindFromSubArch(SubArch), IsWave32);
474}
475
477 const GPUInfo *Info = getAMDGPUInfo(AK);
478 return Info ? Info->MaxHWAddressableLocalMemorySize : 32768;
479}
480
481unsigned
485
486unsigned AMDGPU::getLocalMemorySize(GPUKind AK, bool FullSIMDMode) {
487 // gfx6 and gfx10/11/12 address half of the physical block.
489 if (getFeatureBitset(AK).test(FEAT_HALF_ADDRESSABLE_PHYSICAL_LOCAL_MEMORY))
490 Size *= 2;
491
492 // In half-SIMD mode the work-group reaches only half of the block.
493 if (!FullSIMDMode)
494 Size /= 2;
495
496 return Size;
497}
498
500 bool FullSIMDMode) {
501 return getLocalMemorySize(getGPUKindFromSubArch(SubArch), FullSIMDMode);
502}
503
504unsigned AMDGPU::getAddressableLocalMemorySize(GPUKind AK, bool FullSIMDMode) {
505 return std::min(getMaxHWAddressableLocalMemorySize(AK),
506 getLocalMemorySize(AK, FullSIMDMode));
507}
508
510 bool FullSIMDMode) {
512 FullSIMDMode);
513}
514
516 const GPUInfo *Info = getAMDGPUInfo(AK);
517 return Info ? Info->LDSBankCount : 32;
518}
519
523
525 const GPUInfo *Info = getAMDGPUInfo(AK);
526 if (!Info || Info->BufferResourceNumRecordsWidth == 0)
527 return std::nullopt;
528 return Info->BufferResourceNumRecordsWidth;
529}
530
531std::optional<unsigned>
535
537 const AMDGPUFeatureBitset &Features = getFeatureBitset(AK);
538 if (Features.none())
539 return 256;
540 assert((Features.test(FEAT_LDS_ALLOC_GRANULARITY_256) ||
541 Features.test(FEAT_LDS_ALLOC_GRANULARITY_512) ||
542 Features.test(FEAT_LDS_ALLOC_GRANULARITY_1024) ||
543 Features.test(FEAT_LDS_ALLOC_GRANULARITY_1280) ||
544 Features.test(FEAT_LDS_ALLOC_GRANULARITY_2048)) &&
545 "missing LDS allocation granularity feature");
546 if (Features.test(FEAT_LDS_ALLOC_GRANULARITY_256))
547 return 256;
548 if (Features.test(FEAT_LDS_ALLOC_GRANULARITY_512))
549 return 512;
550 if (Features.test(FEAT_LDS_ALLOC_GRANULARITY_1024))
551 return 1024;
552 if (Features.test(FEAT_LDS_ALLOC_GRANULARITY_1280))
553 return 1280;
554 if (Features.test(FEAT_LDS_ALLOC_GRANULARITY_2048))
555 return 2048;
556
557 return 256;
558}
559
563
565 const AMDGPUFeatureBitset &Features = getFeatureBitset(AK);
566 if (Features.test(FEAT_LDS_ENCODING_GRANULARITY_256))
567 return 256;
568 if (Features.test(FEAT_LDS_ENCODING_GRANULARITY_512))
569 return 512;
570 if (Features.test(FEAT_LDS_ENCODING_GRANULARITY_1024))
571 return 1024;
572 if (Features.test(FEAT_LDS_ENCODING_GRANULARITY_1280))
573 return 1280;
574 if (Features.test(FEAT_LDS_ENCODING_GRANULARITY_2048))
575 return 2048;
576
577 return 0;
578}
579
583
585 const GPUInfo *Info = getAMDGPUInfo(AK);
586 return Info ? Info->MaxWavesPerEU : 10;
587}
588
592
594 assert(T.isAMDGPU());
595 auto ProcKind = T.isAMDGCN() ? parseArchAMDGCN(Arch) : parseArchR600(Arch);
596 if (ProcKind == GK_NONE)
597 return StringRef();
598
599 return T.isAMDGCN() ? getArchNameAMDGCN(ProcKind) : getArchNameR600(ProcKind);
600}
601
602// Capability features clang queries via the feature bitset but must not
603// serialize into the target-feature string.
604//
605// FIXME: This is hacky, we shouldn't have mismatches between the bitset and
606// feature string map.
608 FEAT_FAST_FMAF,
609 FEAT_FAST_DENORMAL_F32,
610 FEAT_SUPPORTS_WAVE32,
611 FEAT_SUPPORTS_WGP,
612 FEAT_XNACK_SUPPORT,
613 FEAT_SRAMECC_SUPPORT,
614 FEAT_XNACK_ON_OFF_MODES,
615 FEAT_SRAMECC_ON_OFF_MODES,
616 FEAT_APERTURE_REGS,
617 FEAT_GET_DOORBELL_ID,
618 FEAT_AGPR_ALLOC,
619 FEAT_1536_PHYSICAL_VGPRS,
620 FEAT_HALF_ADDRESSABLE_PHYSICAL_LOCAL_MEMORY,
621 FEAT_VGPR_MSBS,
622 FEAT_LDS_ALLOC_GRANULARITY_256,
623 FEAT_LDS_ALLOC_GRANULARITY_512,
624 FEAT_LDS_ALLOC_GRANULARITY_1024,
625 FEAT_LDS_ALLOC_GRANULARITY_1280,
626 FEAT_LDS_ALLOC_GRANULARITY_2048,
627 FEAT_LDS_ENCODING_GRANULARITY_256,
628 FEAT_LDS_ENCODING_GRANULARITY_512,
629 FEAT_LDS_ENCODING_GRANULARITY_1024,
630 FEAT_LDS_ENCODING_GRANULARITY_1280,
631 FEAT_LDS_ENCODING_GRANULARITY_2048};
632
633// Add a GPU's features (minus the frontend-only ones) to \p Features. With \p
634// Overwrite false, existing entries are kept so user -mattr overrides win.
635static void addGPUFeatures(const GPUInfo &Info, bool Overwrite,
636 StringMap<bool> &Features) {
638 getFeatureNames(Info.Features & ~FrontendOnlyFeatures, Names);
639 for (StringRef Name : Names) {
640 if (Overwrite)
641 Features[Name] = true;
642 else
643 Features.insert({Name, true});
644 }
645}
646
647/// Add a GPU's default features to \p Features (preserving user overrides) and
648/// validate any requested wavesize.
649static std::pair<FeatureError, StringRef>
651 StringMap<bool> &Features) {
652 // With no explicit GPU, the triple's subarch identifies the target.
653 GPUKind Kind = GPU.empty() && T.getSubArch() != Triple::NoSubArch
654 ? getGPUKindFromSubArch(T.getSubArch())
655 : parseArchAMDGCN(GPU);
656 const GPUInfo *Info = getAMDGPUInfo(Kind);
657
658 // A bare subarch triple (no -target-cpu) still pins down the target, so it is
659 // not a null GPU. The target's native wavesize (if single-mode) is in the
660 // feature bitset; a dual-mode GPU has neither wave bit set.
661 const bool IsNullGPU = T.getSubArch() == Triple::NoSubArch && GPU.empty();
662 const bool TargetHasWave32 =
663 Info && Info->Features.test(FEAT_WAVEFRONTSIZE32);
664 const bool TargetHasWave64 =
665 Info && Info->Features.test(FEAT_WAVEFRONTSIZE64);
666
667 auto Wave32Itr = Features.find("wavefrontsize32");
668 auto Wave64Itr = Features.find("wavefrontsize64");
669 const bool EnableWave32 =
670 Wave32Itr != Features.end() && Wave32Itr->getValue();
671 const bool EnableWave64 =
672 Wave64Itr != Features.end() && Wave64Itr->getValue();
673 const bool DisableWave32 =
674 Wave32Itr != Features.end() && !Wave32Itr->getValue();
675 const bool DisableWave64 =
676 Wave64Itr != Features.end() && !Wave64Itr->getValue();
677
678 if (EnableWave32 && EnableWave64)
680 "'+wavefrontsize32' and '+wavefrontsize64' are mutually exclusive"};
681 if (DisableWave32 && DisableWave64)
683 "'-wavefrontsize32' and '-wavefrontsize64' are mutually exclusive"};
684
685 if (!IsNullGPU) {
686 if (TargetHasWave64) {
687 if (EnableWave32)
688 return {AMDGPU::UNSUPPORTED_TARGET_FEATURE, "+wavefrontsize32"};
689 if (DisableWave64)
690 return {AMDGPU::UNSUPPORTED_TARGET_FEATURE, "-wavefrontsize64"};
691 }
692
693 if (TargetHasWave32) {
694 if (EnableWave64)
695 return {AMDGPU::UNSUPPORTED_TARGET_FEATURE, "+wavefrontsize64"};
696 if (DisableWave32)
697 return {AMDGPU::UNSUPPORTED_TARGET_FEATURE, "-wavefrontsize32"};
698 }
699 }
700
701 // Don't assume any wavesize with an unknown subtarget.
702 // Default to wave32 if target supports both.
703 if (!IsNullGPU && !EnableWave32 && !EnableWave64 && !TargetHasWave32 &&
704 !TargetHasWave64)
705 Features.insert({"wavefrontsize32", true});
706
707 // Merge the target defaults, keeping any user -mattr overrides.
708 if (Info)
709 addGPUFeatures(*Info, /*Overwrite=*/false, Features);
710
711 return {NO_ERROR, StringRef()};
712}
713
714/// Fills Features map with default values for given target GPU.
715/// \p Features contains overriding target features and this function returns
716/// default target features with entries overridden by \p Features.
717std::pair<FeatureError, StringRef>
719 StringMap<bool> &Features) {
720 // XXX - What does the member GPU mean if device name string passed here?
721 if (T.isSPIRV() && T.getOS() == Triple::OSType::AMDHSA) {
722 // AMDGCN SPIRV must support the union of all AMDGCN features.
725 for (StringRef G : GPUs)
726 if (const GPUInfo *Info = getAMDGPUInfo(parseArchAMDGCN(G)))
727 addGPUFeatures(*Info, /*Overwrite=*/true, Features);
728 Features["wavefrontsize32"] = true;
729 Features["wavefrontsize64"] = true;
730 } else if (T.isAMDGCN()) {
731 return fillAMDGCNFeatureMap(GPU, T, Features);
732 } else {
733 if (GPU.empty())
734 GPU = "r600";
735
736 switch (llvm::AMDGPU::parseArchR600(GPU)) {
737 case GK_CAYMAN:
738 case GK_CYPRESS:
739 case GK_RV770:
740 case GK_RV670:
741 // TODO: Add fp64 when implemented.
742 break;
743 case GK_TURKS:
744 case GK_CAICOS:
745 case GK_BARTS:
746 case GK_SUMO:
747 case GK_REDWOOD:
748 case GK_JUNIPER:
749 case GK_CEDAR:
750 case GK_RV730:
751 case GK_RV710:
752 case GK_RS880:
753 case GK_R630:
754 case GK_R600:
755 break;
756 default:
757 llvm_unreachable("Unhandled GPU!");
758 }
759 }
760 return {NO_ERROR, StringRef()};
761}
762
763TargetID::TargetID(GPUKind Arch, const Triple &TT, TargetIDSetting XnackSetting,
764 TargetIDSetting SramEccSetting)
765 : Arch(Arch),
766 TargetTripleString(TT.normalize(Triple::CanonicalForm::FOUR_IDENT)),
767 XnackSetting(XnackSetting), SramEccSetting(SramEccSetting),
768 IsAMDHSA(TT.getOS() == Triple::AMDHSA) {}
769
770// Parse a feature modifier sign ("+"/"-"). Returns "Unsupported" if \p Sign is
771// neither (i.e. the modifier is malformed).
773 if (Sign == "+")
774 return TargetIDSetting::On;
775 if (Sign == "-")
776 return TargetIDSetting::Off;
777
778 return TargetIDSetting::Unsupported;
779}
780
781// Derive the architecture from the processor name in \p TargetIDStr. "generic"
782// and the empty processor name act as a wildcard.
783static GPUKind getGPUKindFromTargetID(const Triple &TT, StringRef TargetIDStr) {
784 StringRef CPUName = TargetIDStr.split(':').first;
785 return (CPUName.empty() || CPUName == "generic")
786 ? getGPUKindFromSubArch(TT.getSubArch())
787 : parseArchAMDGCN(CPUName);
788}
789
790// Compute the default xnack/sramecc settings for processor \p Arch, before any
791// explicit feature modifiers are applied.
795 const AMDGPUFeatureBitset &Features = getFeatureBitset(Arch);
796 // Features with on/off modes default to Any; supported without on/off modes
797 // is hardwired On; unsupported is Unsupported.
798 if (!Features.test(FEAT_XNACK_SUPPORT))
799 XnackSetting = TargetIDSetting::Unsupported;
800 else if (Features.test(FEAT_XNACK_ON_OFF_MODES))
801 XnackSetting = TargetIDSetting::Any;
802 else
803 XnackSetting = TargetIDSetting::On;
804 if (!Features.test(FEAT_SRAMECC_SUPPORT))
805 SramEccSetting = TargetIDSetting::Unsupported;
806 else if (Features.test(FEAT_SRAMECC_ON_OFF_MODES))
807 SramEccSetting = TargetIDSetting::Any;
808 else
809 SramEccSetting = TargetIDSetting::On;
810}
811
812// Compute the xnack/sramecc settings for processor \p Arch from the
813// processor+features string \p TargetIDStr
814// (e.g. "gfx90a:xnack+:sramecc-"). Returns false if a modifier names an unknown
815// or repeated feature, names one the processor does not support, or has a
816// malformed sign.
817static bool computeTargetIDFeatures(GPUKind Arch, StringRef TargetIDStr,
820 const AMDGPUFeatureBitset &Features = getFeatureBitset(Arch);
822
823 // The first component is the processor; the rest are feature modifiers of the
824 // form "<feature><+|->".
826 TargetIDStr.split(Split, ':');
827 bool SeenXnack = false;
828 bool SeenSramEcc = false;
829 bool Valid = true;
830 for (unsigned I = 1, E = Split.size(); I != E; ++I) {
831 StringRef FeatureString = Split[I];
832 if (FeatureString.consume_front("xnack")) {
834 // An xnack modifier is only valid with on/off modes: rejected when xnack
835 // is unsupported or hardwired on (e.g. gfx1250).
836 if (SeenXnack || !Features.test(FEAT_XNACK_ON_OFF_MODES) ||
837 Sign == TargetIDSetting::Unsupported)
838 Valid = false;
839 else
840 XnackSetting = Sign;
841 SeenXnack = true;
842 } else if (FeatureString.consume_front("sramecc")) {
844 if (SeenSramEcc || !Features.test(FEAT_SRAMECC_ON_OFF_MODES) ||
845 Sign == TargetIDSetting::Unsupported)
846 Valid = false;
847 else
848 SramEccSetting = Sign;
849 SeenSramEcc = true;
850 } else {
851 // Unknown feature name.
852 Valid = false;
853 }
854 }
855 return Valid;
856}
857
858TargetID::TargetID(const Triple &TT, StringRef TargetIDStr)
859 : TargetID(getGPUKindFromTargetID(TT, TargetIDStr), TT,
861 // Derive the feature settings from the string. Validity is not checked here;
862 // parseTargetIDString validates untrusted input.
863 computeTargetIDFeatures(Arch, TargetIDStr, XnackSetting, SramEccSetting);
864}
865
867 StringRef FeatureString) {
868 GPUKind Arch = parseArchAMDGCN(CPU);
869 TargetIDSetting XnackSetting, SramEccSetting;
870 getDefaultTargetIDFeatures(Arch, XnackSetting, SramEccSetting);
871
872 // Apply the +/-xnack and +/-sramecc modifiers from the feature string, only
873 // for targets that can toggle the corresponding mode.
874 bool XnackToggleable = XnackSetting == TargetIDSetting::Any;
875 bool SramEccToggleable = SramEccSetting == TargetIDSetting::Any;
877 FeatureString.split(Features, ',', /*MaxSplit=*/-1, /*KeepEmpty=*/false);
878 for (StringRef Feature : Features) {
879 TargetIDSetting Sign =
880 getTargetIDSettingFromFeatureString(Feature.take_front());
881 if (Sign == TargetIDSetting::Unsupported)
882 continue;
883 StringRef Name = Feature.drop_front();
884 if (Name == "xnack" && XnackToggleable)
885 XnackSetting = Sign;
886 else if (Name == "sramecc" && SramEccToggleable)
887 SramEccSetting = Sign;
888 }
889
890 return TargetID(Arch, TT, XnackSetting, SramEccSetting);
891}
892
893std::optional<TargetID> TargetID::parse(const Triple &TT,
894 StringRef ProcAndFeatures) {
895 if (!TT.isAMDGCN())
896 return std::nullopt;
897
898 // Filter out unrecognized subarch suffixes.
899 if (TT.getSubArch() == Triple::NoSubArch && TT.getArchName() != "amdgcn")
900 return std::nullopt;
901
902 // A named processor (i.e. not the empty/generic wildcard, which is resolved
903 // from the triple's subarch) must be a recognized GPU that is consistent with
904 // the triple's subarch.
905 StringRef CPUName = ProcAndFeatures.split(':').first;
906 if (!CPUName.empty() && CPUName != "generic" &&
907 !isCPUValidForSubArch(TT.getSubArch(), CPUName))
908 return std::nullopt;
909
910 // Parse the processor and its feature modifiers, then construct directly from
911 // the resulting fields.
912 GPUKind Arch = getGPUKindFromTargetID(TT, ProcAndFeatures);
913 TargetIDSetting XnackSetting, SramEccSetting;
914 if (!computeTargetIDFeatures(Arch, ProcAndFeatures, XnackSetting,
915 SramEccSetting))
916 return std::nullopt;
917
918 return TargetID(Arch, TT, XnackSetting, SramEccSetting);
919}
920
921std::optional<TargetID>
923 // Split on '-' to get arch-vendor-os-environment-processor:features. There is
924 // a single dash separator after the 4-component triple, so the
925 // processor+features field must be present (even if empty).
927 TargetIDDirective.split(Parts, '-', /*MaxSplit=*/4);
928 if (Parts.size() < 5)
929 return std::nullopt;
930
931 return parse(Triple(Parts[0], Parts[1], Parts[2], Parts[3]), Parts[4]);
932}
933
934// Returns true if \p Arch hardwires xnack on (supports xnack but has no on/off
935// modes, e.g. gfx1250), so xnack is not a selectable target-id modifier.
936static bool isXnackHardwiredOn(GPUKind Arch) {
937 const AMDGPUFeatureBitset &Features = getFeatureBitset(Arch);
938 return Features.test(FEAT_XNACK_SUPPORT) &&
939 !Features.test(FEAT_XNACK_ON_OFF_MODES);
940}
941
942static bool isSramEccHardwiredOn(GPUKind Arch) {
943 const AMDGPUFeatureBitset &Features = getFeatureBitset(Arch);
944 return Features.test(FEAT_SRAMECC_SUPPORT) &&
945 !Features.test(FEAT_SRAMECC_ON_OFF_MODES);
946}
947
948// Append the explicit (On/Off) sramecc/xnack feature modifiers in canonical
949// order, e.g. ":sramecc-:xnack+". Hardwired-on features are never emitted.
951 TargetIDSetting Xnack,
952 bool SramEccHardwiredOn,
953 bool XnackHardwiredOn) {
954 if (!SramEccHardwiredOn) {
955 if (SramEcc == TargetIDSetting::Off)
956 OS << ":sramecc-";
957 else if (SramEcc == TargetIDSetting::On)
958 OS << ":sramecc+";
959 }
960
961 if (XnackHardwiredOn)
962 return;
963
964 if (Xnack == TargetIDSetting::Off)
965 OS << ":xnack-";
966 else if (Xnack == TargetIDSetting::On)
967 OS << ":xnack+";
968}
969
970void TargetID::print(raw_ostream &StreamRep) const {
971 StreamRep << TargetTripleString << '-' << getArchNameAMDGCN(Arch);
972
973 if (IsAMDHSA) {
976 }
977}
978
979std::string TargetID::toString() const {
980 std::string Str;
981 raw_string_ostream OS(Str);
982 OS << *this;
983 return Str;
984}
985
991
993 std::string Str;
994 raw_string_ostream OS(Str);
996 return Str;
997}
998
1000 return Arch == Other.Arch && XnackSetting == Other.XnackSetting &&
1001 SramEccSetting == Other.SramEccSetting && IsAMDHSA == Other.IsAMDHSA &&
1002 TargetTripleString == Other.TargetTripleString;
1003}
1004
1006 TargetIDSetting Requested) {
1007 return Provided == TargetIDSetting::Any ||
1008 Provided == TargetIDSetting::Unsupported || Provided == Requested;
1009}
1010
1012 // The processor and feature settings must match exactly
1013 if (Arch != Other.Arch || XnackSetting != Other.XnackSetting ||
1014 SramEccSetting != Other.SramEccSetting)
1015 return false;
1016
1018 .isCompatibleWith(Triple(Other.getTargetTripleString()));
1019}
1020
1022 // A major-family/generic processor (e.g. amdgpu9) provides for a specific
1023 // member of its family (e.g. gfx900), but not the reverse. Otherwise the
1024 // processors must match.
1025 if (Arch != Other.Arch && Arch != GK_NONE && Other.Arch != GK_NONE) {
1026 Triple::SubArchType ThisSubArch = getSubArch(Arch);
1027 if (ThisSubArch != getMajorSubArch(ThisSubArch) ||
1028 ThisSubArch != getMajorSubArch(getSubArch(Other.Arch)))
1029 return false;
1030 }
1031
1032 if (!featureProvidesFor(XnackSetting, Other.XnackSetting) ||
1033 !featureProvidesFor(SramEccSetting, Other.SramEccSetting))
1034 return false;
1035
1037 .isCompatibleWith(Triple(Other.getTargetTripleString()));
1038}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static cl::opt< bool > SramEccSetting("amdgpu-sramecc", cl::desc("Force amdgpu.sramecc for testing"), cl::ReallyHidden)
static cl::opt< bool > XnackSetting("amdgpu-xnack", cl::desc("Force amdgpu.xnack value for testing"), cl::ReallyHidden)
static GPUKind getGPUKindFromTargetID(const Triple &TT, StringRef TargetIDStr)
static std::pair< FeatureError, StringRef > fillAMDGCNFeatureMap(StringRef GPU, const Triple &T, StringMap< bool > &Features)
Add a GPU's default features to Features (preserving user overrides) and validate any requested waves...
static bool computeTargetIDFeatures(GPUKind Arch, StringRef TargetIDStr, TargetIDSetting &XnackSetting, TargetIDSetting &SramEccSetting)
static bool isSramEccHardwiredOn(GPUKind Arch)
static void getDefaultTargetIDFeatures(GPUKind Arch, TargetIDSetting &XnackSetting, TargetIDSetting &SramEccSetting)
static TargetIDSetting getTargetIDSettingFromFeatureString(StringRef Sign)
static bool featureProvidesFor(TargetIDSetting Provided, TargetIDSetting Requested)
static bool isXnackHardwiredOn(GPUKind Arch)
static void addGPUFeatures(const GPUInfo &Info, bool Overwrite, StringMap< bool > &Features)
static void printFeatureModifiers(raw_ostream &OS, TargetIDSetting SramEcc, TargetIDSetting Xnack, bool SramEccHardwiredOn, bool XnackHardwiredOn)
static const AMDGPUFeatureBitset FrontendOnlyFeatures
#define X(NUM, ENUM, NAME)
Definition ELF.h:665
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define I(x, y, z)
Definition MD5.cpp:57
#define G(x, y, z)
Definition MD5.cpp:55
#define T
modulo schedule test
This file defines the SmallVector class.
LocallyHashedType DenseMapInfo< LocallyHashedType >::Empty
static TargetID createFromSubtargetFeatures(const Triple &TT, StringRef CPU, StringRef FeatureString)
Construct a TargetID for triple TT and processor CPU, taking the xnack/sramecc modes from the subtarg...
void printCanonicalTargetIDString(raw_ostream &OS) const
Print the canonical processor name followed by any explicit xnack and sramecc feature modifiers (e....
static std::optional< TargetID > parseTargetIDString(StringRef TargetIDDirective)
Parse and validate a TargetID from a full "<triple>-<processor>:<features>" directive string.
void print(raw_ostream &OS) const
TargetIDSetting getXnackSetting() const
bool isEquivalent(const TargetID &Other) const
Returns true if Other denotes the same target as *this, i.e.
bool operator==(const TargetID &Other) const
bool providesFor(const TargetID &Other) const
Returns true if a device image for *this can provide the device code for a request for Other.
StringRef getTargetTripleString() const
std::string getCanonicalFeatureString() const
TargetID(GPUKind Arch, const Triple &TT, TargetIDSetting XnackSetting, TargetIDSetting SramEccSetting)
static std::optional< TargetID > parse(const Triple &TT, StringRef ProcAndFeatures)
Parse and validate a TargetID for triple TT from the processor+features string ProcAndFeatures (e....
std::string toString() const
TargetIDSetting getSramEccSetting() const
constexpr bool none() const
Definition Bitset.h:120
constexpr bool test(unsigned I) const
Definition Bitset.h:109
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition StringMap.h:129
iterator end()
Definition StringMap.h:214
iterator find(StringRef Key)
Definition StringMap.h:227
bool insert(MapEntryTy *KeyValue)
insert - Insert the specified key/value pair into the map.
Definition StringMap.h:311
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
Definition StringRef.h:736
constexpr bool empty() const
Check if the string is empty.
Definition StringRef.h:141
bool consume_front(char Prefix)
Returns true if this StringRef has the given prefix and removes that prefix.
Definition StringRef.h:661
A table of densely packed, null-terminated strings indexed by offset.
Definition StringTable.h:34
Triple - Helper class for working with autoconf configuration names.
Definition Triple.h:48
@ FirstAMDGPUSubArch
Definition Triple.h:279
@ LastAMDGPUSubArch
Definition Triple.h:280
LLVM_ABI bool isCompatibleWith(const Triple &Other) const
Test whether target triples are compatible.
Definition Triple.cpp:2276
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
A raw_ostream that writes to an std::string.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
LLVM_ABI StringRef getArchNameR600(GPUKind AK)
LLVM_ABI void fillValidArchListAMDGCN(SmallVectorImpl< StringRef > &Values, Triple::SubArchType SubArch=Triple::NoSubArch)
Append the valid AMDGCN GPU names to Values.
LLVM_ABI unsigned getLDSEncodingGranule(GPUKind AK)
LLVM_ABI unsigned getLDSAllocGranule(GPUKind AK)
LLVM_ABI unsigned getMaxWavesPerEU(GPUKind AK)
LLVM_ABI StringRef getCanonicalArchName(const Triple &T, StringRef Arch)
LLVM_ABI unsigned getAddressableLocalMemorySize(GPUKind AK, bool FullSIMDMode)
LLVM_ABI void fillValidArchListR600(SmallVectorImpl< StringRef > &Values)
LLVM_ABI std::string mergeSubArch(const Triple &A, const Triple &B)
Returns the effective triple appropriate to use when linking B into A by merging the subarches in cas...
LLVM_ABI bool isCPUValidForSubArch(Triple::SubArchType SubArch, GPUKind AK)
Return true if the GPU AK is usable with the triple subarch SubArch.
LLVM_ABI bool isSubArchCompatible(const Triple &A, const Triple &B)
Return true if subarch A is compatible with subarch B, i.e.
LLVM_ABI unsigned getLDSBankCount(GPUKind AK)
LLVM_ABI unsigned getMaxHWAddressableLocalMemorySize(GPUKind AK)
LDS size queries.
LLVM_ABI StringRef getArchFamilyNameAMDGCN(GPUKind AK)
LLVM_ABI StringRef getSubArchName(Triple::SubArchType SubArch)
Returns the triple subarch name for an AMDGPU subarch, e.g.
LLVM_ABI unsigned getAddressableNumSGPRs(GPUKind AK)
LLVM_ABI IsaVersion getIsaVersion(StringRef GPU)
LLVM_ABI unsigned getTotalNumVGPRs(GPUKind AK, bool IsWave32)
LLVM_ABI unsigned getTotalNumSGPRs(GPUKind AK)
LLVM_ABI std::optional< unsigned > getBufferResourceNumRecordsWidth(GPUKind AK)
GPUKind
GPU kinds supported by the AMDGPU target.
Bitset< NUM_FEATURES > AMDGPUFeatureBitset
LLVM_ABI Triple::SubArchType getSubArchFromGPUName(StringRef CPU)
Returns the preferred subarch for a GPU name CPU, or NoSubArch if unrecognized.
LLVM_ABI unsigned getLocalMemorySize(GPUKind AK, bool FullSIMDMode)
LLVM_ABI unsigned getSGPRAllocGranule(GPUKind AK)
LLVM_ABI Triple::SubArchType getSubArch(GPUKind AK)
LLVM_ABI StringRef getArchNameFromSubArch(Triple::SubArchType SubArch)
Returns the canonical GPU name for an AMDGPU subarch, e.g.
LLVM_ABI unsigned getVGPRAllocGranule(GPUKind AK, bool IsWave32)
LLVM_ABI GPUKind parseArchAMDGCN(StringRef CPU)
LLVM_ABI bool isPseudoTarget(GPUKind AK)
Return true if AK is a pseudo target (e.g.
LLVM_ABI GPUKind getGPUKindFromSubArch(Triple::SubArchType SubArch)
AMDGPU::TargetID TargetID
LLVM_ABI std::pair< FeatureError, StringRef > fillAMDGPUFeatureMap(StringRef GPU, const Triple &T, StringMap< bool > &Features)
Fills Features map with default values for given target GPU.
LLVM_ABI unsigned getAddressableNumVGPRs(GPUKind AK, bool IsWave32)
LLVM_ABI void getFeatureNames(const AMDGPUFeatureBitset &Features, SmallVectorImpl< StringRef > &Names)
Appends the feature name of each bit set in Features to Names.
LLVM_ABI StringRef getArchNameAMDGCN(GPUKind AK)
LLVM_ABI Triple::SubArchType getMajorSubArch(Triple::SubArchType SubArch)
LLVM_ABI const AMDGPUFeatureBitset & getFeatureBitset(GPUKind AK)
Returns AK's feature bitset, or an empty bitset if unknown.
LLVM_ABI const R600FeatureBitset & getFeatureBitsetR600(GPUKind AK)
Returns R600 GPU AK's feature bitset, or an empty bitset if unknown.
Bitset< R600_NUM_FEATURES > R600FeatureBitset
LLVM_ABI GPUKind parseArchR600(StringRef CPU)
This is an optimization pass for GlobalISel generic memory operations.
RelativeUniformCounterPtr Values
Definition InstrProf.h:91
#define N
Instruction set architecture version.