189b57061SReid Kleckner //===--- TargetRegistry.cpp - Target registration -------------------------===// 289b57061SReid Kleckner // 389b57061SReid Kleckner // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 489b57061SReid Kleckner // See https://llvm.org/LICENSE.txt for license information. 589b57061SReid Kleckner // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 689b57061SReid Kleckner // 789b57061SReid Kleckner //===----------------------------------------------------------------------===// 889b57061SReid Kleckner 989b57061SReid Kleckner #include "llvm/MC/TargetRegistry.h" 1089b57061SReid Kleckner #include "llvm/ADT/STLExtras.h" 1189b57061SReid Kleckner #include "llvm/ADT/StringRef.h" 12d69eb7b7SFangrui Song #include "llvm/MC/MCAsmBackend.h" 13d69eb7b7SFangrui Song #include "llvm/MC/MCCodeEmitter.h" 149e69e6b8SFangrui Song #include "llvm/MC/MCContext.h" 15d69eb7b7SFangrui Song #include "llvm/MC/MCObjectStreamer.h" 16d69eb7b7SFangrui Song #include "llvm/MC/MCObjectWriter.h" 1789b57061SReid Kleckner #include "llvm/Support/raw_ostream.h" 1889b57061SReid Kleckner #include <cassert> 1989b57061SReid Kleckner #include <vector> 2089b57061SReid Kleckner using namespace llvm; 2189b57061SReid Kleckner 2289b57061SReid Kleckner // Clients are responsible for avoid race conditions in registration. 2389b57061SReid Kleckner static Target *FirstTarget = nullptr; 2489b57061SReid Kleckner 25d69eb7b7SFangrui Song MCStreamer *Target::createMCObjectStreamer( 26d69eb7b7SFangrui Song const Triple &T, MCContext &Ctx, std::unique_ptr<MCAsmBackend> TAB, 27d69eb7b7SFangrui Song std::unique_ptr<MCObjectWriter> OW, std::unique_ptr<MCCodeEmitter> Emitter, 28d69eb7b7SFangrui Song const MCSubtargetInfo &STI) const { 29d69eb7b7SFangrui Song MCStreamer *S = nullptr; 30d69eb7b7SFangrui Song switch (T.getObjectFormat()) { 31d69eb7b7SFangrui Song case Triple::UnknownObjectFormat: 32d69eb7b7SFangrui Song llvm_unreachable("Unknown object format"); 33d69eb7b7SFangrui Song case Triple::COFF: 34*e7f02241SPrabhuk assert(T.isOSWindowsOrUEFI() && "only Windows and UEFI COFF are supported"); 35d69eb7b7SFangrui Song S = COFFStreamerCtorFn(Ctx, std::move(TAB), std::move(OW), 36d69eb7b7SFangrui Song std::move(Emitter)); 37d69eb7b7SFangrui Song break; 38d69eb7b7SFangrui Song case Triple::MachO: 39d69eb7b7SFangrui Song if (MachOStreamerCtorFn) 40d69eb7b7SFangrui Song S = MachOStreamerCtorFn(Ctx, std::move(TAB), std::move(OW), 41d69eb7b7SFangrui Song std::move(Emitter)); 42d69eb7b7SFangrui Song else 43d69eb7b7SFangrui Song S = createMachOStreamer(Ctx, std::move(TAB), std::move(OW), 44d69eb7b7SFangrui Song std::move(Emitter), false); 45d69eb7b7SFangrui Song break; 46d69eb7b7SFangrui Song case Triple::ELF: 47d69eb7b7SFangrui Song if (ELFStreamerCtorFn) 48d69eb7b7SFangrui Song S = ELFStreamerCtorFn(T, Ctx, std::move(TAB), std::move(OW), 49d69eb7b7SFangrui Song std::move(Emitter)); 50d69eb7b7SFangrui Song else 51d69eb7b7SFangrui Song S = createELFStreamer(Ctx, std::move(TAB), std::move(OW), 52d69eb7b7SFangrui Song std::move(Emitter)); 53d69eb7b7SFangrui Song break; 54d69eb7b7SFangrui Song case Triple::Wasm: 55d69eb7b7SFangrui Song S = createWasmStreamer(Ctx, std::move(TAB), std::move(OW), 56d69eb7b7SFangrui Song std::move(Emitter)); 57d69eb7b7SFangrui Song break; 58d69eb7b7SFangrui Song case Triple::GOFF: 59d69eb7b7SFangrui Song S = createGOFFStreamer(Ctx, std::move(TAB), std::move(OW), 60d69eb7b7SFangrui Song std::move(Emitter)); 61d69eb7b7SFangrui Song break; 62d69eb7b7SFangrui Song case Triple::XCOFF: 63d69eb7b7SFangrui Song S = XCOFFStreamerCtorFn(T, Ctx, std::move(TAB), std::move(OW), 64d69eb7b7SFangrui Song std::move(Emitter)); 65d69eb7b7SFangrui Song break; 66d69eb7b7SFangrui Song case Triple::SPIRV: 67d69eb7b7SFangrui Song S = createSPIRVStreamer(Ctx, std::move(TAB), std::move(OW), 68d69eb7b7SFangrui Song std::move(Emitter)); 69d69eb7b7SFangrui Song break; 70d69eb7b7SFangrui Song case Triple::DXContainer: 71d69eb7b7SFangrui Song S = createDXContainerStreamer(Ctx, std::move(TAB), std::move(OW), 72d69eb7b7SFangrui Song std::move(Emitter)); 73d69eb7b7SFangrui Song break; 74d69eb7b7SFangrui Song } 75d69eb7b7SFangrui Song if (ObjectTargetStreamerCtorFn) 76d69eb7b7SFangrui Song ObjectTargetStreamerCtorFn(*S, STI); 77d69eb7b7SFangrui Song return S; 78d69eb7b7SFangrui Song } 79d69eb7b7SFangrui Song 80d69eb7b7SFangrui Song MCStreamer *Target::createMCObjectStreamer( 81d69eb7b7SFangrui Song const Triple &T, MCContext &Ctx, std::unique_ptr<MCAsmBackend> &&TAB, 82d69eb7b7SFangrui Song std::unique_ptr<MCObjectWriter> &&OW, 83d69eb7b7SFangrui Song std::unique_ptr<MCCodeEmitter> &&Emitter, const MCSubtargetInfo &STI, bool, 84d69eb7b7SFangrui Song bool, bool) const { 85d69eb7b7SFangrui Song return createMCObjectStreamer(T, Ctx, std::move(TAB), std::move(OW), 86d69eb7b7SFangrui Song std::move(Emitter), STI); 87d69eb7b7SFangrui Song } 88d69eb7b7SFangrui Song 89d69eb7b7SFangrui Song MCStreamer *Target::createAsmStreamer(MCContext &Ctx, 90d69eb7b7SFangrui Song std::unique_ptr<formatted_raw_ostream> OS, 919e69e6b8SFangrui Song MCInstPrinter *IP, 929e69e6b8SFangrui Song std::unique_ptr<MCCodeEmitter> CE, 939e69e6b8SFangrui Song std::unique_ptr<MCAsmBackend> TAB) const { 949e69e6b8SFangrui Song formatted_raw_ostream &OSRef = *OS; 95867faeecSFangrui Song MCStreamer *S = llvm::createAsmStreamer(Ctx, std::move(OS), IP, 96867faeecSFangrui Song std::move(CE), std::move(TAB)); 97e9c85148SFangrui Song createAsmTargetStreamer(*S, OSRef, IP); 989e69e6b8SFangrui Song return S; 999e69e6b8SFangrui Song } 1009e69e6b8SFangrui Song 1019e69e6b8SFangrui Song MCStreamer *Target::createAsmStreamer(MCContext &Ctx, 1029e69e6b8SFangrui Song std::unique_ptr<formatted_raw_ostream> OS, 103d69eb7b7SFangrui Song bool IsVerboseAsm, bool UseDwarfDirectory, 1049e69e6b8SFangrui Song MCInstPrinter *IP, 105d69eb7b7SFangrui Song std::unique_ptr<MCCodeEmitter> &&CE, 106d69eb7b7SFangrui Song std::unique_ptr<MCAsmBackend> &&TAB, 107d69eb7b7SFangrui Song bool ShowInst) const { 1089e69e6b8SFangrui Song return createAsmStreamer(Ctx, std::move(OS), IP, std::move(CE), 1099e69e6b8SFangrui Song std::move(TAB)); 110d69eb7b7SFangrui Song } 111d69eb7b7SFangrui Song 11289b57061SReid Kleckner iterator_range<TargetRegistry::iterator> TargetRegistry::targets() { 11389b57061SReid Kleckner return make_range(iterator(FirstTarget), iterator()); 11489b57061SReid Kleckner } 11589b57061SReid Kleckner 1165a1de140SOndrej Sykora const Target *TargetRegistry::lookupTarget(StringRef ArchName, 11789b57061SReid Kleckner Triple &TheTriple, 11889b57061SReid Kleckner std::string &Error) { 11989b57061SReid Kleckner // Allocate target machine. First, check whether the user has explicitly 12089b57061SReid Kleckner // specified an architecture to compile for. If so we have to look it up by 12189b57061SReid Kleckner // name, because it might be a backend that has no mapping to a target triple. 12289b57061SReid Kleckner const Target *TheTarget = nullptr; 12389b57061SReid Kleckner if (!ArchName.empty()) { 12489b57061SReid Kleckner auto I = find_if(targets(), 12589b57061SReid Kleckner [&](const Target &T) { return ArchName == T.getName(); }); 12689b57061SReid Kleckner 12789b57061SReid Kleckner if (I == targets().end()) { 128aff3e68dSShao-Ce SUN Error = ("invalid target '" + ArchName + "'.").str(); 12989b57061SReid Kleckner return nullptr; 13089b57061SReid Kleckner } 13189b57061SReid Kleckner 13289b57061SReid Kleckner TheTarget = &*I; 13389b57061SReid Kleckner 13489b57061SReid Kleckner // Adjust the triple to match (if known), otherwise stick with the 13589b57061SReid Kleckner // given triple. 13689b57061SReid Kleckner Triple::ArchType Type = Triple::getArchTypeForLLVMName(ArchName); 13789b57061SReid Kleckner if (Type != Triple::UnknownArch) 13889b57061SReid Kleckner TheTriple.setArch(Type); 13989b57061SReid Kleckner } else { 14089b57061SReid Kleckner // Get the target specific parser. 14189b57061SReid Kleckner std::string TempError; 14289b57061SReid Kleckner TheTarget = TargetRegistry::lookupTarget(TheTriple.getTriple(), TempError); 14389b57061SReid Kleckner if (!TheTarget) { 144696eb3a5SAlex Richardson Error = "unable to get target for '" + TheTriple.getTriple() + 145696eb3a5SAlex Richardson "', see --version and --triple."; 14689b57061SReid Kleckner return nullptr; 14789b57061SReid Kleckner } 14889b57061SReid Kleckner } 14989b57061SReid Kleckner 15089b57061SReid Kleckner return TheTarget; 15189b57061SReid Kleckner } 15289b57061SReid Kleckner 1535a1de140SOndrej Sykora const Target *TargetRegistry::lookupTarget(StringRef TT, std::string &Error) { 15489b57061SReid Kleckner // Provide special warning when no targets are initialized. 15589b57061SReid Kleckner if (targets().begin() == targets().end()) { 15689b57061SReid Kleckner Error = "Unable to find target for this triple (no targets are registered)"; 15789b57061SReid Kleckner return nullptr; 15889b57061SReid Kleckner } 15989b57061SReid Kleckner Triple::ArchType Arch = Triple(TT).getArch(); 16089b57061SReid Kleckner auto ArchMatch = [&](const Target &T) { return T.ArchMatchFn(Arch); }; 16189b57061SReid Kleckner auto I = find_if(targets(), ArchMatch); 16289b57061SReid Kleckner 16389b57061SReid Kleckner if (I == targets().end()) { 1645a1de140SOndrej Sykora Error = ("No available targets are compatible with triple \"" + TT + "\"") 1655a1de140SOndrej Sykora .str(); 16689b57061SReid Kleckner return nullptr; 16789b57061SReid Kleckner } 16889b57061SReid Kleckner 16989b57061SReid Kleckner auto J = std::find_if(std::next(I), targets().end(), ArchMatch); 17089b57061SReid Kleckner if (J != targets().end()) { 17189b57061SReid Kleckner Error = std::string("Cannot choose between targets \"") + I->Name + 17289b57061SReid Kleckner "\" and \"" + J->Name + "\""; 17389b57061SReid Kleckner return nullptr; 17489b57061SReid Kleckner } 17589b57061SReid Kleckner 17689b57061SReid Kleckner return &*I; 17789b57061SReid Kleckner } 17889b57061SReid Kleckner 17989b57061SReid Kleckner void TargetRegistry::RegisterTarget(Target &T, const char *Name, 18089b57061SReid Kleckner const char *ShortDesc, 18189b57061SReid Kleckner const char *BackendName, 18289b57061SReid Kleckner Target::ArchMatchFnTy ArchMatchFn, 18389b57061SReid Kleckner bool HasJIT) { 18489b57061SReid Kleckner assert(Name && ShortDesc && ArchMatchFn && 18589b57061SReid Kleckner "Missing required target information!"); 18689b57061SReid Kleckner 18789b57061SReid Kleckner // Check if this target has already been initialized, we allow this as a 18889b57061SReid Kleckner // convenience to some clients. 18989b57061SReid Kleckner if (T.Name) 19089b57061SReid Kleckner return; 19189b57061SReid Kleckner 19289b57061SReid Kleckner // Add to the list of targets. 19389b57061SReid Kleckner T.Next = FirstTarget; 19489b57061SReid Kleckner FirstTarget = &T; 19589b57061SReid Kleckner 19689b57061SReid Kleckner T.Name = Name; 19789b57061SReid Kleckner T.ShortDesc = ShortDesc; 19889b57061SReid Kleckner T.BackendName = BackendName; 19989b57061SReid Kleckner T.ArchMatchFn = ArchMatchFn; 20089b57061SReid Kleckner T.HasJIT = HasJIT; 20189b57061SReid Kleckner } 20289b57061SReid Kleckner 20389b57061SReid Kleckner static int TargetArraySortFn(const std::pair<StringRef, const Target *> *LHS, 20489b57061SReid Kleckner const std::pair<StringRef, const Target *> *RHS) { 20589b57061SReid Kleckner return LHS->first.compare(RHS->first); 20689b57061SReid Kleckner } 20789b57061SReid Kleckner 20889b57061SReid Kleckner void TargetRegistry::printRegisteredTargetsForVersion(raw_ostream &OS) { 20989b57061SReid Kleckner std::vector<std::pair<StringRef, const Target*> > Targets; 21089b57061SReid Kleckner size_t Width = 0; 21189b57061SReid Kleckner for (const auto &T : TargetRegistry::targets()) { 21289b57061SReid Kleckner Targets.push_back(std::make_pair(T.getName(), &T)); 21389b57061SReid Kleckner Width = std::max(Width, Targets.back().first.size()); 21489b57061SReid Kleckner } 21589b57061SReid Kleckner array_pod_sort(Targets.begin(), Targets.end(), TargetArraySortFn); 21689b57061SReid Kleckner 217142aa1bdSArchibald Elliott OS << "\n"; 21889b57061SReid Kleckner OS << " Registered Targets:\n"; 219ccdd5bb2SKazu Hirata for (const auto &Target : Targets) { 220ccdd5bb2SKazu Hirata OS << " " << Target.first; 221ccdd5bb2SKazu Hirata OS.indent(Width - Target.first.size()) 222ccdd5bb2SKazu Hirata << " - " << Target.second->getShortDescription() << '\n'; 22389b57061SReid Kleckner } 22489b57061SReid Kleckner if (Targets.empty()) 22589b57061SReid Kleckner OS << " (none)\n"; 22689b57061SReid Kleckner } 227