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
13#include "llvm/TargetParser/AMDGPUTargetParser.h"
14#include "llvm/ADT/SmallVector.h"
15#include "llvm/ADT/StringTable.h"
16#include "llvm/ADT/Twine.h"
17#include "llvm/Support/raw_ostream.h"
18#include "llvm/TargetParser/Triple.h"
19#include <algorithm>
20#include <array>
21#include <cassert>
22
23using namespace llvm;
24using namespace AMDGPU;
25
26namespace {
27constexpr unsigned NumAMDGPUSubArches =
28 Triple::LastAMDGPUSubArch - Triple::FirstAMDGPUSubArch + 1;
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) {
121 Map[SubArch - Triple::FirstAMDGPUSubArch] =
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] =
135 static_cast<Triple::SubArchType>(Triple::FirstAMDGPUSubArch + 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
165StringRef llvm::AMDGPU::getArchFamilyNameAMDGCN(GPUKind AK) {
166 const GPUInfo *Info = getAMDGPUInfo(AK);
167 return Info ? AMDGPUNameStrTab[Info->FamilyName] : "";
168}
169
170Triple::SubArchType llvm::AMDGPU::getSubArch(GPUKind AK) {
171 const GPUInfo *Info = getAMDGPUInfo(AK);
172 return Info ? Info->SubArch : Triple::SubArchType::NoSubArch;
173}
174
175Triple::SubArchType llvm::AMDGPU::getSubArchFromGPUName(StringRef CPU) {
176 return getSubArch(AK: parseArchAMDGCN(CPU));
177}
178
179AMDGPU::GPUKind
180llvm::AMDGPU::getGPUKindFromSubArch(Triple::SubArchType SubArch) {
181 if (SubArch < Triple::FirstAMDGPUSubArch ||
182 SubArch > Triple::LastAMDGPUSubArch)
183 return GK_NONE;
184 return AMDGPUSubArchToGPUKind[SubArch - Triple::FirstAMDGPUSubArch];
185}
186
187Triple::SubArchType AMDGPU::getMajorSubArch(Triple::SubArchType X) {
188 if (X < Triple::FirstAMDGPUSubArch || X > Triple::LastAMDGPUSubArch)
189 return Triple::NoSubArch;
190 return AMDGPUMajorFamilies[X - Triple::FirstAMDGPUSubArch];
191}
192
193bool AMDGPU::isSubArchCompatible(Triple::SubArchType A, Triple::SubArchType B) {
194 if (A == B || A == Triple::NoSubArch || B == Triple::NoSubArch)
195 return true;
196
197 Triple::SubArchType MajorA = AMDGPU::getMajorSubArch(X: A);
198 Triple::SubArchType MajorB = AMDGPU::getMajorSubArch(X: B);
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
209bool AMDGPU::isCPUValidForSubArch(Triple::SubArchType SubArch, GPUKind AK) {
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(A: GPUSubArch, B: SubArch);
223}
224
225bool AMDGPU::isCPUValidForSubArch(Triple::SubArchType SubArch, StringRef CPU) {
226 return isCPUValidForSubArch(SubArch, AK: parseArchAMDGCN(CPU));
227}
228
229bool AMDGPU::isPseudoTarget(GPUKind AK) {
230 const GPUInfo *Info = getAMDGPUInfo(AK);
231 return Info && Info->SubArch == Triple::NoSubArch;
232}
233
234bool AMDGPU::isPseudoTarget(StringRef CPU) {
235 return isPseudoTarget(AK: parseArchAMDGCN(CPU));
236}
237
238bool AMDGPU::isSubArchCompatible(const Triple &A, const Triple &B) {
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: A.getSubArch(), B: 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(X: A.getSubArch());
259 Triple::SubArchType MajorB = AMDGPU::getMajorSubArch(X: 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
276StringRef llvm::AMDGPU::getArchNameAMDGCN(GPUKind AK) {
277 const GPUInfo *Info = getAMDGPUInfo(AK);
278 return Info ? AMDGPUNameStrTab[Info->Name] : "";
279}
280
281StringRef llvm::AMDGPU::getArchNameFromSubArch(Triple::SubArchType SubArch) {
282 if (SubArch < Triple::FirstAMDGPUSubArch ||
283 SubArch > Triple::LastAMDGPUSubArch)
284 return "";
285 return AMDGPUNameStrTab[AMDGPUSubArchNameOffsets[SubArch -
286 Triple::FirstAMDGPUSubArch]];
287}
288
289StringRef llvm::AMDGPU::getSubArchName(Triple::SubArchType SubArch) {
290 if (SubArch == Triple::NoSubArch)
291 return AMDGPUNameStrTab[AMDGPUNoSubArchNameOffset];
292
293 assert(SubArch >= Triple::FirstAMDGPUSubArch &&
294 SubArch <= Triple::LastAMDGPUSubArch &&
295 "expected an AMDGPU subarch or NoSubArch");
296 return AMDGPUNameStrTab
297 [AMDGPUSubArchTripleNameOffsets[SubArch - Triple::FirstAMDGPUSubArch]];
298}
299
300StringRef llvm::AMDGPU::getArchNameR600(GPUKind AK) {
301 const R600Info *Info = getR600Info(AK);
302 return Info ? R600NameStrTab[Info->Name] : "";
303}
304
305AMDGPU::GPUKind llvm::AMDGPU::parseArchAMDGCN(StringRef CPU) {
306 return parseArchImpl(CPU, Table: AMDGPUGPUTable, FirstKind: AMDGPUFirstGPUKind,
307 StrTab: AMDGPUNameStrTab, Aliases: AMDGPUGPUAliases);
308}
309
310AMDGPU::GPUKind llvm::AMDGPU::parseArchR600(StringRef CPU) {
311 return parseArchImpl(CPU, Table: R600GPUTable, FirstKind: R600FirstGPUKind, StrTab: R600NameStrTab,
312 Aliases: R600GPUAliases);
313}
314
315const AMDGPUFeatureBitset &AMDGPU::getFeatureBitset(GPUKind AK) {
316 static constexpr AMDGPUFeatureBitset Empty{};
317 const GPUInfo *Info = getAMDGPUInfo(AK);
318 return Info ? Info->Features : Empty;
319}
320
321const R600FeatureBitset &AMDGPU::getFeatureBitsetR600(GPUKind AK) {
322 static constexpr R600FeatureBitset Empty{};
323 const R600Info *Info = getR600Info(AK);
324 return Info ? Info->Features : Empty;
325}
326
327void AMDGPU::getFeatureNames(const AMDGPUFeatureBitset &Features,
328 SmallVectorImpl<StringRef> &Names) {
329 for (unsigned I = 0; I != NUM_FEATURES; ++I) {
330 if (Features.test(I))
331 Names.push_back(Elt: AMDGPUNameStrTab[AMDGPUFeatureNames[I]]);
332 }
333}
334
335void AMDGPU::fillValidArchListAMDGCN(SmallVectorImpl<StringRef> &Values,
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, AK: Kind))
343 Values.push_back(Elt: AMDGPUNameStrTab[AMDGPUGPUTable[I].Name]);
344 }
345
346 for (const GPUNameAlias &A : AMDGPUGPUAliases) {
347 if (isCPUValidForSubArch(SubArch, AK: A.Kind))
348 Values.push_back(Elt: AMDGPUNameStrTab[A.AltName]);
349 }
350}
351
352void AMDGPU::fillValidArchListR600(SmallVectorImpl<StringRef> &Values) {
353 for (const R600Info &Info : R600GPUTable)
354 Values.push_back(Elt: R600NameStrTab[Info.Name]);
355 for (const GPUNameAlias &A : R600GPUAliases)
356 Values.push_back(Elt: R600NameStrTab[A.AltName]);
357}
358
359AMDGPU::IsaVersion AMDGPU::getIsaVersion(StringRef GPU) {
360 const GPUInfo *Info = getAMDGPUInfo(AK: parseArchAMDGCN(CPU: GPU));
361 return Info ? Info->Version : IsaVersion{.Major: 0, .Minor: 0, .Stepping: 0};
362}
363
364AMDGPU::IsaVersion AMDGPU::getIsaVersion(Triple::SubArchType SubArch) {
365 const GPUInfo *Info = getAMDGPUInfo(AK: getGPUKindFromSubArch(SubArch));
366 return Info ? Info->Version : IsaVersion{.Major: 0, .Minor: 0, .Stepping: 0};
367}
368
369unsigned AMDGPU::getTotalNumSGPRs(GPUKind AK) {
370 IsaVersion Version = getIsaVersion(SubArch: getSubArch(AK));
371 if (Version.Major >= 8)
372 return 800;
373 return 512;
374}
375
376unsigned AMDGPU::getTotalNumSGPRs(Triple::SubArchType SubArch) {
377 IsaVersion Version = getIsaVersion(SubArch);
378 if (Version.Major >= 8)
379 return 800;
380 return 512;
381}
382
383unsigned AMDGPU::getAddressableNumSGPRs(GPUKind AK) {
384 if (getFeatureBitset(AK).test(I: FEAT_SGPR_INIT_BUG))
385 return FIXED_NUM_SGPRS_FOR_INIT_BUG;
386
387 IsaVersion Version = getIsaVersion(SubArch: getSubArch(AK));
388 if (Version.Major >= 10)
389 return 106;
390 if (Version.Major >= 8)
391 return 102;
392 return 104;
393}
394
395unsigned AMDGPU::getAddressableNumSGPRs(Triple::SubArchType SubArch) {
396 if (getFeatureBitset(AK: getGPUKindFromSubArch(SubArch)).test(I: FEAT_SGPR_INIT_BUG))
397 return FIXED_NUM_SGPRS_FOR_INIT_BUG;
398
399 IsaVersion Version = getIsaVersion(SubArch);
400 if (Version.Major >= 10)
401 return 106;
402 if (Version.Major >= 8)
403 return 102;
404 return 104;
405}
406
407unsigned AMDGPU::getSGPRAllocGranule(GPUKind AK) {
408 IsaVersion Version = getIsaVersion(SubArch: getSubArch(AK));
409 if (Version.Major >= 10)
410 return getAddressableNumSGPRs(AK);
411 if (Version.Major >= 8)
412 return 16;
413 return 8;
414}
415
416unsigned AMDGPU::getSGPRAllocGranule(Triple::SubArchType SubArch) {
417 IsaVersion Version = getIsaVersion(SubArch);
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(I: FEAT_GFX90A_INSTS))
428 return 8;
429 if (Features.test(I: FEAT_1536_PHYSICAL_VGPRS))
430 return IsWave32 ? 24 : 12;
431 if (Features.test(I: FEAT_GFX10_3_INSTS))
432 return IsWave32 ? 16 : 8;
433 return IsWave32 ? 8 : 4;
434}
435
436unsigned AMDGPU::getVGPRAllocGranule(Triple::SubArchType SubArch,
437 bool IsWave32) {
438 return getVGPRAllocGranule(AK: getGPUKindFromSubArch(SubArch), IsWave32);
439}
440
441unsigned AMDGPU::getTotalNumVGPRs(GPUKind AK, bool IsWave32) {
442 const AMDGPUFeatureBitset &Features = getFeatureBitset(AK);
443 if (Features.test(I: FEAT_GFX90A_INSTS))
444 return 512;
445 if (!Features.test(I: FEAT_GFX10_INSTS))
446 return 256;
447 if (Features.test(I: 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(AK: 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(I: FEAT_GFX90A_INSTS))
460 return 512;
461 if (Features.test(I: FEAT_1024_ADDRESSABLE_VGPRS))
462 return IsWave32 ? 1024 : 512;
463 return 256;
464}
465
466unsigned AMDGPU::getAddressableNumVGPRs(Triple::SubArchType SubArch,
467 bool IsWave32) {
468 return getAddressableNumVGPRs(AK: getGPUKindFromSubArch(SubArch), IsWave32);
469}
470
471unsigned AMDGPU::getMaxHWAddressableLocalMemorySize(GPUKind AK) {
472 const GPUInfo *Info = getAMDGPUInfo(AK);
473 return Info ? Info->MaxHWAddressableLocalMemorySize : 32768;
474}
475
476unsigned
477AMDGPU::getMaxHWAddressableLocalMemorySize(Triple::SubArchType SubArch) {
478 return getMaxHWAddressableLocalMemorySize(AK: getGPUKindFromSubArch(SubArch));
479}
480
481unsigned AMDGPU::getLocalMemorySize(GPUKind AK, bool FullSIMDMode) {
482 // gfx6 and gfx10/11/12 address half of the physical block.
483 unsigned Size = getMaxHWAddressableLocalMemorySize(AK);
484 if (getFeatureBitset(AK).test(I: FEAT_HALF_ADDRESSABLE_PHYSICAL_LOCAL_MEMORY))
485 Size *= 2;
486
487 // In half-SIMD mode the work-group reaches only half of the block.
488 if (!FullSIMDMode)
489 Size /= 2;
490
491 return Size;
492}
493
494unsigned AMDGPU::getLocalMemorySize(Triple::SubArchType SubArch,
495 bool FullSIMDMode) {
496 return getLocalMemorySize(AK: getGPUKindFromSubArch(SubArch), FullSIMDMode);
497}
498
499unsigned AMDGPU::getAddressableLocalMemorySize(GPUKind AK, bool FullSIMDMode) {
500 return std::min(a: getMaxHWAddressableLocalMemorySize(AK),
501 b: getLocalMemorySize(AK, FullSIMDMode));
502}
503
504unsigned AMDGPU::getAddressableLocalMemorySize(Triple::SubArchType SubArch,
505 bool FullSIMDMode) {
506 return getAddressableLocalMemorySize(AK: getGPUKindFromSubArch(SubArch),
507 FullSIMDMode);
508}
509
510unsigned AMDGPU::getLDSBankCount(GPUKind AK) {
511 const GPUInfo *Info = getAMDGPUInfo(AK);
512 return Info ? Info->LDSBankCount : 32;
513}
514
515unsigned AMDGPU::getLDSBankCount(Triple::SubArchType SubArch) {
516 return getLDSBankCount(AK: getGPUKindFromSubArch(SubArch));
517}
518
519std::optional<unsigned> AMDGPU::getBufferResourceNumRecordsWidth(GPUKind AK) {
520 const GPUInfo *Info = getAMDGPUInfo(AK);
521 if (!Info || Info->BufferResourceNumRecordsWidth == 0)
522 return std::nullopt;
523 return Info->BufferResourceNumRecordsWidth;
524}
525
526std::optional<unsigned>
527AMDGPU::getBufferResourceNumRecordsWidth(Triple::SubArchType SubArch) {
528 return getBufferResourceNumRecordsWidth(AK: getGPUKindFromSubArch(SubArch));
529}
530
531unsigned AMDGPU::getMaxWavesPerEU(GPUKind AK) {
532 const GPUInfo *Info = getAMDGPUInfo(AK);
533 return Info ? Info->MaxWavesPerEU : 10;
534}
535
536unsigned AMDGPU::getMaxWavesPerEU(Triple::SubArchType SubArch) {
537 return getMaxWavesPerEU(AK: getGPUKindFromSubArch(SubArch));
538}
539
540StringRef AMDGPU::getCanonicalArchName(const Triple &T, StringRef Arch) {
541 assert(T.isAMDGPU());
542 auto ProcKind = T.isAMDGCN() ? parseArchAMDGCN(CPU: Arch) : parseArchR600(CPU: Arch);
543 if (ProcKind == GK_NONE)
544 return StringRef();
545
546 return T.isAMDGCN() ? getArchNameAMDGCN(AK: ProcKind) : getArchNameR600(AK: ProcKind);
547}
548
549// Capability features clang queries via the feature bitset but must not
550// serialize into the target-feature string.
551//
552// FIXME: This is hacky, we shouldn't have mismatches between the bitset and
553// feature string map.
554static const AMDGPUFeatureBitset FrontendOnlyFeatures = {
555 FEAT_FAST_FMAF,
556 FEAT_FAST_DENORMAL_F32,
557 FEAT_SUPPORTS_WAVE32,
558 FEAT_SUPPORTS_WGP,
559 FEAT_XNACK_SUPPORT,
560 FEAT_SRAMECC_SUPPORT,
561 FEAT_XNACK_ON_OFF_MODES,
562 FEAT_APERTURE_REGS,
563 FEAT_GET_DOORBELL_ID,
564 FEAT_AGPR_ALLOC,
565 FEAT_1536_PHYSICAL_VGPRS,
566 FEAT_HALF_ADDRESSABLE_PHYSICAL_LOCAL_MEMORY,
567 FEAT_1024_ADDRESSABLE_VGPRS};
568
569// Add a GPU's features (minus the frontend-only ones) to \p Features. With \p
570// Overwrite false, existing entries are kept so user -mattr overrides win.
571static void addGPUFeatures(const GPUInfo &Info, bool Overwrite,
572 StringMap<bool> &Features) {
573 SmallVector<StringRef, NUM_FEATURES> Names;
574 getFeatureNames(Features: Info.Features & ~FrontendOnlyFeatures, Names);
575 for (StringRef Name : Names) {
576 if (Overwrite)
577 Features[Name] = true;
578 else
579 Features.insert(KV: {Name, true});
580 }
581}
582
583/// Add a GPU's default features to \p Features (preserving user overrides) and
584/// validate any requested wavesize.
585static std::pair<FeatureError, StringRef>
586fillAMDGCNFeatureMap(StringRef GPU, const Triple &T,
587 StringMap<bool> &Features) {
588 // With no explicit GPU, the triple's subarch identifies the target.
589 GPUKind Kind = GPU.empty() && T.getSubArch() != Triple::NoSubArch
590 ? getGPUKindFromSubArch(SubArch: T.getSubArch())
591 : parseArchAMDGCN(CPU: GPU);
592 const GPUInfo *Info = getAMDGPUInfo(AK: Kind);
593
594 // A bare subarch triple (no -target-cpu) still pins down the target, so it is
595 // not a null GPU. The target's native wavesize (if single-mode) is in the
596 // feature bitset; a dual-mode GPU has neither wave bit set.
597 const bool IsNullGPU = T.getSubArch() == Triple::NoSubArch && GPU.empty();
598 const bool TargetHasWave32 =
599 Info && Info->Features.test(I: FEAT_WAVEFRONTSIZE32);
600 const bool TargetHasWave64 =
601 Info && Info->Features.test(I: FEAT_WAVEFRONTSIZE64);
602
603 auto Wave32Itr = Features.find(Key: "wavefrontsize32");
604 auto Wave64Itr = Features.find(Key: "wavefrontsize64");
605 const bool EnableWave32 =
606 Wave32Itr != Features.end() && Wave32Itr->getValue();
607 const bool EnableWave64 =
608 Wave64Itr != Features.end() && Wave64Itr->getValue();
609 const bool DisableWave32 =
610 Wave32Itr != Features.end() && !Wave32Itr->getValue();
611 const bool DisableWave64 =
612 Wave64Itr != Features.end() && !Wave64Itr->getValue();
613
614 if (EnableWave32 && EnableWave64)
615 return {AMDGPU::INVALID_FEATURE_COMBINATION,
616 "'+wavefrontsize32' and '+wavefrontsize64' are mutually exclusive"};
617 if (DisableWave32 && DisableWave64)
618 return {AMDGPU::INVALID_FEATURE_COMBINATION,
619 "'-wavefrontsize32' and '-wavefrontsize64' are mutually exclusive"};
620
621 if (!IsNullGPU) {
622 if (TargetHasWave64) {
623 if (EnableWave32)
624 return {AMDGPU::UNSUPPORTED_TARGET_FEATURE, "+wavefrontsize32"};
625 if (DisableWave64)
626 return {AMDGPU::UNSUPPORTED_TARGET_FEATURE, "-wavefrontsize64"};
627 }
628
629 if (TargetHasWave32) {
630 if (EnableWave64)
631 return {AMDGPU::UNSUPPORTED_TARGET_FEATURE, "+wavefrontsize64"};
632 if (DisableWave32)
633 return {AMDGPU::UNSUPPORTED_TARGET_FEATURE, "-wavefrontsize32"};
634 }
635 }
636
637 // Don't assume any wavesize with an unknown subtarget.
638 // Default to wave32 if target supports both.
639 if (!IsNullGPU && !EnableWave32 && !EnableWave64 && !TargetHasWave32 &&
640 !TargetHasWave64)
641 Features.insert(KV: {"wavefrontsize32", true});
642
643 // Merge the target defaults, keeping any user -mattr overrides.
644 if (Info)
645 addGPUFeatures(Info: *Info, /*Overwrite=*/false, Features);
646
647 return {NO_ERROR, StringRef()};
648}
649
650/// Fills Features map with default values for given target GPU.
651/// \p Features contains overriding target features and this function returns
652/// default target features with entries overridden by \p Features.
653std::pair<FeatureError, StringRef>
654AMDGPU::fillAMDGPUFeatureMap(StringRef GPU, const Triple &T,
655 StringMap<bool> &Features) {
656 // XXX - What does the member GPU mean if device name string passed here?
657 if (T.isSPIRV() && T.getOS() == Triple::OSType::AMDHSA) {
658 // AMDGCN SPIRV must support the union of all AMDGCN features.
659 SmallVector<StringRef> GPUs;
660 fillValidArchListAMDGCN(Values&: GPUs);
661 for (StringRef G : GPUs)
662 if (const GPUInfo *Info = getAMDGPUInfo(AK: parseArchAMDGCN(CPU: G)))
663 addGPUFeatures(Info: *Info, /*Overwrite=*/true, Features);
664 Features["wavefrontsize32"] = true;
665 Features["wavefrontsize64"] = true;
666 } else if (T.isAMDGCN()) {
667 return fillAMDGCNFeatureMap(GPU, T, Features);
668 } else {
669 if (GPU.empty())
670 GPU = "r600";
671
672 switch (llvm::AMDGPU::parseArchR600(CPU: GPU)) {
673 case GK_CAYMAN:
674 case GK_CYPRESS:
675 case GK_RV770:
676 case GK_RV670:
677 // TODO: Add fp64 when implemented.
678 break;
679 case GK_TURKS:
680 case GK_CAICOS:
681 case GK_BARTS:
682 case GK_SUMO:
683 case GK_REDWOOD:
684 case GK_JUNIPER:
685 case GK_CEDAR:
686 case GK_RV730:
687 case GK_RV710:
688 case GK_RS880:
689 case GK_R630:
690 case GK_R600:
691 break;
692 default:
693 llvm_unreachable("Unhandled GPU!");
694 }
695 }
696 return {NO_ERROR, StringRef()};
697}
698
699TargetID::TargetID(GPUKind Arch, const Triple &TT, TargetIDSetting XnackSetting,
700 TargetIDSetting SramEccSetting)
701 : Arch(Arch),
702 TargetTripleString(TT.normalize(Form: Triple::CanonicalForm::FOUR_IDENT)),
703 XnackSetting(XnackSetting), SramEccSetting(SramEccSetting),
704 IsAMDHSA(TT.getOS() == Triple::AMDHSA) {}
705
706// Parse a feature modifier sign ("+"/"-"). Returns "Unsupported" if \p Sign is
707// neither (i.e. the modifier is malformed).
708static TargetIDSetting getTargetIDSettingFromFeatureString(StringRef Sign) {
709 if (Sign == "+")
710 return TargetIDSetting::On;
711 if (Sign == "-")
712 return TargetIDSetting::Off;
713
714 return TargetIDSetting::Unsupported;
715}
716
717// Derive the architecture from the processor name in \p TargetIDStr. "generic"
718// and the empty processor name act as a wildcard.
719static GPUKind getGPUKindFromTargetID(const Triple &TT, StringRef TargetIDStr) {
720 StringRef CPUName = TargetIDStr.split(Separator: ':').first;
721 return (CPUName.empty() || CPUName == "generic")
722 ? getGPUKindFromSubArch(SubArch: TT.getSubArch())
723 : parseArchAMDGCN(CPU: CPUName);
724}
725
726// Compute the default xnack/sramecc settings for processor \p Arch, before any
727// explicit feature modifiers are applied.
728static void getDefaultTargetIDFeatures(GPUKind Arch,
729 TargetIDSetting &XnackSetting,
730 TargetIDSetting &SramEccSetting) {
731 const AMDGPUFeatureBitset &Features = getFeatureBitset(AK: Arch);
732 // xnack with on/off modes defaults to Any; supported without on/off modes is
733 // hardwired On (e.g. gfx1250); unsupported is Unsupported.
734 if (!Features.test(I: FEAT_XNACK_SUPPORT))
735 XnackSetting = TargetIDSetting::Unsupported;
736 else if (Features.test(I: FEAT_XNACK_ON_OFF_MODES))
737 XnackSetting = TargetIDSetting::Any;
738 else
739 XnackSetting = TargetIDSetting::On;
740 SramEccSetting = Features.test(I: FEAT_SRAMECC_SUPPORT)
741 ? TargetIDSetting::Any
742 : TargetIDSetting::Unsupported;
743}
744
745// Compute the xnack/sramecc settings for processor \p Arch from the
746// processor+features string \p TargetIDStr
747// (e.g. "gfx90a:xnack+:sramecc-"). Returns false if a modifier names an unknown
748// or repeated feature, names one the processor does not support, or has a
749// malformed sign.
750static bool computeTargetIDFeatures(GPUKind Arch, StringRef TargetIDStr,
751 TargetIDSetting &XnackSetting,
752 TargetIDSetting &SramEccSetting) {
753 const AMDGPUFeatureBitset &Features = getFeatureBitset(AK: Arch);
754 getDefaultTargetIDFeatures(Arch, XnackSetting, SramEccSetting);
755
756 // The first component is the processor; the rest are feature modifiers of the
757 // form "<feature><+|->".
758 SmallVector<StringRef, 3> Split;
759 TargetIDStr.split(A&: Split, Separator: ':');
760 bool SeenXnack = false;
761 bool SeenSramEcc = false;
762 bool Valid = true;
763 for (unsigned I = 1, E = Split.size(); I != E; ++I) {
764 StringRef FeatureString = Split[I];
765 if (FeatureString.consume_front(Prefix: "xnack")) {
766 TargetIDSetting Sign = getTargetIDSettingFromFeatureString(Sign: FeatureString);
767 // An xnack modifier is only valid with on/off modes: rejected when xnack
768 // is unsupported or hardwired on (e.g. gfx1250).
769 if (SeenXnack || !Features.test(I: FEAT_XNACK_ON_OFF_MODES) ||
770 Sign == TargetIDSetting::Unsupported)
771 Valid = false;
772 else
773 XnackSetting = Sign;
774 SeenXnack = true;
775 } else if (FeatureString.consume_front(Prefix: "sramecc")) {
776 TargetIDSetting Sign = getTargetIDSettingFromFeatureString(Sign: FeatureString);
777 if (SeenSramEcc || SramEccSetting == TargetIDSetting::Unsupported ||
778 Sign == TargetIDSetting::Unsupported)
779 Valid = false;
780 else
781 SramEccSetting = Sign;
782 SeenSramEcc = true;
783 } else {
784 // Unknown feature name.
785 Valid = false;
786 }
787 }
788 return Valid;
789}
790
791TargetID::TargetID(const Triple &TT, StringRef TargetIDStr)
792 : TargetID(getGPUKindFromTargetID(TT, TargetIDStr), TT,
793 TargetIDSetting::Unsupported, TargetIDSetting::Unsupported) {
794 // Derive the feature settings from the string. Validity is not checked here;
795 // parseTargetIDString validates untrusted input.
796 computeTargetIDFeatures(Arch, TargetIDStr, XnackSetting, SramEccSetting);
797}
798
799TargetID TargetID::createFromSubtargetFeatures(const Triple &TT, StringRef CPU,
800 StringRef FeatureString) {
801 GPUKind Arch = parseArchAMDGCN(CPU);
802 TargetIDSetting XnackSetting, SramEccSetting;
803 getDefaultTargetIDFeatures(Arch, XnackSetting, SramEccSetting);
804
805 // Apply the +/-xnack and +/-sramecc modifiers from the feature string, only
806 // for targets that can toggle the corresponding mode.
807 bool XnackToggleable = XnackSetting == TargetIDSetting::Any;
808 bool SramEccToggleable = SramEccSetting == TargetIDSetting::Any;
809 SmallVector<StringRef, 4> Features;
810 FeatureString.split(A&: Features, Separator: ',', /*MaxSplit=*/-1, /*KeepEmpty=*/false);
811 for (StringRef Feature : Features) {
812 TargetIDSetting Sign =
813 getTargetIDSettingFromFeatureString(Sign: Feature.take_front());
814 if (Sign == TargetIDSetting::Unsupported)
815 continue;
816 StringRef Name = Feature.drop_front();
817 if (Name == "xnack" && XnackToggleable)
818 XnackSetting = Sign;
819 else if (Name == "sramecc" && SramEccToggleable)
820 SramEccSetting = Sign;
821 }
822
823 return TargetID(Arch, TT, XnackSetting, SramEccSetting);
824}
825
826std::optional<TargetID> TargetID::parse(const Triple &TT,
827 StringRef ProcAndFeatures) {
828 if (!TT.isAMDGCN())
829 return std::nullopt;
830
831 // Filter out unrecognized subarch suffixes.
832 if (TT.getSubArch() == Triple::NoSubArch && TT.getArchName() != "amdgcn")
833 return std::nullopt;
834
835 // A named processor (i.e. not the empty/generic wildcard, which is resolved
836 // from the triple's subarch) must be a recognized GPU that is consistent with
837 // the triple's subarch.
838 StringRef CPUName = ProcAndFeatures.split(Separator: ':').first;
839 if (!CPUName.empty() && CPUName != "generic" &&
840 !isCPUValidForSubArch(SubArch: TT.getSubArch(), CPU: CPUName))
841 return std::nullopt;
842
843 // Parse the processor and its feature modifiers, then construct directly from
844 // the resulting fields.
845 GPUKind Arch = getGPUKindFromTargetID(TT, TargetIDStr: ProcAndFeatures);
846 TargetIDSetting XnackSetting, SramEccSetting;
847 if (!computeTargetIDFeatures(Arch, TargetIDStr: ProcAndFeatures, XnackSetting,
848 SramEccSetting))
849 return std::nullopt;
850
851 return TargetID(Arch, TT, XnackSetting, SramEccSetting);
852}
853
854std::optional<TargetID>
855TargetID::parseTargetIDString(StringRef TargetIDDirective) {
856 // Split on '-' to get arch-vendor-os-environment-processor:features. There is
857 // a single dash separator after the 4-component triple, so the
858 // processor+features field must be present (even if empty).
859 SmallVector<StringRef, 5> Parts;
860 TargetIDDirective.split(A&: Parts, Separator: '-', /*MaxSplit=*/4);
861 if (Parts.size() < 5)
862 return std::nullopt;
863
864 return parse(TT: Triple(Parts[0], Parts[1], Parts[2], Parts[3]), ProcAndFeatures: Parts[4]);
865}
866
867// Returns true if \p Arch hardwires xnack on (supports xnack but has no on/off
868// modes, e.g. gfx1250), so xnack is not a selectable target-id modifier.
869static bool isXnackHardwiredOn(GPUKind Arch) {
870 const AMDGPUFeatureBitset &Features = getFeatureBitset(AK: Arch);
871 return Features.test(I: FEAT_XNACK_SUPPORT) &&
872 !Features.test(I: FEAT_XNACK_ON_OFF_MODES);
873}
874
875// Append the explicit (On/Off) sramecc/xnack feature modifiers in canonical
876// order, e.g. ":sramecc-:xnack+". Xnack is never emitted for hardwired-on
877// targets.
878static void printFeatureModifiers(raw_ostream &OS, TargetIDSetting SramEcc,
879 TargetIDSetting Xnack,
880 bool XnackHardwiredOn) {
881 if (SramEcc == TargetIDSetting::Off)
882 OS << ":sramecc-";
883 else if (SramEcc == TargetIDSetting::On)
884 OS << ":sramecc+";
885
886 if (XnackHardwiredOn)
887 return;
888
889 if (Xnack == TargetIDSetting::Off)
890 OS << ":xnack-";
891 else if (Xnack == TargetIDSetting::On)
892 OS << ":xnack+";
893}
894
895void TargetID::print(raw_ostream &StreamRep) const {
896 StreamRep << TargetTripleString << '-' << getArchNameAMDGCN(AK: Arch);
897
898 if (IsAMDHSA) {
899 printFeatureModifiers(OS&: StreamRep, SramEcc: getSramEccSetting(), Xnack: getXnackSetting(),
900 XnackHardwiredOn: isXnackHardwiredOn(Arch));
901 }
902}
903
904std::string TargetID::toString() const {
905 std::string Str;
906 raw_string_ostream OS(Str);
907 OS << *this;
908 return Str;
909}
910
911void TargetID::printCanonicalTargetIDString(raw_ostream &OS) const {
912 OS << getArchNameAMDGCN(AK: Arch);
913 printFeatureModifiers(OS, SramEcc: getSramEccSetting(), Xnack: getXnackSetting(),
914 XnackHardwiredOn: isXnackHardwiredOn(Arch));
915}
916
917std::string TargetID::getCanonicalFeatureString() const {
918 std::string Str;
919 raw_string_ostream OS(Str);
920 printCanonicalTargetIDString(OS);
921 return Str;
922}
923
924bool TargetID::operator==(const TargetID &Other) const {
925 return Arch == Other.Arch && XnackSetting == Other.XnackSetting &&
926 SramEccSetting == Other.SramEccSetting && IsAMDHSA == Other.IsAMDHSA &&
927 TargetTripleString == Other.TargetTripleString;
928}
929
930static bool featureProvidesFor(TargetIDSetting Provided,
931 TargetIDSetting Requested) {
932 return Provided == TargetIDSetting::Any ||
933 Provided == TargetIDSetting::Unsupported || Provided == Requested;
934}
935
936bool TargetID::isEquivalent(const TargetID &Other) const {
937 // The processor and feature settings must match exactly
938 if (Arch != Other.Arch || XnackSetting != Other.XnackSetting ||
939 SramEccSetting != Other.SramEccSetting)
940 return false;
941
942 return Triple(getTargetTripleString())
943 .isCompatibleWith(Other: Triple(Other.getTargetTripleString()));
944}
945
946bool TargetID::providesFor(const TargetID &Other) const {
947 // A major-family/generic processor (e.g. amdgpu9) provides for a specific
948 // member of its family (e.g. gfx900), but not the reverse. Otherwise the
949 // processors must match.
950 if (Arch != Other.Arch && Arch != GK_NONE && Other.Arch != GK_NONE) {
951 Triple::SubArchType ThisSubArch = getSubArch(AK: Arch);
952 if (ThisSubArch != getMajorSubArch(X: ThisSubArch) ||
953 ThisSubArch != getMajorSubArch(X: getSubArch(AK: Other.Arch)))
954 return false;
955 }
956
957 if (!featureProvidesFor(Provided: XnackSetting, Requested: Other.XnackSetting) ||
958 !featureProvidesFor(Provided: SramEccSetting, Requested: Other.SramEccSetting))
959 return false;
960
961 return Triple(getTargetTripleString())
962 .isCompatibleWith(Other: Triple(Other.getTargetTripleString()));
963}
964