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