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