Skip to content

Commit 320061a

Browse files
committed
[RISCV] Implement multi-lib reuse rule for RISC-V bare-metal toolchain
Extend the multi-lib re-use selection mechanism for RISC-V. This function 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 have 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 18b4157 commit 320061a

File tree

2 files changed

+212
-1
lines changed

2 files changed

+212
-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 funciton 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 has 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+
RISCVMultilibSelect(const MultilibSet &RISCVMultilibSet, StringRef Arch,
1731+
const Multilib::flags_list &Flags,
1732+
llvm::SmallVector<Multilib> &SelectedMultilibs) {
1733+
// Try to find the perfect matching multi-lib first.
1734+
if (RISCVMultilibSet.select(Flags, SelectedMultilibs))
1735+
return true;
1736+
1737+
llvm::StringMap<bool> FlagSet;
1738+
Multilib::flags_list NewFlags;
1739+
std::vector<MultilibBuilder> NewMultilibs;
1740+
1741+
auto ParseResult = llvm::RISCVISAInfo::parseArchString(
1742+
Arch, /*EnableExperimentalExtension=*/true,
1743+
/*ExperimentalExtensionVersionCheck=*/false);
1744+
if (!ParseResult) {
1745+
// Ignore any error here, we assume it will handled in another place.
1746+
consumeError(ParseResult.takeError());
1747+
return false;
1748+
}
1749+
auto &ISAInfo = *ParseResult;
1750+
1751+
auto CurrentExts = ISAInfo->getExtensions();
1752+
1753+
addMultilibFlag(ISAInfo->getXLen() == 32, "-m32", NewFlags);
1754+
addMultilibFlag(ISAInfo->getXLen() == 64, "-m64", NewFlags);
1755+
1756+
// Collect all flags except march=*
1757+
for (StringRef Flag : Flags) {
1758+
if (Flag.startswith("!march=") || Flag.startswith("-march="))
1759+
continue;
1760+
1761+
NewFlags.push_back(Flag.str());
1762+
}
1763+
1764+
llvm::StringSet<> AllArchExts;
1765+
// Reconstruct multi-lib list, and break march option into seperated
1766+
// extension. e.g. march=rv32im -> +i +m
1767+
for (auto M : RISCVMultilibSet) {
1768+
bool Skip = false;
1769+
1770+
MultilibBuilder NewMultilib =
1771+
MultilibBuilder(M.gccSuffix(), M.osSuffix(), M.includeSuffix());
1772+
for (StringRef Flag : M.flags()) {
1773+
// Add back the all option except -march.
1774+
if (!Flag.startswith("-march=")) {
1775+
NewMultilib.flag(Flag);
1776+
continue;
1777+
}
1778+
1779+
// Break down -march into individual extension.
1780+
auto MLConfigParseResult = llvm::RISCVISAInfo::parseArchString(
1781+
Flag.drop_front(7), /*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 got 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+
auto MLConfigArchExts = MLConfigISAInfo->getExtensions();
1795+
for (auto MLConfigArchExt : MLConfigArchExts) {
1796+
auto ExtName = MLConfigArchExt.first;
1797+
NewMultilib.flag(Twine("-", ExtName).str());
1798+
1799+
if (!AllArchExts.contains(ExtName)) {
1800+
AllArchExts.insert(ExtName);
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 (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 (RISCVMultilibSelect(RISCVMultilibs, MArch, Flags,
1894+
Result.SelectedMultilibs))
17701895
Result.Multilibs = RISCVMultilibs;
17711896
}
17721897

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

0 commit comments

Comments
 (0)