1a9ac8606Spatrick //===--- TargetID.cpp - Utilities for parsing target ID -------------------===//
2a9ac8606Spatrick //
3a9ac8606Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a9ac8606Spatrick // See https://llvm.org/LICENSE.txt for license information.
5a9ac8606Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a9ac8606Spatrick //
7a9ac8606Spatrick //===----------------------------------------------------------------------===//
8a9ac8606Spatrick
9a9ac8606Spatrick #include "clang/Basic/TargetID.h"
10a9ac8606Spatrick #include "llvm/ADT/SmallSet.h"
11a9ac8606Spatrick #include "llvm/ADT/Triple.h"
12a9ac8606Spatrick #include "llvm/Support/TargetParser.h"
13a9ac8606Spatrick #include "llvm/Support/raw_ostream.h"
14a9ac8606Spatrick #include <map>
15*12c85518Srobert #include <optional>
16a9ac8606Spatrick
17a9ac8606Spatrick namespace clang {
18a9ac8606Spatrick
19*12c85518Srobert static llvm::SmallVector<llvm::StringRef, 4>
getAllPossibleAMDGPUTargetIDFeatures(const llvm::Triple & T,llvm::StringRef Proc)20a9ac8606Spatrick getAllPossibleAMDGPUTargetIDFeatures(const llvm::Triple &T,
21a9ac8606Spatrick llvm::StringRef Proc) {
22a9ac8606Spatrick // Entries in returned vector should be in alphabetical order.
23a9ac8606Spatrick llvm::SmallVector<llvm::StringRef, 4> Ret;
24a9ac8606Spatrick auto ProcKind = T.isAMDGCN() ? llvm::AMDGPU::parseArchAMDGCN(Proc)
25a9ac8606Spatrick : llvm::AMDGPU::parseArchR600(Proc);
26a9ac8606Spatrick if (ProcKind == llvm::AMDGPU::GK_NONE)
27a9ac8606Spatrick return Ret;
28a9ac8606Spatrick auto Features = T.isAMDGCN() ? llvm::AMDGPU::getArchAttrAMDGCN(ProcKind)
29a9ac8606Spatrick : llvm::AMDGPU::getArchAttrR600(ProcKind);
30a9ac8606Spatrick if (Features & llvm::AMDGPU::FEATURE_SRAMECC)
31a9ac8606Spatrick Ret.push_back("sramecc");
32a9ac8606Spatrick if (Features & llvm::AMDGPU::FEATURE_XNACK)
33a9ac8606Spatrick Ret.push_back("xnack");
34a9ac8606Spatrick return Ret;
35a9ac8606Spatrick }
36a9ac8606Spatrick
37*12c85518Srobert llvm::SmallVector<llvm::StringRef, 4>
getAllPossibleTargetIDFeatures(const llvm::Triple & T,llvm::StringRef Processor)38a9ac8606Spatrick getAllPossibleTargetIDFeatures(const llvm::Triple &T,
39a9ac8606Spatrick llvm::StringRef Processor) {
40a9ac8606Spatrick llvm::SmallVector<llvm::StringRef, 4> Ret;
41a9ac8606Spatrick if (T.isAMDGPU())
42a9ac8606Spatrick return getAllPossibleAMDGPUTargetIDFeatures(T, Processor);
43a9ac8606Spatrick return Ret;
44a9ac8606Spatrick }
45a9ac8606Spatrick
46a9ac8606Spatrick /// Returns canonical processor name or empty string if \p Processor is invalid.
getCanonicalProcessorName(const llvm::Triple & T,llvm::StringRef Processor)47a9ac8606Spatrick static llvm::StringRef getCanonicalProcessorName(const llvm::Triple &T,
48a9ac8606Spatrick llvm::StringRef Processor) {
49a9ac8606Spatrick if (T.isAMDGPU())
50a9ac8606Spatrick return llvm::AMDGPU::getCanonicalArchName(T, Processor);
51a9ac8606Spatrick return Processor;
52a9ac8606Spatrick }
53a9ac8606Spatrick
getProcessorFromTargetID(const llvm::Triple & T,llvm::StringRef TargetID)54a9ac8606Spatrick llvm::StringRef getProcessorFromTargetID(const llvm::Triple &T,
55a9ac8606Spatrick llvm::StringRef TargetID) {
56a9ac8606Spatrick auto Split = TargetID.split(':');
57a9ac8606Spatrick return getCanonicalProcessorName(T, Split.first);
58a9ac8606Spatrick }
59a9ac8606Spatrick
60a9ac8606Spatrick // Parse a target ID with format checking only. Do not check whether processor
61a9ac8606Spatrick // name or features are valid for the processor.
62a9ac8606Spatrick //
63a9ac8606Spatrick // A target ID is a processor name followed by a list of target features
64a9ac8606Spatrick // delimited by colon. Each target feature is a string post-fixed by a plus
65a9ac8606Spatrick // or minus sign, e.g. gfx908:sramecc+:xnack-.
66*12c85518Srobert static std::optional<llvm::StringRef>
parseTargetIDWithFormatCheckingOnly(llvm::StringRef TargetID,llvm::StringMap<bool> * FeatureMap)67a9ac8606Spatrick parseTargetIDWithFormatCheckingOnly(llvm::StringRef TargetID,
68a9ac8606Spatrick llvm::StringMap<bool> *FeatureMap) {
69a9ac8606Spatrick llvm::StringRef Processor;
70a9ac8606Spatrick
71a9ac8606Spatrick if (TargetID.empty())
72a9ac8606Spatrick return llvm::StringRef();
73a9ac8606Spatrick
74a9ac8606Spatrick auto Split = TargetID.split(':');
75a9ac8606Spatrick Processor = Split.first;
76a9ac8606Spatrick if (Processor.empty())
77*12c85518Srobert return std::nullopt;
78a9ac8606Spatrick
79a9ac8606Spatrick auto Features = Split.second;
80a9ac8606Spatrick if (Features.empty())
81a9ac8606Spatrick return Processor;
82a9ac8606Spatrick
83a9ac8606Spatrick llvm::StringMap<bool> LocalFeatureMap;
84a9ac8606Spatrick if (!FeatureMap)
85a9ac8606Spatrick FeatureMap = &LocalFeatureMap;
86a9ac8606Spatrick
87a9ac8606Spatrick while (!Features.empty()) {
88a9ac8606Spatrick auto Splits = Features.split(':');
89a9ac8606Spatrick auto Sign = Splits.first.back();
90a9ac8606Spatrick auto Feature = Splits.first.drop_back();
91a9ac8606Spatrick if (Sign != '+' && Sign != '-')
92*12c85518Srobert return std::nullopt;
93a9ac8606Spatrick bool IsOn = Sign == '+';
94a9ac8606Spatrick auto Loc = FeatureMap->find(Feature);
95a9ac8606Spatrick // Each feature can only show up at most once in target ID.
96a9ac8606Spatrick if (Loc != FeatureMap->end())
97*12c85518Srobert return std::nullopt;
98a9ac8606Spatrick (*FeatureMap)[Feature] = IsOn;
99a9ac8606Spatrick Features = Splits.second;
100a9ac8606Spatrick }
101a9ac8606Spatrick return Processor;
102a9ac8606Spatrick }
103a9ac8606Spatrick
104*12c85518Srobert std::optional<llvm::StringRef>
parseTargetID(const llvm::Triple & T,llvm::StringRef TargetID,llvm::StringMap<bool> * FeatureMap)105a9ac8606Spatrick parseTargetID(const llvm::Triple &T, llvm::StringRef TargetID,
106a9ac8606Spatrick llvm::StringMap<bool> *FeatureMap) {
107a9ac8606Spatrick auto OptionalProcessor =
108a9ac8606Spatrick parseTargetIDWithFormatCheckingOnly(TargetID, FeatureMap);
109a9ac8606Spatrick
110a9ac8606Spatrick if (!OptionalProcessor)
111*12c85518Srobert return std::nullopt;
112a9ac8606Spatrick
113*12c85518Srobert llvm::StringRef Processor = getCanonicalProcessorName(T, *OptionalProcessor);
114a9ac8606Spatrick if (Processor.empty())
115*12c85518Srobert return std::nullopt;
116a9ac8606Spatrick
117a9ac8606Spatrick llvm::SmallSet<llvm::StringRef, 4> AllFeatures;
118a9ac8606Spatrick for (auto &&F : getAllPossibleTargetIDFeatures(T, Processor))
119a9ac8606Spatrick AllFeatures.insert(F);
120a9ac8606Spatrick
121a9ac8606Spatrick for (auto &&F : *FeatureMap)
122a9ac8606Spatrick if (!AllFeatures.count(F.first()))
123*12c85518Srobert return std::nullopt;
124a9ac8606Spatrick
125a9ac8606Spatrick return Processor;
126a9ac8606Spatrick }
127a9ac8606Spatrick
128a9ac8606Spatrick // A canonical target ID is a target ID containing a canonical processor name
129a9ac8606Spatrick // and features in alphabetical order.
getCanonicalTargetID(llvm::StringRef Processor,const llvm::StringMap<bool> & Features)130a9ac8606Spatrick std::string getCanonicalTargetID(llvm::StringRef Processor,
131a9ac8606Spatrick const llvm::StringMap<bool> &Features) {
132a9ac8606Spatrick std::string TargetID = Processor.str();
133a9ac8606Spatrick std::map<const llvm::StringRef, bool> OrderedMap;
134a9ac8606Spatrick for (const auto &F : Features)
135a9ac8606Spatrick OrderedMap[F.first()] = F.second;
136a9ac8606Spatrick for (auto F : OrderedMap)
137a9ac8606Spatrick TargetID = TargetID + ':' + F.first.str() + (F.second ? "+" : "-");
138a9ac8606Spatrick return TargetID;
139a9ac8606Spatrick }
140a9ac8606Spatrick
141a9ac8606Spatrick // For a specific processor, a feature either shows up in all target IDs, or
142a9ac8606Spatrick // does not show up in any target IDs. Otherwise the target ID combination
143a9ac8606Spatrick // is invalid.
144*12c85518Srobert std::optional<std::pair<llvm::StringRef, llvm::StringRef>>
getConflictTargetIDCombination(const std::set<llvm::StringRef> & TargetIDs)145a9ac8606Spatrick getConflictTargetIDCombination(const std::set<llvm::StringRef> &TargetIDs) {
146a9ac8606Spatrick struct Info {
147a9ac8606Spatrick llvm::StringRef TargetID;
148a9ac8606Spatrick llvm::StringMap<bool> Features;
149a9ac8606Spatrick };
150a9ac8606Spatrick llvm::StringMap<Info> FeatureMap;
151a9ac8606Spatrick for (auto &&ID : TargetIDs) {
152a9ac8606Spatrick llvm::StringMap<bool> Features;
153*12c85518Srobert llvm::StringRef Proc = *parseTargetIDWithFormatCheckingOnly(ID, &Features);
154a9ac8606Spatrick auto Loc = FeatureMap.find(Proc);
155a9ac8606Spatrick if (Loc == FeatureMap.end())
156a9ac8606Spatrick FeatureMap[Proc] = Info{ID, Features};
157a9ac8606Spatrick else {
158a9ac8606Spatrick auto &ExistingFeatures = Loc->second.Features;
159a9ac8606Spatrick if (llvm::any_of(Features, [&](auto &F) {
160a9ac8606Spatrick return ExistingFeatures.count(F.first()) == 0;
161a9ac8606Spatrick }))
162a9ac8606Spatrick return std::make_pair(Loc->second.TargetID, ID);
163a9ac8606Spatrick }
164a9ac8606Spatrick }
165*12c85518Srobert return std::nullopt;
166*12c85518Srobert }
167*12c85518Srobert
isCompatibleTargetID(llvm::StringRef Provided,llvm::StringRef Requested)168*12c85518Srobert bool isCompatibleTargetID(llvm::StringRef Provided, llvm::StringRef Requested) {
169*12c85518Srobert llvm::StringMap<bool> ProvidedFeatures, RequestedFeatures;
170*12c85518Srobert llvm::StringRef ProvidedProc =
171*12c85518Srobert *parseTargetIDWithFormatCheckingOnly(Provided, &ProvidedFeatures);
172*12c85518Srobert llvm::StringRef RequestedProc =
173*12c85518Srobert *parseTargetIDWithFormatCheckingOnly(Requested, &RequestedFeatures);
174*12c85518Srobert if (ProvidedProc != RequestedProc)
175*12c85518Srobert return false;
176*12c85518Srobert for (const auto &F : ProvidedFeatures) {
177*12c85518Srobert auto Loc = RequestedFeatures.find(F.first());
178*12c85518Srobert // The default (unspecified) value of a feature is 'All', which can match
179*12c85518Srobert // either 'On' or 'Off'.
180*12c85518Srobert if (Loc == RequestedFeatures.end())
181*12c85518Srobert return false;
182*12c85518Srobert // If a feature is specified, it must have exact match.
183*12c85518Srobert if (Loc->second != F.second)
184*12c85518Srobert return false;
185*12c85518Srobert }
186*12c85518Srobert return true;
187a9ac8606Spatrick }
188a9ac8606Spatrick
189a9ac8606Spatrick } // namespace clang
190