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