17546b29eSYaxun (Sam) Liu //===--- TargetID.cpp - Utilities for parsing target ID -------------------===// 27546b29eSYaxun (Sam) Liu // 37546b29eSYaxun (Sam) Liu // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 47546b29eSYaxun (Sam) Liu // See https://llvm.org/LICENSE.txt for license information. 57546b29eSYaxun (Sam) Liu // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 67546b29eSYaxun (Sam) Liu // 77546b29eSYaxun (Sam) Liu //===----------------------------------------------------------------------===// 87546b29eSYaxun (Sam) Liu 97546b29eSYaxun (Sam) Liu #include "clang/Basic/TargetID.h" 10ce6c236cSVictor Campos #include "llvm/ADT/STLExtras.h" 117546b29eSYaxun (Sam) Liu #include "llvm/ADT/SmallSet.h" 127546b29eSYaxun (Sam) Liu #include "llvm/Support/raw_ostream.h" 138e3d7cf5SArchibald Elliott #include "llvm/TargetParser/TargetParser.h" 1462c7f035SArchibald Elliott #include "llvm/TargetParser/Triple.h" 157546b29eSYaxun (Sam) Liu #include <map> 16defa6eecSKazu Hirata #include <optional> 177546b29eSYaxun (Sam) Liu 187546b29eSYaxun (Sam) Liu namespace clang { 197546b29eSYaxun (Sam) Liu 20ee3f557aSKazu Hirata static llvm::SmallVector<llvm::StringRef, 4> 217546b29eSYaxun (Sam) Liu getAllPossibleAMDGPUTargetIDFeatures(const llvm::Triple &T, 227546b29eSYaxun (Sam) Liu llvm::StringRef Proc) { 237546b29eSYaxun (Sam) Liu // Entries in returned vector should be in alphabetical order. 247546b29eSYaxun (Sam) Liu llvm::SmallVector<llvm::StringRef, 4> Ret; 257546b29eSYaxun (Sam) Liu auto ProcKind = T.isAMDGCN() ? llvm::AMDGPU::parseArchAMDGCN(Proc) 267546b29eSYaxun (Sam) Liu : llvm::AMDGPU::parseArchR600(Proc); 277546b29eSYaxun (Sam) Liu if (ProcKind == llvm::AMDGPU::GK_NONE) 287546b29eSYaxun (Sam) Liu return Ret; 297546b29eSYaxun (Sam) Liu auto Features = T.isAMDGCN() ? llvm::AMDGPU::getArchAttrAMDGCN(ProcKind) 307546b29eSYaxun (Sam) Liu : llvm::AMDGPU::getArchAttrR600(ProcKind); 3140ad476aSYaxun (Sam) Liu if (Features & llvm::AMDGPU::FEATURE_SRAMECC) 3240ad476aSYaxun (Sam) Liu Ret.push_back("sramecc"); 337546b29eSYaxun (Sam) Liu if (Features & llvm::AMDGPU::FEATURE_XNACK) 347546b29eSYaxun (Sam) Liu Ret.push_back("xnack"); 357546b29eSYaxun (Sam) Liu return Ret; 367546b29eSYaxun (Sam) Liu } 377546b29eSYaxun (Sam) Liu 38ee3f557aSKazu Hirata llvm::SmallVector<llvm::StringRef, 4> 397546b29eSYaxun (Sam) Liu getAllPossibleTargetIDFeatures(const llvm::Triple &T, 407546b29eSYaxun (Sam) Liu llvm::StringRef Processor) { 417546b29eSYaxun (Sam) Liu llvm::SmallVector<llvm::StringRef, 4> Ret; 427546b29eSYaxun (Sam) Liu if (T.isAMDGPU()) 437546b29eSYaxun (Sam) Liu return getAllPossibleAMDGPUTargetIDFeatures(T, Processor); 447546b29eSYaxun (Sam) Liu return Ret; 457546b29eSYaxun (Sam) Liu } 467546b29eSYaxun (Sam) Liu 477546b29eSYaxun (Sam) Liu /// Returns canonical processor name or empty string if \p Processor is invalid. 487546b29eSYaxun (Sam) Liu static llvm::StringRef getCanonicalProcessorName(const llvm::Triple &T, 497546b29eSYaxun (Sam) Liu llvm::StringRef Processor) { 507546b29eSYaxun (Sam) Liu if (T.isAMDGPU()) 517546b29eSYaxun (Sam) Liu return llvm::AMDGPU::getCanonicalArchName(T, Processor); 527546b29eSYaxun (Sam) Liu return Processor; 537546b29eSYaxun (Sam) Liu } 547546b29eSYaxun (Sam) Liu 557546b29eSYaxun (Sam) Liu llvm::StringRef getProcessorFromTargetID(const llvm::Triple &T, 567546b29eSYaxun (Sam) Liu llvm::StringRef TargetID) { 577546b29eSYaxun (Sam) Liu auto Split = TargetID.split(':'); 587546b29eSYaxun (Sam) Liu return getCanonicalProcessorName(T, Split.first); 597546b29eSYaxun (Sam) Liu } 607546b29eSYaxun (Sam) Liu 617546b29eSYaxun (Sam) Liu // Parse a target ID with format checking only. Do not check whether processor 627546b29eSYaxun (Sam) Liu // name or features are valid for the processor. 637546b29eSYaxun (Sam) Liu // 647546b29eSYaxun (Sam) Liu // A target ID is a processor name followed by a list of target features 657546b29eSYaxun (Sam) Liu // delimited by colon. Each target feature is a string post-fixed by a plus 6640ad476aSYaxun (Sam) Liu // or minus sign, e.g. gfx908:sramecc+:xnack-. 67defa6eecSKazu Hirata static std::optional<llvm::StringRef> 687546b29eSYaxun (Sam) Liu parseTargetIDWithFormatCheckingOnly(llvm::StringRef TargetID, 697546b29eSYaxun (Sam) Liu llvm::StringMap<bool> *FeatureMap) { 707546b29eSYaxun (Sam) Liu llvm::StringRef Processor; 717546b29eSYaxun (Sam) Liu 727546b29eSYaxun (Sam) Liu if (TargetID.empty()) 737546b29eSYaxun (Sam) Liu return llvm::StringRef(); 747546b29eSYaxun (Sam) Liu 757546b29eSYaxun (Sam) Liu auto Split = TargetID.split(':'); 767546b29eSYaxun (Sam) Liu Processor = Split.first; 777546b29eSYaxun (Sam) Liu if (Processor.empty()) 78eeee3feeSKazu Hirata return std::nullopt; 797546b29eSYaxun (Sam) Liu 807546b29eSYaxun (Sam) Liu auto Features = Split.second; 817546b29eSYaxun (Sam) Liu if (Features.empty()) 827546b29eSYaxun (Sam) Liu return Processor; 837546b29eSYaxun (Sam) Liu 847546b29eSYaxun (Sam) Liu llvm::StringMap<bool> LocalFeatureMap; 857546b29eSYaxun (Sam) Liu if (!FeatureMap) 867546b29eSYaxun (Sam) Liu FeatureMap = &LocalFeatureMap; 877546b29eSYaxun (Sam) Liu 887546b29eSYaxun (Sam) Liu while (!Features.empty()) { 897546b29eSYaxun (Sam) Liu auto Splits = Features.split(':'); 907546b29eSYaxun (Sam) Liu auto Sign = Splits.first.back(); 917546b29eSYaxun (Sam) Liu auto Feature = Splits.first.drop_back(); 927546b29eSYaxun (Sam) Liu if (Sign != '+' && Sign != '-') 93eeee3feeSKazu Hirata return std::nullopt; 947546b29eSYaxun (Sam) Liu bool IsOn = Sign == '+'; 957546b29eSYaxun (Sam) Liu // Each feature can only show up at most once in target ID. 96*73683cc1SKazu Hirata if (!FeatureMap->try_emplace(Feature, IsOn).second) 97eeee3feeSKazu Hirata return std::nullopt; 987546b29eSYaxun (Sam) Liu Features = Splits.second; 997546b29eSYaxun (Sam) Liu } 1007546b29eSYaxun (Sam) Liu return Processor; 101cb6cf18fSMartin Storsjö } 1027546b29eSYaxun (Sam) Liu 1039cf4419eSKazu Hirata std::optional<llvm::StringRef> 1047546b29eSYaxun (Sam) Liu parseTargetID(const llvm::Triple &T, llvm::StringRef TargetID, 1057546b29eSYaxun (Sam) Liu llvm::StringMap<bool> *FeatureMap) { 1067546b29eSYaxun (Sam) Liu auto OptionalProcessor = 1077546b29eSYaxun (Sam) Liu parseTargetIDWithFormatCheckingOnly(TargetID, FeatureMap); 1087546b29eSYaxun (Sam) Liu 1097546b29eSYaxun (Sam) Liu if (!OptionalProcessor) 110eeee3feeSKazu Hirata return std::nullopt; 1117546b29eSYaxun (Sam) Liu 112ca4af13eSKazu Hirata llvm::StringRef Processor = getCanonicalProcessorName(T, *OptionalProcessor); 1137546b29eSYaxun (Sam) Liu if (Processor.empty()) 114eeee3feeSKazu Hirata return std::nullopt; 1157546b29eSYaxun (Sam) Liu 1167546b29eSYaxun (Sam) Liu llvm::SmallSet<llvm::StringRef, 4> AllFeatures; 1177546b29eSYaxun (Sam) Liu for (auto &&F : getAllPossibleTargetIDFeatures(T, Processor)) 1187546b29eSYaxun (Sam) Liu AllFeatures.insert(F); 1197546b29eSYaxun (Sam) Liu 1207546b29eSYaxun (Sam) Liu for (auto &&F : *FeatureMap) 1217546b29eSYaxun (Sam) Liu if (!AllFeatures.count(F.first())) 122eeee3feeSKazu Hirata return std::nullopt; 1237546b29eSYaxun (Sam) Liu 1247546b29eSYaxun (Sam) Liu return Processor; 125cb6cf18fSMartin Storsjö } 1267546b29eSYaxun (Sam) Liu 1277546b29eSYaxun (Sam) Liu // A canonical target ID is a target ID containing a canonical processor name 1287546b29eSYaxun (Sam) Liu // and features in alphabetical order. 1297546b29eSYaxun (Sam) Liu std::string getCanonicalTargetID(llvm::StringRef Processor, 1307546b29eSYaxun (Sam) Liu const llvm::StringMap<bool> &Features) { 1317546b29eSYaxun (Sam) Liu std::string TargetID = Processor.str(); 1327546b29eSYaxun (Sam) Liu std::map<const llvm::StringRef, bool> OrderedMap; 1337546b29eSYaxun (Sam) Liu for (const auto &F : Features) 1347546b29eSYaxun (Sam) Liu OrderedMap[F.first()] = F.second; 135e52a8b89SManna, Soumi for (const auto &F : OrderedMap) 1367546b29eSYaxun (Sam) Liu TargetID = TargetID + ':' + F.first.str() + (F.second ? "+" : "-"); 1377546b29eSYaxun (Sam) Liu return TargetID; 1387546b29eSYaxun (Sam) Liu } 1397546b29eSYaxun (Sam) Liu 1407546b29eSYaxun (Sam) Liu // For a specific processor, a feature either shows up in all target IDs, or 1417546b29eSYaxun (Sam) Liu // does not show up in any target IDs. Otherwise the target ID combination 1427546b29eSYaxun (Sam) Liu // is invalid. 1432c5d49cfSFangrui Song std::optional<std::pair<llvm::StringRef, llvm::StringRef>> 1447546b29eSYaxun (Sam) Liu getConflictTargetIDCombination(const std::set<llvm::StringRef> &TargetIDs) { 1457546b29eSYaxun (Sam) Liu struct Info { 1467546b29eSYaxun (Sam) Liu llvm::StringRef TargetID; 1477546b29eSYaxun (Sam) Liu llvm::StringMap<bool> Features; 148*73683cc1SKazu Hirata Info(llvm::StringRef TargetID, const llvm::StringMap<bool> &Features) 149*73683cc1SKazu Hirata : TargetID(TargetID), Features(Features) {} 1507546b29eSYaxun (Sam) Liu }; 1517546b29eSYaxun (Sam) Liu llvm::StringMap<Info> FeatureMap; 1527546b29eSYaxun (Sam) Liu for (auto &&ID : TargetIDs) { 1537546b29eSYaxun (Sam) Liu llvm::StringMap<bool> Features; 154ca4af13eSKazu Hirata llvm::StringRef Proc = *parseTargetIDWithFormatCheckingOnly(ID, &Features); 155*73683cc1SKazu Hirata auto [Loc, Inserted] = FeatureMap.try_emplace(Proc, ID, Features); 156*73683cc1SKazu Hirata if (!Inserted) { 1577546b29eSYaxun (Sam) Liu auto &ExistingFeatures = Loc->second.Features; 1587546b29eSYaxun (Sam) Liu if (llvm::any_of(Features, [&](auto &F) { 1597546b29eSYaxun (Sam) Liu return ExistingFeatures.count(F.first()) == 0; 1607546b29eSYaxun (Sam) Liu })) 1617546b29eSYaxun (Sam) Liu return std::make_pair(Loc->second.TargetID, ID); 1627546b29eSYaxun (Sam) Liu } 1637546b29eSYaxun (Sam) Liu } 164eeee3feeSKazu Hirata return std::nullopt; 1657546b29eSYaxun (Sam) Liu } 1667546b29eSYaxun (Sam) Liu 167844b84afSYaxun (Sam) Liu bool isCompatibleTargetID(llvm::StringRef Provided, llvm::StringRef Requested) { 168844b84afSYaxun (Sam) Liu llvm::StringMap<bool> ProvidedFeatures, RequestedFeatures; 169844b84afSYaxun (Sam) Liu llvm::StringRef ProvidedProc = 170844b84afSYaxun (Sam) Liu *parseTargetIDWithFormatCheckingOnly(Provided, &ProvidedFeatures); 171844b84afSYaxun (Sam) Liu llvm::StringRef RequestedProc = 172844b84afSYaxun (Sam) Liu *parseTargetIDWithFormatCheckingOnly(Requested, &RequestedFeatures); 173844b84afSYaxun (Sam) Liu if (ProvidedProc != RequestedProc) 174844b84afSYaxun (Sam) Liu return false; 175844b84afSYaxun (Sam) Liu for (const auto &F : ProvidedFeatures) { 176844b84afSYaxun (Sam) Liu auto Loc = RequestedFeatures.find(F.first()); 177844b84afSYaxun (Sam) Liu // The default (unspecified) value of a feature is 'All', which can match 178844b84afSYaxun (Sam) Liu // either 'On' or 'Off'. 179844b84afSYaxun (Sam) Liu if (Loc == RequestedFeatures.end()) 180844b84afSYaxun (Sam) Liu return false; 181844b84afSYaxun (Sam) Liu // If a feature is specified, it must have exact match. 182844b84afSYaxun (Sam) Liu if (Loc->second != F.second) 183844b84afSYaxun (Sam) Liu return false; 184844b84afSYaxun (Sam) Liu } 185844b84afSYaxun (Sam) Liu return true; 186844b84afSYaxun (Sam) Liu } 187844b84afSYaxun (Sam) Liu 1887546b29eSYaxun (Sam) Liu } // namespace clang 189