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 @@ -199,8 +199,8 @@ const llvm::opt::ArgList &Args, Multilib::flags_list &Result) { std::vector Features; - llvm::ARM::FPUKind FPUKind = - tools::arm::getARMTargetFeatures(D, Triple, Args, Features, false); + llvm::ARM::FPUKind FPUKind = tools::arm::getARMTargetFeatures( + D, Triple, Args, Features, false /*ForAs*/, true /*ForMultilib*/); 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 @@ -67,7 +67,7 @@ const llvm::Triple &Triple, const llvm::opt::ArgList &Args, std::vector &Features, - bool ForAS); + bool ForAS, bool ForMultilib = false); int getARMSubArchVersionNumber(const llvm::Triple &Triple); bool isARMMProfile(const llvm::Triple &Triple); bool isARMAProfile(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 @@ -467,7 +467,7 @@ const llvm::Triple &Triple, const ArgList &Args, std::vector &Features, - bool ForAS) { + bool ForAS, bool ForMultilib) { bool KernelOrKext = Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext); arm::FloatABI ABI = arm::getARMFloatABI(D, Triple, Args); @@ -807,7 +807,9 @@ // Generate execute-only output (no data access to code sections). // This only makes sense for the compiler, not for the assembler. - if (!ForAS) { + // It's not needed for multilib selection and may hide an unused + // argument diagnostic if the code is always run. + if (!ForAS && !ForMultilib) { // 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,46 @@ 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; + Multilib::flags_list Flags = TC.getMultilibFlags(Args); + llvm::ErrorOr ErrorOrMultilibSet = + MultilibSet::parseYaml(*MB.get()); + if (ErrorOrMultilibSet.getError()) + return false; + Result.Multilibs = ErrorOrMultilibSet.get(); + return Result.Multilibs.select(Flags, Result.SelectedMultilib); +} + +static constexpr llvm::StringLiteral MultilibFilename = "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, MultilibFilename); + + // 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 +203,12 @@ SelectedMultilib = Result.SelectedMultilib; Multilibs = Result.Multilibs; } + } else { + llvm::SmallString<128> MultilibPath(computeBaseSysRoot(D, Triple)); + llvm::sys::path::append(MultilibPath, MultilibFilename); + findMultilibsFromYAML(*this, D, MultilibPath, Args, Result); + SelectedMultilib = Result.SelectedMultilib; + Multilibs = Result.Multilibs; } } @@ -176,15 +222,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/baremetal-multilib.yaml b/clang/test/Driver/baremetal-multilib.yaml new file mode 100644 --- /dev/null +++ b/clang/test/Driver/baremetal-multilib.yaml @@ -0,0 +1,145 @@ +# 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 %T/baremetal_multilib/lib/clang-runtimes/multilib.yaml + +# RUN: %T/baremetal_multilib/bin/clang -no-canonical-prefixes -x c++ %s -### -o %t.out 2>&1 \ +# RUN: --target=thumbv8m.main-none-eabihf --sysroot= \ +# RUN: | FileCheck -DSYSROOT=%T/baremetal_multilib %s +# CHECK: "-cc1" "-triple" "thumbv8m.main-none-unknown-eabihf" +# CHECK-SAME: "-internal-isystem" "[[SYSROOT]]/bin/../lib/clang-runtimes/arm-none-eabi/thumb/v8-m.main/fp/include/c++/v1" +# CHECK-SAME: "-internal-isystem" "[[SYSROOT]]/bin/../lib/clang-runtimes/arm-none-eabi/thumb/v8-m.main/fp/include" +# CHECK-SAME: "-x" "c++" "{{.*}}baremetal-multilib.yaml" +# CHECK-NEXT: ld{{(.exe)?}}" "{{.*}}.o" "-Bstatic" +# CHECK-SAME: "-L[[SYSROOT]]/bin/../lib/clang-runtimes/arm-none-eabi/thumb/v8-m.main/fp/lib" +# CHECK-SAME: "-lc" "-lm" "-lclang_rt.builtins" +# CHECK-SAME: "-o" "{{.*}}.tmp.out" + +# 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-unknown-eabi@mfpu=none +# CHECK-PRINT-MULTI-LIB: arm-none-eabi/thumb/v7-m/nofp;@-target=thumbv7m-none-unknown-eabi@mfpu=none +# CHECK-PRINT-MULTI-LIB: arm-none-eabi/thumb/v7e-m/nofp;@-target=thumbv7em-none-unknown-eabi@mfpu=none +# CHECK-PRINT-MULTI-LIB: arm-none-eabi/thumb/v8-m.main/nofp;@-target=thumbv8m.main-none-unknown-eabi@mfpu=none +# CHECK-PRINT-MULTI-LIB: arm-none-eabi/thumb/v8.1-m.main/nofp/nomve;@-target=thumbv8.1m.main-none-unknown-eabi@mfpu=none +# CHECK-PRINT-MULTI-LIB: arm-none-eabi/thumb/v7e-m/fpv4_sp_d16;@-target=thumbv7em-none-unknown-eabihf@mfpu=fpv4-sp-d16 +# CHECK-PRINT-MULTI-LIB: arm-none-eabi/thumb/v7e-m/fpv5_d16;@-target=thumbv7em-none-unknown-eabihf@mfpu=fpv5-d16 +# CHECK-PRINT-MULTI-LIB: arm-none-eabi/thumb/v8-m.main/fp;@-target=thumbv8m.main-none-unknown-eabihf@mfpu=fpv5-d16 +# CHECK-PRINT-MULTI-LIB: arm-none-eabi/thumb/v8.1-m.main/fp;@-target=thumbv8.1m.main-none-unknown-eabihf@mfpu=fp-armv8-fullfp16-sp-d16 +# CHECK-PRINT-MULTI-LIB: arm-none-eabi/thumb/v8.1-m.main/nofp/mve;@-target=thumbv8.1m.main-none-unknown-eabihf@march=thumbv8.1m.main+mve@mfpu=none + +# 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' + +--- +# 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-flags-experimental` 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. + +# Clang will emit an error if this number is greater than its current multilib +# version or if its major version differs, but will accept lesser minor +# versions. +MultilibVersion: 1.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. + +Variants: +- Dir: arm-none-eabi/thumb/v6-m/nofp + Flags: [--target=thumbv6m-none-unknown-eabi, -mfpu=none] + +- Dir: arm-none-eabi/thumb/v7-m/nofp + Flags: [--target=thumbv7m-none-unknown-eabi, -mfpu=none] + +- Dir: arm-none-eabi/thumb/v7e-m/nofp + Flags: [--target=thumbv7em-none-unknown-eabi, -mfpu=none] + +- Dir: arm-none-eabi/thumb/v8-m.main/nofp + Flags: [--target=thumbv8m.main-none-unknown-eabi, -mfpu=none] + +- Dir: arm-none-eabi/thumb/v8.1-m.main/nofp/nomve + Flags: [--target=thumbv8.1m.main-none-unknown-eabi, -mfpu=none] + +- Dir: arm-none-eabi/thumb/v7e-m/fpv4_sp_d16 + Flags: [--target=thumbv7em-none-unknown-eabihf, -mfpu=fpv4-sp-d16] + +- Dir: arm-none-eabi/thumb/v7e-m/fpv5_d16 + Flags: [--target=thumbv7em-none-unknown-eabihf, -mfpu=fpv5-d16] + +- Dir: arm-none-eabi/thumb/v8-m.main/fp + Flags: [--target=thumbv8m.main-none-unknown-eabihf, -mfpu=fpv5-d16] + +- Dir: arm-none-eabi/thumb/v8.1-m.main/fp + Flags: [--target=thumbv8.1m.main-none-unknown-eabihf, -mfpu=fp-armv8-fullfp16-sp-d16] + +- Dir: arm-none-eabi/thumb/v8.1-m.main/nofp/mve + Flags: [--target=thumbv8.1m.main-none-unknown-eabihf, -march=thumbv8.1m.main+mve, -mfpu=none] + + +# 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-flags-experimental`. +# The regex must match a whole flag string. +# All flags in the "Flags" list will be added if an argument matches. +Mappings: +# For v8m.base (and potential later v8m baseline versions) use v6m +- Match: --target=thumbv8(\.[0-9]+)?m\.base-none-unknown-eabi + Flags: [--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. +- Match: --target=thumbv8\.[1-9]m\.main-none-unknown-eabi + Flags: [--target=thumbv8.1m.main-none-unknown-eabi] +- Match: --target=thumbv8\.[1-9]m\.main-none-unknown-eabihf + Flags: [--target=thumbv8.1m.main-none-unknown-eabihf] + +- Match: -march=thumbv8\.[1-9]m\.main.*\+mve($|\+).* + Flags: [-march=thumbv8.1m.main+mve] + +# Hierarchy among FPUs: fpvN-d16 is a superset of fpvN-sp-d16, and +# fpvN-d16 is a superset of fpv[N-1]-d16, for all N. +- Match: -mfpu=fpv5-d16 + Flags: + - -mfpu=fpv4-d16 + - -mfpu=fpv5-sp-d16 + - -mfpu=fpv4-sp-d16 +- Match: -mfpu=fpv5-sp-d16 + Flags: + - -mfpu=fpv4-sp-d16 +- Match: -mfpu=fpv4-d16 + Flags: + - -mfpu=fpv4-sp-d16 + +... 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 \ diff --git a/clang/test/Driver/lit.local.cfg b/clang/test/Driver/lit.local.cfg --- a/clang/test/Driver/lit.local.cfg +++ b/clang/test/Driver/lit.local.cfg @@ -19,6 +19,7 @@ ".hip", ".hipi", ".hlsl", + ".yaml", ] config.substitutions = list(config.substitutions) config.substitutions.insert(