| 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 | |