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/STLExtras.h" 11 #include "llvm/ADT/SmallSet.h" 12 #include "llvm/Support/raw_ostream.h" 13 #include "llvm/TargetParser/TargetParser.h" 14 #include "llvm/TargetParser/Triple.h" 15 #include <map> 16 #include <optional> 17 18 namespace clang { 19 20 static llvm::SmallVector<llvm::StringRef, 4> 21 getAllPossibleAMDGPUTargetIDFeatures(const llvm::Triple &T, 22 llvm::StringRef Proc) { 23 // Entries in returned vector should be in alphabetical order. 24 llvm::SmallVector<llvm::StringRef, 4> Ret; 25 auto ProcKind = T.isAMDGCN() ? llvm::AMDGPU::parseArchAMDGCN(Proc) 26 : llvm::AMDGPU::parseArchR600(Proc); 27 if (ProcKind == llvm::AMDGPU::GK_NONE) 28 return Ret; 29 auto Features = T.isAMDGCN() ? llvm::AMDGPU::getArchAttrAMDGCN(ProcKind) 30 : llvm::AMDGPU::getArchAttrR600(ProcKind); 31 if (Features & llvm::AMDGPU::FEATURE_SRAMECC) 32 Ret.push_back("sramecc"); 33 if (Features & llvm::AMDGPU::FEATURE_XNACK) 34 Ret.push_back("xnack"); 35 return Ret; 36 } 37 38 llvm::SmallVector<llvm::StringRef, 4> 39 getAllPossibleTargetIDFeatures(const llvm::Triple &T, 40 llvm::StringRef Processor) { 41 llvm::SmallVector<llvm::StringRef, 4> Ret; 42 if (T.isAMDGPU()) 43 return getAllPossibleAMDGPUTargetIDFeatures(T, Processor); 44 return Ret; 45 } 46 47 /// Returns canonical processor name or empty string if \p Processor is invalid. 48 static llvm::StringRef getCanonicalProcessorName(const llvm::Triple &T, 49 llvm::StringRef Processor) { 50 if (T.isAMDGPU()) 51 return llvm::AMDGPU::getCanonicalArchName(T, Processor); 52 return Processor; 53 } 54 55 llvm::StringRef getProcessorFromTargetID(const llvm::Triple &T, 56 llvm::StringRef TargetID) { 57 auto Split = TargetID.split(':'); 58 return getCanonicalProcessorName(T, Split.first); 59 } 60 61 // Parse a target ID with format checking only. Do not check whether processor 62 // name or features are valid for the processor. 63 // 64 // A target ID is a processor name followed by a list of target features 65 // delimited by colon. Each target feature is a string post-fixed by a plus 66 // or minus sign, e.g. gfx908:sramecc+:xnack-. 67 static std::optional<llvm::StringRef> 68 parseTargetIDWithFormatCheckingOnly(llvm::StringRef TargetID, 69 llvm::StringMap<bool> *FeatureMap) { 70 llvm::StringRef Processor; 71 72 if (TargetID.empty()) 73 return llvm::StringRef(); 74 75 auto Split = TargetID.split(':'); 76 Processor = Split.first; 77 if (Processor.empty()) 78 return std::nullopt; 79 80 auto Features = Split.second; 81 if (Features.empty()) 82 return Processor; 83 84 llvm::StringMap<bool> LocalFeatureMap; 85 if (!FeatureMap) 86 FeatureMap = &LocalFeatureMap; 87 88 while (!Features.empty()) { 89 auto Splits = Features.split(':'); 90 auto Sign = Splits.first.back(); 91 auto Feature = Splits.first.drop_back(); 92 if (Sign != '+' && Sign != '-') 93 return std::nullopt; 94 bool IsOn = Sign == '+'; 95 // Each feature can only show up at most once in target ID. 96 if (!FeatureMap->try_emplace(Feature, IsOn).second) 97 return std::nullopt; 98 Features = Splits.second; 99 } 100 return Processor; 101 } 102 103 std::optional<llvm::StringRef> 104 parseTargetID(const llvm::Triple &T, llvm::StringRef TargetID, 105 llvm::StringMap<bool> *FeatureMap) { 106 auto OptionalProcessor = 107 parseTargetIDWithFormatCheckingOnly(TargetID, FeatureMap); 108 109 if (!OptionalProcessor) 110 return std::nullopt; 111 112 llvm::StringRef Processor = getCanonicalProcessorName(T, *OptionalProcessor); 113 if (Processor.empty()) 114 return std::nullopt; 115 116 llvm::SmallSet<llvm::StringRef, 4> AllFeatures; 117 for (auto &&F : getAllPossibleTargetIDFeatures(T, Processor)) 118 AllFeatures.insert(F); 119 120 for (auto &&F : *FeatureMap) 121 if (!AllFeatures.count(F.first())) 122 return std::nullopt; 123 124 return Processor; 125 } 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 const llvm::StringMap<bool> &Features) { 131 std::string TargetID = Processor.str(); 132 std::map<const llvm::StringRef, bool> OrderedMap; 133 for (const auto &F : Features) 134 OrderedMap[F.first()] = F.second; 135 for (const auto &F : OrderedMap) 136 TargetID = TargetID + ':' + F.first.str() + (F.second ? "+" : "-"); 137 return TargetID; 138 } 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 std::optional<std::pair<llvm::StringRef, llvm::StringRef>> 144 getConflictTargetIDCombination(const std::set<llvm::StringRef> &TargetIDs) { 145 struct Info { 146 llvm::StringRef TargetID; 147 llvm::StringMap<bool> Features; 148 Info(llvm::StringRef TargetID, const llvm::StringMap<bool> &Features) 149 : TargetID(TargetID), Features(Features) {} 150 }; 151 llvm::StringMap<Info> FeatureMap; 152 for (auto &&ID : TargetIDs) { 153 llvm::StringMap<bool> Features; 154 llvm::StringRef Proc = *parseTargetIDWithFormatCheckingOnly(ID, &Features); 155 auto [Loc, Inserted] = FeatureMap.try_emplace(Proc, ID, Features); 156 if (!Inserted) { 157 auto &ExistingFeatures = Loc->second.Features; 158 if (llvm::any_of(Features, [&](auto &F) { 159 return ExistingFeatures.count(F.first()) == 0; 160 })) 161 return std::make_pair(Loc->second.TargetID, ID); 162 } 163 } 164 return std::nullopt; 165 } 166 167 bool isCompatibleTargetID(llvm::StringRef Provided, llvm::StringRef Requested) { 168 llvm::StringMap<bool> ProvidedFeatures, RequestedFeatures; 169 llvm::StringRef ProvidedProc = 170 *parseTargetIDWithFormatCheckingOnly(Provided, &ProvidedFeatures); 171 llvm::StringRef RequestedProc = 172 *parseTargetIDWithFormatCheckingOnly(Requested, &RequestedFeatures); 173 if (ProvidedProc != RequestedProc) 174 return false; 175 for (const auto &F : ProvidedFeatures) { 176 auto Loc = RequestedFeatures.find(F.first()); 177 // The default (unspecified) value of a feature is 'All', which can match 178 // either 'On' or 'Off'. 179 if (Loc == RequestedFeatures.end()) 180 return false; 181 // If a feature is specified, it must have exact match. 182 if (Loc->second != F.second) 183 return false; 184 } 185 return true; 186 } 187 188 } // namespace clang 189