[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
 
diff --git a/clang/lib/Driver/ToolChains.h b/clang/lib/Driver/ToolChains.h
index ceb61ca..257750e 100644
--- a/clang/lib/Driver/ToolChains.h
+++ b/clang/lib/Driver/ToolChains.h
@@ -875,14 +875,17 @@
     return true;
   }
 
-  std::string GetGnuDir(const std::string &InstalledDir,
-                        const llvm::opt::ArgList &Args) const;
+  std::string getHexagonTargetDir(
+      const std::string &InstalledDir,
+      const SmallVectorImpl<std::string> &PrefixDirs) const;
+  void getHexagonLibraryPaths(const llvm::opt::ArgList &Args,
+      ToolChain::path_list &LibPaths) const;
 
-  static StringRef GetTargetCPU(const llvm::opt::ArgList &Args);
+  static const StringRef GetDefaultCPU();
+  static const StringRef GetTargetCPUVersion(const llvm::opt::ArgList &Args);
 
-  static const char *GetSmallDataThreshold(const llvm::opt::ArgList &Args);
-
-  static bool UsesG0(const char *smallDataThreshold);
+  static Optional<unsigned> getSmallDataThreshold(
+      const llvm::opt::ArgList &Args);
 };
 
 class LLVM_LIBRARY_VISIBILITY AMDGPUToolChain : public Generic_ELF {
diff --git a/clang/lib/Driver/Tools.cpp b/clang/lib/Driver/Tools.cpp
index a73c086..7a02a11 100644
--- a/clang/lib/Driver/Tools.cpp
+++ b/clang/lib/Driver/Tools.cpp
@@ -1714,7 +1714,8 @@
     return getX86TargetCPU(Args, T);
 
   case llvm::Triple::hexagon:
-    return "hexagon" + toolchains::HexagonToolChain::GetTargetCPU(Args).str();
+    return "hexagon" +
+           toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str();
 
   case llvm::Triple::systemz:
     return getSystemZTargetCPU(Args);
@@ -1997,12 +1998,11 @@
   CmdArgs.push_back("-mqdsp6-compat");
   CmdArgs.push_back("-Wreturn-type");
 
-  if (const char *v =
-          toolchains::HexagonToolChain::GetSmallDataThreshold(Args)) {
-    std::string SmallDataThreshold = "-hexagon-small-data-threshold=";
-    SmallDataThreshold += v;
+  if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
+    std::string N = llvm::utostr(G.getValue());
+    std::string Opt = std::string("-hexagon-small-data-threshold=") + N;
     CmdArgs.push_back("-mllvm");
-    CmdArgs.push_back(Args.MakeArgString(SmallDataThreshold));
+    CmdArgs.push_back(Args.MakeArgString(Opt));
   }
 
   if (!Args.hasArg(options::OPT_fno_short_enums))
@@ -2182,6 +2182,29 @@
     Features.push_back("+reserve-x18");
 }
 
+static void getHexagonTargetFeatures(const ArgList &Args,
+                                     std::vector<const char *> &Features) {
+  bool HasHVX = false, HasHVXD = false;
+
+  for (auto &A : Args) {
+    auto &Opt = A->getOption();
+    if (Opt.matches(options::OPT_mhexagon_hvx))
+      HasHVX = true;
+    else if (Opt.matches(options::OPT_mno_hexagon_hvx))
+      HasHVXD = HasHVX = false;
+    else if (Opt.matches(options::OPT_mhexagon_hvx_double))
+      HasHVXD = HasHVX = true;
+    else if (Opt.matches(options::OPT_mno_hexagon_hvx_double))
+      HasHVXD = false;
+    else
+      continue;
+    A->claim();
+  }
+
+  Features.push_back(HasHVX  ? "+hvx" : "-hvx");
+  Features.push_back(HasHVXD ? "+hvx-double" : "-hvx-double");
+}
+
 static void getWebAssemblyTargetFeatures(const ArgList &Args,
                                          std::vector<const char *> &Features) {
   for (const Arg *A : Args.filtered(options::OPT_m_wasm_Features_Group)) {
@@ -2238,6 +2261,9 @@
   case llvm::Triple::x86_64:
     getX86TargetFeatures(D, Triple, Args, Features);
     break;
+  case llvm::Triple::hexagon:
+    getHexagonTargetFeatures(Args, Features);
+    break;
   case llvm::Triple::wasm32:
   case llvm::Triple::wasm64:
     getWebAssemblyTargetFeatures(Args, Features);
@@ -6049,7 +6075,9 @@
 
 // Hexagon tools start.
 void hexagon::Assembler::RenderExtraToolArgs(const JobAction &JA,
-                                             ArgStringList &CmdArgs) const {}
+                                             ArgStringList &CmdArgs) const {
+}
+
 void hexagon::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
                                       const InputInfo &Output,
                                       const InputInfoList &Inputs,
@@ -6057,15 +6085,21 @@
                                       const char *LinkingOutput) const {
   claimNoWarnArgs(Args);
 
-  const Driver &D = getToolChain().getDriver();
+  auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain());
+  const Driver &D = HTC.getDriver();
   ArgStringList CmdArgs;
 
