Skip to content

Conversation

@quic-k
Copy link
Contributor

@quic-k quic-k commented Nov 26, 2025

This patch adds Picolibc as part of triple so toolchains can switch the to Picolibc based on triple.
Hexagon toolchain uses the triple hexagon-none-picolibc.

@llvmbot llvmbot added backend:Hexagon clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' labels Nov 26, 2025
@llvmbot
Copy link
Member

llvmbot commented Nov 26, 2025

@llvm/pr-subscribers-backend-hexagon

Author: None (quic-k)

Changes

This patch adds Picolibc as part of triple so toolchains can switch the to Picolibc based on triple.
Hexagon toolchain uses the triple hexagon-none-picolibc.


Patch is 20.97 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/169613.diff

5 Files Affected:

  • (modified) clang/lib/Driver/ToolChains/Hexagon.cpp (+172-13)
  • (modified) clang/lib/Driver/ToolChains/Hexagon.h (+8)
  • (added) clang/test/Driver/hexagon-toolchain-picolibc.c (+133)
  • (modified) llvm/include/llvm/TargetParser/Triple.h (+4)
  • (modified) llvm/lib/TargetParser/Triple.cpp (+2)
diff --git a/clang/lib/Driver/ToolChains/Hexagon.cpp b/clang/lib/Driver/ToolChains/Hexagon.cpp
index 084f51721315c..151798e7e572b 100644
--- a/clang/lib/Driver/ToolChains/Hexagon.cpp
+++ b/clang/lib/Driver/ToolChains/Hexagon.cpp
@@ -273,6 +273,101 @@ void hexagon::Linker::RenderExtraToolArgs(const JobAction &JA,
                                           ArgStringList &CmdArgs) const {
 }
 
+static void constructHexagonPicolibcLinkArgs(
+    Compilation &C, const JobAction &JA,
+    const toolchains::HexagonToolChain &HTC, const InputInfo &Output,
+    const InputInfoList &Inputs, const ArgList &Args, ArgStringList &CmdArgs,
+    const char *LinkingOutput) {
+  const Driver &D = HTC.getDriver();
+  bool IsShared = Args.hasArg(options::OPT_shared);
+  bool IncStdLib = !Args.hasArg(options::OPT_nostdlib);
+  bool IncStartFiles = !Args.hasArg(options::OPT_nostartfiles);
+  bool IncDefLibs = !Args.hasArg(options::OPT_nodefaultlibs);
+  StringRef CpuVer = toolchains::HexagonToolChain::GetTargetCPUVersion(Args);
+  // Use G0 for Picolibc
+  bool UseG0 = true;
+  auto OsType = HTC.getOS();
+
+  CmdArgs.push_back("--eh-frame-hdr");
+  // Propagate arch flags to the linker when not using LLD, to match
+  // upstream Hexagon driver behavior validated by tests.
+  bool UseLLD = false;
+  const char *LinkerPath = Args.MakeArgString(HTC.GetLinkerPath(&UseLLD));
+  UseLLD = UseLLD ||
+           llvm::sys::path::filename(LinkerPath).ends_with("ld.lld") ||
+           llvm::sys::path::stem(LinkerPath).ends_with("ld.lld");
+  if (!UseLLD) {
+    CmdArgs.push_back("-march=hexagon");
+    CmdArgs.push_back(Args.MakeArgString("-mcpu=hexagon" + CpuVer));
+  }
+  CmdArgs.push_back("-o");
+  CmdArgs.push_back(Output.getFilename());
+
+  // Inputs
+  Args.addAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_s,
+                            options::OPT_t, options::OPT_u_Group});
+  AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA);
+
+  //----------------------------------------------------------------------------
+  // Start Files
+  //----------------------------------------------------------------------------
+  const std::string MCpuSuffix = "/" + CpuVer.str();
+  const std::string MCpuG0Suffix = MCpuSuffix + "/G0";
+  const std::string RootDir =
+      HTC.getHexagonTargetDir(D.Dir, D.PrefixDirs) + "/";
+  std::string NormalizedTriple =
+      HTC.getTriple().normalize(llvm::Triple::CanonicalForm::FOUR_IDENT);
+  const std::string StartSubDir =
+      NormalizedTriple + "/lib" + (UseG0 ? MCpuG0Suffix : MCpuSuffix);
+
+  if (IncStdLib && IncStartFiles) {
+    if (!IsShared) {
+      if (OsType == "none" || OsType == "unknown") {
+        std::string Crt0 = RootDir + StartSubDir + "/crt0-semihost.o";
+        CmdArgs.push_back(Args.MakeArgString(Crt0));
+      }
+    }
+  }
+
+  //----------------------------------------------------------------------------
+  // Library Search Paths
+  //----------------------------------------------------------------------------
+  const ToolChain::path_list &LibPaths = HTC.getFilePaths();
+  for (const auto &LibPath : LibPaths)
+    CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath));
+  //----------------------------------------------------------------------------
+  // Libraries
+  //----------------------------------------------------------------------------
+  if (IncStdLib && IncDefLibs) {
+    if (D.CCCIsCXX()) {
+      if (HTC.ShouldLinkCXXStdlib(Args))
+        HTC.AddCXXStdlibLibArgs(Args, CmdArgs);
+      CmdArgs.push_back("-lm");
+    }
+
+    CmdArgs.push_back("--start-group");
+
+    if (!IsShared) {
+      // add OS libraries to link
+      std::vector<std::string> OsLibs{};
+      if (OsType == "none" || OsType == "unknown") {
+        OsLibs.push_back("semihost");
+      } else if (OsType == "h2") {
+        OsLibs.push_back("h2");
+      } else if (OsType == "qurt") {
+        OsLibs.push_back("qurt");
+      }
+      for (StringRef Lib : OsLibs)
+        CmdArgs.push_back(Args.MakeArgString("-l" + Lib));
+      if (!Args.hasArg(options::OPT_nolibc))
+        CmdArgs.push_back("-lc");
+    }
+    // Force compiler-rt for Picolibc
+    CmdArgs.push_back("-lclang_rt.builtins");
+    CmdArgs.push_back("--end-group");
+  }
+}
+
 static void
 constructHexagonLinkArgs(Compilation &C, const JobAction &JA,
                          const toolchains::HexagonToolChain &HTC,
@@ -437,8 +532,8 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA,
       CmdArgs.push_back(Args.MakeArgString(Crt0));
     }
     std::string Init = UseShared
