[Hexagon] Update default paths and arguments

- Removed support for hexagonv3 and earlier.
- Added handling of hexagonv55 and hexagonv60.
- Added handling of target features (hvx, hvx-double).
- Updated paths to reflect current directory layout.

llvm-svn: 255502
diff --git a/clang/lib/Driver/ToolChains.cpp b/clang/lib/Driver/ToolChains.cpp
index 7370e62..2d882eb 100644
--- a/clang/lib/Driver/ToolChains.cpp
+++ b/clang/lib/Driver/ToolChains.cpp
@@ -2555,122 +2555,108 @@
 
 /// Hexagon Toolchain
 
-std::string HexagonToolChain::GetGnuDir(const std::string &InstalledDir,
-                                        const ArgList &Args) const {
+std::string HexagonToolChain::getHexagonTargetDir(
+      const std::string &InstalledDir,
+      const SmallVectorImpl<std::string> &PrefixDirs) const {
+  std::string InstallRelDir;
+  const Driver &D = getDriver();
+
   // Locate the rest of the toolchain ...
-  std::string GccToolchain = getGCCToolchainDir(Args);
+  for (auto &I : PrefixDirs)
+    if (D.getVFS().exists(I))
+      return I;
 
-  if (!GccToolchain.empty())
-    return GccToolchain;
-
-  std::string InstallRelDir = InstalledDir + "/../../gnu";
-  if (getVFS().exists(InstallRelDir))
+  if (getVFS().exists(InstallRelDir = InstalledDir + "/../target"))
     return InstallRelDir;
 
-  std::string PrefixRelDir = std::string(LLVM_PREFIX) + "/../gnu";
+  std::string PrefixRelDir = std::string(LLVM_PREFIX) + "/target";
   if (getVFS().exists(PrefixRelDir))
     return PrefixRelDir;
 
   return InstallRelDir;
 }
 
-const char *HexagonToolChain::GetSmallDataThreshold(const ArgList &Args) {
-  Arg *A;
 
-  A = Args.getLastArg(options::OPT_G, options::OPT_G_EQ,
-                      options::OPT_msmall_data_threshold_EQ);
-  if (A)
-    return A->getValue();
+Optional<unsigned> HexagonToolChain::getSmallDataThreshold(
+      const ArgList &Args) {
+  StringRef Gn = "";
+  if (Arg *A = Args.getLastArg(options::OPT_G, options::OPT_G_EQ,
+                               options::OPT_msmall_data_threshold_EQ)) {
+    Gn = A->getValue();
+  } else if (Args.getLastArg(options::OPT_shared, options::OPT_fpic,
+                             options::OPT_fPIC)) {
+    Gn = "0";
+  }
 
-  A = Args.getLastArg(options::OPT_shared, options::OPT_fpic,
-                      options::OPT_fPIC);
-  if (A)
-    return "0";
+  unsigned G;
+  if (!Gn.getAsInteger(10, G))
+    return G;
 
-  return nullptr;
+  return None;
 }
 
-bool HexagonToolChain::UsesG0(const char *smallDataThreshold) {
-  return smallDataThreshold && smallDataThreshold[0] == '0';
-}
 
-static void GetHexagonLibraryPaths(const HexagonToolChain &TC,
-                                   const ArgList &Args, const std::string &Ver,
-                                   const std::string &MarchString,
-                                   const std::string &InstalledDir,
-                                   ToolChain::path_list *LibPaths) {
-  bool buildingLib = Args.hasArg(options::OPT_shared);
+void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args,
+      ToolChain::path_list &LibPaths) const {
+  const Driver &D = getDriver();
 
   //----------------------------------------------------------------------------
   // -L Args
   //----------------------------------------------------------------------------
   for (Arg *A : Args.filtered(options::OPT_L))
     for (const char *Value : A->getValues())
-      LibPaths->push_back(Value);
+      LibPaths.push_back(Value);
 
   //----------------------------------------------------------------------------
   // Other standard paths
   //----------------------------------------------------------------------------
-  const std::string MarchSuffix = "/" + MarchString;
-  const std::string G0Suffix = "/G0";
-  const std::string MarchG0Suffix = MarchSuffix + G0Suffix;
-  const std::string RootDir = TC.GetGnuDir(InstalledDir, Args) + "/";
+  std::vector<std::string> RootDirs;
+  std::copy(D.PrefixDirs.begin(), D.PrefixDirs.end(), RootDirs.begin());
 
-  // lib/gcc/hexagon/...
-  std::string LibGCCHexagonDir = RootDir + "lib/gcc/hexagon/";
-  if (buildingLib) {
-    LibPaths->push_back(LibGCCHexagonDir + Ver + MarchG0Suffix);
-    LibPaths->push_back(LibGCCHexagonDir + Ver + G0Suffix);
+  std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
+                                              D.PrefixDirs);
+  if (std::find(RootDirs.begin(), RootDirs.end(), TargetDir) == RootDirs.end())
+    RootDirs.push_back(TargetDir);
+
+  bool HasPIC = Args.hasArg(options::OPT_fpic, options::OPT_fPIC);
+  // Assume G0 with -shared.
+  bool HasG0 = Args.hasArg(options::OPT_shared);
+  if (auto G = getSmallDataThreshold(Args))
+    HasG0 = G.getValue() == 0;
+
+  const std::string CpuVer = GetTargetCPUVersion(Args).str();
+  for (auto &Dir : RootDirs) {
+    std::string LibDir = Dir + "/hexagon/lib";
+    std::string LibDirCpu = LibDir + '/' + CpuVer;
+    if (HasG0) {
+      if (HasPIC)
+        LibPaths.push_back(LibDirCpu + "/G0/pic");
+      LibPaths.push_back(LibDirCpu + "/G0");
+    }
+    LibPaths.push_back(LibDirCpu);
+    LibPaths.push_back(LibDir);
   }
-  LibPaths->push_back(LibGCCHexagonDir + Ver + MarchSuffix);
-  LibPaths->push_back(LibGCCHexagonDir + Ver);
-
-  // lib/gcc/...
-  LibPaths->push_back(RootDir + "lib/gcc");
-
-  // hexagon/lib/...
-  std::string HexagonLibDir = RootDir + "hexagon/lib";
-  if (buildingLib) {
-    LibPaths->push_back(HexagonLibDir + MarchG0Suffix);
-    LibPaths->push_back(HexagonLibDir + G0Suffix);
-  }
-  LibPaths->push_back(HexagonLibDir + MarchSuffix);
-  LibPaths->push_back(HexagonLibDir);
 }
 
 HexagonToolChain::HexagonToolChain(const Driver &D, const llvm::Triple &Triple,
-                                   const ArgList &Args)
+                                   const llvm::opt::ArgList &Args)
     : Linux(D, Triple, Args) {
-  const std::string InstalledDir(getDriver().getInstalledDir());
-  const std::string GnuDir = GetGnuDir(InstalledDir, Args);
+  const std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
+                                                    D.PrefixDirs);
 
   // Note: Generic_GCC::Generic_GCC adds InstalledDir and getDriver().Dir to
   // program paths
-  const std::string BinDir(GnuDir + "/bin");
+  const std::string BinDir(TargetDir + "/bin");
   if (D.getVFS().exists(BinDir))
     getProgramPaths().push_back(BinDir);
 
-  // Determine version of GCC libraries and headers to use.
-  const std::string HexagonDir(GnuDir + "/lib/gcc/hexagon");
-  std::error_code ec;
-  GCCVersion MaxVersion = GCCVersion::Parse("0.0.0");
-  for (vfs::directory_iterator di = D.getVFS().dir_begin(HexagonDir, ec), de;
-       !ec && di != de; di = di.increment(ec)) {
-    GCCVersion cv = GCCVersion::Parse(llvm::sys::path::filename(di->getName()));
-    if (MaxVersion < cv)
-      MaxVersion = cv;
-  }
-  GCCLibAndIncVersion = MaxVersion;
-
-  ToolChain::path_list *LibPaths = &getFilePaths();
+  ToolChain::path_list &LibPaths = getFilePaths();
 
   // Remove paths added by Linux toolchain. Currently Hexagon_TC really targets
   // 'elf' OS type, so the Linux paths are not appropriate. When we actually
   // support 'linux' we'll need to fix this up
-  LibPaths->clear();
-
-  GetHexagonLibraryPaths(*this, Args, GetGCCLibAndIncVersion(),
-                         GetTargetCPU(Args), InstalledDir, LibPaths);
+  LibPaths.clear();
+  getHexagonLibraryPaths(Args, LibPaths);
 }
 
 HexagonToolChain::~HexagonToolChain() {}
