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