-  std::string MarchString = "-march=";
-  MarchString += toolchains::HexagonToolChain::GetTargetCPU(Args);
-  CmdArgs.push_back(Args.MakeArgString(MarchString));
+  std::string MArchString = "-march=hexagon";
+  CmdArgs.push_back(Args.MakeArgString(MArchString));
 
   RenderExtraToolArgs(JA, CmdArgs);
 
+  std::string AsName = "hexagon-llvm-mc";
+  std::string MCpuString = "-mcpu=hexagon" +
+        toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str();
+  CmdArgs.push_back("-filetype=obj");
+  CmdArgs.push_back(Args.MakeArgString(MCpuString));
+
   if (Output.isFilename()) {
     CmdArgs.push_back("-o");
     CmdArgs.push_back(Output.getFilename());
@@ -6074,8 +6108,10 @@
     CmdArgs.push_back("-fsyntax-only");
   }
 
-  if (const char *v = toolchains::HexagonToolChain::GetSmallDataThreshold(Args))
-    CmdArgs.push_back(Args.MakeArgString(std::string("-G") + v));
+  if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
+    std::string N = llvm::utostr(G.getValue());
+    CmdArgs.push_back(Args.MakeArgString(std::string("-gpsize=") + N));
+  }
 
   Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
 
@@ -6091,13 +6127,13 @@
     // Don't try to pass LLVM or AST inputs to a generic gcc.
     if (types::isLLVMIR(II.getType()))
       D.Diag(clang::diag::err_drv_no_linker_llvm_support)
-          << getToolChain().getTripleString();
+          << HTC.getTripleString();
     else if (II.getType() == types::TY_AST)
       D.Diag(clang::diag::err_drv_no_ast_support)
-          << getToolChain().getTripleString();
+          << HTC.getTripleString();
     else if (II.getType() == types::TY_ModuleFile)
       D.Diag(diag::err_drv_no_module_support)
-          << getToolChain().getTripleString();
+          << HTC.getTripleString();
 
     if (II.isFilename())
       CmdArgs.push_back(II.getFilename());
@@ -6107,41 +6143,38 @@
       II.getInputArg().render(Args, CmdArgs);
   }
 
