1bd5abe19SDimitry Andric //===-- TargetSelect.cpp - Target Chooser Code ----------------------------===//
2bd5abe19SDimitry Andric //
3bd5abe19SDimitry Andric //                     The LLVM Compiler Infrastructure
4bd5abe19SDimitry Andric //
5bd5abe19SDimitry Andric // This file is distributed under the University of Illinois Open Source
6bd5abe19SDimitry Andric // License. See LICENSE.TXT for details.
7bd5abe19SDimitry Andric //
8bd5abe19SDimitry Andric //===----------------------------------------------------------------------===//
9bd5abe19SDimitry Andric //
10dff0c46cSDimitry Andric // This just asks the TargetRegistry for the appropriate target to use, and
11dff0c46cSDimitry Andric // allows the user to specify a specific one on the commandline with -march=x,
12dff0c46cSDimitry Andric // -mcpu=y, and -mattr=a,-b,+c. Clients should initialize targets prior to
13dff0c46cSDimitry Andric // calling selectTarget().
14bd5abe19SDimitry Andric //
15bd5abe19SDimitry Andric //===----------------------------------------------------------------------===//
16bd5abe19SDimitry Andric 
17bd5abe19SDimitry Andric #include "llvm/ADT/Triple.h"
183ca95b02SDimitry Andric #include "llvm/ExecutionEngine/ExecutionEngine.h"
19139f7f9bSDimitry Andric #include "llvm/IR/Module.h"
2017a519f9SDimitry Andric #include "llvm/MC/SubtargetFeature.h"
216122f3e6SDimitry Andric #include "llvm/Support/Host.h"
226122f3e6SDimitry Andric #include "llvm/Support/TargetRegistry.h"
23139f7f9bSDimitry Andric #include "llvm/Target/TargetMachine.h"
24dff0c46cSDimitry Andric 
25bd5abe19SDimitry Andric using namespace llvm;
26bd5abe19SDimitry Andric 
selectTarget()27dff0c46cSDimitry Andric TargetMachine *EngineBuilder::selectTarget() {
283861d79fSDimitry Andric   Triple TT;
293861d79fSDimitry Andric 
303861d79fSDimitry Andric   // MCJIT can generate code for remote targets, but the old JIT and Interpreter
313861d79fSDimitry Andric   // must use the host architecture.
3239d628a0SDimitry Andric   if (WhichEngine != EngineKind::Interpreter && M)
333861d79fSDimitry Andric     TT.setTriple(M->getTargetTriple());
34139f7f9bSDimitry Andric 
35dff0c46cSDimitry Andric   return selectTarget(TT, MArch, MCPU, MAttrs);
36dff0c46cSDimitry Andric }
37dff0c46cSDimitry Andric 
38bd5abe19SDimitry Andric /// selectTarget - Pick a target either via -march or by guessing the native
39bd5abe19SDimitry Andric /// arch.  Add any CPU features specified via -mcpu or -mattr.
selectTarget(const Triple & TargetTriple,StringRef MArch,StringRef MCPU,const SmallVectorImpl<std::string> & MAttrs)40dff0c46cSDimitry Andric TargetMachine *EngineBuilder::selectTarget(const Triple &TargetTriple,
41bd5abe19SDimitry Andric                               StringRef MArch,
42bd5abe19SDimitry Andric                               StringRef MCPU,
43dff0c46cSDimitry Andric                               const SmallVectorImpl<std::string>& MAttrs) {
44dff0c46cSDimitry Andric   Triple TheTriple(TargetTriple);
45bd5abe19SDimitry Andric   if (TheTriple.getTriple().empty())
46139f7f9bSDimitry Andric     TheTriple.setTriple(sys::getProcessTriple());
47bd5abe19SDimitry Andric 
48bd5abe19SDimitry Andric   // Adjust the triple to match what the user requested.
4991bc56edSDimitry Andric   const Target *TheTarget = nullptr;
50bd5abe19SDimitry Andric   if (!MArch.empty()) {
51d88c1a5aSDimitry Andric     auto I = find_if(TargetRegistry::targets(),
52ff0cc061SDimitry Andric                      [&](const Target &T) { return MArch == T.getName(); });
53bd5abe19SDimitry Andric 
54ff0cc061SDimitry Andric     if (I == TargetRegistry::targets().end()) {
557ae0e2c9SDimitry Andric       if (ErrorStr)
56bd5abe19SDimitry Andric         *ErrorStr = "No available targets are compatible with this -march, "
57bd5abe19SDimitry Andric                     "see -version for the available targets.\n";
5891bc56edSDimitry Andric       return nullptr;
59bd5abe19SDimitry Andric     }
60bd5abe19SDimitry Andric 
61ff0cc061SDimitry Andric     TheTarget = &*I;
62ff0cc061SDimitry Andric 
63bd5abe19SDimitry Andric     // Adjust the triple to match (if known), otherwise stick with the
64dff0c46cSDimitry Andric     // requested/host triple.
65bd5abe19SDimitry Andric     Triple::ArchType Type = Triple::getArchTypeForLLVMName(MArch);
66bd5abe19SDimitry Andric     if (Type != Triple::UnknownArch)
67bd5abe19SDimitry Andric       TheTriple.setArch(Type);
68bd5abe19SDimitry Andric   } else {
69bd5abe19SDimitry Andric     std::string Error;
70bd5abe19SDimitry Andric     TheTarget = TargetRegistry::lookupTarget(TheTriple.getTriple(), Error);
7191bc56edSDimitry Andric     if (!TheTarget) {
72bd5abe19SDimitry Andric       if (ErrorStr)
73bd5abe19SDimitry Andric         *ErrorStr = Error;
7491bc56edSDimitry Andric       return nullptr;
75bd5abe19SDimitry Andric     }
76bd5abe19SDimitry Andric   }
77bd5abe19SDimitry Andric 
78bd5abe19SDimitry Andric   // Package up features to be passed to target/subtarget
79bd5abe19SDimitry Andric   std::string FeaturesStr;
8017a519f9SDimitry Andric   if (!MAttrs.empty()) {
81bd5abe19SDimitry Andric     SubtargetFeatures Features;
82bd5abe19SDimitry Andric     for (unsigned i = 0; i != MAttrs.size(); ++i)
83bd5abe19SDimitry Andric       Features.AddFeature(MAttrs[i]);
84bd5abe19SDimitry Andric     FeaturesStr = Features.getString();
85bd5abe19SDimitry Andric   }
86bd5abe19SDimitry Andric 
87f785676fSDimitry Andric   // FIXME: non-iOS ARM FastISel is broken with MCJIT.
8839d628a0SDimitry Andric   if (TheTriple.getArch() == Triple::arm &&
89f785676fSDimitry Andric       !TheTriple.isiOS() &&
90f785676fSDimitry Andric       OptLevel == CodeGenOpt::None) {
91f785676fSDimitry Andric     OptLevel = CodeGenOpt::Less;
92f785676fSDimitry Andric   }
93f785676fSDimitry Andric 
94bd5abe19SDimitry Andric   // Allocate a target...
952cab237bSDimitry Andric   TargetMachine *Target =
962cab237bSDimitry Andric       TheTarget->createTargetMachine(TheTriple.getTriple(), MCPU, FeaturesStr,
972cab237bSDimitry Andric                                      Options, RelocModel, CMModel, OptLevel,
982cab237bSDimitry Andric 				     /*JIT*/ true);
992cab237bSDimitry Andric   Target->Options.EmulatedTLS = EmulatedTLS;
100*4ba319b5SDimitry Andric   Target->Options.ExplicitEmulatedTLS = true;
101*4ba319b5SDimitry Andric 
102bd5abe19SDimitry Andric   assert(Target && "Could not allocate target machine!");
103bd5abe19SDimitry Andric   return Target;
104bd5abe19SDimitry Andric }
105