]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/Driver/ToolChains/Hexagon.cpp
Import libxo-0.9.0:
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / lib / Driver / ToolChains / Hexagon.cpp
1 //===--- Hexagon.cpp - Hexagon ToolChain Implementations --------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "Hexagon.h"
11 #include "InputInfo.h"
12 #include "CommonArgs.h"
13 #include "clang/Basic/VirtualFileSystem.h"
14 #include "clang/Config/config.h"
15 #include "clang/Driver/Compilation.h"
16 #include "clang/Driver/Driver.h"
17 #include "clang/Driver/DriverDiagnostic.h"
18 #include "clang/Driver/Options.h"
19 #include "llvm/ADT/StringExtras.h"
20 #include "llvm/Option/ArgList.h"
21 #include "llvm/Support/FileSystem.h"
22 #include "llvm/Support/Path.h"
23
24 using namespace clang::driver;
25 using namespace clang::driver::tools;
26 using namespace clang::driver::toolchains;
27 using namespace clang;
28 using namespace llvm::opt;
29
30 // Default hvx-length for various versions.
31 static StringRef getDefaultHvxLength(StringRef Cpu) {
32   return llvm::StringSwitch<StringRef>(Cpu)
33       .Case("v60", "64b")
34       .Case("v62", "64b")
35       .Case("v65", "64b")
36       .Default("128b");
37 }
38
39 static void handleHVXWarnings(const Driver &D, const ArgList &Args) {
40   // Handle deprecated HVX double warnings.
41   if (Arg *A = Args.getLastArg(options::OPT_mhexagon_hvx_double))
42     D.Diag(diag::warn_drv_deprecated_arg)
43         << A->getAsString(Args) << "-mhvx-length=128B";
44   if (Arg *A = Args.getLastArg(options::OPT_mno_hexagon_hvx_double))
45     D.Diag(diag::warn_drv_deprecated_arg) << A->getAsString(Args) << "-mno-hvx";
46   // Handle the unsupported values passed to mhvx-length.
47   if (Arg *A = Args.getLastArg(options::OPT_mhexagon_hvx_length_EQ)) {
48     StringRef Val = A->getValue();
49     if (!Val.equals_lower("64b") && !Val.equals_lower("128b"))
50       D.Diag(diag::err_drv_unsupported_option_argument)
51           << A->getOption().getName() << Val;
52   }
53 }
54
55 // Handle hvx target features explicitly.
56 static void handleHVXTargetFeatures(const Driver &D, const ArgList &Args,
57                                     std::vector<StringRef> &Features,
58                                     bool &HasHVX) {
59   // Handle HVX warnings.
60   handleHVXWarnings(D, Args);
61
62   // Add the +hvx* features based on commandline flags.
63   StringRef HVXFeature, HVXLength;
64   StringRef Cpu(toolchains::HexagonToolChain::GetTargetCPUVersion(Args));
65
66   // Handle -mhvx, -mhvx=, -mno-hvx, -mno-hvx-double.
67   if (Arg *A = Args.getLastArg(
68           options::OPT_mno_hexagon_hvx, options::OPT_mno_hexagon_hvx_double,
69           options::OPT_mhexagon_hvx, options::OPT_mhexagon_hvx_EQ)) {
70     if (A->getOption().matches(options::OPT_mno_hexagon_hvx) ||
71         A->getOption().matches(options::OPT_mno_hexagon_hvx_double)) {
72       return;
73     } else if (A->getOption().matches(options::OPT_mhexagon_hvx_EQ)) {
74       HasHVX = true;
75       HVXFeature = Cpu = A->getValue();
76       HVXFeature = Args.MakeArgString(llvm::Twine("+hvx") + HVXFeature.lower());
77     } else if (A->getOption().matches(options::OPT_mhexagon_hvx)) {
78       HasHVX = true;
79       HVXFeature = Args.MakeArgString(llvm::Twine("+hvx") + Cpu);
80     }
81     Features.push_back(HVXFeature);
82   }
83
84   // Handle -mhvx-length=, -mhvx-double.
85   if (Arg *A = Args.getLastArg(options::OPT_mhexagon_hvx_length_EQ,
86                                options::OPT_mhexagon_hvx_double)) {
87     // These falgs are valid only if HVX in enabled.
88     if (!HasHVX)
89       D.Diag(diag::err_drv_invalid_hvx_length);
90     else if (A->getOption().matches(options::OPT_mhexagon_hvx_length_EQ))
91       HVXLength = A->getValue();
92     else if (A->getOption().matches(options::OPT_mhexagon_hvx_double))
93       HVXLength = "128b";
94   }
95   // Default hvx-length based on Cpu.
96   else if (HasHVX)
97     HVXLength = getDefaultHvxLength(Cpu);
98
99   if (!HVXLength.empty()) {
100     HVXFeature =
101         Args.MakeArgString(llvm::Twine("+hvx-length") + HVXLength.lower());
102     Features.push_back(HVXFeature);
103   }
104 }
105
106 // Hexagon target features.
107 void hexagon::getHexagonTargetFeatures(const Driver &D, const ArgList &Args,
108                                        std::vector<StringRef> &Features) {
109   handleTargetFeaturesGroup(Args, Features,
110                             options::OPT_m_hexagon_Features_Group);
111
112   bool UseLongCalls = false;
113   if (Arg *A = Args.getLastArg(options::OPT_mlong_calls,
114                                options::OPT_mno_long_calls)) {
115     if (A->getOption().matches(options::OPT_mlong_calls))
116       UseLongCalls = true;
117   }
118
119   Features.push_back(UseLongCalls ? "+long-calls" : "-long-calls");
120
121   bool HasHVX(false);
122   handleHVXTargetFeatures(D, Args, Features, HasHVX);
123 }
124
125 // Hexagon tools start.
126 void hexagon::Assembler::RenderExtraToolArgs(const JobAction &JA,
127                                              ArgStringList &CmdArgs) const {
128 }
129
130 void hexagon::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
131                                       const InputInfo &Output,
132                                       const InputInfoList &Inputs,
133                                       const ArgList &Args,
134                                       const char *LinkingOutput) const {
135   claimNoWarnArgs(Args);
136
137   auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain());
138   const Driver &D = HTC.getDriver();
139   ArgStringList CmdArgs;
140
141   CmdArgs.push_back("-march=hexagon");
142
143   RenderExtraToolArgs(JA, CmdArgs);
144
145   const char *AsName = "hexagon-llvm-mc";
146   CmdArgs.push_back("-filetype=obj");
147   CmdArgs.push_back(Args.MakeArgString(
148       "-mcpu=hexagon" +
149       toolchains::HexagonToolChain::GetTargetCPUVersion(Args)));
150
151   if (Output.isFilename()) {
152     CmdArgs.push_back("-o");
153     CmdArgs.push_back(Output.getFilename());
154   } else {
155     assert(Output.isNothing() && "Unexpected output");
156     CmdArgs.push_back("-fsyntax-only");
157   }
158
159   if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
160     CmdArgs.push_back(Args.MakeArgString("-gpsize=" + Twine(G.getValue())));
161   }
162
163   Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
164
165   // Only pass -x if gcc will understand it; otherwise hope gcc
166   // understands the suffix correctly. The main use case this would go
167   // wrong in is for linker inputs if they happened to have an odd
168   // suffix; really the only way to get this to happen is a command
169   // like '-x foobar a.c' which will treat a.c like a linker input.
170   //
171   // FIXME: For the linker case specifically, can we safely convert
172   // inputs into '-Wl,' options?
173   for (const auto &II : Inputs) {
174     // Don't try to pass LLVM or AST inputs to a generic gcc.
175     if (types::isLLVMIR(II.getType()))
176       D.Diag(clang::diag::err_drv_no_linker_llvm_support)
177           << HTC.getTripleString();
178     else if (II.getType() == types::TY_AST)
179       D.Diag(clang::diag::err_drv_no_ast_support)
180           << HTC.getTripleString();
181     else if (II.getType() == types::TY_ModuleFile)
182       D.Diag(diag::err_drv_no_module_support)
183           << HTC.getTripleString();
184
185     if (II.isFilename())
186       CmdArgs.push_back(II.getFilename());
187     else
188       // Don't render as input, we need gcc to do the translations.
189       // FIXME: What is this?
190       II.getInputArg().render(Args, CmdArgs);
191   }
192
193   auto *Exec = Args.MakeArgString(HTC.GetProgramPath(AsName));
194   C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
195 }
196
197 void hexagon::Linker::RenderExtraToolArgs(const JobAction &JA,
198                                           ArgStringList &CmdArgs) const {
199 }
200
201 static void
202 constructHexagonLinkArgs(Compilation &C, const JobAction &JA,
203                          const toolchains::HexagonToolChain &HTC,
204                          const InputInfo &Output, const InputInfoList &Inputs,
205                          const ArgList &Args, ArgStringList &CmdArgs,
206                          const char *LinkingOutput) {
207
208   const Driver &D = HTC.getDriver();
209
210   //----------------------------------------------------------------------------
211   //
212   //----------------------------------------------------------------------------
213   bool IsStatic = Args.hasArg(options::OPT_static);
214   bool IsShared = Args.hasArg(options::OPT_shared);
215   bool IsPIE = Args.hasArg(options::OPT_pie);
216   bool IncStdLib = !Args.hasArg(options::OPT_nostdlib);
217   bool IncStartFiles = !Args.hasArg(options::OPT_nostartfiles);
218   bool IncDefLibs = !Args.hasArg(options::OPT_nodefaultlibs);
219   bool UseG0 = false;
220   bool UseShared = IsShared && !IsStatic;
221
222   //----------------------------------------------------------------------------
223   // Silence warnings for various options
224   //----------------------------------------------------------------------------
225   Args.ClaimAllArgs(options::OPT_g_Group);
226   Args.ClaimAllArgs(options::OPT_emit_llvm);
227   Args.ClaimAllArgs(options::OPT_w); // Other warning options are already
228                                      // handled somewhere else.
229   Args.ClaimAllArgs(options::OPT_static_libgcc);
230
231   //----------------------------------------------------------------------------
232   //
233   //----------------------------------------------------------------------------
234   if (Args.hasArg(options::OPT_s))
235     CmdArgs.push_back("-s");
236
237   if (Args.hasArg(options::OPT_r))
238     CmdArgs.push_back("-r");
239
240   for (const auto &Opt : HTC.ExtraOpts)
241     CmdArgs.push_back(Opt.c_str());
242
243   CmdArgs.push_back("-march=hexagon");
244   StringRef CpuVer = toolchains::HexagonToolChain::GetTargetCPUVersion(Args);
245   CmdArgs.push_back(Args.MakeArgString("-mcpu=hexagon" + CpuVer));
246
247   if (IsShared) {
248     CmdArgs.push_back("-shared");
249     // The following should be the default, but doing as hexagon-gcc does.
250     CmdArgs.push_back("-call_shared");
251   }
252
253   if (IsStatic)
254     CmdArgs.push_back("-static");
255
256   if (IsPIE && !IsShared)
257     CmdArgs.push_back("-pie");
258
259   if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
260     CmdArgs.push_back(Args.MakeArgString("-G" + Twine(G.getValue())));
261     UseG0 = G.getValue() == 0;
262   }
263
264   //----------------------------------------------------------------------------
265   //
266   //----------------------------------------------------------------------------
267   CmdArgs.push_back("-o");
268   CmdArgs.push_back(Output.getFilename());
269
270   //----------------------------------------------------------------------------
271   // moslib
272   //----------------------------------------------------------------------------
273   std::vector<std::string> OsLibs;
274   bool HasStandalone = false;
275
276   for (const Arg *A : Args.filtered(options::OPT_moslib_EQ)) {
277     A->claim();
278     OsLibs.emplace_back(A->getValue());
279     HasStandalone = HasStandalone || (OsLibs.back() == "standalone");
280   }
281   if (OsLibs.empty()) {
282     OsLibs.push_back("standalone");
283     HasStandalone = true;
284   }
285
286   //----------------------------------------------------------------------------
287   // Start Files
288   //----------------------------------------------------------------------------
289   const std::string MCpuSuffix = "/" + CpuVer.str();
290   const std::string MCpuG0Suffix = MCpuSuffix + "/G0";
291   const std::string RootDir =
292       HTC.getHexagonTargetDir(D.InstalledDir, D.PrefixDirs) + "/";
293   const std::string StartSubDir =
294       "hexagon/lib" + (UseG0 ? MCpuG0Suffix : MCpuSuffix);
295
296   auto Find = [&HTC] (const std::string &RootDir, const std::string &SubDir,
297                       const char *Name) -> std::string {
298     std::string RelName = SubDir + Name;
299     std::string P = HTC.GetFilePath(RelName.c_str());
300     if (llvm::sys::fs::exists(P))
301       return P;
302     return RootDir + RelName;
303   };
304
305   if (IncStdLib && IncStartFiles) {
306     if (!IsShared) {
307       if (HasStandalone) {
308         std::string Crt0SA = Find(RootDir, StartSubDir, "/crt0_standalone.o");
309         CmdArgs.push_back(Args.MakeArgString(Crt0SA));
310       }
311       std::string Crt0 = Find(RootDir, StartSubDir, "/crt0.o");
312       CmdArgs.push_back(Args.MakeArgString(Crt0));
313     }
314     std::string Init = UseShared
315           ? Find(RootDir, StartSubDir + "/pic", "/initS.o")
316           : Find(RootDir, StartSubDir, "/init.o");
317     CmdArgs.push_back(Args.MakeArgString(Init));
318   }
319
320   //----------------------------------------------------------------------------
321   // Library Search Paths
322   //----------------------------------------------------------------------------
323   const ToolChain::path_list &LibPaths = HTC.getFilePaths();
324   for (const auto &LibPath : LibPaths)
325     CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath));
326
327   //----------------------------------------------------------------------------
328   //
329   //----------------------------------------------------------------------------
330   Args.AddAllArgs(CmdArgs,
331                   {options::OPT_T_Group, options::OPT_e, options::OPT_s,
332                    options::OPT_t, options::OPT_u_Group});
333
334   AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA);
335
336   //----------------------------------------------------------------------------
337   // Libraries
338   //----------------------------------------------------------------------------
339   if (IncStdLib && IncDefLibs) {
340     if (D.CCCIsCXX()) {
341       if (HTC.ShouldLinkCXXStdlib(Args))
342         HTC.AddCXXStdlibLibArgs(Args, CmdArgs);
343       CmdArgs.push_back("-lm");
344     }
345
346     CmdArgs.push_back("--start-group");
347
348     if (!IsShared) {
349       for (StringRef Lib : OsLibs)
350         CmdArgs.push_back(Args.MakeArgString("-l" + Lib));
351       CmdArgs.push_back("-lc");
352     }
353     CmdArgs.push_back("-lgcc");
354
355     CmdArgs.push_back("--end-group");
356   }
357
358   //----------------------------------------------------------------------------
359   // End files
360   //----------------------------------------------------------------------------
361   if (IncStdLib && IncStartFiles) {
362     std::string Fini = UseShared
363           ? Find(RootDir, StartSubDir + "/pic", "/finiS.o")
364           : Find(RootDir, StartSubDir, "/fini.o");
365     CmdArgs.push_back(Args.MakeArgString(Fini));
366   }
367 }
368
369 void hexagon::Linker::ConstructJob(Compilation &C, const JobAction &JA,
370                                    const InputInfo &Output,
371                                    const InputInfoList &Inputs,
372                                    const ArgList &Args,
373                                    const char *LinkingOutput) const {
374   auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain());
375
376   ArgStringList CmdArgs;
377   constructHexagonLinkArgs(C, JA, HTC, Output, Inputs, Args, CmdArgs,
378                            LinkingOutput);
379
380   std::string Linker = HTC.GetProgramPath("hexagon-link");
381   C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker),
382                                           CmdArgs, Inputs));
383 }
384 // Hexagon tools end.
385
386 /// Hexagon Toolchain
387
388 std::string HexagonToolChain::getHexagonTargetDir(
389       const std::string &InstalledDir,
390       const SmallVectorImpl<std::string> &PrefixDirs) const {
391   std::string InstallRelDir;
392   const Driver &D = getDriver();
393
394   // Locate the rest of the toolchain ...
395   for (auto &I : PrefixDirs)
396     if (D.getVFS().exists(I))
397       return I;
398
399   if (getVFS().exists(InstallRelDir = InstalledDir + "/../target"))
400     return InstallRelDir;
401
402   return InstalledDir;
403 }
404
405 Optional<unsigned> HexagonToolChain::getSmallDataThreshold(
406       const ArgList &Args) {
407   StringRef Gn = "";
408   if (Arg *A = Args.getLastArg(options::OPT_G)) {
409     Gn = A->getValue();
410   } else if (Args.getLastArg(options::OPT_shared, options::OPT_fpic,
411                              options::OPT_fPIC)) {
412     Gn = "0";
413   }
414
415   unsigned G;
416   if (!Gn.getAsInteger(10, G))
417     return G;
418
419   return None;
420 }
421
422 void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args,
423       ToolChain::path_list &LibPaths) const {
424   const Driver &D = getDriver();
425
426   //----------------------------------------------------------------------------
427   // -L Args
428   //----------------------------------------------------------------------------
429   for (Arg *A : Args.filtered(options::OPT_L))
430     for (const char *Value : A->getValues())
431       LibPaths.push_back(Value);
432
433   //----------------------------------------------------------------------------
434   // Other standard paths
435   //----------------------------------------------------------------------------
436   std::vector<std::string> RootDirs;
437   std::copy(D.PrefixDirs.begin(), D.PrefixDirs.end(),
438             std::back_inserter(RootDirs));
439
440   std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
441                                               D.PrefixDirs);
442   if (std::find(RootDirs.begin(), RootDirs.end(), TargetDir) == RootDirs.end())
443     RootDirs.push_back(TargetDir);
444
445   bool HasPIC = Args.hasArg(options::OPT_fpic, options::OPT_fPIC);
446   // Assume G0 with -shared.
447   bool HasG0 = Args.hasArg(options::OPT_shared);
448   if (auto G = getSmallDataThreshold(Args))
449     HasG0 = G.getValue() == 0;
450
451   const std::string CpuVer = GetTargetCPUVersion(Args).str();
452   for (auto &Dir : RootDirs) {
453     std::string LibDir = Dir + "/hexagon/lib";
454     std::string LibDirCpu = LibDir + '/' + CpuVer;
455     if (HasG0) {
456       if (HasPIC)
457         LibPaths.push_back(LibDirCpu + "/G0/pic");
458       LibPaths.push_back(LibDirCpu + "/G0");
459     }
460     LibPaths.push_back(LibDirCpu);
461     LibPaths.push_back(LibDir);
462   }
463 }
464
465 HexagonToolChain::HexagonToolChain(const Driver &D, const llvm::Triple &Triple,
466                                    const llvm::opt::ArgList &Args)
467     : Linux(D, Triple, Args) {
468   const std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
469                                                     D.PrefixDirs);
470
471   // Note: Generic_GCC::Generic_GCC adds InstalledDir and getDriver().Dir to
472   // program paths
473   const std::string BinDir(TargetDir + "/bin");
474   if (D.getVFS().exists(BinDir))
475     getProgramPaths().push_back(BinDir);
476
477   ToolChain::path_list &LibPaths = getFilePaths();
478
479   // Remove paths added by Linux toolchain. Currently Hexagon_TC really targets
480   // 'elf' OS type, so the Linux paths are not appropriate. When we actually
481   // support 'linux' we'll need to fix this up
482   LibPaths.clear();
483   getHexagonLibraryPaths(Args, LibPaths);
484 }
485
486 HexagonToolChain::~HexagonToolChain() {}
487
488 Tool *HexagonToolChain::buildAssembler() const {
489   return new tools::hexagon::Assembler(*this);
490 }
491
492 Tool *HexagonToolChain::buildLinker() const {
493   return new tools::hexagon::Linker(*this);
494 }
495
496 unsigned HexagonToolChain::getOptimizationLevel(
497     const llvm::opt::ArgList &DriverArgs) const {
498   // Copied in large part from lib/Frontend/CompilerInvocation.cpp.
499   Arg *A = DriverArgs.getLastArg(options::OPT_O_Group);
500   if (!A)
501     return 0;
502
503   if (A->getOption().matches(options::OPT_O0))
504     return 0;
505   if (A->getOption().matches(options::OPT_Ofast) ||
506       A->getOption().matches(options::OPT_O4))
507     return 3;
508   assert(A->getNumValues() != 0);
509   StringRef S(A->getValue());
510   if (S == "s" || S == "z" || S.empty())
511     return 2;
512   if (S == "g")
513     return 1;
514
515   unsigned OptLevel;
516   if (S.getAsInteger(10, OptLevel))
517     return 0;
518   return OptLevel;
519 }
520
521 void HexagonToolChain::addClangTargetOptions(const ArgList &DriverArgs,
522                                              ArgStringList &CC1Args,
523                                              Action::OffloadKind) const {
524   if (DriverArgs.hasArg(options::OPT_ffp_contract))
525     return;
526   unsigned OptLevel = getOptimizationLevel(DriverArgs);
527   if (OptLevel >= 3)
528     CC1Args.push_back("-ffp-contract=fast");
529 }
530
531 void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
532                                                  ArgStringList &CC1Args) const {
533   if (DriverArgs.hasArg(options::OPT_nostdinc) ||
534       DriverArgs.hasArg(options::OPT_nostdlibinc))
535     return;
536
537   const Driver &D = getDriver();
538   std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
539                                               D.PrefixDirs);
540   addExternCSystemInclude(DriverArgs, CC1Args, TargetDir + "/hexagon/include");
541 }
542
543
544 void HexagonToolChain::addLibStdCxxIncludePaths(
545     const llvm::opt::ArgList &DriverArgs,
546     llvm::opt::ArgStringList &CC1Args) const {
547   const Driver &D = getDriver();
548   std::string TargetDir = getHexagonTargetDir(D.InstalledDir, D.PrefixDirs);
549   addLibStdCXXIncludePaths(TargetDir, "/hexagon/include/c++", "", "", "", "",
550                            DriverArgs, CC1Args);
551 }
552
553 ToolChain::CXXStdlibType
554 HexagonToolChain::GetCXXStdlibType(const ArgList &Args) const {
555   Arg *A = Args.getLastArg(options::OPT_stdlib_EQ);
556   if (!A)
557     return ToolChain::CST_Libstdcxx;
558
559   StringRef Value = A->getValue();
560   if (Value != "libstdc++")
561     getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args);
562
563   return ToolChain::CST_Libstdcxx;
564 }
565
566 //
567 // Returns the default CPU for Hexagon. This is the default compilation target
568 // if no Hexagon processor is selected at the command-line.
569 //
570 const StringRef HexagonToolChain::GetDefaultCPU() {
571   return "hexagonv60";
572 }
573
574 const StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) {
575   Arg *CpuArg = nullptr;
576   if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ, options::OPT_march_EQ))
577     CpuArg = A;
578
579   StringRef CPU = CpuArg ? CpuArg->getValue() : GetDefaultCPU();
580   if (CPU.startswith("hexagon"))
581     return CPU.substr(sizeof("hexagon") - 1);
582   return CPU;
583 }