diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -195,7 +195,8 @@ std::vector &Result) { std::vector Features; unsigned FPUKind = llvm::ARM::FK_INVALID; - tools::arm::getARMTargetFeatures(D, Triple, Args, Features, false, &FPUKind); + tools::arm::getARMTargetFeatures(D, Triple, Args, Features, false, false, + &FPUKind); const auto UnifiedFeatures = tools::unifyTargetFeatures(Features); llvm::DenseSet FeatureSet(UnifiedFeatures.begin(), UnifiedFeatures.end()); diff --git a/clang/lib/Driver/ToolChains/Arch/ARM.h b/clang/lib/Driver/ToolChains/Arch/ARM.h --- a/clang/lib/Driver/ToolChains/Arch/ARM.h +++ b/clang/lib/Driver/ToolChains/Arch/ARM.h @@ -68,6 +68,7 @@ void getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args, std::vector &Features, bool ForAS, + bool GetExecuteOnly = true, unsigned *OutFPUKind = nullptr); int getARMSubArchVersionNumber(const llvm::Triple &Triple); bool isARMMProfile(const llvm::Triple &Triple); diff --git a/clang/lib/Driver/ToolChains/Arch/ARM.cpp b/clang/lib/Driver/ToolChains/Arch/ARM.cpp --- a/clang/lib/Driver/ToolChains/Arch/ARM.cpp +++ b/clang/lib/Driver/ToolChains/Arch/ARM.cpp @@ -439,7 +439,7 @@ void arm::getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, const ArgList &Args, std::vector &Features, bool ForAS, - unsigned *OutFPUKind) { + bool GetExecuteOnly, unsigned *OutFPUKind) { bool KernelOrKext = Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext); arm::FloatABI ABI = arm::getARMFloatABI(D, Triple, Args); @@ -776,7 +776,7 @@ // Generate execute-only output (no data access to code sections). // This only makes sense for the compiler, not for the assembler. - if (!ForAS) { + if (!ForAS && GetExecuteOnly) { // Supported only on ARMv6T2 and ARMv7 and above. // Cannot be combined with -mno-movt. if (Arg *A = Args.getLastArg(options::OPT_mexecute_only, options::OPT_mno_execute_only)) { diff --git a/clang/lib/Driver/ToolChains/BareMetal.cpp b/clang/lib/Driver/ToolChains/BareMetal.cpp --- a/clang/lib/Driver/ToolChains/BareMetal.cpp +++ b/clang/lib/Driver/ToolChains/BareMetal.cpp @@ -155,6 +155,49 @@ return Triple.getEnvironmentName() == "elf"; } +static bool findMultilibsFromYAML(const ToolChain &TC, const Driver &D, + StringRef MultilibPath, const ArgList &Args, + DetectedMultilibs &Result) { + llvm::ErrorOr> MB = + D.getVFS().getBufferForFile(MultilibPath); + if (!MB) + return false; + + std::vector ArgsFlags = TC.getMultiSelectionFlags(Args); + + if (!Result.Multilibs.parse(*MB.get())) { + return false; + } + + Multilib::flag_set Flags(ArgsFlags.begin(), ArgsFlags.end()); + return Result.Multilibs.select(Flags, Result.SelectedMultilib); +} + +#define MULTILIB_YAML_FILENAME "multilib.yaml" + +// Get the sysroot, before multilib takes effect. +static std::string computeBaseSysRoot(const Driver &D, + const llvm::Triple &Triple) { + if (!D.SysRoot.empty()) + return D.SysRoot; + + SmallString<128> SysRootDir(D.Dir); + llvm::sys::path::append(SysRootDir, "../lib/clang-runtimes"); + + SmallString<128> MultilibPath(SysRootDir); + llvm::sys::path::append(MultilibPath, MULTILIB_YAML_FILENAME); + + // New behaviour: if multilib.yaml is found then use clang-runtimes as the + // sysroot. + if (D.getVFS().exists(MultilibPath)) { + return std::string(SysRootDir); + } + + // Otherwise fall back to the old behaviour of appending the target triple. + llvm::sys::path::append(SysRootDir, D.getTargetTriple()); + return std::string(SysRootDir); +} + void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) { DetectedMultilibs Result; @@ -163,6 +206,12 @@ SelectedMultilib = Result.SelectedMultilib; Multilibs = Result.Multilibs; } + } else { + llvm::SmallString<128> MultilibPath(computeBaseSysRoot(D, Triple)); + llvm::sys::path::append(MultilibPath, MULTILIB_YAML_FILENAME); + findMultilibsFromYAML(*this, D, MultilibPath, Args, Result); + SelectedMultilib = Result.SelectedMultilib; + Multilibs = Result.Multilibs; } } @@ -176,15 +225,8 @@ } std::string BareMetal::computeSysRoot() const { - if (!getDriver().SysRoot.empty()) - return getDriver().SysRoot + SelectedMultilib.osSuffix(); - - SmallString<128> SysRootDir; - llvm::sys::path::append(SysRootDir, getDriver().Dir, "../lib/clang-runtimes", - getDriver().getTargetTriple()); - - SysRootDir += SelectedMultilib.osSuffix(); - return std::string(SysRootDir); + return computeBaseSysRoot(getDriver(), getTriple()) + + SelectedMultilib.osSuffix(); } void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs, diff --git a/clang/test/Driver/Inputs/baremetal_multilib/multilib.yaml b/clang/test/Driver/Inputs/baremetal_multilib/multilib.yaml new file mode 100644 --- /dev/null +++ b/clang/test/Driver/Inputs/baremetal_multilib/multilib.yaml @@ -0,0 +1,95 @@ +# This file is in two parts: +# 1. A list of library variants. +# 2. A mapping from flags generated from command line arguments to further +# flags. + +# How does clang use this file? +# 1. If the ToolChain class for the architecture supports this form of +# multilib it then it loads the file if present in sysroot. +# 2. Generate flags from the user provided arguments. +# (Use `clang -print-multi-selection-flags` to see which flags are +# generated). +# 3. Compare the arguments against each regular expression and store +# associated flags if there's a match. +# 4. Find the last library variant whose flags are a subset of the +# flags derived from the user provided arguments. +# 5. Use the directory for the library variant as the sysroot. + +# This defines the minimum version of Clang required to use this file. +# It is required to be present. +# Clang will emit an error if this number is greater than its version, but +# will accept lesser versions. +clangMinimumVersion: 17.0.0 + +# The first section of the file is the list of library variants. +# A library is considered compatible if the are a subset of the flags derived +# from the arguments provided by the user. +# If multiple libraries are deemed compatible then the one that appears +# last in the list wins. A ToolChain may instead opt to use more than one +# multilib, layered on top of each other. +# Each library variant must have a "printArgs" attribute. This is solely to +# support `clang -print-multi-lib`. + +variants: +- dir: arm-none-eabi/thumb/v6-m/nofp + flags: [target=thumbv6m-none-unknown-eabi] + printArgs: [--target=thumbv6m-none-eabi, -mfloat-abi=soft] + +- dir: arm-none-eabi/thumb/v7-m/nofp + flags: [target=thumbv7m-none-unknown-eabi] + printArgs: [--target=thumbv7m-none-eabi, -mfloat-abi=soft] + +- dir: arm-none-eabi/thumb/v7e-m/nofp + flags: [target=thumbv7em-none-unknown-eabi] + printArgs: [--target=thumbv7em-none-eabi, -mfloat-abi=soft, -mfpu=none] + +- dir: arm-none-eabi/thumb/v8-m.main/nofp + flags: [target=thumbv8m.main-none-unknown-eabi] + printArgs: [--target=arm-none-eabi, -mfloat-abi=soft, -march=armv8m.main+nofp] + +- dir: arm-none-eabi/thumb/v8.1-m.main/nofp/nomve + flags: [target=thumbv8.1m.main-none-unknown-eabi] + printArgs: [--target=arm-none-eabi, -mfloat-abi=soft, -march=armv8.1m.main+nofp+nomve] + +- dir: arm-none-eabi/thumb/v7e-m/fpv4_sp_d16 + flags: [target=thumbv7em-none-unknown-eabihf, mfpu=fpv4-sp-d16] + printArgs: [--target=thumbv7em-none-eabihf, -mfpu=fpv4-sp-d16] + +- dir: arm-none-eabi/thumb/v7e-m/fpv5_d16 + flags: [target=thumbv7em-none-unknown-eabihf, mfpu=fpv5-d16] + printArgs: [--target=thumbv7em-none-eabihf, -mfpu=fpv5-d16] + +- dir: arm-none-eabi/thumb/v8-m.main/fp + flags: [target=thumbv8m.main-none-unknown-eabihf, hasfpu] + printArgs: [--target=thumbv8m.main-none-eabihf] + +- dir: arm-none-eabi/thumb/v8.1-m.main/fp + flags: [target=thumbv8.1m.main-none-unknown-eabihf, hasfpu] + printArgs: [--target=thumbv8.1m.main-none-eabihf] + +- dir: arm-none-eabi/thumb/v8.1-m.main/nofp/mve + flags: [target=thumbv8.1m.main-none-unknown-eabihf, march=+mve] + printArgs: [--target=arm-none-eabihf, -march=armv8.1m.main+nofp+mve] + + +# The second section of the file is a map from auto-detected flags +# to custom flags. The auto-detected flags can be printed out +# by running clang with `-print-multi-selection-flags`. +# The regex must match a whole flag string. +# "matchFlags" flags will be added if an argument matches, while +# "noMatchFlags" flags will be added otherwise. +flagMap: +- regex: mfpu=none + noMatchFlags: [hasfpu] +# For v8m.base (and potential later v8m baseline versions) use v6m +- regex: target=thumbv8(\.[0-9]+)?m\.base-none-unknown-eabi + matchFlags: [target=thumbv6m-none-unknown-eabi] +# Match versions after v8.1m.main. We assume that v8.2m (if/when it exists) will +# be backwards compatible with v8.1m. +# The alternative is to not recognise later versions, and require that +# this multilib spec is updated before it can be used with newer +# architecture versions. +- regex: thumbv8\.[1-9]m\.main-none-unknown-eabi + matchFlags: [target=thumbv8.1m.main-none-unknown-eabi] +- regex: thumbv8\.[1-9]m\.main-none-unknown-eabihf + matchFlags: [target=thumbv8.1m.main-none-unknown-eabihf] diff --git a/clang/test/Driver/baremetal-multilib.cpp b/clang/test/Driver/baremetal-multilib.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Driver/baremetal-multilib.cpp @@ -0,0 +1,45 @@ +// REQUIRES: shell +// UNSUPPORTED: system-windows + +// RUN: rm -rf %T/baremetal_multilib +// RUN: mkdir -p %T/baremetal_multilib/bin +// RUN: mkdir -p %T/baremetal_multilib/lib/clang-runtimes/arm-none-eabi/thumb/v8-m.main/fp/lib +// RUN: touch %T/baremetal_multilib/lib/clang-runtimes/arm-none-eabi/thumb/v8-m.main/fp/lib/libclang_rt.builtins.a +// RUN: ln -s %clang %T/baremetal_multilib/bin/clang +// RUN: ln -s %S/Inputs/baremetal_multilib/multilib.yaml %T/baremetal_multilib/lib/clang-runtimes/multilib.yaml + +// RUN: %T/baremetal_multilib/bin/clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \ +// RUN: --target=thumbv8m.main-none-eabihf --sysroot= \ +// RUN: | FileCheck %s +// CHECK: "{{.*}}clang{{.*}}" "-cc1" "-triple" "thumbv8m.main-none-unknown-eabihf" +// CHECK-SAME: "-internal-isystem" "{{.*}}/baremetal_multilib/bin/../lib/clang-runtimes/arm-none-eabi/thumb/v8-m.main/fp/include/c++/v1" +// CHECK-SAME: "-internal-isystem" "{{.*}}/baremetal_multilib/bin/../lib/clang-runtimes/arm-none-eabi/thumb/v8-m.main/fp/include" +// CHECK-SAME: "-x" "c++" "{{.*}}/baremetal-multilib.cpp" +// CHECK-NEXT: "{{[^"]*}}ld{{(\.(lld|bfd|gold))?}}{{(\.exe)?}}" "{{.*}}.o" "-Bstatic" +// CHECK-SAME: "-L{{.*}}/baremetal_multilib/bin/../lib/clang-runtimes/arm-none-eabi/thumb/v8-m.main/fp/lib" +// CHECK-SAME: "-lc" "-lm" "-lclang_rt.builtins" +// CHECK-SAME: "-o" "{{.*}}.o" + +// RUN: %T/baremetal_multilib/bin/clang -no-canonical-prefixes -print-multi-directory 2>&1 \ +// RUN: --target=thumbv8m.main-none-eabihf --sysroot= \ +// RUN: | FileCheck --check-prefix=CHECK-PRINT-MULTI-DIRECTORY %s +// CHECK-PRINT-MULTI-DIRECTORY: arm-none-eabi/thumb/v8-m.main/fp + +// RUN: %T/baremetal_multilib/bin/clang -no-canonical-prefixes -print-multi-lib 2>&1 \ +// RUN: --target=arm-none-eabi --sysroot= \ +// RUN: | FileCheck --check-prefix=CHECK-PRINT-MULTI-LIB %s +// CHECK-PRINT-MULTI-LIB: arm-none-eabi/thumb/v6-m/nofp;@-target=thumbv6m-none-eabi@mfloat-abi=soft +// CHECK-PRINT-MULTI-LIB: arm-none-eabi/thumb/v7-m/nofp;@-target=thumbv7m-none-eabi@mfloat-abi=soft +// CHECK-PRINT-MULTI-LIB: arm-none-eabi/thumb/v7e-m/nofp;@-target=thumbv7em-none-eabi@mfloat-abi=soft@mfpu=none +// CHECK-PRINT-MULTI-LIB: arm-none-eabi/thumb/v8-m.main/nofp;@-target=arm-none-eabi@mfloat-abi=soft@march=armv8m.main+nofp +// CHECK-PRINT-MULTI-LIB: arm-none-eabi/thumb/v8.1-m.main/nofp/nomve;@-target=arm-none-eabi@mfloat-abi=soft@march=armv8.1m.main+nofp+nomve +// CHECK-PRINT-MULTI-LIB: arm-none-eabi/thumb/v7e-m/fpv4_sp_d16;@-target=thumbv7em-none-eabihf@mfpu=fpv4-sp-d16 +// CHECK-PRINT-MULTI-LIB: arm-none-eabi/thumb/v7e-m/fpv5_d16;@-target=thumbv7em-none-eabihf@mfpu=fpv5-d16 +// CHECK-PRINT-MULTI-LIB: arm-none-eabi/thumb/v8-m.main/fp;@-target=thumbv8m.main-none-eabihf +// CHECK-PRINT-MULTI-LIB: arm-none-eabi/thumb/v8.1-m.main/fp;@-target=thumbv8.1m.main-none-eabihf +// CHECK-PRINT-MULTI-LIB: arm-none-eabi/thumb/v8.1-m.main/nofp/mve;@-target=arm-none-eabihf@march=armv8.1m.main+nofp+mve + +// RUN: %T/baremetal_multilib/bin/clang -no-canonical-prefixes -x assembler -mexecute-only \ +// RUN: --target=arm-none-eabi --sysroot= %s -c -### 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-NO-EXECUTE-ONLY-ASM +// CHECK-NO-EXECUTE-ONLY-ASM: warning: argument unused during compilation: '-mexecute-only' diff --git a/clang/test/Driver/baremetal.cpp b/clang/test/Driver/baremetal.cpp --- a/clang/test/Driver/baremetal.cpp +++ b/clang/test/Driver/baremetal.cpp @@ -118,9 +118,9 @@ // Verify that the bare metal driver does not include any host system paths: // CHECK-AARCH64-NO-HOST-INC: InstalledDir: [[INSTALLEDDIR:.+]] // CHECK-AARCH64-NO-HOST-INC: "-resource-dir" "[[RESOURCE:[^"]+]]" -// CHECK-AARCH64-NO-HOST-INC-SAME: "-internal-isystem" "[[INSTALLEDDIR]]{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}clang-runtimes{{[/\\]+}}aarch64-none-elf{{[/\\]+}}include{{[/\\]+}}c++{{[/\\]+}}v1" +// CHECK-AARCH64-NO-HOST-INC-SAME: "-internal-isystem" "[[INSTALLEDDIR]]{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}clang-runtimes{{[/\\]+[^"]*}}include{{[/\\]+}}c++{{[/\\]+}}v1" // CHECK-AARCH64-NO-HOST-INC-SAME: "-internal-isystem" "[[RESOURCE]]{{[/\\]+}}include" -// CHECK-AARCH64-NO-HOST-INC-SAME: "-internal-isystem" "[[INSTALLEDDIR]]{{[/\\]+}}..{{[/\\]+}}lib{{[/\\]+}}clang-runtimes{{[/\\]+}}aarch64-none-elf{{[/\\]+}}include" +// CHECK-AARCH64-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 \