https://github.com/Mintsuki created https://github.com/llvm/llvm-project/pull/223703
Clang did not handle loongarch32-\*-none-elf and loongarch64-\*-none-elf in the bare-metal toolchain, so these targets fell back to the generic ELF toolchain, which links by running gcc. Any -fuse-ld or --ld-path option is forwarded to gcc, and linking fails when there is no gcc. On a host whose gcc does not target LoongArch, which is the usual case when cross compiling, gcc drives the linker for the host, and the link fails with errors such as "a.o is incompatible with elf_x86_64". The generic ELF toolchain also searches /usr/local/include and /usr/include of the host. The other bare-metal targets, Arm, AArch64, RISC-V, PowerPC, and x86 since 25f0d08bafa4, use the bare-metal toolchain, which runs the selected linker directly and does not search host include directories. Handle LoongArch there as well. As the GNU toolchain does for LoongArch, and the bare-metal toolchain already does for RISC-V, pass -X to the linker, and --no-relax with -mno-relax. Assisted-by: Claude Code (Claude Opus 5) >From 30c73ab84a189647befb3108faf9862167ec9789 Mon Sep 17 00:00:00 2001 From: Mintsuki <[email protected]> Date: Tue, 15 Sep 2026 14:51:23 +0200 Subject: [PATCH] [clang][Driver] Use the bare-metal toolchain for LoongArch Clang did not handle loongarch32-*-none-elf and loongarch64-*-none-elf in the bare-metal toolchain, so these targets fell back to the generic ELF toolchain, which links by running gcc. Any -fuse-ld or --ld-path option is forwarded to gcc, and linking fails when there is no gcc. On a host whose gcc does not target LoongArch, which is the usual case when cross compiling, gcc drives the linker for the host, and the link fails with errors such as "a.o is incompatible with elf_x86_64". The generic ELF toolchain also searches /usr/local/include and /usr/include of the host. The other bare-metal targets, Arm, AArch64, RISC-V, PowerPC, and x86 since 25f0d08bafa4, use the bare-metal toolchain, which runs the selected linker directly and does not search host include directories. Handle LoongArch there as well. As the GNU toolchain does for LoongArch, and the bare-metal toolchain already does for RISC-V, pass -X to the linker, and --no-relax with -mno-relax. Assisted-by: Claude Code (Claude Opus 5) Signed-off-by: Mintsuki <[email protected]> --- clang/docs/ReleaseNotes.md | 5 +++ clang/lib/Driver/ToolChains/BareMetal.cpp | 11 +++++- clang/test/Driver/baremetal.cpp | 46 +++++++++++++++++++++++ clang/test/Driver/loongarch-toolchain.c | 4 ++ 4 files changed, 64 insertions(+), 2 deletions(-) diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index 043a0ddae2a6c..1a052ff8b7db9 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -769,6 +769,11 @@ features cannot lower the translation-unit ABI level; #### LoongArch Support +- `loongarch32-*-none-elf` and `loongarch64-*-none-elf` targets now use the + bare-metal toolchain, like other bare-metal targets. The linker is run + directly instead of through `gcc`, and host include directories are no + longer searched. + #### RISC-V Support - Fixed a bug where the `interrupt` attribute did not accept `machine` together diff --git a/clang/lib/Driver/ToolChains/BareMetal.cpp b/clang/lib/Driver/ToolChains/BareMetal.cpp index 19fbb6b07cebe..619a7fb974615 100644 --- a/clang/lib/Driver/ToolChains/BareMetal.cpp +++ b/clang/lib/Driver/ToolChains/BareMetal.cpp @@ -55,6 +55,12 @@ static bool isX86BareMetal(const llvm::Triple &Triple) { Triple.getEnvironmentName() == "elf"; } +/// Is the triple loongarch{32,64}-*-none-elf? +static bool isLoongArchBareMetal(const llvm::Triple &Triple) { + return Triple.isLoongArch() && Triple.getOS() == llvm::Triple::UnknownOS && + Triple.getEnvironmentName() == "elf"; +} + static bool findRISCVMultilibs(const Driver &D, const llvm::Triple &TargetTriple, const ArgList &Args, DetectedMultilibs &Result) { @@ -281,7 +287,8 @@ void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple, bool BareMetal::handlesTarget(const llvm::Triple &Triple) { return arm::isARMEABIBareMetal(Triple) || aarch64::isAArch64BareMetal(Triple) || isRISCVBareMetal(Triple) || - isPPCBareMetal(Triple) || isX86BareMetal(Triple); + isPPCBareMetal(Triple) || isX86BareMetal(Triple) || + isLoongArchBareMetal(Triple); } Tool *BareMetal::buildLinker() const { @@ -547,7 +554,7 @@ void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA, return; } - if (Triple.isRISCV()) { + if (Triple.isLoongArch() || Triple.isRISCV()) { CmdArgs.push_back("-X"); if (Args.hasArg(options::OPT_mno_relax)) CmdArgs.push_back("--no-relax"); diff --git a/clang/test/Driver/baremetal.cpp b/clang/test/Driver/baremetal.cpp index aa2aa9696c08e..0e08e946d68c5 100644 --- a/clang/test/Driver/baremetal.cpp +++ b/clang/test/Driver/baremetal.cpp @@ -300,6 +300,22 @@ // CHECK-PCX86_64-NO-HOST-INC-SAME: "-internal-isystem" "[[RESOURCE]]{{[/\\]+}}include" // CHECK-PCX86_64-NO-HOST-INC-SAME: "-internal-isystem" "[[INSTALLEDDIR]]{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}clang-runtimes{{[/\\]+[^"]*}}include" +// RUN: %clang -no-canonical-prefixes %s -### --target=loongarch32-unknown-elf 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-LA32-NO-HOST-INC %s +// CHECK-LA32-NO-HOST-INC: InstalledDir: [[INSTALLEDDIR:.+]] +// CHECK-LA32-NO-HOST-INC: "-resource-dir" "[[RESOURCE:[^"]+]]" +// CHECK-LA32-NO-HOST-INC-SAME: "-internal-isystem" "[[INSTALLEDDIR]]{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}clang-runtimes{{[/\\]+[^"]*}}include{{[/\\]+}}c++{{[/\\]+}}v1" +// CHECK-LA32-NO-HOST-INC-SAME: "-internal-isystem" "[[RESOURCE]]{{[/\\]+}}include" +// CHECK-LA32-NO-HOST-INC-SAME: "-internal-isystem" "[[INSTALLEDDIR]]{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}clang-runtimes{{[/\\]+[^"]*}}include" + +// RUN: %clang -no-canonical-prefixes %s -### --target=loongarch64-unknown-elf 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-LA64-NO-HOST-INC %s +// CHECK-LA64-NO-HOST-INC: InstalledDir: [[INSTALLEDDIR:.+]] +// CHECK-LA64-NO-HOST-INC: "-resource-dir" "[[RESOURCE:[^"]+]]" +// CHECK-LA64-NO-HOST-INC-SAME: "-internal-isystem" "[[INSTALLEDDIR]]{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}clang-runtimes{{[/\\]+[^"]*}}include{{[/\\]+}}c++{{[/\\]+}}v1" +// CHECK-LA64-NO-HOST-INC-SAME: "-internal-isystem" "[[RESOURCE]]{{[/\\]+}}include" +// CHECK-LA64-NO-HOST-INC-SAME: "-internal-isystem" "[[INSTALLEDDIR]]{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}clang-runtimes{{[/\\]+[^"]*}}include" + // RUN: %clang %s -### --target=riscv64-unknown-elf -o %t.out -L some/directory/user/asked/for \ // RUN: --sysroot=%S/Inputs/basic_riscv64_tree/riscv64-unknown-elf 2>&1 \ // RUN: | FileCheck --check-prefix=CHECK-RV64 %s @@ -646,6 +662,36 @@ // CHECK-PCX86_64ELF-SAME: "-lc" // CHECK-PCX86_64ELF-SAME: "-o" "a.out" +// RUN: %clang -no-canonical-prefixes %s -### --target=loongarch32-unknown-elf 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-LA32ELF %s +// CHECK-LA32ELF: InstalledDir: [[INSTALLEDDIR:.+]] +// CHECK-LA32ELF: "-nostdsysteminc" +// CHECK-LA32ELF-SAME: "-resource-dir" "[[RESOURCE:[^"]+]]" +// CHECK-LA32ELF-SAME: "-internal-isystem" "[[INSTALLEDDIR]]{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}clang-runtimes{{[/\\]+[^"]*}}include{{[/\\]+}}c++{{[/\\]+}}v1" +// CHECK-LA32ELF-SAME: "-internal-isystem" "[[RESOURCE]]{{[/\\]+}}include" +// CHECK-LA32ELF-SAME: "-internal-isystem" "[[INSTALLEDDIR]]{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}clang-runtimes{{[/\\]+[^"]*}}include" +// CHECK-LA32ELF-NEXT: ld{{(.exe)?}}" "-Bstatic" "-m" "elf32loongarch" "-X" +// CHECK-LA32ELF-SAME: "-L[[INSTALLEDDIR]]{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}clang-runtimes{{[/\\]+[^"]*}}lib" +// CHECK-LA32ELF-SAME:"{{.*}}.o" +// CHECK-LA32ELF-SAME: "{{[^"]*}}libclang_rt.builtins.a" +// CHECK-LA32ELF-SAME: "-lc" +// CHECK-LA32ELF-SAME: "-o" "a.out" + +// RUN: %clang -no-canonical-prefixes %s -### --target=loongarch64-unknown-elf 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-LA64ELF %s +// CHECK-LA64ELF: InstalledDir: [[INSTALLEDDIR:.+]] +// CHECK-LA64ELF: "-nostdsysteminc" +// CHECK-LA64ELF-SAME: "-resource-dir" "[[RESOURCE:[^"]+]]" +// CHECK-LA64ELF-SAME: "-internal-isystem" "[[INSTALLEDDIR]]{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}clang-runtimes{{[/\\]+[^"]*}}include{{[/\\]+}}c++{{[/\\]+}}v1" +// CHECK-LA64ELF-SAME: "-internal-isystem" "[[RESOURCE]]{{[/\\]+}}include" +// CHECK-LA64ELF-SAME: "-internal-isystem" "[[INSTALLEDDIR]]{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}clang-runtimes{{[/\\]+[^"]*}}include" +// CHECK-LA64ELF-NEXT: ld{{(.exe)?}}" "-Bstatic" "-m" "elf64loongarch" "-X" +// CHECK-LA64ELF-SAME: "-L[[INSTALLEDDIR]]{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}clang-runtimes{{[/\\]+[^"]*}}lib" +// CHECK-LA64ELF-SAME:"{{.*}}.o" +// CHECK-LA64ELF-SAME: "{{[^"]*}}libclang_rt.builtins.a" +// CHECK-LA64ELF-SAME: "-lc" +// CHECK-LA64ELF-SAME: "-o" "a.out" + // Check that compiler-rt library without the arch filename suffix will // be used if present. // RUN: rm -rf %t.dir/baremetal_clang_rt_noarch diff --git a/clang/test/Driver/loongarch-toolchain.c b/clang/test/Driver/loongarch-toolchain.c index 54a2519e0a70d..de7720b34ea53 100644 --- a/clang/test/Driver/loongarch-toolchain.c +++ b/clang/test/Driver/loongarch-toolchain.c @@ -31,6 +31,10 @@ // RUN: FileCheck --check-prefix=LA64-RELAX %s // RUN: %clang --target=loongarch64-unknown-linux-gnu -mno-relax -### %s 2>&1 | \ // RUN: FileCheck --check-prefix=LA64-NORELAX %s +// RUN: %clang --target=loongarch64-unknown-elf -### %s 2>&1 | \ +// RUN: FileCheck --check-prefix=LA64-RELAX %s +// RUN: %clang --target=loongarch64-unknown-elf -mno-relax -### %s 2>&1 | \ +// RUN: FileCheck --check-prefix=LA64-NORELAX %s // LA64-RELAX: "-X" // LA64-RELAX-NOT: "--no-relax" // LA64-NORELAX: "-X" "--no-relax" _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
