1 //===--- TargetRegistry.cpp - Target registration -------------------------===// 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 "llvm/MC/TargetRegistry.h" 10 #include "llvm/ADT/STLExtras.h" 11 #include "llvm/ADT/StringRef.h" 12 #include "llvm/Support/raw_ostream.h" 13 #include <cassert> 14 #include <vector> 15 using namespace llvm; 16 17 // Clients are responsible for avoid race conditions in registration. 18 static Target *FirstTarget = nullptr; 19 20 iterator_range<TargetRegistry::iterator> TargetRegistry::targets() { 21 return make_range(iterator(FirstTarget), iterator()); 22 } 23 24 const Target *TargetRegistry::lookupTarget(const std::string &ArchName, 25 Triple &TheTriple, 26 std::string &Error) { 27 // Allocate target machine. First, check whether the user has explicitly 28 // specified an architecture to compile for. If so we have to look it up by 29 // name, because it might be a backend that has no mapping to a target triple. 30 const Target *TheTarget = nullptr; 31 if (!ArchName.empty()) { 32 auto I = find_if(targets(), 33 [&](const Target &T) { return ArchName == T.getName(); }); 34 35 if (I == targets().end()) { 36 Error = "invalid target '" + ArchName + "'.\n"; 37 return nullptr; 38 } 39 40 TheTarget = &*I; 41 42 // Adjust the triple to match (if known), otherwise stick with the 43 // given triple. 44 Triple::ArchType Type = Triple::getArchTypeForLLVMName(ArchName); 45 if (Type != Triple::UnknownArch) 46 TheTriple.setArch(Type); 47 } else { 48 // Get the target specific parser. 49 std::string TempError; 50 TheTarget = TargetRegistry::lookupTarget(TheTriple.getTriple(), TempError); 51 if (!TheTarget) { 52 Error = "unable to get target for '" 53 + TheTriple.getTriple() 54 + "', see --version and --triple.\n"; 55 return nullptr; 56 } 57 } 58 59 return TheTarget; 60 } 61 62 const Target *TargetRegistry::lookupTarget(const std::string &TT, 63 std::string &Error) { 64 // Provide special warning when no targets are initialized. 65 if (targets().begin() == targets().end()) { 66 Error = "Unable to find target for this triple (no targets are registered)"; 67 return nullptr; 68 } 69 Triple::ArchType Arch = Triple(TT).getArch(); 70 auto ArchMatch = [&](const Target &T) { return T.ArchMatchFn(Arch); }; 71 auto I = find_if(targets(), ArchMatch); 72 73 if (I == targets().end()) { 74 Error = "No available targets are compatible with triple \"" + TT + "\""; 75 return nullptr; 76 } 77 78 auto J = std::find_if(std::next(I), targets().end(), ArchMatch); 79 if (J != targets().end()) { 80 Error = std::string("Cannot choose between targets \"") + I->Name + 81 "\" and \"" + J->Name + "\""; 82 return nullptr; 83 } 84 85 return &*I; 86 } 87 88 void TargetRegistry::RegisterTarget(Target &T, const char *Name, 89 const char *ShortDesc, 90 const char *BackendName, 91 Target::ArchMatchFnTy ArchMatchFn, 92 bool HasJIT) { 93 assert(Name && ShortDesc && ArchMatchFn && 94 "Missing required target information!"); 95 96 // Check if this target has already been initialized, we allow this as a 97 // convenience to some clients. 98 if (T.Name) 99 return; 100 101 // Add to the list of targets. 102 T.Next = FirstTarget; 103 FirstTarget = &T; 104 105 T.Name = Name; 106 T.ShortDesc = ShortDesc; 107 T.BackendName = BackendName; 108 T.ArchMatchFn = ArchMatchFn; 109 T.HasJIT = HasJIT; 110 } 111 112 static int TargetArraySortFn(const std::pair<StringRef, const Target *> *LHS, 113 const std::pair<StringRef, const Target *> *RHS) { 114 return LHS->first.compare(RHS->first); 115 } 116 117 void TargetRegistry::printRegisteredTargetsForVersion(raw_ostream &OS) { 118 std::vector<std::pair<StringRef, const Target*> > Targets; 119 size_t Width = 0; 120 for (const auto &T : TargetRegistry::targets()) { 121 Targets.push_back(std::make_pair(T.getName(), &T)); 122 Width = std::max(Width, Targets.back().first.size()); 123 } 124 array_pod_sort(Targets.begin(), Targets.end(), TargetArraySortFn); 125 126 OS << " Registered Targets:\n"; 127 for (const auto &Target : Targets) { 128 OS << " " << Target.first; 129 OS.indent(Width - Target.first.size()) 130 << " - " << Target.second->getShortDescription() << '\n'; 131 } 132 if (Targets.empty()) 133 OS << " (none)\n"; 134 } 135