Skip to content

Commit 111a229

Browse files
authored
[RISCV] Implement multi-lib reuse rule for RISC-V bare-metal toolchain (#73765)
Extend the multi-lib re-use selection mechanism for RISC-V. This funciton will try to re-use multi-lib if they are compatible. Definition of compatible: - ABI must be the same. - multi-lib is a subset of current arch, e.g. multi-lib=march=rv32im is a subset of march=rv32imc. - march that contains atomic extension can't reuse multi-lib that doesn't has atomic, vice versa. e.g. multi-lib=march=rv32im and march=rv32ima are not compatible, because software and hardware atomic operation can't work together correctly.
1 parent b83b287 commit 111a229

File tree

2 files changed

+207
-1
lines changed

2 files changed

+207
-1
lines changed

clang/lib/Driver/ToolChains/Gnu.cpp

Lines changed: 126 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "llvm/Option/ArgList.h"
3131
#include "llvm/Support/CodeGen.h"
3232
#include "llvm/Support/Path.h"
33+
#include "llvm/Support/RISCVISAInfo.h"
3334
#include "llvm/Support/VirtualFileSystem.h"
3435
#include "llvm/TargetParser/TargetParser.h"
3536
#include <system_error>
@@ -1715,6 +1716,129 @@ static void findCSKYMultilibs(const Driver &D, const llvm::Triple &TargetTriple,
17151716
Result.Multilibs = CSKYMultilibs;
17161717
}
17171718

1719+
/// Extend the multi-lib re-use selection mechanism for RISC-V.
1720+
/// This function will try to re-use multi-lib if they are compatible.
1721+
/// Definition of compatible:
1722+
/// - ABI must be the same.
1723+
/// - multi-lib is a subset of current arch, e.g. multi-lib=march=rv32im
1724+
/// is a subset of march=rv32imc.
1725+
/// - march that contains atomic extension can't reuse multi-lib that
1726+
/// doesn't have atomic, vice versa. e.g. multi-lib=march=rv32im and
1727+
/// march=rv32ima are not compatible, because software and hardware
1728+
/// atomic operation can't work together correctly.
1729+
static bool
1730+
selectRISCVMultilib(const MultilibSet &RISCVMultilibSet, StringRef Arch,
1731+
const Multilib::flags_list &Flags,
1732+
llvm::SmallVectorImpl<Multilib> &SelectedMultilibs) {
1733+
// Try to find the perfect matching multi-lib first.
1734+
if (RISCVMultilibSet.select(Flags, SelectedMultilibs))
1735+
return true;
1736+
1737+
Multilib::flags_list NewFlags;
1738+
std::vector<MultilibBuilder> NewMultilibs;
1739+
1740+
llvm::Expected<std::unique_ptr<llvm::RISCVISAInfo>> ParseResult =
1741+
llvm::RISCVISAInfo::parseArchString(
1742+
Arch, /*EnableExperimentalExtension=*/true,
1743+
/*ExperimentalExtensionVersionCheck=*/false);
1744+
if (!ParseResult) {
1745+
// Ignore any error here, we assume it will be handled in another place.
1746+
consumeError(ParseResult.takeError());
1747+
return false;
1748+
}
1749+
1750+
auto &ISAInfo = *ParseResult;
1751+
1752+
addMultilibFlag(ISAInfo->getXLen() == 32, "-m32", NewFlags);
1753+
addMultilibFlag(ISAInfo->getXLen() == 64, "-m64", NewFlags);
1754+
1755+
// Collect all flags except march=*
1756+
for (StringRef Flag : Flags) {
1757+
if (Flag.startswith("!march=") || Flag.startswith("-march="))
1758+
continue;
1759+
1760+
NewFlags.push_back(Flag.str());
1761+
}
1762+
1763+
llvm::StringSet<> AllArchExts;
1764+
// Reconstruct multi-lib list, and break march option into separated
1765+
// extension. e.g. march=rv32im -> +i +m
1766+
for (const auto &M : RISCVMultilibSet) {
1767+
bool Skip = false;
1768+
1769+
MultilibBuilder NewMultilib =
1770+
MultilibBuilder(M.gccSuffix(), M.osSuffix(), M.includeSuffix());
1771+
for (StringRef Flag : M.flags()) {
1772+
// Add back all flags except -march.
1773+
if (!Flag.consume_front("-march=")) {
1774+
NewMultilib.flag(Flag);
1775+
continue;
1776+
}
1777+
1778+
// Break down -march into individual extension.
1779+
llvm::Expected<std::unique_ptr<llvm::RISCVISAInfo>> MLConfigParseResult =
1780+
llvm::RISCVISAInfo::parseArchString(
1781+
Flag, /*EnableExperimentalExtension=*/true,
1782+
/*ExperimentalExtensionVersionCheck=*/false);
1783+
if (!MLConfigParseResult) {
1784+
// Ignore any error here, we assume it will handled in another place.
1785+
llvm::consumeError(MLConfigParseResult.takeError());
1786+
1787+
// We might get a parsing error if rv32e in the list, we could just skip
1788+
// that and process the rest of multi-lib configs.
1789+
Skip = true;
1790+
continue;
1791+
}
1792+
auto &MLConfigISAInfo = *MLConfigParseResult;
1793+
1794+
const llvm::RISCVISAInfo::OrderedExtensionMap &MLConfigArchExts =
1795+
MLConfigISAInfo->getExtensions();
1796+
for (auto MLConfigArchExt : MLConfigArchExts) {
1797+
auto ExtName = MLConfigArchExt.first;
1798+
NewMultilib.flag(Twine("-", ExtName).str());
1799+
1800+
if (AllArchExts.insert(ExtName).second) {
1801+
addMultilibFlag(ISAInfo->hasExtension(ExtName),
1802+
Twine("-", ExtName).str(), NewFlags);
1803+
}
1804+
}
1805+
1806+
// Check the XLEN explicitly.
1807+
if (MLConfigISAInfo->getXLen() == 32) {
1808+
NewMultilib.flag("-m32");
1809+
NewMultilib.flag("!m64");
1810+
} else {
1811+
NewMultilib.flag("!m32");
1812+
NewMultilib.flag("-m64");
1813+
}
1814+
1815+
// Atomic extension must be explicitly checked, soft and hard atomic
1816+
// operation never co-work correctly.
1817+
if (!MLConfigISAInfo->hasExtension("a"))
1818+
NewMultilib.flag("!a");
1819+
}
1820+
1821+
if (Skip)
1822+
continue;
1823+
1824+
NewMultilibs.emplace_back(NewMultilib);
1825+
}
1826+
1827+
// Build an internal used only multi-lib list, used for checking any
1828+
// compatible multi-lib.
1829+
MultilibSet NewRISCVMultilibs =
1830+
MultilibSetBuilder().Either(NewMultilibs).makeMultilibSet();
1831+
1832+
if (NewRISCVMultilibs.select(NewFlags, SelectedMultilibs))
1833+
for (const Multilib &NewSelectedM : SelectedMultilibs)
1834+
for (const auto &M : RISCVMultilibSet)
1835+
// Look up the corresponding multi-lib entry in original multi-lib set.
1836+
if (M.gccSuffix() == NewSelectedM.gccSuffix())
1837+
return true;
1838+
1839+
return false;
1840+
}
1841+
17181842
static void findRISCVBareMetalMultilibs(const Driver &D,
17191843
const llvm::Triple &TargetTriple,
17201844
StringRef Path, const ArgList &Args,
@@ -1766,7 +1890,8 @@ static void findRISCVBareMetalMultilibs(const Driver &D,
17661890
}
17671891
}
17681892

1769-
if (RISCVMultilibs.select(Flags, Result.SelectedMultilibs))
1893+
if (selectRISCVMultilib(RISCVMultilibs, MArch, Flags,
1894+
Result.SelectedMultilibs))
17701895
Result.Multilibs = RISCVMultilibs;
17711896
}
17721897

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// RUN: %clang %s \
2+
// RUN: -target riscv64-unknown-elf \
3+
// RUN: --gcc-toolchain=%S/Inputs/multilib_riscv_elf_sdk \
4+
// RUN: --print-multi-directory \
5+
// RUN: -march=rv32imc -mabi=ilp32 \
6+
// RUN: | FileCheck -check-prefix=GCC-MULTI-LIB-REUSE-RV32IMC-ILP32 %s
7+
// GCC-MULTI-LIB-REUSE-RV32IMC-ILP32: rv32im/ilp32
8+
// GCC-MULTI-LIB-REUSE-RV32IMC-ILP32-NOT: {{^.+$}}
9+
10+
// Check rv32imac won't reuse rv32im or rv32ic
11+
// RUN: %clang %s \
12+
// RUN: -target riscv64-unknown-elf \
13+
// RUN: --gcc-toolchain=%S/Inputs/multilib_riscv_elf_sdk \
14+
// RUN: --print-multi-directory \
15+
// RUN: -march=rv32imac -mabi=ilp32 \
16+
// RUN: | FileCheck -check-prefix=GCC-MULTI-LIB-REUSE-RV32IMAC-ILP32 %s
17+
// GCC-MULTI-LIB-REUSE-RV32IMAC-ILP32: rv32imac/ilp32
18+
// GCC-MULTI-LIB-REUSE-RV32IMAC-ILP32--NOT: {{^.+$}}
19+
20+
// RUN: %clang %s \
21+
// RUN: -target riscv64-unknown-elf \
22+
// RUN: --gcc-toolchain=%S/Inputs/multilib_riscv_elf_sdk \
23+
// RUN: --print-multi-directory \
24+
// RUN: -march=rv32iac -mabi=ilp32 \
25+
// RUN: | FileCheck -check-prefix=GCC-MULTI-LIB-REUSE-RV32IAC-ILP32 %s
26+
// GCC-MULTI-LIB-REUSE-RV32IAC-ILP32: rv32iac/ilp32
27+
// GCC-MULTI-LIB-REUSE-RV32IAC-ILP32-NOT: {{^.+$}}
28+
29+
// RUN: %clang %s \
30+
// RUN: -target riscv64-unknown-elf \
31+
// RUN: --gcc-toolchain=%S/Inputs/multilib_riscv_elf_sdk \
32+
// RUN: --print-multi-directory \
33+
// RUN: -march=rv32imafdc -mabi=ilp32f \
34+
// RUN: | FileCheck -check-prefix=GCC-MULTI-LIB-REUSE-RV32IMAFDC-ILP32F %s
35+
// GCC-MULTI-LIB-REUSE-RV32IMAFDC-ILP32F: rv32imafc/ilp32f
36+
// GCC-MULTI-LIB-REUSE-RV32IMAFDC-ILP32F-NOT: {{^.+$}}
37+
38+
// RUN: %clang %s \
39+
// RUN: -target riscv64-unknown-elf \
40+
// RUN: --gcc-toolchain=%S/Inputs/multilib_riscv_elf_sdk \
41+
// RUN: --print-multi-directory \
42+
// RUN: -march=rv32imafdc -mabi=ilp32d \
43+
// RUN: | FileCheck -check-prefix=GCC-MULTI-LIB-REUSE-RV32IMAFDC-ILP32D %s
44+
// GCC-MULTI-LIB-REUSE-RV32IMAFDC-ILP32D: .
45+
// GCC-MULTI-LIB-REUSE-RV32IMAFDC-ILP32D-NOT: {{^.+$}}
46+
47+
// RUN: %clang %s \
48+
// RUN: -target riscv64-unknown-elf \
49+
// RUN: --gcc-toolchain=%S/Inputs/multilib_riscv_elf_sdk \
50+
// RUN: --print-multi-directory \
51+
// RUN: -march=rv64imafc -mabi=lp64 \
52+
// RUN: | FileCheck -check-prefix=GCC-MULTI-LIB-REUSE-RV64IMAFC-LP64 %s
53+
// GCC-MULTI-LIB-REUSE-RV64IMAFC-LP64: rv64imac/lp64
54+
// GCC-MULTI-LIB-REUSE-RV64IMAFC-LP64-NOT: {{^.+$}}
55+
56+
// RUN: %clang %s \
57+
// RUN: -target riscv64-unknown-elf \
58+
// RUN: --gcc-toolchain=%S/Inputs/multilib_riscv_elf_sdk \
59+
// RUN: --print-multi-directory \
60+
// RUN: -march=rv32imafc_zfh -mabi=ilp32 \
61+
// RUN: | FileCheck -check-prefix=GCC-MULTI-LIB-REUSE-RV32IMAFC_ZFH-ILP32 %s
62+
// GCC-MULTI-LIB-REUSE-RV32IMAFC_ZFH-ILP32: rv32imac/ilp32
63+
// GCC-MULTI-LIB-REUSE-RV32IMAFC_ZFH-ILP32-NOT: {{^.+$}}
64+
65+
// RUN: %clang %s \
66+
// RUN: -target riscv64-unknown-elf \
67+
// RUN: --gcc-toolchain=%S/Inputs/multilib_riscv_elf_sdk \
68+
// RUN: --print-multi-directory \
69+
// RUN: -march=rv32i_zvkb -mabi=ilp32 \
70+
// RUN: | FileCheck -check-prefix=GCC-MULTI-LIB-REUSE-RV32I_ZVKB-ILP32 %s
71+
// GCC-MULTI-LIB-REUSE-RV32I_ZVKB-ILP32: rv32i/ilp32
72+
// GCC-MULTI-LIB-REUSE-RV32I_ZVKB-ILP32-NOT: {{^.+$}}
73+
74+
// RUN: %clang %s \
75+
// RUN: -target riscv64-unknown-elf \
76+
// RUN: --gcc-toolchain=%S/Inputs/multilib_riscv_elf_sdk \
77+
// RUN: --print-multi-directory \
78+
// RUN: -march=rv64imfc -mabi=lp64 \
79+
// RUN: | FileCheck -check-prefix=GCC-MULTI-LIB-REUSE-RV64IMFC-LP64 %s
80+
// GCC-MULTI-LIB-REUSE-RV64IMFC-LP64: .
81+
// GCC-MULTI-LIB-REUSE-RV64IMFC-LP64-NOT: {{^.+$}}

0 commit comments

Comments
 (0)