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