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