xref: /openbsd-src/gnu/llvm/clang/lib/Basic/TargetID.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
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