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