Skip to content

Commit

Permalink
[Driver] Enable multilib.yaml in the BareMetal ToolChain
Browse files Browse the repository at this point in the history
The default location for multilib.yaml is lib/clang-runtimes, without
any target-specific suffix. This will allow multilibs for different
architectures to share a common include directory.

To avoid breaking the arm-execute-only.c CHECK-NO-EXECUTE-ONLY-ASM
test, add a ForMultilib argument to getARMTargetFeatures.

Since the presence of multilib.yaml can change the exact location of a
library, relax the baremetal.cpp test.

Differential Revision: https://reviews.llvm.org/D142986
  • Loading branch information
mplatings committed Jun 14, 2023
1 parent a794ab9 commit b4eebc8
Show file tree
Hide file tree
Showing 7 changed files with 203 additions and 16 deletions.
4 changes: 2 additions & 2 deletions clang/lib/Driver/ToolChain.cpp
Expand Up @@ -199,8 +199,8 @@ static void getARMMultilibFlags(const Driver &D,
const llvm::opt::ArgList &Args,
Multilib::flags_list &Result) {
std::vector<StringRef> 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<StringRef> FeatureSet(UnifiedFeatures.begin(),
UnifiedFeatures.end());
Expand Down
6 changes: 4 additions & 2 deletions clang/lib/Driver/ToolChains/Arch/ARM.cpp
Expand Up @@ -467,7 +467,7 @@ llvm::ARM::FPUKind arm::getARMTargetFeatures(const Driver &D,
const llvm::Triple &Triple,
const ArgList &Args,
std::vector<StringRef> &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);
Expand Down Expand Up @@ -807,7 +807,9 @@ llvm::ARM::FPUKind arm::getARMTargetFeatures(const Driver &D,

// 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)) {
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Driver/ToolChains/Arch/ARM.h
Expand Up @@ -67,7 +67,7 @@ llvm::ARM::FPUKind getARMTargetFeatures(const Driver &D,
const llvm::Triple &Triple,
const llvm::opt::ArgList &Args,
std::vector<llvm::StringRef> &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);
Expand Down
57 changes: 48 additions & 9 deletions clang/lib/Driver/ToolChains/BareMetal.cpp
Expand Up @@ -155,6 +155,46 @@ static bool isRISCVBareMetal(const llvm::Triple &Triple) {
return Triple.getEnvironmentName() == "elf";
}

static bool findMultilibsFromYAML(const ToolChain &TC, const Driver &D,
StringRef MultilibPath, const ArgList &Args,
DetectedMultilibs &Result) {
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MB =
D.getVFS().getBufferForFile(MultilibPath);
if (!MB)
return false;
Multilib::flags_list Flags = TC.getMultilibFlags(Args);
llvm::ErrorOr<MultilibSet> 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;
Expand All @@ -163,6 +203,12 @@ void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple,
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;
}
}

Expand All @@ -176,15 +222,8 @@ Tool *BareMetal::buildLinker() const {
}

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,
Expand Down
145 changes: 145 additions & 0 deletions 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

...
4 changes: 2 additions & 2 deletions clang/test/Driver/baremetal.cpp
Expand Up @@ -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 \
Expand Down
1 change: 1 addition & 0 deletions clang/test/Driver/lit.local.cfg
Expand Up @@ -19,6 +19,7 @@ config.suffixes = [
".hip",
".hipi",
".hlsl",
".yaml",
]
config.substitutions = list(config.substitutions)
config.substitutions.insert(
Expand Down

0 comments on commit b4eebc8

Please sign in to comment.