-          ? Find(RootDir, StartSubDir + "/pic", "/initS.o")
-          : Find(RootDir, StartSubDir, "/init.o");
+                           ? Find(RootDir, StartSubDir + "/pic", "/initS.o")
+                           : Find(RootDir, StartSubDir, "/init.o");
     CmdArgs.push_back(Args.MakeArgString(Init));
   }
 
@@ -500,8 +595,12 @@ void hexagon::Linker::ConstructJob(Compilation &C, const JobAction &JA,
   auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain());
 
   ArgStringList CmdArgs;
-  constructHexagonLinkArgs(C, JA, HTC, Output, Inputs, Args, CmdArgs,
-                           LinkingOutput);
+  if (HTC.getTriple().isPicolibc())
+    constructHexagonPicolibcLinkArgs(C, JA, HTC, Output, Inputs, Args, CmdArgs,
+                                     LinkingOutput);
+  else
+    constructHexagonLinkArgs(C, JA, HTC, Output, Inputs, Args, CmdArgs,
+                             LinkingOutput);
 
   const char *Exec = Args.MakeArgString(HTC.GetLinkerPath());
   C.addCommand(std::make_unique<Command>(JA, *this,
@@ -583,16 +682,38 @@ void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args,
     HasG0 = *G == 0;
 
   const std::string CpuVer = GetTargetCPUVersion(Args).str();
-  for (auto &Dir : RootDirs) {
-    std::string LibDir = Dir + "/hexagon/lib";
-    std::string LibDirCpu = LibDir + '/' + CpuVer;
+  // Special-case Picolibc baremetal layout:
+  //   <install>/../target/<normalized-triple>/lib/<vXX>/G0[/pic]
+  if (getTriple().isPicolibc()) {
+    std::string SubDir = '/' + CpuVer;
+    // Force G0 for Picolibc
+    HasG0 = true;
     if (HasG0) {
       if (HasPIC)
-        LibPaths.push_back(LibDirCpu + "/G0/pic");
-      LibPaths.push_back(LibDirCpu + "/G0");
+        SubDir += "/G0/pic";
+      else
+        SubDir += "/G0";
+    }
+    if (getTriple().getOS() != llvm::Triple::Linux) {
+      for (auto &Dir : RootDirs) {
+        auto NormalizedTriple = getTriple().normalize();
+        std::string LibDir = Dir + '/' + NormalizedTriple + "/lib";
+        LibPaths.push_back(LibDir + SubDir);
+      }
+    }
+    return;
+  } else {
+    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(LibDirCpu);
-    LibPaths.push_back(LibDir);
   }
 }
 
@@ -637,7 +758,9 @@ void HexagonToolChain::AddCXXStdlibLibArgs(const ArgList &Args,
     if (Args.hasArg(options::OPT_fexperimental_library))
       CmdArgs.push_back("-lc++experimental");
     CmdArgs.push_back("-lc++abi");
-    if (UNW != ToolChain::UNW_None)
+    // For Picolibc baremetal, always link libunwind with libc++ regardless of
+    // -unwindlib setting; libunwind is the only supported unwinding library.
+    if (UNW != ToolChain::UNW_None || getTriple().isPicolibc())
       CmdArgs.push_back("-lunwind");
     break;
 
@@ -711,6 +834,16 @@ void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
 
   const Driver &D = getDriver();
   SmallString<128> ResourceDirInclude(D.ResourceDir);
+  // Picolibc baremetal headers live under the normalized triple tree.
+  if (getTriple().isPicolibc()) {
+    if (DriverArgs.hasArg(options::OPT_nostdlibinc))
+      return;
+    std::string TargetDir = getHexagonTargetDir(D.Dir, D.PrefixDirs);
+    std::string Target = getTriple().normalize();
+    addExternCSystemInclude(DriverArgs, CC1Args,
+                            TargetDir + "/" + Target + "/include");
+    return;
+  }
   if (!IsELF) {
     llvm::sys::path::append(ResourceDirInclude, "include");
     if (!DriverArgs.hasArg(options::OPT_nobuiltininc) &&
@@ -769,11 +902,37 @@ void HexagonToolChain::addLibStdCxxIncludePaths(
                            DriverArgs, CC1Args);
 }
 
+void HexagonToolChain::AddClangCXXStdlibIncludeArgs(
+    const llvm::opt::ArgList &DriverArgs,
+    llvm::opt::ArgStringList &CC1Args) const {
+  if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
+      DriverArgs.hasArg(options::OPT_nostdincxx))
+    return;
+
+  const Driver &D = getDriver();
+  if (getTriple().getOS() != llvm::Triple::Linux) {
+    if (getTriple().isPicolibc()) {
+      StringRef InstallDir = D.Dir;
+      addExternCSystemInclude(DriverArgs, CC1Args,
+                              InstallDir + "/../target/" +
+                                  getTriple().normalize() + "/include/c++/v1");
+    } else {
+      if (getTriple().isPicolibc()) {
+        StringRef InstallDir = D.Dir;
+        addExternCSystemInclude(DriverArgs, CC1Args,
+                                InstallDir + "/../target/" +
+                                    getTriple().normalize() +
+                                    "/include/c++/v1");
+      }
+    }
+  }
+}
+
 ToolChain::CXXStdlibType
 HexagonToolChain::GetCXXStdlibType(const ArgList &Args) const {
   Arg *A = Args.getLastArg(options::OPT_stdlib_EQ);
   if (!A) {
-    if (getTriple().isMusl())
+    if (getTriple().isMusl() || getTriple().isPicolibc())
       return ToolChain::CST_Libcxx;
     else
       return ToolChain::CST_Libstdcxx;
diff --git a/clang/lib/Driver/ToolChains/Hexagon.h b/clang/lib/Driver/ToolChains/Hexagon.h
index 033d9b48cae10..446c7cea2264b 100644
--- a/clang/lib/Driver/ToolChains/Hexagon.h
+++ b/clang/lib/Driver/ToolChains/Hexagon.h
@@ -33,6 +33,11 @@ class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool {
                     const InputInfo &Output, const InputInfoList &Inputs,
                     const llvm::opt::ArgList &TCArgs,
                     const char *LinkingOutput) const override;
+  void ConstructJobForPicolibc(Compilation &C, const JobAction &JA,
+                               const InputInfo &Output,
+                               const InputInfoList &Inputs,
+                               const llvm::opt::ArgList &TCArgs,
+                               const char *LinkingOutput) const;
 };
 
 class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
@@ -78,6 +83,9 @@ class LLVM_LIBRARY_VISIBILITY HexagonToolChain : public Linux {
   void
   AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
                             llvm::opt::ArgStringList &CC1Args) const override;
+  void AddClangCXXStdlibIncludeArgs(
+      const llvm::opt::ArgList &DriverArgs,
+      llvm::opt::ArgStringList &CC1Args) const override;
   void addLibStdCxxIncludePaths(
       const llvm::opt::ArgList &DriverArgs,
       llvm::opt::ArgStringList &CC1Args) const override;
diff --git a/clang/test/Driver/hexagon-toolchain-picolibc.c b/clang/test/Driver/hexagon-toolchain-picolibc.c
new file mode 100644
index 0000000000000..00b092358006b
--- /dev/null
+++ b/clang/test/Driver/hexagon-toolchain-picolibc.c
@@ -0,0 +1,133 @@
+// UNSUPPORTED: system-windows
+// REQUIRES: hexagon-registered-target
+
+// -----------------------------------------------------------------------------
+// Test standard include paths
+// -----------------------------------------------------------------------------
+// RUN: %clang -### --target=hexagon-none-picolibc \
+// RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin %s 2>&1 | FileCheck -check-prefix=CHECK-C-INCLUDES %s
+// CHECK-C-INCLUDES: "-cc1" {{.*}} "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon-unknown-none-picolibc/include"
+
+// RUN: %clangxx -### --target=hexagon-none-picolibc \
+// RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin %s 2>&1 | FileCheck -check-prefix=CHECK-CXX-INCLUDES %s
+// CHECK-CXX-INCLUDES: "-cc1" {{.*}} "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon-unknown-none-picolibc/include/c++/v1"
+// CHECK-CXX-INCLUDES: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon-unknown-none-picolibc/include"
+// -----------------------------------------------------------------------------
+// Passing start files for Picolibc
+// -----------------------------------------------------------------------------
+// RUN: %clang -target hexagon-none-picolibc -### %s 2>&1 | FileCheck %s --check-prefix=CHECK-STARTUP
+// CHECK-STARTUP: "{{.*}}crt0-semihost.o"
+//
+// RUN: %clang -target hexagon-none-picolibc -nostartfiles -### %s 2>&1 | FileCheck %s --check-prefix=CHECK-NOSTART
+// CHECK-NOSTART-NOT: "{{.*}}crt0-semihost.o"
+// -----------------------------------------------------------------------------
+// Passing  -nostdlib, -nostartfiles, -nodefaultlibs, -nolibc
+// -----------------------------------------------------------------------------
+// RUN: %clangxx -### --target=hexagon-none-picolibc \
+// RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN:   -mcpu=hexagonv60 \
+// RUN:   -nostdlib %s 2>&1 | FileCheck -check-prefix=CHECK-NOSTDLIB %s
+// CHECK-NOSTDLIB: "-cc1"
+// CHECK-NOSTDLIB: {{hexagon-link|ld}}
+// CHECK-NOSTDLIB-NOT: {{.*}}crt0-semihost.o
+// CHECK-NOSTDLIB-NOT: "-lc++"
+// CHECK-NOSTDLIB-NOT: "-lm"
+// CHECK-NOSTDLIB-NOT: "--start-group"
+// CHECK-NOSTDLIB-NOT: "-lsemihost"
+// CHECK-NOSTDLIB-NOT: "-lc"
+// CHECK-NOSTDLIB-NOT: "-lclang_rt.builtins"
+// CHECK-NOSTDLIB-NOT: "--end-group"
+
+// RUN: %clangxx -### --target=hexagon-none-picolibc \
+// RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN:   -mcpu=hexagonv60 \
+// RUN:   -nostartfiles %s 2>&1 | FileCheck -check-prefix=CHECK-NOSTARTFILES %s
+// CHECK-NOSTARTFILES: "-cc1"
+// CHECK-NOSTARTFILES: {{hexagon-link|ld}}
+// CHECK-NOSTARTFILES-NOT: {{.*}}crt0-semihost.o
+// CHECK-NOSTARTFILES: "-lc++" "-lc++abi" "-lunwind" "-lm" "--start-group" "-lsemihost" "-lc" "-lclang_rt.builtins" "--end-group"
+
+// RUN: %clangxx -### --target=hexagon-none-picolibc \
+// RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN:   -mcpu=hexagonv60 \
+// RUN:   -nodefaultlibs %s 2>&1 | FileCheck -check-prefix=CHECK-NODEFAULTLIBS %s
+// CHECK-NODEFAULTLIBS: "-cc1"
+// CHECK-NODEFAULTLIBS: {{hexagon-link|ld}}
+// CHECK-NODEFAULTLIBS: "{{.*}}crt0-semihost.o"
+// CHECK-NODEFAULTLIBS-NOT: "-lc++"
+// CHECK-NODEFAULTLIBS-NOT: "-lm"
+// CHECK-NODEFAULTLIBS-NOT: "--start-group"
+// CHECK-NODEFAULTLIBS-NOT: "-lsemihost"
+// CHECK-NODEFAULTLIBS-NOT: "-lc"
+// CHECK-NODEFAULTLIBS-NOT: "-lclang_rt.builtins"
+// CHECK-NODEFAULTLIBS-NOT: "--end-group"
+
+// RUN: %clangxx -### --target=hexagon-none-picolibc \
+// RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin -mcpu=hexagonv60 \
+// RUN:   -nolibc %s 2>&1 | FileCheck -check-prefix=CHECK-NOLIBC %s
+// CHECK-NOLIBC: "-cc1"
+// CHECK-NOLIBC: hexagon-link
+// CHECK-NOLIBC-SAME: "{{.*}}crt0-semihost.o"
+// CHECK-NOLIBC-SAME: "-lc++"
+// CHECK-NOLIBC-SAME: "-lm"
+// CHECK-NOLIBC-SAME: "--start-group"
+// CHECK-NOLIBC-SAME: "-lsemihost"
+// CHECK-NOLIBC-NOT: "-lc"
+// CHECK-NOLIBC-SAME: "-lclang_rt.builtins"
+// CHECK-NOLIBC-SAME: "--end-group"
+// -----------------------------------------------------------------------------
+// Force compiler-rt when Picolibc is selected
+// -----------------------------------------------------------------------------
+// RUN: %clang -target hexagon-none-picolibc -### %s 2>&1 | FileCheck %s --check-prefix=CHECK-RTLIB
+// RUN: %clangxx -target hexagon-none-picolibc -### %s 2>&1 | FileCheck %s --check-prefix=CHECK-RTLIB
+// CHECK-RTLIB: "-lclang_rt.builtins"
+// -----------------------------------------------------------------------------
+// Force libunwind when Picolibc is selected
+// -----------------------------------------------------------------------------
+// RUN: %clang -target hexagon-none-picolibc -### %s 2>&1 | FileCheck %s --check-prefix=CHECK-C-UNWIND
+// RUN: %clangxx -target hexagon-none-picolibc -### %s 2>&1 | FileCheck %s --check-prefix=CHECK-CXX-UNWIND
+// CHECK-C-UNWIND-NOT: "-lunwind"
+// CHECK-CXX-UNWIND: "-lunwind"
+// -----------------------------------------------------------------------------
+// Force G0 for Picolibc
+// -----------------------------------------------------------------------------
+// RUN: %clang -target hexagon-none-picolibc -### \
+// RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN:   -mcpu=hexagonv68 %s 2>&1 | FileCheck %s --check-prefix=CHECK-G0
+// RUN: %clangxx -target hexagon-none-picolibc -### \
+// RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN:   -mcpu=hexagonv68 %s 2>&1 | FileCheck %s --check-prefix=CHECK-G0
+// CHECK-G0: "{{.*}}/G0/crt0-semihost.o"
+// CHECK-G0-SAME: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon-unknown-none-picolibc/lib/v68/G0"
+// -----------------------------------------------------------------------------
+// Libc++ experimental library linkage
+// -----------------------------------------------------------------------------
+// RUN: %clangxx -### --target=hexagon-none-picolibc -fexperimental-library %s 2>&1 | FileCheck %s --check-prefix=CHECK-EXPERIMENTAL
+// CHECK-EXPERIMENTAL: "-lc++experimental"
+// -----------------------------------------------------------------------------
+// Custom -L forwarding
+// -----------------------------------------------------------------------------
+// RUN: %clang -### --target=hexagon-none-picolibc -L/foo/bar %s 2>&1 | FileCheck %s --check-prefix=CHECK-CUSTOM-L
+// CHECK-CUSTOM-L: "-L/foo/bar"
+// -----------------------------------------------------------------------------
+// Link arch flags propagation
+// -----------------------------------------------------------------------------
+// RUN: %clang -### --target=hexagon-none-picolibc -mcpu=hexagonv68 %s 2>&1 | FileCheck %s --check-prefix=CHECK-LINK-ARCH
+// CHECK-LINK-ARCH: "-march=hexagon"
+// CHECK-LINK-ARCH: "-mcpu=hexagonv68"
+// -----------------------------------------------------------------------------
+// No standard includes when -nostdinc (C only); -nostdinc++ blocks C++ headers
+// -----------------------------------------------------------------------------
+// RUN: %clang -### --target=hexagon-none-picolibc \
+// RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin -nostdinc %s 2>&1 | FileCheck %s --check-prefix=CHECK-NOSTDINC-C
+// CHECK-NOSTDINC-C-NOT: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon-unknown-none-picolibc/include"
+// RUN: %clangxx -### --target=hexagon-none-picolibc \
+// RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin -nostdinc++ %s 2>&1 | FileCheck %s --check-prefix=CHECK-NOSTDINCXX
+// CHECK-NOSTDINCXX-NOT: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon-unknown-none-picolibc/include/c++/v1"
+// CHECK-NOSTDINCXX: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon-unknown-none-picolibc/include"
+// -----------------------------------------------------------------------------
+// C linking does not include -lm by default
+// -----------------------------------------------------------------------------
+// RUN: %clang -### --target=hexagon-none-picolibc %s 2>&1 | FileCheck %s --check-prefix=CHECK-C-NO-LM
+// CHECK-C-NO-LM-NOT: "-lm"
+// -----------------------------------------------------------------------------
diff --git a/llvm/include/llvm/TargetParser/Triple.h b/llvm/include/llvm/TargetParser/Triple.h
index 11b76cd183108..06fbc9cddfe36 100644
--- a/llvm/include/llvm/TargetParser/Triple.h
+++ b/llvm/include/llvm/TargetParser/Triple.h
@@ -311,6 +311,7 @@ class Triple {
     OpenCL,
     OpenHOS,
     Mlibc,
+    Picolibc,
 
     PAuthTest,
     MTIA,
@@ -866,6 +867,9 @@ class Triple {
            getEnvironment() == Triple::OpenHOS || isOSLiteOS();
   }
 
+  // Tests whether the environment is picolibc
+  bool isPicolibc() const { return getEnvironment() == Triple::Picolibc; }
+
   /// Tests whether the target is OHOS
   /// LiteOS default enviroment is also OHOS, but omited on triple.
   bool isO...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Nov 26, 2025

@llvm/pr-subscribers-clang-driver

Author: None (quic-k)

Changes

This patch adds Picolibc as part of triple so toolchains can switch the to Picolibc based on triple.
Hexagon toolchain uses the triple hexagon-none-picolibc.


Patch is 20.97 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/169613.diff

5 Files Affected:

  • (modified) clang/lib/Driver/ToolChains/Hexagon.cpp (+172-13)
  • (modified) clang/lib/Driver/ToolChains/Hexagon.h (+8)
  • (added) clang/test/Driver/hexagon-toolchain-picolibc.c (+133)
  • (modified) llvm/include/llvm/TargetParser/Triple.h (+4)
  • (modified) llvm/lib/TargetParser/Triple.cpp (+2)
diff --git a/clang/lib/Driver/ToolChains/Hexagon.cpp b/clang/lib/Driver/ToolChains/Hexagon.cpp
index 084f51721315c..151798e7e572b 100644
--- a/clang/lib/Driver/ToolChains/Hexagon.cpp
+++ b/clang/lib/Driver/ToolChains/Hexagon.cpp
@@ -273,6 +273,101 @@ void hexagon::Linker::RenderExtraToolArgs(const JobAction &JA,
                                           ArgStringList &CmdArgs) const {
 }
 
+static void constructHexagonPicolibcLinkArgs(
+    Compilation &C, const JobAction &JA,
+    const toolchains::HexagonToolChain &HTC, const InputInfo &Output,
+    const InputInfoList &Inputs, const ArgList &Args, ArgStringList &CmdArgs,
+    const char *LinkingOutput) {
+  const Driver &D = HTC.getDriver();
+  bool IsShared = Args.hasArg(options::OPT_shared);
+  bool IncStdLib = !Args.hasArg(options::OPT_nostdlib);
+  bool IncStartFiles = !Args.hasArg(options::OPT_nostartfiles);
+  bool IncDefLibs = !Args.hasArg(options::OPT_nodefaultlibs);
+  StringRef CpuVer = toolchains::HexagonToolChain::GetTargetCPUVersion(Args);
+  // Use G0 for Picolibc
+  bool UseG0 = true;
+  auto OsType = HTC.getOS();
+
+  CmdArgs.push_back("--eh-frame-hdr");
+  // Propagate arch flags to the linker when not using LLD, to match
+  // upstream Hexagon driver behavior validated by tests.
+  bool UseLLD = false;
+  const char *LinkerPath = Args.MakeArgString(HTC.GetLinkerPath(&UseLLD));
+  UseLLD = UseLLD ||
+           llvm::sys::path::filename(LinkerPath).ends_with("ld.lld") ||
+           llvm::sys::path::stem(LinkerPath).ends_with("ld.lld");
+  if (!UseLLD) {
+    CmdArgs.push_back("-march=hexagon");
+    CmdArgs.push_back(Args.MakeArgString("-mcpu=hexagon" + CpuVer));
+  }
+  CmdArgs.push_back("-o");
+  CmdArgs.push_back(Output.getFilename());
+
+  // Inputs
+  Args.addAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_s,
+                            options::OPT_t, options::OPT_u_Group});
+  AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA);
+
+  //----------------------------------------------------------------------------
+  // Start Files
+  //----------------------------------------------------------------------------
+  const std::string MCpuSuffix = "/" + CpuVer.str();
+  const std::string MCpuG0Suffix = MCpuSuffix + "/G0";
+  const std::string RootDir =
+      HTC.getHexagonTargetDir(D.Dir, D.PrefixDirs) + "/";
+  std::string NormalizedTriple =
+      HTC.getTriple().normalize(llvm::Triple::CanonicalForm::FOUR_IDENT);
+  const std::string StartSubDir =
+      NormalizedTriple + "/lib" + (UseG0 ? MCpuG0Suffix : MCpuSuffix);
+
+  if (IncStdLib && IncStartFiles) {
+    if (!IsShared) {
+      if (OsType == "none" || OsType == "unknown") {
+        std::string Crt0 = RootDir + StartSubDir + "/crt0-semihost.o";
+        CmdArgs.push_back(Args.MakeArgString(Crt0));
+      }
+    }
+  }
+
+  //----------------------------------------------------------------------------
+  // Library Search Paths
+  //----------------------------------------------------------------------------
+  const ToolChain::path_list &LibPaths = HTC.getFilePaths();
+  for (const auto &LibPath : LibPaths)
+    CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath));
+  //----------------------------------------------------------------------------
+  // Libraries
+  //----------------------------------------------------------------------------
+  if (IncStdLib && IncDefLibs) {
+    if (D.CCCIsCXX()) {
+      if (HTC.ShouldLinkCXXStdlib(Args))
+        HTC.AddCXXStdlibLibArgs(Args, CmdArgs);
+      CmdArgs.push_back("-lm");
+    }
+
+    CmdArgs.push_back("--start-group");
+
+    if (!IsShared) {
+      // add OS libraries to link
+      std::vector<std::string> OsLibs{};
+      if (OsType == "none" || OsType == "unknown") {
+        OsLibs.push_back("semihost");
+      } else if (OsType == "h2") {
+        OsLibs.push_back("h2");
+      } else if (OsType == "qurt") {
+        OsLibs.push_back("qurt");
+      }
+      for (StringRef Lib : OsLibs)
+        CmdArgs.push_back(Args.MakeArgString("-l" + Lib));
+      if (!Args.hasArg(options::OPT_nolibc))
+        CmdArgs.push_back("-lc");
+    }
+    // Force compiler-rt for Picolibc
+    CmdArgs.push_back("-lclang_rt.builtins");
+    CmdArgs.push_back("--end-group");
+  }
+}
+
 static void
 constructHexagonLinkArgs(Compilation &C, const JobAction &JA,
                          const toolchains::HexagonToolChain &HTC,
@@ -437,8 +532,8 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA,
       CmdArgs.push_back(Args.MakeArgString(Crt0));
     }
     std::string Init = UseShared
