| //===--- TargetRegistry.cpp - Target registration -------------------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm/MC/TargetRegistry.h" | |
| #include "llvm/ADT/STLExtras.h" | |
| #include "llvm/ADT/StringRef.h" | |
| #include "llvm/Support/raw_ostream.h" | |
| #include <cassert> | |
| #include <vector> | |
| using namespace llvm; | |
| // Clients are responsible for avoid race conditions in registration. | |
| static Target *FirstTarget = nullptr; | |
| iterator_range<TargetRegistry::iterator> TargetRegistry::targets() { | |
| return make_range(iterator(FirstTarget), iterator()); | |
| } | |
| const Target *TargetRegistry::lookupTarget(const std::string &ArchName, | |
| Triple &TheTriple, | |
| std::string &Error) { | |
| // Allocate target machine. First, check whether the user has explicitly | |
| // specified an architecture to compile for. If so we have to look it up by | |
| // name, because it might be a backend that has no mapping to a target triple. | |
| const Target *TheTarget = nullptr; | |
| if (!ArchName.empty()) { | |
| auto I = find_if(targets(), | |
| [&](const Target &T) { return ArchName == T.getName(); }); | |
| if (I == targets().end()) { | |
| Error = "invalid target '" + ArchName + "'.\n"; | |
| return nullptr; | |
| } | |
| TheTarget = &*I; | |
| // Adjust the triple to match (if known), otherwise stick with the | |
| // given triple. | |
| Triple::ArchType Type = Triple::getArchTypeForLLVMName(ArchName); | |
| if (Type != Triple::UnknownArch) | |
| TheTriple.setArch(Type); | |
| } else { | |
| // Get the target specific parser. | |
| std::string TempError; | |
| TheTarget = TargetRegistry::lookupTarget(TheTriple.getTriple(), TempError); | |
| if (!TheTarget) { | |
| Error = "unable to get target for '" | |
| + TheTriple.getTriple() | |
| + "', see --version and --triple.\n"; | |
| return nullptr; | |
| } | |
| } | |
| return TheTarget; | |
| } | |
| const Target *TargetRegistry::lookupTarget(const std::string &TT, | |
| std::string &Error) { | |
| // Provide special warning when no targets are initialized. | |
| if (targets().begin() == targets().end()) { | |
| Error = "Unable to find target for this triple (no targets are registered)"; | |
| return nullptr; | |
| } | |
| Triple::ArchType Arch = Triple(TT).getArch(); | |
| auto ArchMatch = [&](const Target &T) { return T.ArchMatchFn(Arch); }; | |
| auto I = find_if(targets(), ArchMatch); | |
| if (I == targets().end()) { | |
| Error = "No available targets are compatible with triple \"" + TT + "\""; | |
| return nullptr; | |
| } | |
| auto J = std::find_if(std::next(I), targets().end(), ArchMatch); | |
| if (J != targets().end()) { | |
| Error = std::string("Cannot choose between targets \"") + I->Name + | |
| "\" and \"" + J->Name + "\""; | |
| return nullptr; | |
| } | |
| return &*I; | |
| } | |
| void TargetRegistry::RegisterTarget(Target &T, const char *Name, | |
| const char *ShortDesc, | |
| const char *BackendName, | |
| Target::ArchMatchFnTy ArchMatchFn, | |
| bool HasJIT) { | |
| assert(Name && ShortDesc && ArchMatchFn && | |
| "Missing required target information!"); | |
| // Check if this target has already been initialized, we allow this as a | |
| // convenience to some clients. | |
| if (T.Name) | |
| return; | |
| // Add to the list of targets. | |
| T.Next = FirstTarget; | |
| FirstTarget = &T; | |
| T.Name = Name; | |
| T.ShortDesc = ShortDesc; | |
| T.BackendName = BackendName; | |
| T.ArchMatchFn = ArchMatchFn; | |
| T.HasJIT = HasJIT; | |
| } | |
| static int TargetArraySortFn(const std::pair<StringRef, const Target *> *LHS, | |
| const std::pair<StringRef, const Target *> *RHS) { | |
| return LHS->first.compare(RHS->first); | |
| } | |
| void TargetRegistry::printRegisteredTargetsForVersion(raw_ostream &OS) { | |
| std::vector<std::pair<StringRef, const Target*> > Targets; | |
| size_t Width = 0; | |
| for (const auto &T : TargetRegistry::targets()) { | |
| Targets.push_back(std::make_pair(T.getName(), &T)); | |
| Width = std::max(Width, Targets.back().first.size()); | |
| } | |
| array_pod_sort(Targets.begin(), Targets.end(), TargetArraySortFn); | |
| OS << "\n"; | |
| OS << " Registered Targets:\n"; | |
| for (const auto &Target : Targets) { | |
| OS << " " << Target.first; | |
| OS.indent(Width - Target.first.size()) | |
| << " - " << Target.second->getShortDescription() << '\n'; | |
| } | |
| if (Targets.empty()) | |
| OS << " (none)\n"; | |
| } |