1//===--- Hexagon.cpp - Hexagon ToolChain Implementations --------*- C++ -*-===//
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 "Hexagon.h"
10#include "clang/Driver/CommonArgs.h"
11#include "clang/Driver/Compilation.h"
12#include "clang/Driver/Driver.h"
13#include "clang/Driver/InputInfo.h"
14#include "clang/Options/Options.h"
15#include "llvm/Option/ArgList.h"
16#include "llvm/Support/FileSystem.h"
17#include "llvm/Support/Path.h"
18#include "llvm/Support/VirtualFileSystem.h"
19
20using namespace clang::driver;
21using namespace clang::driver::tools;
22using namespace clang::driver::toolchains;
23using namespace clang;
24using namespace llvm::opt;
25
26// Default hvx-length for various versions.
27static StringRef getDefaultHvxLength(StringRef HvxVer) {
28 return llvm::StringSwitch<StringRef>(HvxVer)
29 .Case(S: "v60", Value: "64b")
30 .Case(S: "v62", Value: "64b")
31 .Case(S: "v65", Value: "64b")
32 .Default(Value: "128b");
33}
34
35static void handleHVXWarnings(const Driver &D, const ArgList &Args) {
36 // Handle the unsupported values passed to mhvx-length.
37 if (Arg *A = Args.getLastArg(Ids: options::OPT_mhexagon_hvx_length_EQ)) {
38 StringRef Val = A->getValue();
39 if (!Val.equals_insensitive(RHS: "64b") && !Val.equals_insensitive(RHS: "128b"))
40 D.Diag(DiagID: diag::err_drv_unsupported_option_argument)
41 << A->getSpelling() << Val;
42 }
43}
44
45// Handle hvx target features explicitly.
46static void handleHVXTargetFeatures(const Driver &D, const ArgList &Args,
47 std::vector<StringRef> &Features,
48 StringRef Cpu, bool &HasHVX) {
49 // Handle HVX warnings.
50 handleHVXWarnings(D, Args);
51
52 auto makeFeature = [&Args](Twine T, bool Enable) -> StringRef {
53 const std::string &S = T.str();
54 StringRef Opt(S);
55 Opt.consume_back(Suffix: "=");
56 if (Opt.starts_with(Prefix: "mno-"))
57 Opt = Opt.drop_front(N: 4);
58 else if (Opt.starts_with(Prefix: "m"))
59 Opt = Opt.drop_front(N: 1);
60 return Args.MakeArgString(Str: Twine(Enable ? "+" : "-") + Twine(Opt));
61 };
62
63 auto withMinus = [](StringRef S) -> std::string {
64 return "-" + S.str();
65 };
66
67 std::optional<std::string> HvxVer =
68 toolchains::HexagonToolChain::GetHVXVersion(Args);
69 HasHVX = HvxVer.has_value();
70 if (HasHVX)
71 Features.push_back(x: makeFeature(Twine("hvx") + *HvxVer, true));
72 else {
73 if (Arg *A = Args.getLastArg(Ids: options::OPT_mno_hexagon_hvx)) {
74 // If there was an explicit -mno-hvx, add -hvx to target features.
75 Features.push_back(x: makeFeature(A->getOption().getName(), false));
76 }
77 }
78
79 StringRef HvxLen =
80 getDefaultHvxLength(HvxVer: HasHVX ? StringRef(*HvxVer) : StringRef(""));
81
82 // Handle -mhvx-length=.
83 if (Arg *A = Args.getLastArg(Ids: options::OPT_mhexagon_hvx_length_EQ)) {
84 // These flags are valid only if HVX in enabled.
85 if (!HasHVX)
86 D.Diag(DiagID: diag::err_drv_needs_hvx) << withMinus(A->getOption().getName());
87 else if (A->getOption().matches(ID: options::OPT_mhexagon_hvx_length_EQ))
88 HvxLen = A->getValue();
89 }
90
91 if (HasHVX) {
92 StringRef L = makeFeature(Twine("hvx-length") + HvxLen.lower(), true);
93 Features.push_back(x: L);
94 }
95
96 unsigned HvxVerNum = 0;
97 // getAsInteger returns 'true' on error.
98 if (HasHVX) {
99 StringRef HvxVerRef(*HvxVer);
100 if (HvxVerRef.size() <= 1 ||
101 HvxVerRef.drop_front(N: 1).getAsInteger(Radix: 10, Result&: HvxVerNum))
102 HvxVerNum = 0;
103 }
104
105 // Handle HVX floating point flags.
106 auto checkFlagHvxVersion =
107 [&](auto FlagOn, auto FlagOff,
108 unsigned MinVerNum) -> std::optional<StringRef> {
109 // Return an std::optional<StringRef>:
110 // - std::nullopt indicates a verification failure, or that the flag was not
111 // present in Args.
112 // - Otherwise the returned value is that name of the feature to add
113 // to Features.
114 Arg *A = Args.getLastArg(FlagOn, FlagOff);
115 if (!A)
116 return std::nullopt;
117
118 StringRef OptName = A->getOption().getName();
119 if (A->getOption().matches(ID: FlagOff))
120 return makeFeature(OptName, false);
121
122 if (!HasHVX) {
123 D.Diag(DiagID: diag::err_drv_needs_hvx) << withMinus(OptName);
124 return std::nullopt;
125 }
126 if (HvxVerNum < MinVerNum) {
127 D.Diag(DiagID: diag::err_drv_needs_hvx_version)
128 << withMinus(OptName) << ("v" + std::to_string(val: HvxVerNum));
129 return std::nullopt;
130 }
131 return makeFeature(OptName, true);
132 };
133
134 if (auto F = checkFlagHvxVersion(options::OPT_mhexagon_hvx_qfloat,
135 options::OPT_mno_hexagon_hvx_qfloat, 68)) {
136 Features.push_back(x: *F);
137 }
138 if (auto F = checkFlagHvxVersion(options::OPT_mhexagon_hvx_ieee_fp,
139 options::OPT_mno_hexagon_hvx_ieee_fp, 68)) {
140 Features.push_back(x: *F);
141 }
142}
143
144// Hexagon target features.
145void hexagon::getHexagonTargetFeatures(const Driver &D,
146 const llvm::Triple &Triple,
147 const ArgList &Args,
148 std::vector<StringRef> &Features) {
149 handleTargetFeaturesGroup(D, Triple, Args, Features,
150 Group: options::OPT_m_hexagon_Features_Group);
151
152 bool UseLongCalls = false;
153 if (Arg *A = Args.getLastArg(Ids: options::OPT_mlong_calls,
154 Ids: options::OPT_mno_long_calls)) {
155 if (A->getOption().matches(ID: options::OPT_mlong_calls))
156 UseLongCalls = true;
157 }
158
159 Features.push_back(x: UseLongCalls ? "+long-calls" : "-long-calls");
160
161 bool HasHVX = false;
162 StringRef Cpu(toolchains::HexagonToolChain::GetTargetCPUVersion(Args));
163 // 't' in Cpu denotes tiny-core micro-architecture. For now, the co-processors
164 // have no dependency on micro-architecture.
165 const bool TinyCore = Cpu.contains(C: 't');
166
167 if (TinyCore)
168 Cpu = Cpu.take_front(N: Cpu.size() - 1);
169
170 handleHVXTargetFeatures(D, Args, Features, Cpu, HasHVX);
171
172 if (HexagonToolChain::isAutoHVXEnabled(Args) && !HasHVX)
173 D.Diag(DiagID: diag::warn_drv_needs_hvx) << "auto-vectorization";
174}
175
176// Hexagon tools start.
177void hexagon::Assembler::RenderExtraToolArgs(const JobAction &JA,
178 ArgStringList &CmdArgs) const {
179}
180
181void hexagon::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
182 const InputInfo &Output,
183 const InputInfoList &Inputs,
184 const ArgList &Args,
185 const char *LinkingOutput) const {
186 claimNoWarnArgs(Args);
187
188 auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain());
189 const Driver &D = HTC.getDriver();
190 ArgStringList CmdArgs;
191
192 CmdArgs.push_back(Elt: "--arch=hexagon");
193
194 RenderExtraToolArgs(JA, CmdArgs);
195
196 const char *AsName = "llvm-mc";
197 CmdArgs.push_back(Elt: "-filetype=obj");
198 CmdArgs.push_back(Elt: Args.MakeArgString(
199 Str: "-mcpu=hexagon" +
200 toolchains::HexagonToolChain::GetTargetCPUVersion(Args)));
201
202 addSanitizerRuntimes(TC: HTC, Args, CmdArgs);
203
204 assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
205 if (Output.isFilename()) {
206 CmdArgs.push_back(Elt: "-o");
207 CmdArgs.push_back(Elt: Output.getFilename());
208 } else {
209 CmdArgs.push_back(Elt: "-fsyntax-only");
210 }
211
212 if (Arg *A = Args.getLastArg(Ids: options::OPT_mhexagon_hvx_ieee_fp,
213 Ids: options::OPT_mno_hexagon_hvx_ieee_fp)) {
214 if (A->getOption().matches(ID: options::OPT_mhexagon_hvx_ieee_fp))
215 CmdArgs.push_back(Elt: "-mhvx-ieee-fp");
216 }
217
218 if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
219 CmdArgs.push_back(Elt: Args.MakeArgString(Str: "-gpsize=" + Twine(*G)));
220 }
221
222 Args.AddAllArgValues(Output&: CmdArgs, Id0: options::OPT_Wa_COMMA, Id1: options::OPT_Xassembler);
223
224 // Only pass -x if gcc will understand it; otherwise hope gcc
225 // understands the suffix correctly. The main use case this would go
226 // wrong in is for linker inputs if they happened to have an odd
227 // suffix; really the only way to get this to happen is a command
228 // like '-x foobar a.c' which will treat a.c like a linker input.
229 //
230 // FIXME: For the linker case specifically, can we safely convert
231 // inputs into '-Wl,' options?
232 for (const auto &II : Inputs) {
233 // Don't try to pass LLVM or AST inputs to a generic gcc.
234 if (types::isLLVMIR(Id: II.getType()))
235 D.Diag(DiagID: clang::diag::err_drv_no_linker_llvm_support)
236 << HTC.getTripleString();
237 else if (II.getType() == types::TY_AST)
238 D.Diag(DiagID: clang::diag::err_drv_no_ast_support)
239 << HTC.getTripleString();
240 else if (II.getType() == types::TY_ModuleFile)
241 D.Diag(DiagID: diag::err_drv_no_module_support)
242 << HTC.getTripleString();
243
244 if (II.isFilename())
245 CmdArgs.push_back(Elt: II.getFilename());
246 else
247 // Don't render as input, we need gcc to do the translations.
248 // FIXME: What is this?
249 II.getInputArg().render(Args, Output&: CmdArgs);
250 }
251
252 auto *Exec = Args.MakeArgString(Str: HTC.GetProgramPath(Name: AsName));
253 C.addCommand(C: std::make_unique<Command>(args: JA, args: *this,
254 args: ResponseFileSupport::AtFileCurCP(),
255 args&: Exec, args&: CmdArgs, args: Inputs, args: Output));
256}
257
258void hexagon::Linker::RenderExtraToolArgs(const JobAction &JA,
259 ArgStringList &CmdArgs) const {
260}
261
262static void
263constructHexagonLinkArgs(Compilation &C, const JobAction &JA,
264 const toolchains::HexagonToolChain &HTC,
265 const InputInfo &Output, const InputInfoList &Inputs,
266 const ArgList &Args, ArgStringList &CmdArgs,
267 const char *LinkingOutput) {
268
269 const Driver &D = HTC.getDriver();
270
271 //----------------------------------------------------------------------------
272 //
273 //----------------------------------------------------------------------------
274 bool IsStatic = Args.hasArg(Ids: options::OPT_static);
275 bool IsShared = Args.hasArg(Ids: options::OPT_shared);
276 bool IsPIE = Args.hasArg(Ids: options::OPT_pie);
277 bool IncStdLib = !Args.hasArg(Ids: options::OPT_nostdlib);
278 bool IncStartFiles = !Args.hasArg(Ids: options::OPT_nostartfiles);
279 bool IncDefLibs = !Args.hasArg(Ids: options::OPT_nodefaultlibs);
280 bool UseLLD = false;
281 const char *Exec = Args.MakeArgString(Str: HTC.GetLinkerPath(LinkerIsLLD: &UseLLD));
282 UseLLD = UseLLD || llvm::sys::path::filename(path: Exec).ends_with(Suffix: "ld.lld") ||
283 llvm::sys::path::stem(path: Exec).ends_with(Suffix: "ld.lld");
284 bool UseShared = IsShared && !IsStatic;
285 StringRef CpuVer = toolchains::HexagonToolChain::GetTargetCPUVersion(Args);
286
287 bool NeedsSanitizerDeps = addSanitizerRuntimes(TC: HTC, Args, CmdArgs);
288 bool NeedsXRayDeps = addXRayRuntime(TC: HTC, Args, CmdArgs);
289
290 //----------------------------------------------------------------------------
291 // Silence warnings for various options
292 //----------------------------------------------------------------------------
293 Args.ClaimAllArgs(Id0: options::OPT_g_Group);
294 Args.ClaimAllArgs(Id0: options::OPT_emit_llvm);
295 Args.ClaimAllArgs(Id0: options::OPT_w); // Other warning options are already
296 // handled somewhere else.
297 Args.ClaimAllArgs(Id0: options::OPT_static_libgcc);
298
299 CmdArgs.push_back(Elt: "--eh-frame-hdr");
300 //----------------------------------------------------------------------------
301 //
302 //----------------------------------------------------------------------------
303 if (Args.hasArg(Ids: options::OPT_s))
304 CmdArgs.push_back(Elt: "-s");
305
306 if (Args.hasArg(Ids: options::OPT_r))
307 CmdArgs.push_back(Elt: "-r");
308
309 for (const auto &Opt : HTC.ExtraOpts)
310 CmdArgs.push_back(Elt: Opt.c_str());
311
312 if (!UseLLD) {
313 CmdArgs.push_back(Elt: "-march=hexagon");
314 CmdArgs.push_back(Elt: Args.MakeArgString(Str: "-mcpu=hexagon" + CpuVer));
315 }
316
317 if (IsShared) {
318 CmdArgs.push_back(Elt: "-shared");
319 // The following should be the default, but doing as hexagon-gcc does.
320 CmdArgs.push_back(Elt: "-call_shared");
321 }
322
323 if (IsStatic)
324 CmdArgs.push_back(Elt: "-static");
325
326 if (IsPIE && !IsShared)
327 CmdArgs.push_back(Elt: "-pie");
328
329 if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args))
330 CmdArgs.push_back(Elt: Args.MakeArgString(Str: "-G" + Twine(*G)));
331
332 CmdArgs.push_back(Elt: "-o");
333 CmdArgs.push_back(Elt: Output.getFilename());
334
335 if (HTC.getTriple().isMusl()) {
336 if (!Args.hasArg(Ids: options::OPT_shared, Ids: options::OPT_static))
337 CmdArgs.push_back(Elt: "-dynamic-linker=/lib/ld-musl-hexagon.so.1");
338
339 if (!Args.hasArg(Ids: options::OPT_shared, Ids: options::OPT_nostartfiles,
340 Ids: options::OPT_nostdlib))
341 CmdArgs.push_back(Elt: Args.MakeArgString(Str: D.SysRoot + "/usr/lib/crt1.o"));
342 else if (Args.hasArg(Ids: options::OPT_shared) &&
343 !Args.hasArg(Ids: options::OPT_nostartfiles, Ids: options::OPT_nostdlib))
344 CmdArgs.push_back(Elt: Args.MakeArgString(Str: D.SysRoot + "/usr/lib/crti.o"));
345
346 CmdArgs.push_back(
347 Elt: Args.MakeArgString(Str: StringRef("-L") + D.SysRoot + "/usr/lib"));
348 Args.addAllArgs(Output&: CmdArgs, Ids: {options::OPT_T_Group, options::OPT_s,
349 options::OPT_t, options::OPT_u_Group});
350 AddLinkerInputs(TC: HTC, Inputs, Args, CmdArgs, JA);
351
352 ToolChain::UnwindLibType UNW = HTC.GetUnwindLibType(Args);
353
354 if (!Args.hasArg(Ids: options::OPT_nostdlib, Ids: options::OPT_nodefaultlibs)) {
355 if (NeedsSanitizerDeps) {
356 linkSanitizerRuntimeDeps(TC: HTC, Args, CmdArgs);
357
358 if (UNW != ToolChain::UNW_None)
359 CmdArgs.push_back(Elt: "-lunwind");
360 }
361 if (NeedsXRayDeps)
362 linkXRayRuntimeDeps(TC: HTC, Args, CmdArgs);
363
364 if (!Args.hasArg(Ids: options::OPT_nolibc))
365 CmdArgs.push_back(Elt: "-lc");
366 CmdArgs.push_back(Elt: "-lclang_rt.builtins-hexagon");
367 }
368 if (D.CCCIsCXX()) {
369 if (HTC.ShouldLinkCXXStdlib(Args))
370 HTC.AddCXXStdlibLibArgs(Args, CmdArgs);
371 }
372 const ToolChain::path_list &LibPaths = HTC.getFilePaths();
373 for (const auto &LibPath : LibPaths)
374 CmdArgs.push_back(Elt: Args.MakeArgString(Str: StringRef("-L") + LibPath));
375 Args.ClaimAllArgs(Id0: options::OPT_L);
376 return;
377 }
378
379 //----------------------------------------------------------------------------
380 // moslib
381 //----------------------------------------------------------------------------
382 std::vector<std::string> OsLibs;
383 bool HasStandalone = false;
384 for (const Arg *A : Args.filtered(Ids: options::OPT_moslib_EQ)) {
385 A->claim();
386 OsLibs.emplace_back(args: A->getValue());
387 HasStandalone = HasStandalone || (OsLibs.back() == "standalone");
388 }
389 if (OsLibs.empty()) {
390 OsLibs.push_back(x: "standalone");
391 HasStandalone = true;
392 }
393
394 //----------------------------------------------------------------------------
395 // Start Files
396 //----------------------------------------------------------------------------
397 SmallString<128> LibraryDir;
398 HTC.getLibraryDir(Args, LibraryDir);
399
400 if (IncStdLib && IncStartFiles) {
401 if (!IsShared) {
402 if (HasStandalone) {
403 SmallString<128> Crt0SA = LibraryDir;
404 llvm::sys::path::append(path&: Crt0SA, a: "crt0_standalone.o");
405 CmdArgs.push_back(Elt: Args.MakeArgString(Str: Crt0SA));
406 }
407 SmallString<128> Crt0 = LibraryDir;
408 llvm::sys::path::append(path&: Crt0, a: "crt0.o");
409 CmdArgs.push_back(Elt: Args.MakeArgString(Str: Crt0));
410 }
411 SmallString<128> Init = LibraryDir;
412 llvm::sys::path::append(path&: Init, a: UseShared ? "initS.o" : "init.o");
413 CmdArgs.push_back(Elt: Args.MakeArgString(Str: Init));
414 }
415
416 //----------------------------------------------------------------------------
417 // Library Search Paths
418 //----------------------------------------------------------------------------
419 const ToolChain::path_list &LibPaths = HTC.getFilePaths();
420 for (const auto &LibPath : LibPaths)
421 CmdArgs.push_back(Elt: Args.MakeArgString(Str: StringRef("-L") + LibPath));
422 Args.ClaimAllArgs(Id0: options::OPT_L);
423
424 //----------------------------------------------------------------------------
425 //
426 //----------------------------------------------------------------------------
427 Args.addAllArgs(Output&: CmdArgs, Ids: {options::OPT_T_Group, options::OPT_s,
428 options::OPT_t, options::OPT_u_Group});
429
430 AddLinkerInputs(TC: HTC, Inputs, Args, CmdArgs, JA);
431
432 //----------------------------------------------------------------------------
433 // Libraries
434 //----------------------------------------------------------------------------
435 if (IncStdLib && IncDefLibs) {
436 if (D.CCCIsCXX()) {
437 if (HTC.ShouldLinkCXXStdlib(Args))
438 HTC.AddCXXStdlibLibArgs(Args, CmdArgs);
439 CmdArgs.push_back(Elt: "-lm");
440 }
441
442 CmdArgs.push_back(Elt: "--start-group");
443
444 if (!IsShared) {
445 for (StringRef Lib : OsLibs)
446 CmdArgs.push_back(Elt: Args.MakeArgString(Str: "-l" + Lib));
447 if (!Args.hasArg(Ids: options::OPT_nolibc))
448 CmdArgs.push_back(Elt: "-lc");
449 }
450 CmdArgs.push_back(Elt: "-lgcc");
451
452 CmdArgs.push_back(Elt: "--end-group");
453 }
454
455 //----------------------------------------------------------------------------
456 // End files
457 //----------------------------------------------------------------------------
458 if (IncStdLib && IncStartFiles) {
459 SmallString<128> Fini = LibraryDir;
460 llvm::sys::path::append(path&: Fini, a: UseShared ? "finiS.o" : "fini.o");
461 CmdArgs.push_back(Elt: Args.MakeArgString(Str: Fini));
462 }
463}
464
465void hexagon::Linker::ConstructJob(Compilation &C, const JobAction &JA,
466 const InputInfo &Output,
467 const InputInfoList &Inputs,
468 const ArgList &Args,
469 const char *LinkingOutput) const {
470 auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain());
471
472 ArgStringList CmdArgs;
473 constructHexagonLinkArgs(C, JA, HTC, Output, Inputs, Args, CmdArgs,
474 LinkingOutput);
475
476 const char *Exec = Args.MakeArgString(Str: HTC.GetLinkerPath());
477 C.addCommand(C: std::make_unique<Command>(args: JA, args: *this,
478 args: ResponseFileSupport::AtFileCurCP(),
479 args&: Exec, args&: CmdArgs, args: Inputs, args: Output));
480}
481// Hexagon tools end.
482
483/// Hexagon Toolchain
484
485std::string HexagonToolChain::getHexagonTargetDir(
486 const std::string &InstalledDir,
487 const SmallVectorImpl<std::string> &PrefixDirs) const {
488 std::string InstallRelDir;
489 const Driver &D = getDriver();
490
491 // Locate the rest of the toolchain ...
492 for (auto &I : PrefixDirs)
493 if (D.getVFS().exists(Path: I))
494 return I;
495
496 SmallString<128> Dir(InstalledDir);
497 llvm::sys::path::append(path&: Dir, a: "..", b: "target");
498 return std::string(Dir);
499}
500
501SmallString<128> HexagonToolChain::getEffectiveSysRoot() const {
502 const Driver &D = getDriver();
503 // The user-specified `--sysroot` always takes precedence.
504 if (!D.SysRoot.empty())
505 return SmallString<128>(D.SysRoot);
506 // Otherwise, pick a path relative to the install directory. Try a triple
507 // subdirectory first.
508 SmallString<128> Dir(getHexagonTargetDir(InstalledDir: D.Dir, PrefixDirs: D.PrefixDirs));
509 llvm::sys::path::append(path&: Dir, a: getTriple().normalize());
510 if (getVFS().exists(Path: Dir))
511 return Dir;
512 // Otherwise, fall back to "../target/hexagon".
513 Dir = getHexagonTargetDir(InstalledDir: D.Dir, PrefixDirs: D.PrefixDirs);
514 llvm::sys::path::append(path&: Dir, a: "hexagon");
515 return Dir;
516}
517
518void HexagonToolChain::getLibraryDir(const ArgList &Args,
519 llvm::SmallString<128> &Dir) const {
520 bool IsLinuxMusl = getTriple().isMusl() && getTriple().isOSLinux();
521 const llvm::SmallString<128> SysRoot = getEffectiveSysRoot();
522 // Linux toolchain uses "usr/lib" but it also should accept "lib" in case an
523 // external sysroot is used. Similar logic is for include paths.
524 if (IsLinuxMusl) {
525 Dir = SysRoot;
526 llvm::sys::path::append(path&: Dir, a: "usr", b: "lib");
527 }
528 if (!IsLinuxMusl || !getVFS().exists(Path: Dir)) {
529 Dir = SysRoot;
530 llvm::sys::path::append(path&: Dir, a: "lib");
531 }
532 std::string CpuVer = GetTargetCPUVersion(Args).str();
533 llvm::sys::path::append(path&: Dir, a: CpuVer);
534 if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args))
535 if (*G == 0)
536 llvm::sys::path::append(path&: Dir, a: "G0");
537 bool IsStatic = Args.hasArg(Ids: options::OPT_static);
538 bool IsShared = Args.hasArg(Ids: options::OPT_shared);
539 if (IsShared && !IsStatic)
540 llvm::sys::path::append(path&: Dir, a: "pic");
541}
542
543void HexagonToolChain::getBaseIncludeDir(llvm::SmallString<128> &Dir) const {
544 bool IsLinuxMusl = getTriple().isMusl() && getTriple().isOSLinux();
545 const llvm::SmallString<128> SysRoot = getEffectiveSysRoot();
546 if (IsLinuxMusl) {
547 Dir = SysRoot;
548 llvm::sys::path::append(path&: Dir, a: "usr", b: "include");
549 }
550 if (!IsLinuxMusl || !getVFS().exists(Path: Dir)) {
551 Dir = SysRoot;
552 llvm::sys::path::append(path&: Dir, a: "include");
553 }
554}
555
556std::optional<unsigned>
557HexagonToolChain::getSmallDataThreshold(const ArgList &Args) {
558 StringRef Gn = "";
559 if (Arg *A = Args.getLastArg(Ids: options::OPT_G)) {
560 Gn = A->getValue();
561 } else if (Args.getLastArg(Ids: options::OPT_shared, Ids: options::OPT_fpic,
562 Ids: options::OPT_fPIC)) {
563 Gn = "0";
564 }
565
566 unsigned G;
567 if (!Gn.getAsInteger(Radix: 10, Result&: G))
568 return G;
569
570 return std::nullopt;
571}
572
573std::string HexagonToolChain::getCompilerRTPath() const {
574 SmallString<128> Dir(getDriver().SysRoot);
575 llvm::sys::path::append(path&: Dir, a: "usr", b: "lib");
576 if (!SelectedMultilibs.empty()) {
577 Dir += SelectedMultilibs.back().gccSuffix();
578 }
579 return std::string(Dir);
580}
581
582void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args,
583 ToolChain::path_list &LibPaths) const {
584 const Driver &D = getDriver();
585
586 //----------------------------------------------------------------------------
587 // -L Args
588 //----------------------------------------------------------------------------
589 for (Arg *A : Args.filtered(Ids: options::OPT_L))
590 llvm::append_range(C&: LibPaths, R&: A->getValues());
591
592 //----------------------------------------------------------------------------
593 // Other standard paths
594 //----------------------------------------------------------------------------
595 std::vector<std::string> RootDirs;
596 std::copy(first: D.PrefixDirs.begin(), last: D.PrefixDirs.end(),
597 result: std::back_inserter(x&: RootDirs));
598
599 std::string SysRoot(getEffectiveSysRoot());
600 if (!llvm::is_contained(Range&: RootDirs, Element: SysRoot))
601 RootDirs.push_back(x: SysRoot);
602
603 bool HasPIC = Args.hasArg(Ids: options::OPT_fpic, Ids: options::OPT_fPIC);
604 // Assume G0 with -shared.
605 bool HasG0 = Args.hasArg(Ids: options::OPT_shared);
606 if (auto G = getSmallDataThreshold(Args))
607 HasG0 = *G == 0;
608
609 const std::string CpuVer = GetTargetCPUVersion(Args).str();
610 for (auto &Dir : RootDirs) {
611 std::string LibDir = Dir + "/lib";
612 std::string LibDirCpu = LibDir + '/' + CpuVer;
613 if (HasG0) {
614 if (HasPIC)
615 LibPaths.push_back(Elt: LibDirCpu + "/G0/pic");
616 LibPaths.push_back(Elt: LibDirCpu + "/G0");
617 }
618 LibPaths.push_back(Elt: LibDirCpu);
619 LibPaths.push_back(Elt: LibDir);
620 }
621}
622
623HexagonToolChain::HexagonToolChain(const Driver &D, const llvm::Triple &Triple,
624 const llvm::opt::ArgList &Args)
625 : Linux(D, Triple, Args) {
626 ToolChain::path_list &LibPaths = getFilePaths();
627
628 // Remove paths added by Linux toolchain. Currently Hexagon_TC really targets
629 // 'elf' OS type, so the Linux paths are not appropriate. When we actually
630 // support 'linux' we'll need to fix this up
631 LibPaths.clear();
632 getHexagonLibraryPaths(Args, LibPaths);
633}
634
635HexagonToolChain::~HexagonToolChain() {}
636
637void HexagonToolChain::AddCXXStdlibLibArgs(const ArgList &Args,
638 ArgStringList &CmdArgs) const {
639 CXXStdlibType Type = GetCXXStdlibType(Args);
640 ToolChain::UnwindLibType UNW = GetUnwindLibType(Args);
641 if (UNW != ToolChain::UNW_None && UNW != ToolChain::UNW_CompilerRT) {
642 const Arg *A = Args.getLastArg(Ids: options::OPT_unwindlib_EQ);
643 if (A) {
644 getDriver().Diag(DiagID: diag::err_drv_unsupported_unwind_for_platform)
645 << A->getValue() << getTriple().normalize();
646 return;
647 }
648 }
649
650 switch (Type) {
651 case ToolChain::CST_Libcxx:
652 CmdArgs.push_back(Elt: "-lc++");
653 if (Args.hasArg(Ids: options::OPT_fexperimental_library))
654 CmdArgs.push_back(Elt: "-lc++experimental");
655 CmdArgs.push_back(Elt: "-lc++abi");
656 if (UNW != ToolChain::UNW_None)
657 CmdArgs.push_back(Elt: "-lunwind");
658 break;
659
660 case ToolChain::CST_Libstdcxx:
661 CmdArgs.push_back(Elt: "-lstdc++");
662 break;
663 }
664}
665
666Tool *HexagonToolChain::buildAssembler() const {
667 return new tools::hexagon::Assembler(*this);
668}
669
670Tool *HexagonToolChain::buildLinker() const {
671 return new tools::hexagon::Linker(*this);
672}
673
674unsigned HexagonToolChain::getOptimizationLevel(
675 const llvm::opt::ArgList &DriverArgs) const {
676 // Copied in large part from lib/Frontend/CompilerInvocation.cpp.
677 Arg *A = DriverArgs.getLastArg(Ids: options::OPT_O_Group);
678 if (!A)
679 return 0;
680
681 if (A->getOption().matches(ID: options::OPT_O0))
682 return 0;
683 if (A->getOption().matches(ID: options::OPT_Ofast) ||
684 A->getOption().matches(ID: options::OPT_O4))
685 return 3;
686 assert(A->getNumValues() != 0);
687 StringRef S(A->getValue());
688 if (S == "s" || S == "z" || S.empty())
689 return 2;
690 if (S == "g")
691 return 1;
692
693 unsigned OptLevel;
694 if (S.getAsInteger(Radix: 10, Result&: OptLevel))
695 return 0;
696 return OptLevel;
697}
698
699void HexagonToolChain::addClangTargetOptions(const ArgList &DriverArgs,
700 ArgStringList &CC1Args,
701 Action::OffloadKind) const {
702
703 bool UseInitArrayDefault = getTriple().isMusl();
704
705 if (!DriverArgs.hasFlag(Pos: options::OPT_fuse_init_array,
706 Neg: options::OPT_fno_use_init_array,
707 Default: UseInitArrayDefault))
708 CC1Args.push_back(Elt: "-fno-use-init-array");
709
710 if (DriverArgs.hasArg(Ids: options::OPT_ffixed_r19)) {
711 CC1Args.push_back(Elt: "-target-feature");
712 CC1Args.push_back(Elt: "+reserved-r19");
713 }
714 if (isAutoHVXEnabled(Args: DriverArgs)) {
715 CC1Args.push_back(Elt: "-mllvm");
716 CC1Args.push_back(Elt: "-hexagon-autohvx");
717 }
718}
719
720void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
721 ArgStringList &CC1Args) const {
722 if (DriverArgs.hasArg(Ids: options::OPT_nostdinc))
723 return;
724
725 const Driver &D = getDriver();
726 const bool UseBuiltins = !DriverArgs.hasArg(Ids: options::OPT_nobuiltininc);
727 if (UseBuiltins) {
728 SmallString<128> ResourceDirInclude(D.ResourceDir);
729 llvm::sys::path::append(path&: ResourceDirInclude, a: "include");
730 addSystemInclude(DriverArgs, CC1Args, Path: ResourceDirInclude);
731 }
732 if (!DriverArgs.hasArg(Ids: options::OPT_nostdlibinc)) {
733 SmallString<128> CIncludeDir;
734 getBaseIncludeDir(Dir&: CIncludeDir);
735 addExternCSystemInclude(DriverArgs, CC1Args, Path: std::string(CIncludeDir));
736 bool IsLinuxMusl = getTriple().isMusl() && getTriple().isOSLinux();
737 if (IsLinuxMusl) {
738 SmallString<128> LocalIncludeDir = getEffectiveSysRoot();
739 llvm::sys::path::append(path&: LocalIncludeDir, a: "usr", b: "local", c: "include");
740 addSystemInclude(DriverArgs, CC1Args, Path: LocalIncludeDir);
741 }
742 // TOOL_INCLUDE_DIR
743 AddMultilibIncludeArgs(DriverArgs, CC1Args);
744 }
745}
746
747void HexagonToolChain::addLibCxxIncludePaths(
748 const llvm::opt::ArgList &DriverArgs,
749 llvm::opt::ArgStringList &CC1Args) const {
750 SmallString<128> Dir;
751 getBaseIncludeDir(Dir);
752 llvm::sys::path::append(path&: Dir, a: "c++", b: "v1");
753 addLibStdCXXIncludePaths(IncludeDir: Dir, Triple: "", IncludeSuffix: "", DriverArgs, CC1Args);
754}
755
756void HexagonToolChain::addLibStdCxxIncludePaths(
757 const llvm::opt::ArgList &DriverArgs,
758 llvm::opt::ArgStringList &CC1Args) const {
759 SmallString<128> Dir;
760 getBaseIncludeDir(Dir);
761 llvm::sys::path::append(path&: Dir, a: "c++");
762 addLibStdCXXIncludePaths(IncludeDir: Dir, Triple: "", IncludeSuffix: "", DriverArgs, CC1Args);
763}
764
765ToolChain::CXXStdlibType
766HexagonToolChain::GetCXXStdlibType(const ArgList &Args) const {
767 Arg *A = Args.getLastArg(Ids: options::OPT_stdlib_EQ);
768 if (!A) {
769 if (getTriple().isMusl())
770 return ToolChain::CST_Libcxx;
771 else
772 return ToolChain::CST_Libstdcxx;
773 }
774 StringRef Value = A->getValue();
775 if (Value != "libstdc++" && Value != "libc++")
776 getDriver().Diag(DiagID: diag::err_drv_invalid_stdlib_name) << A->getAsString(Args);
777
778 if (Value == "libstdc++")
779 return ToolChain::CST_Libstdcxx;
780 else if (Value == "libc++")
781 return ToolChain::CST_Libcxx;
782 else
783 return ToolChain::CST_Libstdcxx;
784}
785
786bool HexagonToolChain::isAutoHVXEnabled(const llvm::opt::ArgList &Args) {
787 if (Arg *A = Args.getLastArg(Ids: options::OPT_fvectorize,
788 Ids: options::OPT_fno_vectorize))
789 return A->getOption().matches(ID: options::OPT_fvectorize);
790 return false;
791}
792
793//
794// Returns the default CPU for Hexagon. This is the default compilation target
795// if no Hexagon processor is selected at the command-line.
796//
797StringRef HexagonToolChain::GetDefaultCPU() { return "hexagonv68"; }
798
799StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) {
800 Arg *CpuArg = nullptr;
801 if (Arg *A = Args.getLastArg(Ids: options::OPT_mcpu_EQ))
802 CpuArg = A;
803
804 StringRef CPU = CpuArg ? CpuArg->getValue() : GetDefaultCPU();
805 CPU.consume_front(Prefix: "hexagon");
806 return CPU;
807}
808
809std::optional<std::string>
810HexagonToolChain::GetHVXVersion(const ArgList &Args) {
811 // Handle -mh[v]x= and -mno-hvx. If versioned and versionless flags
812 // are both present, the last one wins.
813 Arg *HvxEnablingArg =
814 Args.getLastArg(Ids: options::OPT_mhexagon_hvx, Ids: options::OPT_mhexagon_hvx_EQ,
815 Ids: options::OPT_mno_hexagon_hvx);
816 if (!HvxEnablingArg ||
817 HvxEnablingArg->getOption().matches(ID: options::OPT_mno_hexagon_hvx))
818 return std::nullopt;
819
820 StringRef Cpu(toolchains::HexagonToolChain::GetTargetCPUVersion(Args));
821 std::string HvxVer;
822 if (!Cpu.empty() && (Cpu.back() == 'T' || Cpu.back() == 't'))
823 HvxVer = Cpu.drop_back(N: 1).str();
824 else
825 HvxVer = Cpu.str();
826
827 if (HvxEnablingArg->getOption().matches(ID: options::OPT_mhexagon_hvx_EQ))
828 HvxVer = StringRef(HvxEnablingArg->getValue()).lower();
829
830 return HvxVer;
831}
832
833// End Hexagon
834