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(x: iterator(FirstTarget), y: iterator()); |
22 | } |
23 | |
24 | const Target *TargetRegistry::lookupTarget(StringRef 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(Range: targets(), |
33 | P: [&](const Target &T) { return ArchName == T.getName(); }); |
34 | |
35 | if (I == targets().end()) { |
36 | Error = ("invalid target '" + ArchName + "'.\n" ).str(); |
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(Str: ArchName); |
45 | if (Type != Triple::UnknownArch) |
46 | TheTriple.setArch(Kind: Type); |
47 | } else { |
48 | // Get the target specific parser. |
49 | std::string TempError; |
50 | TheTarget = TargetRegistry::lookupTarget(Triple: TheTriple.getTriple(), Error&: TempError); |
51 | if (!TheTarget) { |
52 | Error = "unable to get target for '" + TheTriple.getTriple() + |
53 | "', see --version and --triple." ; |
54 | return nullptr; |
55 | } |
56 | } |
57 | |
58 | return TheTarget; |
59 | } |
60 | |
61 | const Target *TargetRegistry::lookupTarget(StringRef TT, std::string &Error) { |
62 | // Provide special warning when no targets are initialized. |
63 | if (targets().begin() == targets().end()) { |
64 | Error = "Unable to find target for this triple (no targets are registered)" ; |
65 | return nullptr; |
66 | } |
67 | Triple::ArchType Arch = Triple(TT).getArch(); |
68 | auto ArchMatch = [&](const Target &T) { return T.ArchMatchFn(Arch); }; |
69 | auto I = find_if(Range: targets(), P: ArchMatch); |
70 | |
71 | if (I == targets().end()) { |
72 | Error = ("No available targets are compatible with triple \"" + TT + "\"" ) |
73 | .str(); |
74 | return nullptr; |
75 | } |
76 | |
77 | auto J = std::find_if(first: std::next(x: I), last: targets().end(), pred: ArchMatch); |
78 | if (J != targets().end()) { |
79 | Error = std::string("Cannot choose between targets \"" ) + I->Name + |
80 | "\" and \"" + J->Name + "\"" ; |
81 | return nullptr; |
82 | } |
83 | |
84 | return &*I; |
85 | } |
86 | |
87 | void TargetRegistry::RegisterTarget(Target &T, const char *Name, |
88 | const char *ShortDesc, |
89 | const char *BackendName, |
90 | Target::ArchMatchFnTy ArchMatchFn, |
91 | bool HasJIT) { |
92 | assert(Name && ShortDesc && ArchMatchFn && |
93 | "Missing required target information!" ); |
94 | |
95 | // Check if this target has already been initialized, we allow this as a |
96 | // convenience to some clients. |
97 | if (T.Name) |
98 | return; |
99 | |
100 | // Add to the list of targets. |
101 | T.Next = FirstTarget; |
102 | FirstTarget = &T; |
103 | |
104 | T.Name = Name; |
105 | T.ShortDesc = ShortDesc; |
106 | T.BackendName = BackendName; |
107 | T.ArchMatchFn = ArchMatchFn; |
108 | T.HasJIT = HasJIT; |
109 | } |
110 | |
111 | static int TargetArraySortFn(const std::pair<StringRef, const Target *> *LHS, |
112 | const std::pair<StringRef, const Target *> *RHS) { |
113 | return LHS->first.compare(RHS: RHS->first); |
114 | } |
115 | |
116 | void TargetRegistry::printRegisteredTargetsForVersion(raw_ostream &OS) { |
117 | std::vector<std::pair<StringRef, const Target*> > Targets; |
118 | size_t Width = 0; |
119 | for (const auto &T : TargetRegistry::targets()) { |
120 | Targets.push_back(x: std::make_pair(x: T.getName(), y: &T)); |
121 | Width = std::max(a: Width, b: Targets.back().first.size()); |
122 | } |
123 | array_pod_sort(Start: Targets.begin(), End: Targets.end(), Compare: TargetArraySortFn); |
124 | |
125 | OS << "\n" ; |
126 | OS << " Registered Targets:\n" ; |
127 | for (const auto &Target : Targets) { |
128 | OS << " " << Target.first; |
129 | OS.indent(NumSpaces: Width - Target.first.size()) |
130 | << " - " << Target.second->getShortDescription() << '\n'; |
131 | } |
132 | if (Targets.empty()) |
133 | OS << " (none)\n" ; |
134 | } |
135 | |