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