-  const char *GCCName = "hexagon-as";
-  const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(GCCName));
+  auto *Exec = Args.MakeArgString(HTC.GetProgramPath(AsName.c_str()));
   C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
 }
 
 void hexagon::Linker::RenderExtraToolArgs(const JobAction &JA,
                                           ArgStringList &CmdArgs) const {
-  // The types are (hopefully) good enough.
 }
 
 static void
 constructHexagonLinkArgs(Compilation &C, const JobAction &JA,
-                         const toolchains::HexagonToolChain &ToolChain,
+                         const toolchains::HexagonToolChain &HTC,
                          const InputInfo &Output, const InputInfoList &Inputs,
                          const ArgList &Args, ArgStringList &CmdArgs,
                          const char *LinkingOutput) {
 
-  const Driver &D = ToolChain.getDriver();
+  const Driver &D = HTC.getDriver();
 
   //----------------------------------------------------------------------------
   //
   //----------------------------------------------------------------------------
-  bool hasStaticArg = Args.hasArg(options::OPT_static);
-  bool buildingLib = Args.hasArg(options::OPT_shared);
-  bool buildPIE = Args.hasArg(options::OPT_pie);
-  bool incStdLib = !Args.hasArg(options::OPT_nostdlib);
-  bool incStartFiles = !Args.hasArg(options::OPT_nostartfiles);
-  bool incDefLibs = !Args.hasArg(options::OPT_nodefaultlibs);
-  bool useG0 = false;
-  bool useShared = buildingLib && !hasStaticArg;
+  bool IsStatic = Args.hasArg(options::OPT_static);
+  bool IsShared = Args.hasArg(options::OPT_shared);
+  bool IsPIE = Args.hasArg(options::OPT_pie);
+  bool IncStdLib = !Args.hasArg(options::OPT_nostdlib);
+  bool IncStartFiles = !Args.hasArg(options::OPT_nostartfiles);
+  bool IncDefLibs = !Args.hasArg(options::OPT_nodefaultlibs);
+  bool UseG0 = false;
+  bool UseShared = IsShared && !IsStatic;
 
   //----------------------------------------------------------------------------
   // Silence warnings for various options
   //----------------------------------------------------------------------------
-
   Args.ClaimAllArgs(options::OPT_g_Group);
   Args.ClaimAllArgs(options::OPT_emit_llvm);
   Args.ClaimAllArgs(options::OPT_w); // Other warning options are already
@@ -6151,28 +6184,37 @@
   //----------------------------------------------------------------------------
   //
   //----------------------------------------------------------------------------
-  for (const auto &Opt : ToolChain.ExtraOpts)
+  if (Args.hasArg(options::OPT_s))
+    CmdArgs.push_back("-s");
+
+  if (Args.hasArg(options::OPT_r))
+    CmdArgs.push_back("-r");
+
+  for (const auto &Opt : HTC.ExtraOpts)
     CmdArgs.push_back(Opt.c_str());
 
-  std::string MarchString = toolchains::HexagonToolChain::GetTargetCPU(Args);
-  CmdArgs.push_back(Args.MakeArgString("-m" + MarchString));
+  CmdArgs.push_back("-march=hexagon");
+  std::string CpuVer =
+        toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str();
+  std::string MCpuString = "-mcpu=hexagon" + CpuVer;
+  CmdArgs.push_back(Args.MakeArgString(MCpuString));
 
-  if (buildingLib) {
+  if (IsShared) {
     CmdArgs.push_back("-shared");
-    CmdArgs.push_back("-call_shared"); // should be the default, but doing as
-                                       // hexagon-gcc does
+    // The following should be the default, but doing as hexagon-gcc does.
+    CmdArgs.push_back("-call_shared");
   }
 
-  if (hasStaticArg)
+  if (IsStatic)
     CmdArgs.push_back("-static");
 
-  if (buildPIE && !buildingLib)
+  if (IsPIE && !IsShared)
     CmdArgs.push_back("-pie");
 
-  if (const char *v =
-          toolchains::HexagonToolChain::GetSmallDataThreshold(Args)) {
-    CmdArgs.push_back(Args.MakeArgString(std::string("-G") + v));
-    useG0 = toolchains::HexagonToolChain::UsesG0(v);
+  if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
+    std::string N = llvm::utostr(G.getValue());
+    CmdArgs.push_back(Args.MakeArgString(std::string("-G") + N));
+    UseG0 = G.getValue() == 0;
   }
 
   //----------------------------------------------------------------------------
@@ -6181,49 +6223,62 @@
   CmdArgs.push_back("-o");
   CmdArgs.push_back(Output.getFilename());
 
-  const std::string MarchSuffix = "/" + MarchString;
-  const std::string G0Suffix = "/G0";
-  const std::string MarchG0Suffix = MarchSuffix + G0Suffix;
-  const std::string RootDir = ToolChain.GetGnuDir(D.InstalledDir, Args) + "/";
-  const std::string StartFilesDir =
-      RootDir + "hexagon/lib" + (useG0 ? MarchG0Suffix : MarchSuffix);
-
   //----------------------------------------------------------------------------
   // moslib
   //----------------------------------------------------------------------------
-  std::vector<std::string> oslibs;
-  bool hasStandalone = false;
+  std::vector<std::string> OsLibs;
+  bool HasStandalone = false;
 
   for (const Arg *A : Args.filtered(options::OPT_moslib_EQ)) {
     A->claim();
-    oslibs.emplace_back(A->getValue());
-    hasStandalone = hasStandalone || (oslibs.back() == "standalone");
+    OsLibs.emplace_back(A->getValue());
+    HasStandalone = HasStandalone || (OsLibs.back() == "standalone");
   }
-  if (oslibs.empty()) {
-    oslibs.push_back("standalone");
-    hasStandalone = true;
+  if (OsLibs.empty()) {
+    OsLibs.push_back("standalone");
+    HasStandalone = true;
   }
 
   //----------------------------------------------------------------------------
   // Start Files
   //----------------------------------------------------------------------------
-  if (incStdLib && incStartFiles) {
+  const std::string MCpuSuffix = "/" + CpuVer;
+  const std::string MCpuG0Suffix = MCpuSuffix + "/G0";
+  const std::string RootDir =
+      HTC.getHexagonTargetDir(D.InstalledDir, D.PrefixDirs) + "/";
+  const std::string StartSubDir =
+      "hexagon/lib" + (UseG0 ? MCpuG0Suffix : MCpuSuffix);
 
-    if (!buildingLib) {
-      if (hasStandalone) {
-        CmdArgs.push_back(
-            Args.MakeArgString(StartFilesDir + "/crt0_standalone.o"));
+  auto Find = [&HTC] (const std::string &RootDir, const std::string &SubDir,
+                      const char *Name) -> std::string {
+    std::string RelName = SubDir + Name;
+    std::string P = HTC.GetFilePath(RelName.c_str());
+    if (llvm::sys::fs::exists(P))
+      return P;
+    return RootDir + RelName;
+  };
+
+  if (IncStdLib && IncStartFiles) {
+    if (!IsShared) {
+      if (HasStandalone) {
+        std::string Crt0SA = Find(RootDir, StartSubDir, "/crt0_standalone.o");
+        CmdArgs.push_back(Args.MakeArgString(Crt0SA));
       }
-      CmdArgs.push_back(Args.MakeArgString(StartFilesDir + "/crt0.o"));
+      std::string Crt0 = Find(RootDir, StartSubDir, "/crt0.o");
+      CmdArgs.push_back(Args.MakeArgString(Crt0));
     }
-    std::string initObj = useShared ? "/initS.o" : "/init.o";
-    CmdArgs.push_back(Args.MakeArgString(StartFilesDir + initObj));
+    std::string Init = UseShared
+          ? Find(RootDir, StartSubDir + "/pic", "/initS.o")
+          : Find(RootDir, StartSubDir, "/init.o");
+    CmdArgs.push_back(Args.MakeArgString(Init));
   }
 
   //----------------------------------------------------------------------------
   // Library Search Paths
   //----------------------------------------------------------------------------
-  ToolChain.AddFilePathLibArgs(Args, CmdArgs);
+  const ToolChain::path_list &LibPaths = HTC.getFilePaths();
+  for (const auto &LibPath : LibPaths)
+    CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath));
 
   //----------------------------------------------------------------------------
   //
@@ -6232,21 +6287,21 @@
                   {options::OPT_T_Group, options::OPT_e, options::OPT_s,
                    options::OPT_t, options::OPT_u_Group});
 
-  AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);
+  AddLinkerInputs(HTC, Inputs, Args, CmdArgs);
 
   //----------------------------------------------------------------------------
   // Libraries
   //----------------------------------------------------------------------------
-  if (incStdLib && incDefLibs) {
+  if (IncStdLib && IncDefLibs) {
     if (D.CCCIsCXX()) {
-      ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
+      HTC.AddCXXStdlibLibArgs(Args, CmdArgs);
       CmdArgs.push_back("-lm");
     }
 
     CmdArgs.push_back("--start-group");
 
-    if (!buildingLib) {
-      for (const std::string &Lib : oslibs)
+    if (!IsShared) {
+      for (const std::string &Lib : OsLibs)
         CmdArgs.push_back(Args.MakeArgString("-l" + Lib));
       CmdArgs.push_back("-lc");
     }
@@ -6258,9 +6313,11 @@
   //----------------------------------------------------------------------------
   // End files
   //----------------------------------------------------------------------------
-  if (incStdLib && incStartFiles) {
-    std::string finiObj = useShared ? "/finiS.o" : "/fini.o";
-    CmdArgs.push_back(Args.MakeArgString(StartFilesDir + finiObj));
+  if (IncStdLib && IncStartFiles) {
+    std::string Fini = UseShared
+          ? Find(RootDir, StartSubDir + "/pic", "/finiS.o")
+          : Find(RootDir, StartSubDir, "/fini.o");
+    CmdArgs.push_back(Args.MakeArgString(Fini));
   }
 }
 
@@ -6269,15 +6326,13 @@
                                    const InputInfoList &Inputs,
                                    const ArgList &Args,
                                    const char *LinkingOutput) const {
-
-  const toolchains::HexagonToolChain &ToolChain =
-      static_cast<const toolchains::HexagonToolChain &>(getToolChain());
+  auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain());
 
   ArgStringList CmdArgs;
-  constructHexagonLinkArgs(C, JA, ToolChain, Output, Inputs, Args, CmdArgs,
+  constructHexagonLinkArgs(C, JA, HTC, Output, Inputs, Args, CmdArgs,
                            LinkingOutput);
 
-  std::string Linker = ToolChain.GetProgramPath("hexagon-ld");
+  std::string Linker = HTC.GetProgramPath("hexagon-link");
   C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker),
                                           CmdArgs, Inputs));
 }