@@ -2685,18 +2671,14 @@
 
 void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
                                                  ArgStringList &CC1Args) const {
-  const Driver &D = getDriver();
-
   if (DriverArgs.hasArg(options::OPT_nostdinc) ||
       DriverArgs.hasArg(options::OPT_nostdlibinc))
     return;
 
-  std::string Ver(GetGCCLibAndIncVersion());
-  std::string GnuDir = GetGnuDir(D.InstalledDir, DriverArgs);
-  std::string HexagonDir(GnuDir + "/lib/gcc/hexagon/" + Ver);
-  addExternCSystemInclude(DriverArgs, CC1Args, HexagonDir + "/include");
-  addExternCSystemInclude(DriverArgs, CC1Args, HexagonDir + "/include-fixed");
-  addExternCSystemInclude(DriverArgs, CC1Args, GnuDir + "/hexagon/include");
+  const Driver &D = getDriver();
+  std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
+                                              D.PrefixDirs);
+  addExternCSystemInclude(DriverArgs, CC1Args, TargetDir + "/hexagon/include");
 }
 
 void HexagonToolChain::AddClangCXXStdlibIncludeArgs(
@@ -2706,12 +2688,8 @@
     return;
 
   const Driver &D = getDriver();
-  std::string Ver(GetGCCLibAndIncVersion());
-  SmallString<128> IncludeDir(GetGnuDir(D.InstalledDir, DriverArgs));
-
-  llvm::sys::path::append(IncludeDir, "hexagon/include/c++/");
-  llvm::sys::path::append(IncludeDir, Ver);
-  addSystemInclude(DriverArgs, CC1Args, IncludeDir);
+  std::string TargetDir = getHexagonTargetDir(D.InstalledDir, D.PrefixDirs);
+  addSystemInclude(DriverArgs, CC1Args, TargetDir + "/hexagon/include/c++");
 }
 
 ToolChain::CXXStdlibType
