xref: /openbsd-src/gnu/llvm/clang/lib/Driver/ToolChains/MSP430.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
1e5dd7070Spatrick //===--- MSP430.cpp - MSP430 Helpers for Tools ------------------*- C++ -*-===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick 
9e5dd7070Spatrick #include "MSP430.h"
10e5dd7070Spatrick #include "CommonArgs.h"
11e5dd7070Spatrick #include "Gnu.h"
12e5dd7070Spatrick #include "clang/Driver/Compilation.h"
13a9ac8606Spatrick #include "clang/Driver/InputInfo.h"
14e5dd7070Spatrick #include "clang/Driver/Multilib.h"
15e5dd7070Spatrick #include "clang/Driver/Options.h"
16e5dd7070Spatrick #include "llvm/Option/ArgList.h"
17e5dd7070Spatrick #include "llvm/Support/FileSystem.h"
18e5dd7070Spatrick #include "llvm/Support/Path.h"
19e5dd7070Spatrick 
20e5dd7070Spatrick using namespace clang::driver;
21e5dd7070Spatrick using namespace clang::driver::toolchains;
22e5dd7070Spatrick using namespace clang::driver::tools;
23e5dd7070Spatrick using namespace clang;
24e5dd7070Spatrick using namespace llvm::opt;
25e5dd7070Spatrick 
isSupportedMCU(const StringRef MCU)26e5dd7070Spatrick static bool isSupportedMCU(const StringRef MCU) {
27e5dd7070Spatrick   return llvm::StringSwitch<bool>(MCU)
28e5dd7070Spatrick #define MSP430_MCU(NAME) .Case(NAME, true)
29e5dd7070Spatrick #include "clang/Basic/MSP430Target.def"
30e5dd7070Spatrick       .Default(false);
31e5dd7070Spatrick }
32e5dd7070Spatrick 
getSupportedHWMult(const Arg * MCU)33e5dd7070Spatrick static StringRef getSupportedHWMult(const Arg *MCU) {
34e5dd7070Spatrick   if (!MCU)
35e5dd7070Spatrick     return "none";
36e5dd7070Spatrick 
37e5dd7070Spatrick   return llvm::StringSwitch<StringRef>(MCU->getValue())
38e5dd7070Spatrick #define MSP430_MCU_FEAT(NAME, HWMULT) .Case(NAME, HWMULT)
39e5dd7070Spatrick #include "clang/Basic/MSP430Target.def"
40e5dd7070Spatrick       .Default("none");
41e5dd7070Spatrick }
42e5dd7070Spatrick 
getHWMultLib(const ArgList & Args)43e5dd7070Spatrick static StringRef getHWMultLib(const ArgList &Args) {
44e5dd7070Spatrick   StringRef HWMult = Args.getLastArgValue(options::OPT_mhwmult_EQ, "auto");
45e5dd7070Spatrick   if (HWMult == "auto") {
46e5dd7070Spatrick     HWMult = getSupportedHWMult(Args.getLastArg(options::OPT_mmcu_EQ));
47e5dd7070Spatrick   }
48e5dd7070Spatrick 
49e5dd7070Spatrick   return llvm::StringSwitch<StringRef>(HWMult)
50e5dd7070Spatrick       .Case("16bit", "-lmul_16")
51e5dd7070Spatrick       .Case("32bit", "-lmul_32")
52e5dd7070Spatrick       .Case("f5series", "-lmul_f5")
53e5dd7070Spatrick       .Default("-lmul_none");
54e5dd7070Spatrick }
55e5dd7070Spatrick 
getMSP430TargetFeatures(const Driver & D,const ArgList & Args,std::vector<StringRef> & Features)56e5dd7070Spatrick void msp430::getMSP430TargetFeatures(const Driver &D, const ArgList &Args,
57e5dd7070Spatrick                                      std::vector<StringRef> &Features) {
58e5dd7070Spatrick   const Arg *MCU = Args.getLastArg(options::OPT_mmcu_EQ);
59e5dd7070Spatrick   if (MCU && !isSupportedMCU(MCU->getValue())) {
60e5dd7070Spatrick     D.Diag(diag::err_drv_clang_unsupported) << MCU->getValue();
61e5dd7070Spatrick     return;
62e5dd7070Spatrick   }
63e5dd7070Spatrick 
64e5dd7070Spatrick   const Arg *HWMultArg = Args.getLastArg(options::OPT_mhwmult_EQ);
65e5dd7070Spatrick   if (!MCU && !HWMultArg)
66e5dd7070Spatrick     return;
67e5dd7070Spatrick 
68e5dd7070Spatrick   StringRef HWMult = HWMultArg ? HWMultArg->getValue() : "auto";
69e5dd7070Spatrick   StringRef SupportedHWMult = getSupportedHWMult(MCU);
70e5dd7070Spatrick 
71e5dd7070Spatrick   if (HWMult == "auto") {
72e5dd7070Spatrick     // 'auto' - deduce hw multiplier support based on mcu name provided.
73e5dd7070Spatrick     // If no mcu name is provided, assume no hw multiplier is supported.
74e5dd7070Spatrick     if (!MCU)
75e5dd7070Spatrick       D.Diag(clang::diag::warn_drv_msp430_hwmult_no_device);
76e5dd7070Spatrick     HWMult = SupportedHWMult;
77e5dd7070Spatrick   }
78e5dd7070Spatrick 
79e5dd7070Spatrick   if (HWMult == "none") {
80e5dd7070Spatrick     // 'none' - disable hw multiplier.
81e5dd7070Spatrick     Features.push_back("-hwmult16");
82e5dd7070Spatrick     Features.push_back("-hwmult32");
83e5dd7070Spatrick     Features.push_back("-hwmultf5");
84e5dd7070Spatrick     return;
85e5dd7070Spatrick   }
86e5dd7070Spatrick 
87e5dd7070Spatrick   if (MCU && SupportedHWMult == "none")
88e5dd7070Spatrick     D.Diag(clang::diag::warn_drv_msp430_hwmult_unsupported) << HWMult;
89e5dd7070Spatrick   if (MCU && HWMult != SupportedHWMult)
90e5dd7070Spatrick     D.Diag(clang::diag::warn_drv_msp430_hwmult_mismatch)
91e5dd7070Spatrick         << SupportedHWMult << HWMult;
92e5dd7070Spatrick 
93e5dd7070Spatrick   if (HWMult == "16bit") {
94e5dd7070Spatrick     // '16bit' - for 16-bit only hw multiplier.
95e5dd7070Spatrick     Features.push_back("+hwmult16");
96e5dd7070Spatrick   } else if (HWMult == "32bit") {
97e5dd7070Spatrick     // '32bit' - for 16/32-bit hw multiplier.
98e5dd7070Spatrick     Features.push_back("+hwmult32");
99e5dd7070Spatrick   } else if (HWMult == "f5series") {
100e5dd7070Spatrick     // 'f5series' - for 16/32-bit hw multiplier supported by F5 series mcus.
101e5dd7070Spatrick     Features.push_back("+hwmultf5");
102e5dd7070Spatrick   } else {
103e5dd7070Spatrick     D.Diag(clang::diag::err_drv_unsupported_option_argument)
104*12c85518Srobert         << HWMultArg->getSpelling() << HWMult;
105e5dd7070Spatrick   }
106e5dd7070Spatrick }
107e5dd7070Spatrick 
108e5dd7070Spatrick /// MSP430 Toolchain
MSP430ToolChain(const Driver & D,const llvm::Triple & Triple,const ArgList & Args)109e5dd7070Spatrick MSP430ToolChain::MSP430ToolChain(const Driver &D, const llvm::Triple &Triple,
110e5dd7070Spatrick                                  const ArgList &Args)
111e5dd7070Spatrick     : Generic_ELF(D, Triple, Args) {
112e5dd7070Spatrick 
113e5dd7070Spatrick   StringRef MultilibSuf = "";
114e5dd7070Spatrick 
115e5dd7070Spatrick   GCCInstallation.init(Triple, Args);
116e5dd7070Spatrick   if (GCCInstallation.isValid()) {
117e5dd7070Spatrick     MultilibSuf = GCCInstallation.getMultilib().gccSuffix();
118e5dd7070Spatrick 
119e5dd7070Spatrick     SmallString<128> GCCBinPath;
120e5dd7070Spatrick     llvm::sys::path::append(GCCBinPath,
121e5dd7070Spatrick                             GCCInstallation.getParentLibPath(), "..", "bin");
122e5dd7070Spatrick     addPathIfExists(D, GCCBinPath, getProgramPaths());
123e5dd7070Spatrick 
124e5dd7070Spatrick     SmallString<128> GCCRtPath;
125e5dd7070Spatrick     llvm::sys::path::append(GCCRtPath,
126e5dd7070Spatrick                             GCCInstallation.getInstallPath(), MultilibSuf);
127e5dd7070Spatrick     addPathIfExists(D, GCCRtPath, getFilePaths());
128e5dd7070Spatrick   }
129e5dd7070Spatrick 
130e5dd7070Spatrick   SmallString<128> SysRootDir(computeSysRoot());
131a9ac8606Spatrick   llvm::sys::path::append(SysRootDir, "msp430-elf", "lib", MultilibSuf);
132e5dd7070Spatrick   addPathIfExists(D, SysRootDir, getFilePaths());
133e5dd7070Spatrick }
134e5dd7070Spatrick 
computeSysRoot() const135e5dd7070Spatrick std::string MSP430ToolChain::computeSysRoot() const {
136e5dd7070Spatrick   if (!getDriver().SysRoot.empty())
137e5dd7070Spatrick     return getDriver().SysRoot;
138e5dd7070Spatrick 
139e5dd7070Spatrick   SmallString<128> Dir;
140e5dd7070Spatrick   if (GCCInstallation.isValid())
141a9ac8606Spatrick     llvm::sys::path::append(Dir, GCCInstallation.getParentLibPath(), "..");
142e5dd7070Spatrick   else
143a9ac8606Spatrick     llvm::sys::path::append(Dir, getDriver().Dir, "..");
144e5dd7070Spatrick 
145ec727ea7Spatrick   return std::string(Dir.str());
146e5dd7070Spatrick }
147e5dd7070Spatrick 
AddClangSystemIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const148e5dd7070Spatrick void MSP430ToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
149e5dd7070Spatrick                                                 ArgStringList &CC1Args) const {
150e5dd7070Spatrick   if (DriverArgs.hasArg(options::OPT_nostdinc) ||
151e5dd7070Spatrick       DriverArgs.hasArg(options::OPT_nostdlibinc))
152e5dd7070Spatrick     return;
153e5dd7070Spatrick 
154e5dd7070Spatrick   SmallString<128> Dir(computeSysRoot());
155a9ac8606Spatrick   llvm::sys::path::append(Dir, "msp430-elf", "include");
156e5dd7070Spatrick   addSystemInclude(DriverArgs, CC1Args, Dir.str());
157e5dd7070Spatrick }
158e5dd7070Spatrick 
addClangTargetOptions(const ArgList & DriverArgs,ArgStringList & CC1Args,Action::OffloadKind) const159e5dd7070Spatrick void MSP430ToolChain::addClangTargetOptions(const ArgList &DriverArgs,
160e5dd7070Spatrick                                             ArgStringList &CC1Args,
161e5dd7070Spatrick                                             Action::OffloadKind) const {
162e5dd7070Spatrick   CC1Args.push_back("-nostdsysteminc");
163e5dd7070Spatrick 
164e5dd7070Spatrick   const auto *MCUArg = DriverArgs.getLastArg(options::OPT_mmcu_EQ);
165e5dd7070Spatrick   if (!MCUArg)
166e5dd7070Spatrick     return;
167e5dd7070Spatrick 
168e5dd7070Spatrick   const StringRef MCU = MCUArg->getValue();
169e5dd7070Spatrick   if (MCU.startswith("msp430i")) {
170e5dd7070Spatrick     // 'i' should be in lower case as it's defined in TI MSP430-GCC headers
171e5dd7070Spatrick     CC1Args.push_back(DriverArgs.MakeArgString(
172e5dd7070Spatrick         "-D__MSP430i" + MCU.drop_front(7).upper() + "__"));
173e5dd7070Spatrick   } else {
174e5dd7070Spatrick     CC1Args.push_back(DriverArgs.MakeArgString("-D__" + MCU.upper() + "__"));
175e5dd7070Spatrick   }
176e5dd7070Spatrick }
177e5dd7070Spatrick 
buildLinker() const178e5dd7070Spatrick Tool *MSP430ToolChain::buildLinker() const {
179e5dd7070Spatrick   return new tools::msp430::Linker(*this);
180e5dd7070Spatrick }
181e5dd7070Spatrick 
AddStartFiles(bool UseExceptions,const ArgList & Args,ArgStringList & CmdArgs) const182a9ac8606Spatrick void msp430::Linker::AddStartFiles(bool UseExceptions, const ArgList &Args,
183a9ac8606Spatrick                                    ArgStringList &CmdArgs) const {
184a9ac8606Spatrick   const ToolChain &ToolChain = getToolChain();
185a9ac8606Spatrick 
186a9ac8606Spatrick   CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o")));
187a9ac8606Spatrick   const char *crtbegin = UseExceptions ? "crtbegin.o" : "crtbegin_no_eh.o";
188a9ac8606Spatrick   CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
189a9ac8606Spatrick }
190a9ac8606Spatrick 
AddDefaultLibs(const llvm::opt::ArgList & Args,llvm::opt::ArgStringList & CmdArgs) const191a9ac8606Spatrick void msp430::Linker::AddDefaultLibs(const llvm::opt::ArgList &Args,
192a9ac8606Spatrick                                     llvm::opt::ArgStringList &CmdArgs) const {
193a9ac8606Spatrick   const ToolChain &ToolChain = getToolChain();
194a9ac8606Spatrick   const Driver &D = ToolChain.getDriver();
195a9ac8606Spatrick 
196a9ac8606Spatrick   CmdArgs.push_back("--start-group");
197a9ac8606Spatrick   CmdArgs.push_back(Args.MakeArgString(getHWMultLib(Args)));
198a9ac8606Spatrick   CmdArgs.push_back("-lc");
199a9ac8606Spatrick   AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
200a9ac8606Spatrick   CmdArgs.push_back("-lcrt");
201a9ac8606Spatrick 
202a9ac8606Spatrick   if (Args.hasArg(options::OPT_msim)) {
203a9ac8606Spatrick     CmdArgs.push_back("-lsim");
204a9ac8606Spatrick 
205a9ac8606Spatrick     // msp430-sim.ld relies on __crt0_call_exit being implicitly .refsym-ed
206a9ac8606Spatrick     // in main() by msp430-gcc.
207a9ac8606Spatrick     // This workaround should work seamlessly unless the compilation unit that
208a9ac8606Spatrick     // contains main() is compiled by clang and then passed to
209a9ac8606Spatrick     // gcc compiler driver for linkage.
210a9ac8606Spatrick     CmdArgs.push_back("--undefined=__crt0_call_exit");
211a9ac8606Spatrick   } else
212a9ac8606Spatrick     CmdArgs.push_back("-lnosys");
213a9ac8606Spatrick 
214a9ac8606Spatrick   CmdArgs.push_back("--end-group");
215a9ac8606Spatrick   AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
216a9ac8606Spatrick }
217a9ac8606Spatrick 
AddEndFiles(bool UseExceptions,const ArgList & Args,ArgStringList & CmdArgs) const218a9ac8606Spatrick void msp430::Linker::AddEndFiles(bool UseExceptions, const ArgList &Args,
219a9ac8606Spatrick                                  ArgStringList &CmdArgs) const {
220a9ac8606Spatrick   const ToolChain &ToolChain = getToolChain();
221a9ac8606Spatrick   const Driver &D = ToolChain.getDriver();
222a9ac8606Spatrick 
223a9ac8606Spatrick   const char *crtend = UseExceptions ? "crtend.o" : "crtend_no_eh.o";
224a9ac8606Spatrick   CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend)));
225a9ac8606Spatrick   AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
226a9ac8606Spatrick }
227a9ac8606Spatrick 
AddSspArgs(const ArgList & Args,ArgStringList & CmdArgs)228a9ac8606Spatrick static void AddSspArgs(const ArgList &Args, ArgStringList &CmdArgs) {
229a9ac8606Spatrick   Arg *SspFlag = Args.getLastArg(
230a9ac8606Spatrick       options::OPT_fno_stack_protector, options::OPT_fstack_protector,
231a9ac8606Spatrick       options::OPT_fstack_protector_all, options::OPT_fstack_protector_strong);
232a9ac8606Spatrick 
233a9ac8606Spatrick   if (SspFlag &&
234a9ac8606Spatrick       !SspFlag->getOption().matches(options::OPT_fno_stack_protector)) {
235a9ac8606Spatrick     CmdArgs.push_back("-lssp_nonshared");
236a9ac8606Spatrick     CmdArgs.push_back("-lssp");
237a9ac8606Spatrick   }
238a9ac8606Spatrick }
239a9ac8606Spatrick 
AddImplicitLinkerScript(const std::string SysRoot,const ArgList & Args,ArgStringList & CmdArgs)240a9ac8606Spatrick static void AddImplicitLinkerScript(const std::string SysRoot,
241a9ac8606Spatrick                                     const ArgList &Args,
242a9ac8606Spatrick                                     ArgStringList &CmdArgs) {
243a9ac8606Spatrick   if (Args.hasArg(options::OPT_T))
244a9ac8606Spatrick     return;
245a9ac8606Spatrick 
246a9ac8606Spatrick   if (Args.hasArg(options::OPT_msim)) {
247a9ac8606Spatrick     CmdArgs.push_back("-Tmsp430-sim.ld");
248a9ac8606Spatrick     return;
249a9ac8606Spatrick   }
250a9ac8606Spatrick 
251a9ac8606Spatrick   const Arg *MCUArg = Args.getLastArg(options::OPT_mmcu_EQ);
252a9ac8606Spatrick   if (!MCUArg)
253a9ac8606Spatrick     return;
254a9ac8606Spatrick 
255a9ac8606Spatrick   SmallString<128> MCULinkerScriptPath(SysRoot);
256a9ac8606Spatrick   llvm::sys::path::append(MCULinkerScriptPath, "include");
257a9ac8606Spatrick   // -L because <mcu>.ld INCLUDEs <mcu>_symbols.ld
258a9ac8606Spatrick   CmdArgs.push_back(Args.MakeArgString("-L" + MCULinkerScriptPath));
259a9ac8606Spatrick   CmdArgs.push_back(
260a9ac8606Spatrick       Args.MakeArgString("-T" + StringRef(MCUArg->getValue()) + ".ld"));
261a9ac8606Spatrick }
262a9ac8606Spatrick 
ConstructJob(Compilation & C,const JobAction & JA,const InputInfo & Output,const InputInfoList & Inputs,const ArgList & Args,const char * LinkingOutput) const263e5dd7070Spatrick void msp430::Linker::ConstructJob(Compilation &C, const JobAction &JA,
264e5dd7070Spatrick                                   const InputInfo &Output,
265e5dd7070Spatrick                                   const InputInfoList &Inputs,
266e5dd7070Spatrick                                   const ArgList &Args,
267e5dd7070Spatrick                                   const char *LinkingOutput) const {
268e5dd7070Spatrick   const ToolChain &ToolChain = getToolChain();
269e5dd7070Spatrick   const Driver &D = ToolChain.getDriver();
270e5dd7070Spatrick   std::string Linker = ToolChain.GetProgramPath(getShortName());
271e5dd7070Spatrick   ArgStringList CmdArgs;
272a9ac8606Spatrick   bool UseExceptions = Args.hasFlag(options::OPT_fexceptions,
273a9ac8606Spatrick                                     options::OPT_fno_exceptions, false);
274a9ac8606Spatrick   bool UseStartAndEndFiles = !Args.hasArg(options::OPT_nostdlib, options::OPT_r,
275a9ac8606Spatrick                                           options::OPT_nostartfiles);
276e5dd7070Spatrick 
277a9ac8606Spatrick   if (Args.hasArg(options::OPT_mrelax))
278a9ac8606Spatrick     CmdArgs.push_back("--relax");
279a9ac8606Spatrick   if (!Args.hasArg(options::OPT_r, options::OPT_g_Group))
280a9ac8606Spatrick     CmdArgs.push_back("--gc-sections");
281a9ac8606Spatrick 
282a9ac8606Spatrick   Args.AddAllArgs(CmdArgs, {
283a9ac8606Spatrick                                options::OPT_e,
284a9ac8606Spatrick                                options::OPT_n,
285a9ac8606Spatrick                                options::OPT_s,
286a9ac8606Spatrick                                options::OPT_t,
287a9ac8606Spatrick                                options::OPT_u,
288a9ac8606Spatrick                            });
289a9ac8606Spatrick 
290a9ac8606Spatrick   if (UseStartAndEndFiles)
291a9ac8606Spatrick     AddStartFiles(UseExceptions, Args, CmdArgs);
292e5dd7070Spatrick 
293e5dd7070Spatrick   Args.AddAllArgs(CmdArgs, options::OPT_L);
294e5dd7070Spatrick   ToolChain.AddFilePathLibArgs(Args, CmdArgs);
295e5dd7070Spatrick   AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
296e5dd7070Spatrick 
297a9ac8606Spatrick   if (!Args.hasArg(options::OPT_nostdlib, options::OPT_r,
298a9ac8606Spatrick                    options::OPT_nodefaultlibs)) {
299a9ac8606Spatrick     AddSspArgs(Args, CmdArgs);
300a9ac8606Spatrick     AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
301a9ac8606Spatrick     if (!Args.hasArg(options::OPT_nolibc)) {
302a9ac8606Spatrick       AddDefaultLibs(Args, CmdArgs);
303a9ac8606Spatrick       AddImplicitLinkerScript(D.SysRoot, Args, CmdArgs);
304e5dd7070Spatrick     }
305a9ac8606Spatrick   }
306e5dd7070Spatrick 
307a9ac8606Spatrick   if (UseStartAndEndFiles)
308a9ac8606Spatrick     AddEndFiles(UseExceptions, Args, CmdArgs);
309a9ac8606Spatrick 
310e5dd7070Spatrick   CmdArgs.push_back("-o");
311e5dd7070Spatrick   CmdArgs.push_back(Output.getFilename());
312a9ac8606Spatrick 
313a9ac8606Spatrick   Args.AddAllArgs(CmdArgs, options::OPT_T);
314a9ac8606Spatrick 
315a9ac8606Spatrick   C.addCommand(std::make_unique<Command>(
316a9ac8606Spatrick       JA, *this, ResponseFileSupport::AtFileCurCP(), Args.MakeArgString(Linker),
317a9ac8606Spatrick       CmdArgs, Inputs, Output));
318e5dd7070Spatrick }
319