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/MC/MCAsmBackend.h" |
13 | #include "llvm/MC/MCCodeEmitter.h" |
14 | #include "llvm/MC/MCContext.h" |
15 | #include "llvm/MC/MCInstPrinter.h" |
16 | #include "llvm/MC/MCObjectStreamer.h" |
17 | #include "llvm/MC/MCObjectWriter.h" |
18 | #include "llvm/Support/raw_ostream.h" |
19 | #include <cassert> |
20 | #include <vector> |
21 | using namespace llvm; |
22 | |
23 | // Clients are responsible for avoid race conditions in registration. |
24 | static Target *FirstTarget = nullptr; |
25 | |
26 | MCStreamer *Target::createMCObjectStreamer( |
27 | const Triple &T, MCContext &Ctx, std::unique_ptr<MCAsmBackend> TAB, |
28 | std::unique_ptr<MCObjectWriter> OW, std::unique_ptr<MCCodeEmitter> Emitter, |
29 | const MCSubtargetInfo &STI) const { |
30 | MCStreamer *S = nullptr; |
31 | switch (T.getObjectFormat()) { |
32 | case Triple::UnknownObjectFormat: |
33 | llvm_unreachable("Unknown object format" ); |
34 | case Triple::COFF: |
35 | assert((T.isOSWindows() || T.isUEFI()) && |
36 | "only Windows and UEFI COFF are supported" ); |
37 | S = COFFStreamerCtorFn(Ctx, std::move(TAB), std::move(OW), |
38 | std::move(Emitter)); |
39 | break; |
40 | case Triple::MachO: |
41 | if (MachOStreamerCtorFn) |
42 | S = MachOStreamerCtorFn(Ctx, std::move(TAB), std::move(OW), |
43 | std::move(Emitter)); |
44 | else |
45 | S = createMachOStreamer(Ctx, TAB: std::move(TAB), OW: std::move(OW), |
46 | CE: std::move(Emitter), DWARFMustBeAtTheEnd: false); |
47 | break; |
48 | case Triple::ELF: |
49 | if (ELFStreamerCtorFn) |
50 | S = ELFStreamerCtorFn(T, Ctx, std::move(TAB), std::move(OW), |
51 | std::move(Emitter)); |
52 | else |
53 | S = createELFStreamer(Ctx, TAB: std::move(TAB), OW: std::move(OW), |
54 | CE: std::move(Emitter)); |
55 | break; |
56 | case Triple::Wasm: |
57 | S = createWasmStreamer(Ctx, TAB: std::move(TAB), OW: std::move(OW), |
58 | CE: std::move(Emitter)); |
59 | break; |
60 | case Triple::GOFF: |
61 | S = createGOFFStreamer(Ctx, TAB: std::move(TAB), OW: std::move(OW), |
62 | CE: std::move(Emitter)); |
63 | break; |
64 | case Triple::XCOFF: |
65 | S = XCOFFStreamerCtorFn(T, Ctx, std::move(TAB), std::move(OW), |
66 | std::move(Emitter)); |
67 | break; |
68 | case Triple::SPIRV: |
69 | S = createSPIRVStreamer(Ctx, TAB: std::move(TAB), OW: std::move(OW), |
70 | CE: std::move(Emitter)); |
71 | break; |
72 | case Triple::DXContainer: |
73 | S = createDXContainerStreamer(Ctx, TAB: std::move(TAB), OW: std::move(OW), |
74 | CE: std::move(Emitter)); |
75 | break; |
76 | } |
77 | if (ObjectTargetStreamerCtorFn) |
78 | ObjectTargetStreamerCtorFn(*S, STI); |
79 | return S; |
80 | } |
81 | |
82 | MCStreamer *Target::createAsmStreamer(MCContext &Ctx, |
83 | std::unique_ptr<formatted_raw_ostream> OS, |
84 | std::unique_ptr<MCInstPrinter> IP, |
85 | std::unique_ptr<MCCodeEmitter> CE, |
86 | std::unique_ptr<MCAsmBackend> TAB) const { |
87 | MCInstPrinter *Printer = IP.get(); |
88 | formatted_raw_ostream &OSRef = *OS; |
89 | MCStreamer *S; |
90 | if (AsmStreamerCtorFn) |
91 | S = AsmStreamerCtorFn(Ctx, std::move(OS), std::move(IP), std::move(CE), |
92 | std::move(TAB)); |
93 | else |
94 | S = llvm::createAsmStreamer(Ctx, OS: std::move(OS), InstPrint: std::move(IP), |
95 | CE: std::move(CE), TAB: std::move(TAB)); |
96 | |
97 | createAsmTargetStreamer(S&: *S, OS&: OSRef, InstPrint: Printer); |
98 | return S; |
99 | } |
100 | |
101 | iterator_range<TargetRegistry::iterator> TargetRegistry::targets() { |
102 | return make_range(x: iterator(FirstTarget), y: iterator()); |
103 | } |
104 | |
105 | const Target *TargetRegistry::lookupTarget(StringRef ArchName, |
106 | Triple &TheTriple, |
107 | std::string &Error) { |
108 | // Allocate target machine. First, check whether the user has explicitly |
109 | // specified an architecture to compile for. If so we have to look it up by |
110 | // name, because it might be a backend that has no mapping to a target triple. |
111 | const Target *TheTarget = nullptr; |
112 | if (!ArchName.empty()) { |
113 | auto I = find_if(Range: targets(), |
114 | P: [&](const Target &T) { return ArchName == T.getName(); }); |
115 | |
116 | if (I == targets().end()) { |
117 | Error = ("invalid target '" + ArchName + "'." ).str(); |
118 | return nullptr; |
119 | } |
120 | |
121 | TheTarget = &*I; |
122 | |
123 | // Adjust the triple to match (if known), otherwise stick with the |
124 | // given triple. |
125 | Triple::ArchType Type = Triple::getArchTypeForLLVMName(Str: ArchName); |
126 | if (Type != Triple::UnknownArch) |
127 | TheTriple.setArch(Kind: Type); |
128 | } else { |
129 | // Get the target specific parser. |
130 | std::string TempError; |
131 | TheTarget = TargetRegistry::lookupTarget(TheTriple, Error&: TempError); |
132 | if (!TheTarget) { |
133 | Error = "unable to get target for '" + TheTriple.getTriple() + |
134 | "', see --version and --triple." ; |
135 | return nullptr; |
136 | } |
137 | } |
138 | |
139 | return TheTarget; |
140 | } |
141 | |
142 | const Target *TargetRegistry::lookupTarget(const Triple &TT, |
143 | std::string &Error) { |
144 | // Provide special warning when no targets are initialized. |
145 | if (targets().begin() == targets().end()) { |
146 | Error = "Unable to find target for this triple (no targets are registered)" ; |
147 | return nullptr; |
148 | } |
149 | Triple::ArchType Arch = TT.getArch(); |
150 | auto ArchMatch = [&](const Target &T) { return T.ArchMatchFn(Arch); }; |
151 | auto I = find_if(Range: targets(), P: ArchMatch); |
152 | |
153 | if (I == targets().end()) { |
154 | Error = |
155 | "No available targets are compatible with triple \"" + TT.str() + "\"" ; |
156 | return nullptr; |
157 | } |
158 | |
159 | auto J = std::find_if(first: std::next(x: I), last: targets().end(), pred: ArchMatch); |
160 | if (J != targets().end()) { |
161 | Error = std::string("Cannot choose between targets \"" ) + I->Name + |
162 | "\" and \"" + J->Name + "\"" ; |
163 | return nullptr; |
164 | } |
165 | |
166 | return &*I; |
167 | } |
168 | |
169 | void TargetRegistry::RegisterTarget(Target &T, const char *Name, |
170 | const char *ShortDesc, |
171 | const char *BackendName, |
172 | Target::ArchMatchFnTy ArchMatchFn, |
173 | bool HasJIT) { |
174 | assert(Name && ShortDesc && ArchMatchFn && |
175 | "Missing required target information!" ); |
176 | |
177 | // Check if this target has already been initialized, we allow this as a |
178 | // convenience to some clients. |
179 | if (T.Name) |
180 | return; |
181 | |
182 | // Add to the list of targets. |
183 | T.Next = FirstTarget; |
184 | FirstTarget = &T; |
185 | |
186 | T.Name = Name; |
187 | T.ShortDesc = ShortDesc; |
188 | T.BackendName = BackendName; |
189 | T.ArchMatchFn = ArchMatchFn; |
190 | T.HasJIT = HasJIT; |
191 | } |
192 | |
193 | static int TargetArraySortFn(const std::pair<StringRef, const Target *> *LHS, |
194 | const std::pair<StringRef, const Target *> *RHS) { |
195 | return LHS->first.compare(RHS: RHS->first); |
196 | } |
197 | |
198 | void TargetRegistry::printRegisteredTargetsForVersion(raw_ostream &OS) { |
199 | std::vector<std::pair<StringRef, const Target*> > Targets; |
200 | size_t Width = 0; |
201 | for (const auto &T : TargetRegistry::targets()) { |
202 | Targets.push_back(x: std::make_pair(x: T.getName(), y: &T)); |
203 | Width = std::max(a: Width, b: Targets.back().first.size()); |
204 | } |
205 | array_pod_sort(Start: Targets.begin(), End: Targets.end(), Compare: TargetArraySortFn); |
206 | |
207 | OS << "\n" ; |
208 | OS << " Registered Targets:\n" ; |
209 | for (const auto &Target : Targets) { |
210 | OS << " " << Target.first; |
211 | OS.indent(NumSpaces: Width - Target.first.size()) |
212 | << " - " << Target.second->getShortDescription() << '\n'; |
213 | } |
214 | if (Targets.empty()) |
215 | OS << " (none)\n" ; |
216 | } |
217 | |