@@ -2721,53 +2699,34 @@
     return ToolChain::CST_Libstdcxx;
 
   StringRef Value = A->getValue();
-  if (Value != "libstdc++") {
+  if (Value != "libstdc++")
     getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args);
-  }
 
   return ToolChain::CST_Libstdcxx;
 }
 
-static int getHexagonVersion(const ArgList &Args) {
-  Arg *A = Args.getLastArg(options::OPT_march_EQ, options::OPT_mcpu_EQ);
-  // Select the default CPU (v4) if none was given.
-  if (!A)
-    return 4;
-
-  // FIXME: produce errors if we cannot parse the version.
-  StringRef WhichHexagon = A->getValue();
-  if (WhichHexagon.startswith("hexagonv")) {
-    int Val;
-    if (!WhichHexagon.substr(sizeof("hexagonv") - 1).getAsInteger(10, Val))
-      return Val;
-  }
-  if (WhichHexagon.startswith("v")) {
-    int Val;
-    if (!WhichHexagon.substr(1).getAsInteger(10, Val))
-      return Val;
-  }
-
-  // FIXME: should probably be an error.
-  return 4;
+//
+// Returns the default CPU for Hexagon. This is the default compilation target
+// if no Hexagon processor is selected at the command-line.
+//
+const StringRef HexagonToolChain::GetDefaultCPU() {
+  return "hexagonv60";
 }
 
-StringRef HexagonToolChain::GetTargetCPU(const ArgList &Args) {
-  int V = getHexagonVersion(Args);
-  // FIXME: We don't support versions < 4. We should error on them.
-  switch (V) {
-  default:
-    llvm_unreachable("Unexpected version");
-  case 5:
-    return "v5";
-  case 4:
-    return "v4";
-  case 3:
-    return "v3";
-  case 2:
-    return "v2";
-  case 1:
-    return "v1";
+const StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) {
+  Arg *CpuArg = nullptr;
+
+  for (auto &A : Args) {
+    if (A->getOption().matches(options::OPT_mcpu_EQ)) {
+      CpuArg = A;
+      A->claim();
+    }
   }
+
+  StringRef CPU = CpuArg ? CpuArg->getValue() : GetDefaultCPU();
+  if (CPU.startswith("hexagon"))
+    return CPU.substr(sizeof("hexagon") - 1);
+  return CPU;
 }
 // End Hexagon