-          ? Find(RootDir, StartSubDir + "/pic", "/initS.o")
-          : Find(RootDir, StartSubDir, "/init.o");
+                           ? Find(RootDir, StartSubDir + "/pic", "/initS.o")
+                           : Find(RootDir, StartSubDir, "/init.o");
     CmdArgs.push_back(Args.MakeArgString(Init));
   }
 
@@ -500,8 +595,12 @@ void hexagon::Linker::ConstructJob(Compilation &C, const JobAction &JA,
   auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain());
 
   ArgStringList CmdArgs;
-  constructHexagonLinkArgs(C, JA, HTC, Output, Inputs, Args, CmdArgs,
-                           LinkingOutput);
+  if (HTC.getTriple().isPicolibc())
+    constructHexagonPicolibcLinkArgs(C, JA, HTC, Output, Inputs, Args, CmdArgs,
+                                     LinkingOutput);
+  else
+    constructHexagonLinkArgs(C, JA, HTC, Output, Inputs, Args, CmdArgs,
+                             LinkingOutput);
 
   const char *Exec = Args.MakeArgString(HTC.GetLinkerPath());
   C.addCommand(std::make_unique<Command>(JA, *this,
@@ -583,16 +682,38 @@ void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args,
     HasG0 = *G == 0;
 
   const std::string CpuVer = GetTargetCPUVersion(Args).str();
-  for (auto &Dir : RootDirs) {
-    std::string LibDir = Dir + "/hexagon/lib";
-    std::string LibDirCpu = LibDir + '/' + CpuVer;
+  // Special-case Picolibc baremetal layout:
+  //   <install>/../target/<normalized-triple>/lib/<vXX>/G0[/pic]
+  if (getTriple().isPicolibc()) {
+    std::string SubDir = '/' + CpuVer;
+    // Force G0 for Picolibc
+    HasG0 = true;
     if (HasG0) {
       if (HasPIC)
-        LibPaths.push_back(LibDirCpu + "/G0/pic");
-      LibPaths.push_back(LibDirCpu + "/G0");
+        SubDir += "/G0/pic";
+      else
+        SubDir += "/G0";
+    }
+    if (getTriple().getOS() != llvm::Triple::Linux) {
+      for (auto &Dir : RootDirs) {
+        auto NormalizedTriple = getTriple().normalize();
+        std::string LibDir = Dir + '/' + NormalizedTriple + "/lib";
+        LibPaths.push_back(LibDir + SubDir);
+      }
+    }
+    return;
+  } else {
+    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(LibDirCpu);
-    LibPaths.push_back(LibDir);
   }
 }
 
@@ -637,7 +758,9 @@ void HexagonToolChain::AddCXXStdlibLibArgs(const ArgList &Args,
     if (Args.hasArg(options::OPT_fexperimental_library))
       CmdArgs.push_back("-lc++experimental");
     CmdArgs.push_back("-lc++abi");
-    if (UNW != ToolChain::UNW_None)
+    // For Picolibc baremetal, always link libunwind with libc++ regardless of
+    // -unwindlib setting; libunwind is the only supported unwinding library.
+    if (UNW != ToolChain::UNW_None || getTriple().isPicolibc())
       CmdArgs.push_back("-lunwind");
     break;
 
@@ -711,6 +834,16 @@ void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
 
   const Driver &D = getDriver();
   SmallString<128> ResourceDirInclude(D.ResourceDir);
+  // Picolibc baremetal headers live under the normalized triple tree.
+  if (getTriple().isPicolibc()) {
+    if (DriverArgs.hasArg(options::OPT_nostdlibinc))
+      return;
+    std::string TargetDir = getHexagonTargetDir(D.Dir, D.PrefixDirs);
+    std::string Target = getTriple().normalize();
+    addExternCSystemInclude(DriverArgs, CC1Args,
+                            TargetDir + "/" + Target + "/include");
+    return;
+  }
   if (!IsELF) {
     llvm::sys::path::append(ResourceDirInclude, "include");
     if (!DriverArgs.hasArg(options::OPT_nobuiltininc) &&
@@ -769,11 +902,37 @@ void HexagonToolChain::addLibStdCxxIncludePaths(
                            DriverArgs, CC1Args);
 }
 
+void HexagonToolChain::AddClangCXXStdlibIncludeArgs(
+    const llvm::opt::ArgList &DriverArgs,
+    llvm::opt::ArgStringList &CC1Args) const {
+  if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
+      DriverArgs.hasArg(options::OPT_nostdincxx))
+    return;
+
+  const Driver &D = getDriver();
+  if (getTriple().getOS() != llvm::Triple::Linux) {
+    if (getTriple().isPicolibc()) {
+      StringRef InstallDir = D.Dir;
+      addExternCSystemInclude(DriverArgs, CC1Args,
+                              InstallDir + "/../target/" +
+                                  getTriple().normalize() + "/include/c++/v1");
+    } else {
+      if (getTriple().isPicolibc()) {
+        StringRef InstallDir = D.Dir;
+        addExternCSystemInclude(DriverArgs, CC1Args,
+                                InstallDir + "/../target/" +
+                                    getTriple().normalize() +
+                                    "/include/c++/v1");
+      }
+    }
+  }
+}
+
 ToolChain::CXXStdlibType
 HexagonToolChain::GetCXXStdlibType(const ArgList &Args) const {
   Arg *A = Args.getLastArg(options::OPT_stdlib_EQ);
   if (!A) {
-    if (getTriple().isMusl())
+    if (getTriple().isMusl() || getTriple().isPicolibc())
       return ToolChain::CST_Libcxx;
     else
       return ToolChain::CST_Libstdcxx;
diff --git a/clang/lib/Driver/ToolChains/Hexagon.h b/clang/lib/Driver/ToolChains/Hexagon.h
index 033d9b48cae10..446c7cea2264b 100644
--- a/clang/lib/Driver/ToolChains/Hexagon.h
+++ b/clang/lib/Driver/ToolChains/Hexagon.h
@@ -33,6 +33,11 @@ class LLVM_LIBRARY_VISIBILITY Assembler final : public Tool {
                     const InputInfo &Output, const InputInfoList &Inputs,
                     const llvm::opt::ArgList &TCArgs,
                     const char *LinkingOutput) const override;
+  void ConstructJobForPicolibc(Compilation &C, const JobAction &JA,
+                               const InputInfo &Output,
+                               const InputInfoList &Inputs,
+                               const llvm::opt::ArgList &TCArgs,
+                               const char *LinkingOutput) const;
 };
 
 class LLVM_LIBRARY_VISIBILITY Linker final : public Tool {
@@ -78,6 +83,9 @@ class LLVM_LIBRARY_VISIBILITY HexagonToolChain : public Linux {
   void
   AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
                             llvm::opt::ArgStringList &CC1Args) const override;
+  void AddClangCXXStdlibIncludeArgs(
+      const llvm::opt::ArgList &DriverArgs,
+      llvm::opt::ArgStringList &CC1Args) const override;
   void addLibStdCxxIncludePaths(
       const llvm::opt::ArgList &DriverArgs,
       llvm::opt::ArgStringList &CC1Args) const override;
diff --git a/clang/test/Driver/hexagon-toolchain-picolibc.c b/clang/test/Driver/hexagon-toolchain-picolibc.c
new file mode 100644
index 0000000000000..00b092358006b
--- /dev/null
+++ b/clang/test/Driver/hexagon-toolchain-picolibc.c
@@ -0,0 +1,133 @@
+// UNSUPPORTED: system-windows
+// REQUIRES: hexagon-registered-target
+
+// -----------------------------------------------------------------------------
+// Test standard include paths
+// -----------------------------------------------------------------------------
+// RUN: %clang -### --target=hexagon-none-picolibc \
+// RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin %s 2>&1 | FileCheck -check-prefix=CHECK-C-INCLUDES %s
+// CHECK-C-INCLUDES: "-cc1" {{.*}} "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon-unknown-none-picolibc/include"
+
+// RUN: %clangxx -### --target=hexagon-none-picolibc \
+// RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin %s 2>&1 | FileCheck -check-prefix=CHECK-CXX-INCLUDES %s
+// CHECK-CXX-INCLUDES: "-cc1" {{.*}} "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon-unknown-none-picolibc/include/c++/v1"
+// CHECK-CXX-INCLUDES: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon-unknown-none-picolibc/include"
+// -----------------------------------------------------------------------------
+// Passing start files for Picolibc
+// -----------------------------------------------------------------------------
+// RUN: %clang -target hexagon-none-picolibc -### %s 2>&1 | FileCheck %s --check-prefix=CHECK-STARTUP
+// CHECK-STARTUP: "{{.*}}crt0-semihost.o"
+//
+// RUN: %clang -target hexagon-none-picolibc -nostartfiles -### %s 2>&1 | FileCheck %s --check-prefix=CHECK-NOSTART
+// CHECK-NOSTART-NOT: "{{.*}}crt0-semihost.o"
+// -----------------------------------------------------------------------------
+// Passing  -nostdlib, -nostartfiles, -nodefaultlibs, -nolibc
+// -----------------------------------------------------------------------------
+// RUN: %clangxx -### --target=hexagon-none-picolibc \
+// RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN:   -mcpu=hexagonv60 \
+// RUN:   -nostdlib %s 2>&1 | FileCheck -check-prefix=CHECK-NOSTDLIB %s
+// CHECK-NOSTDLIB: "-cc1"
+// CHECK-NOSTDLIB: {{hexagon-link|ld}}
+// CHECK-NOSTDLIB-NOT: {{.*}}crt0-semihost.o
+// CHECK-NOSTDLIB-NOT: "-lc++"
+// CHECK-NOSTDLIB-NOT: "-lm"
+// CHECK-NOSTDLIB-NOT: "--start-group"
+// CHECK-NOSTDLIB-NOT: "-lsemihost"
+// CHECK-NOSTDLIB-NOT: "-lc"
+// CHECK-NOSTDLIB-NOT: "-lclang_rt.builtins"
+// CHECK-NOSTDLIB-NOT: "--end-group"
+
+// RUN: %clangxx -### --target=hexagon-none-picolibc \
+// RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN:   -mcpu=hexagonv60 \
+// RUN:   -nostartfiles %s 2>&1 | FileCheck -check-prefix=CHECK-NOSTARTFILES %s
+// CHECK-NOSTARTFILES: "-cc1"
+// CHECK-NOSTARTFILES: {{hexagon-link|ld}}
+// CHECK-NOSTARTFILES-NOT: {{.*}}crt0-semihost.o
+// CHECK-NOSTARTFILES: "-lc++" "-lc++abi" "-lunwind" "-lm" "--start-group" "-lsemihost" "-lc" "-lclang_rt.builtins" "--end-group"
+
+// RUN: %clangxx -### --target=hexagon-none-picolibc \
+// RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN:   -mcpu=hexagonv60 \
+// RUN:   -nodefaultlibs %s 2>&1 | FileCheck -check-prefix=CHECK-NODEFAULTLIBS %s
+// CHECK-NODEFAULTLIBS: "-cc1"
+// CHECK-NODEFAULTLIBS: {{hexagon-link|ld}}
+// CHECK-NODEFAULTLIBS: "{{.*}}crt0-semihost.o"
+// CHECK-NODEFAULTLIBS-NOT: "-lc++"
+// CHECK-NODEFAULTLIBS-NOT: "-lm"
+// CHECK-NODEFAULTLIBS-NOT: "--start-group"
+// CHECK-NODEFAULTLIBS-NOT: "-lsemihost"
+// CHECK-NODEFAULTLIBS-NOT: "-lc"
+// CHECK-NODEFAULTLIBS-NOT: "-lclang_rt.builtins"
+// CHECK-NODEFAULTLIBS-NOT: "--end-group"
+
+// RUN: %clangxx -### --target=hexagon-none-picolibc \
+// RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin -mcpu=hexagonv60 \
+// RUN:   -nolibc %s 2>&1 | FileCheck -check-prefix=CHECK-NOLIBC %s
+// CHECK-NOLIBC: "-cc1"
+// CHECK-NOLIBC: hexagon-link
+// CHECK-NOLIBC-SAME: "{{.*}}crt0-semihost.o"
+// CHECK-NOLIBC-SAME: "-lc++"
+// CHECK-NOLIBC-SAME: "-lm"
+// CHECK-NOLIBC-SAME: "--start-group"
+// CHECK-NOLIBC-SAME: "-lsemihost"
+// CHECK-NOLIBC-NOT: "-lc"
+// CHECK-NOLIBC-SAME: "-lclang_rt.builtins"
+// CHECK-NOLIBC-SAME: "--end-group"
+// -----------------------------------------------------------------------------
+// Force compiler-rt when Picolibc is selected
+// -----------------------------------------------------------------------------
+// RUN: %clang -target hexagon-none-picolibc -### %s 2>&1 | FileCheck %s --check-prefix=CHECK-RTLIB
+// RUN: %clangxx -target hexagon-none-picolibc -### %s 2>&1 | FileCheck %s --check-prefix=CHECK-RTLIB
+// CHECK-RTLIB: "-lclang_rt.builtins"
+// -----------------------------------------------------------------------------
+// Force libunwind when Picolibc is selected
+// -----------------------------------------------------------------------------
+// RUN: %clang -target hexagon-none-picolibc -### %s 2>&1 | FileCheck %s --check-prefix=CHECK-C-UNWIND
+// RUN: %clangxx -target hexagon-none-picolibc -### %s 2>&1 | FileCheck %s --check-prefix=CHECK-CXX-UNWIND
+// CHECK-C-UNWIND-NOT: "-lunwind"
+// CHECK-CXX-UNWIND: "-lunwind"
+// -----------------------------------------------------------------------------
+// Force G0 for Picolibc
+// -----------------------------------------------------------------------------
+// RUN: %clang -target hexagon-none-picolibc -### \
+// RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN:   -mcpu=hexagonv68 %s 2>&1 | FileCheck %s --check-prefix=CHECK-G0
+// RUN: %clangxx -target hexagon-none-picolibc -### \
+// RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN:   -mcpu=hexagonv68 %s 2>&1 | FileCheck %s --check-prefix=CHECK-G0
+// CHECK-G0: "{{.*}}/G0/crt0-semihost.o"
+// CHECK-G0-SAME: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon-unknown-none-picolibc/lib/v68/G0"
+// -----------------------------------------------------------------------------
+// Libc++ experimental library linkage
+// -----------------------------------------------------------------------------
+// RUN: %clangxx -### --target=hexagon-none-picolibc -fexperimental-library %s 2>&1 | FileCheck %s --check-prefix=CHECK-EXPERIMENTAL
+// CHECK-EXPERIMENTAL: "-lc++experimental"
+// -----------------------------------------------------------------------------
+// Custom -L forwarding
+// -----------------------------------------------------------------------------
+// RUN: %clang -### --target=hexagon-none-picolibc -L/foo/bar %s 2>&1 | FileCheck %s --check-prefix=CHECK-CUSTOM-L
+// CHECK-CUSTOM-L: "-L/foo/bar"
+// -----------------------------------------------------------------------------
+// Link arch flags propagation
+// -----------------------------------------------------------------------------
+// RUN: %clang -### --target=hexagon-none-picolibc -mcpu=hexagonv68 %s 2>&1 | FileCheck %s --check-prefix=CHECK-LINK-ARCH
+// CHECK-LINK-ARCH: "-march=hexagon"
+// CHECK-LINK-ARCH: "-mcpu=hexagonv68"
+// -----------------------------------------------------------------------------
+// No standard includes when -nostdinc (C only); -nostdinc++ blocks C++ headers
+// -----------------------------------------------------------------------------
+// RUN: %clang -### --target=hexagon-none-picolibc \
+// RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin -nostdinc %s 2>&1 | FileCheck %s --check-prefix=CHECK-NOSTDINC-C
+// CHECK-NOSTDINC-C-NOT: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon-unknown-none-picolibc/include"
+// RUN: %clangxx -### --target=hexagon-none-picolibc \
+// RUN:   -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin -nostdinc++ %s 2>&1 | FileCheck %s --check-prefix=CHECK-NOSTDINCXX
+// CHECK-NOSTDINCXX-NOT: "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon-unknown-none-picolibc/include/c++/v1"
+// CHECK-NOSTDINCXX: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/hexagon-unknown-none-picolibc/include"
+// -----------------------------------------------------------------------------
+// C linking does not include -lm by default
+// -----------------------------------------------------------------------------
+// RUN: %clang -### --target=hexagon-none-picolibc %s 2>&1 | FileCheck %s --check-prefix=CHECK-C-NO-LM
+// CHECK-C-NO-LM-NOT: "-lm"
+// -----------------------------------------------------------------------------
diff --git a/llvm/include/llvm/TargetParser/Triple.h b/llvm/include/llvm/TargetParser/Triple.h
index 11b76cd183108..06fbc9cddfe36 100644
--- a/llvm/include/llvm/TargetParser/Triple.h
+++ b/llvm/include/llvm/TargetParser/Triple.h
@@ -311,6 +311,7 @@ class Triple {
     OpenCL,
     OpenHOS,
     Mlibc,
+    Picolibc,
 
     PAuthTest,
     MTIA,
@@ -866,6 +867,9 @@ class Triple {
            getEnvironment() == Triple::OpenHOS || isOSLiteOS();
   }
 
+  // Tests whether the environment is picolibc
+  bool isPicolibc() const { return getEnvironment() == Triple::Picolibc; }
+
   /// Tests whether the target is OHOS
   /// LiteOS default enviroment is also OHOS, but omited on triple.
   bool isO...
[truncated]

@github-actions
Copy link

github-actions bot commented Nov 26, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@github-actions
Copy link

github-actions bot commented Nov 26, 2025

🐧 Linux x64 Test Results

  • 193020 tests passed
  • 6209 tests skipped

This patch adds Picolibc as part of triple so toolchains can switch
the to Picolibc based on triple.
Hexagon toolchain uses the triple hexagon-none-picolibc.

Signed-off-by: Kushal Pal <kushpal@qti.qualcomm.com>
for (auto &Dir : RootDirs) {
std::string LibDir = Dir + "/hexagon/lib";
std::string LibDirCpu = LibDir + '/' + CpuVer;
// Special-case Picolibc baremetal layout:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once picolibc stabilizes, maybe we could consider migrating other targets to use this and make it the general case.

case ToolChain::CST_Libstdcxx:
addLibStdCxxIncludePaths(DriverArgs, CC1Args);
break;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default case here should be handled (perhaps LLVM_UNREACHABLE?).

@quic-seaswara
Copy link

@MaskRay can you please take a look ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend:Hexagon clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl'

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants