https://github.com/4vtomat updated https://github.com/llvm/llvm-project/pull/73765
>From 320061a69ed129947eab1097d6308af434134a35 Mon Sep 17 00:00:00 2001 From: Brandon Wu <brandon...@sifive.com> Date: Wed, 29 Nov 2023 00:27:25 -0800 Subject: [PATCH 1/3] [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. --- clang/lib/Driver/ToolChains/Gnu.cpp | 127 +++++++++++++++++- .../riscv-toolchain-gcc-multilib-reuse.c | 86 ++++++++++++ 2 files changed, 212 insertions(+), 1 deletion(-) create mode 100644 clang/test/Driver/riscv-toolchain-gcc-multilib-reuse.c diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index b875991844ffff..c373a194ee4064 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -30,6 +30,7 @@ #include "llvm/Option/ArgList.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/Path.h" +#include "llvm/Support/RISCVISAInfo.h" #include "llvm/Support/VirtualFileSystem.h" #include "llvm/TargetParser/TargetParser.h" #include <system_error> @@ -1715,6 +1716,129 @@ static void findCSKYMultilibs(const Driver &D, const llvm::Triple &TargetTriple, Result.Multilibs = CSKYMultilibs; } +/// 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. +static bool +RISCVMultilibSelect(const MultilibSet &RISCVMultilibSet, StringRef Arch, + const Multilib::flags_list &Flags, + llvm::SmallVector<Multilib> &SelectedMultilibs) { + // Try to find the perfect matching multi-lib first. + if (RISCVMultilibSet.select(Flags, SelectedMultilibs)) + return true; + + llvm::StringMap<bool> FlagSet; + Multilib::flags_list NewFlags; + std::vector<MultilibBuilder> NewMultilibs; + + auto ParseResult = llvm::RISCVISAInfo::parseArchString( + Arch, /*EnableExperimentalExtension=*/true, + /*ExperimentalExtensionVersionCheck=*/false); + if (!ParseResult) { + // Ignore any error here, we assume it will handled in another place. + consumeError(ParseResult.takeError()); + return false; + } + auto &ISAInfo = *ParseResult; + + auto CurrentExts = ISAInfo->getExtensions(); + + addMultilibFlag(ISAInfo->getXLen() == 32, "-m32", NewFlags); + addMultilibFlag(ISAInfo->getXLen() == 64, "-m64", NewFlags); + + // Collect all flags except march=* + for (StringRef Flag : Flags) { + if (Flag.startswith("!march=") || Flag.startswith("-march=")) + continue; + + NewFlags.push_back(Flag.str()); + } + + llvm::StringSet<> AllArchExts; + // Reconstruct multi-lib list, and break march option into seperated + // extension. e.g. march=rv32im -> +i +m + for (auto M : RISCVMultilibSet) { + bool Skip = false; + + MultilibBuilder NewMultilib = + MultilibBuilder(M.gccSuffix(), M.osSuffix(), M.includeSuffix()); + for (StringRef Flag : M.flags()) { + // Add back the all option except -march. + if (!Flag.startswith("-march=")) { + NewMultilib.flag(Flag); + continue; + } + + // Break down -march into individual extension. + auto MLConfigParseResult = llvm::RISCVISAInfo::parseArchString( + Flag.drop_front(7), /*EnableExperimentalExtension=*/true, + /*ExperimentalExtensionVersionCheck=*/false); + if (!MLConfigParseResult) { + // Ignore any error here, we assume it will handled in another place. + llvm::consumeError(MLConfigParseResult.takeError()); + + // We might got parsing error if rv32e in the list, we could just skip + // that and process the rest of multi-lib configs. + Skip = true; + continue; + } + auto &MLConfigISAInfo = *MLConfigParseResult; + + auto MLConfigArchExts = MLConfigISAInfo->getExtensions(); + for (auto MLConfigArchExt : MLConfigArchExts) { + auto ExtName = MLConfigArchExt.first; + NewMultilib.flag(Twine("-", ExtName).str()); + + if (!AllArchExts.contains(ExtName)) { + AllArchExts.insert(ExtName); + addMultilibFlag(ISAInfo->hasExtension(ExtName), + Twine("-", ExtName).str(), NewFlags); + } + } + + // Check the XLEN explicitly. + if (MLConfigISAInfo->getXLen() == 32) { + NewMultilib.flag("-m32"); + NewMultilib.flag("!m64"); + } else { + NewMultilib.flag("!m32"); + NewMultilib.flag("-m64"); + } + + // Atomic extension must be explicitly checked, soft and hard atomic + // operation never co-work correctly. + if (!MLConfigISAInfo->hasExtension("a")) + NewMultilib.flag("!a"); + } + + if (Skip) + continue; + + NewMultilibs.emplace_back(NewMultilib); + } + + // Build an internal used only multi-lib list, used for checking any + // compatible multi-lib. + MultilibSet NewRISCVMultilibs = + MultilibSetBuilder().Either(NewMultilibs).makeMultilibSet(); + + if (NewRISCVMultilibs.select(NewFlags, SelectedMultilibs)) + for (const Multilib &NewSelectedM : SelectedMultilibs) + for (auto M : RISCVMultilibSet) + // Look up the corresponding multi-lib entry in original multi-lib set. + if (M.gccSuffix() == NewSelectedM.gccSuffix()) + return true; + + return false; +} + static void findRISCVBareMetalMultilibs(const Driver &D, const llvm::Triple &TargetTriple, StringRef Path, const ArgList &Args, @@ -1766,7 +1890,8 @@ static void findRISCVBareMetalMultilibs(const Driver &D, } } - if (RISCVMultilibs.select(Flags, Result.SelectedMultilibs)) + if (RISCVMultilibSelect(RISCVMultilibs, MArch, Flags, + Result.SelectedMultilibs)) Result.Multilibs = RISCVMultilibs; } diff --git a/clang/test/Driver/riscv-toolchain-gcc-multilib-reuse.c b/clang/test/Driver/riscv-toolchain-gcc-multilib-reuse.c new file mode 100644 index 00000000000000..65afe82931de5c --- /dev/null +++ b/clang/test/Driver/riscv-toolchain-gcc-multilib-reuse.c @@ -0,0 +1,86 @@ +// Test case for scanning input of GCC output as multilib config +// Skip this test on Windows, we can't create a dummy GCC to output +// multilib config, ExecuteAndWait only execute *.exe file. +// UNSUPPORTED: system-windows + +// RUN: %clang %s \ +// RUN: -target riscv64-unknown-elf \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_riscv_elf_sdk \ +// RUN: --print-multi-directory \ +// RUN: -march=rv32imc -mabi=ilp32 \ +// RUN: | FileCheck -check-prefix=GCC-MULTI-LIB-REUSE-RV32IMC-ILP32 %s +// GCC-MULTI-LIB-REUSE-RV32IMC-ILP32: rv32im/ilp32 +// GCC-MULTI-LIB-REUSE-RV32IMC-ILP32-NOT: {{^.+$}} + +// Check rv32imac won't reuse rv32im or rv32ic +// RUN: %clang %s \ +// RUN: -target riscv64-unknown-elf \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_riscv_elf_sdk \ +// RUN: --print-multi-directory \ +// RUN: -march=rv32imac -mabi=ilp32 \ +// RUN: | FileCheck -check-prefix=GCC-MULTI-LIB-REUSE-RV32IMAC-ILP32 %s +// GCC-MULTI-LIB-REUSE-RV32IMAC-ILP32: rv32imac/ilp32 +// GCC-MULTI-LIB-REUSE-RV32IMAC-ILP32--NOT: {{^.+$}} + +// RUN: %clang %s \ +// RUN: -target riscv64-unknown-elf \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_riscv_elf_sdk \ +// RUN: --print-multi-directory \ +// RUN: -march=rv32iac -mabi=ilp32 \ +// RUN: | FileCheck -check-prefix=GCC-MULTI-LIB-REUSE-RV32IAC-ILP32 %s +// GCC-MULTI-LIB-REUSE-RV32IAC-ILP32: rv32iac/ilp32 +// GCC-MULTI-LIB-REUSE-RV32IAC-ILP32-NOT: {{^.+$}} + +// RUN: %clang %s \ +// RUN: -target riscv64-unknown-elf \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_riscv_elf_sdk \ +// RUN: --print-multi-directory \ +// RUN: -march=rv32imafdc -mabi=ilp32f \ +// RUN: | FileCheck -check-prefix=GCC-MULTI-LIB-REUSE-RV32IMAFDC-ILP32F %s +// GCC-MULTI-LIB-REUSE-RV32IMAFDC-ILP32F: rv32imafc/ilp32f +// GCC-MULTI-LIB-REUSE-RV32IMAFDC-ILP32F-NOT: {{^.+$}} + +// RUN: %clang %s \ +// RUN: -target riscv64-unknown-elf \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_riscv_elf_sdk \ +// RUN: --print-multi-directory \ +// RUN: -march=rv32imafdc -mabi=ilp32d \ +// RUN: | FileCheck -check-prefix=GCC-MULTI-LIB-REUSE-RV32IMAFDC-ILP32D %s +// GCC-MULTI-LIB-REUSE-RV32IMAFDC-ILP32D: . +// GCC-MULTI-LIB-REUSE-RV32IMAFDC-ILP32D-NOT: {{^.+$}} + +// RUN: %clang %s \ +// RUN: -target riscv64-unknown-elf \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_riscv_elf_sdk \ +// RUN: --print-multi-directory \ +// RUN: -march=rv64imafc -mabi=lp64 \ +// RUN: | FileCheck -check-prefix=GCC-MULTI-LIB-REUSE-RV64IMAFC-LP64 %s +// GCC-MULTI-LIB-REUSE-RV64IMAFC-LP64: rv64imac/lp64 +// GCC-MULTI-LIB-REUSE-RV64IMAFC-LP64-NOT: {{^.+$}} + +// RUN: %clang %s \ +// RUN: -target riscv64-unknown-elf \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_riscv_elf_sdk \ +// RUN: --print-multi-directory \ +// RUN: -march=rv32imafc_zfh -mabi=ilp32 \ +// RUN: | FileCheck -check-prefix=GCC-MULTI-LIB-REUSE-RV32IMAFC_ZFH-ILP32 %s +// GCC-MULTI-LIB-REUSE-RV32IMAFC_ZFH-ILP32: rv32imac/ilp32 +// GCC-MULTI-LIB-REUSE-RV32IMAFC_ZFH-ILP32-NOT: {{^.+$}} + +// RUN: %clang %s \ +// RUN: -target riscv64-unknown-elf \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_riscv_elf_sdk \ +// RUN: --print-multi-directory \ +// RUN: -march=rv32i_zvkb -mabi=ilp32 \ +// RUN: | FileCheck -check-prefix=GCC-MULTI-LIB-REUSE-RV32I_ZVKB-ILP32 %s +// GCC-MULTI-LIB-REUSE-RV32I_ZVKB-ILP32: rv32i/ilp32 +// GCC-MULTI-LIB-REUSE-RV32I_ZVKB-ILP32-NOT: {{^.+$}} + +// RUN: %clang %s \ +// RUN: -target riscv64-unknown-elf \ +// RUN: --gcc-toolchain=%S/Inputs/multilib_riscv_elf_sdk \ +// RUN: --print-multi-directory \ +// RUN: -march=rv64imfc -mabi=lp64 \ +// RUN: | FileCheck -check-prefix=GCC-MULTI-LIB-REUSE-RV64IMFC-LP64 %s +// GCC-MULTI-LIB-REUSE-RV64IMFC-LP64: . +// GCC-MULTI-LIB-REUSE-RV64IMFC-LP64-NOT: {{^.+$}} >From ecec19053ea034781ea8d301c2dfc1c7abf1af63 Mon Sep 17 00:00:00 2001 From: Brandon Wu <brandon...@sifive.com> Date: Mon, 4 Dec 2023 00:15:33 -0800 Subject: [PATCH 2/3] fixup! [RISCV] Implement multi-lib reuse rule for RISC-V bare-metal toolchain --- clang/lib/Driver/ToolChains/Gnu.cpp | 31 ++++++++++--------- .../riscv-toolchain-gcc-multilib-reuse.c | 5 --- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index c373a194ee4064..1aa71803bbbc44 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -1717,13 +1717,13 @@ static void findCSKYMultilibs(const Driver &D, const llvm::Triple &TargetTriple, } /// Extend the multi-lib re-use selection mechanism for RISC-V. -/// This funciton will try to re-use multi-lib if they are compatible. +/// 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 has atomic, vice versa. e.g. multi-lib=march=rv32im and +/// 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. static bool @@ -1734,21 +1734,20 @@ RISCVMultilibSelect(const MultilibSet &RISCVMultilibSet, StringRef Arch, if (RISCVMultilibSet.select(Flags, SelectedMultilibs)) return true; - llvm::StringMap<bool> FlagSet; Multilib::flags_list NewFlags; std::vector<MultilibBuilder> NewMultilibs; - auto ParseResult = llvm::RISCVISAInfo::parseArchString( - Arch, /*EnableExperimentalExtension=*/true, - /*ExperimentalExtensionVersionCheck=*/false); + llvm::Expected<std::unique_ptr<llvm::RISCVISAInfo>> ParseResult = + llvm::RISCVISAInfo::parseArchString( + Arch, /*EnableExperimentalExtension=*/true, + /*ExperimentalExtensionVersionCheck=*/false); if (!ParseResult) { - // Ignore any error here, we assume it will handled in another place. + // Ignore any error here, we assume it will be handled in another place. consumeError(ParseResult.takeError()); return false; } - auto &ISAInfo = *ParseResult; - auto CurrentExts = ISAInfo->getExtensions(); + auto &ISAInfo = *ParseResult; addMultilibFlag(ISAInfo->getXLen() == 32, "-m32", NewFlags); addMultilibFlag(ISAInfo->getXLen() == 64, "-m64", NewFlags); @@ -1762,7 +1761,7 @@ RISCVMultilibSelect(const MultilibSet &RISCVMultilibSet, StringRef Arch, } llvm::StringSet<> AllArchExts; - // Reconstruct multi-lib list, and break march option into seperated + // Reconstruct multi-lib list, and break march option into separated // extension. e.g. march=rv32im -> +i +m for (auto M : RISCVMultilibSet) { bool Skip = false; @@ -1777,21 +1776,23 @@ RISCVMultilibSelect(const MultilibSet &RISCVMultilibSet, StringRef Arch, } // Break down -march into individual extension. - auto MLConfigParseResult = llvm::RISCVISAInfo::parseArchString( - Flag.drop_front(7), /*EnableExperimentalExtension=*/true, - /*ExperimentalExtensionVersionCheck=*/false); + llvm::Expected<std::unique_ptr<llvm::RISCVISAInfo>> MLConfigParseResult = + llvm::RISCVISAInfo::parseArchString( + Flag.drop_front(7), /*EnableExperimentalExtension=*/true, + /*ExperimentalExtensionVersionCheck=*/false); if (!MLConfigParseResult) { // Ignore any error here, we assume it will handled in another place. llvm::consumeError(MLConfigParseResult.takeError()); - // We might got parsing error if rv32e in the list, we could just skip + // We might get parsing error if rv32e in the list, we could just skip // that and process the rest of multi-lib configs. Skip = true; continue; } auto &MLConfigISAInfo = *MLConfigParseResult; - auto MLConfigArchExts = MLConfigISAInfo->getExtensions(); + const llvm::RISCVISAInfo::OrderedExtensionMap &MLConfigArchExts = + MLConfigISAInfo->getExtensions(); for (auto MLConfigArchExt : MLConfigArchExts) { auto ExtName = MLConfigArchExt.first; NewMultilib.flag(Twine("-", ExtName).str()); diff --git a/clang/test/Driver/riscv-toolchain-gcc-multilib-reuse.c b/clang/test/Driver/riscv-toolchain-gcc-multilib-reuse.c index 65afe82931de5c..1f8a5a8821edfa 100644 --- a/clang/test/Driver/riscv-toolchain-gcc-multilib-reuse.c +++ b/clang/test/Driver/riscv-toolchain-gcc-multilib-reuse.c @@ -1,8 +1,3 @@ -// Test case for scanning input of GCC output as multilib config -// Skip this test on Windows, we can't create a dummy GCC to output -// multilib config, ExecuteAndWait only execute *.exe file. -// UNSUPPORTED: system-windows - // RUN: %clang %s \ // RUN: -target riscv64-unknown-elf \ // RUN: --gcc-toolchain=%S/Inputs/multilib_riscv_elf_sdk \ >From 6caf21f33b21668b8a59d5345b3f9192a61e8418 Mon Sep 17 00:00:00 2001 From: Brandon Wu <brandon...@sifive.com> Date: Tue, 12 Dec 2023 20:40:51 -0800 Subject: [PATCH 3/3] fixup! [RISCV] Implement multi-lib reuse rule for RISC-V bare-metal toolchain --- clang/lib/Driver/ToolChains/Gnu.cpp | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index 1aa71803bbbc44..68be2550debc28 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -1727,9 +1727,9 @@ static void findCSKYMultilibs(const Driver &D, const llvm::Triple &TargetTriple, /// march=rv32ima are not compatible, because software and hardware /// atomic operation can't work together correctly. static bool -RISCVMultilibSelect(const MultilibSet &RISCVMultilibSet, StringRef Arch, +selectRISCVMultilib(const MultilibSet &RISCVMultilibSet, StringRef Arch, const Multilib::flags_list &Flags, - llvm::SmallVector<Multilib> &SelectedMultilibs) { + llvm::SmallVectorImpl<Multilib> &SelectedMultilibs) { // Try to find the perfect matching multi-lib first. if (RISCVMultilibSet.select(Flags, SelectedMultilibs)) return true; @@ -1763,14 +1763,14 @@ RISCVMultilibSelect(const MultilibSet &RISCVMultilibSet, StringRef Arch, llvm::StringSet<> AllArchExts; // Reconstruct multi-lib list, and break march option into separated // extension. e.g. march=rv32im -> +i +m - for (auto M : RISCVMultilibSet) { + for (const auto &M : RISCVMultilibSet) { bool Skip = false; MultilibBuilder NewMultilib = MultilibBuilder(M.gccSuffix(), M.osSuffix(), M.includeSuffix()); for (StringRef Flag : M.flags()) { - // Add back the all option except -march. - if (!Flag.startswith("-march=")) { + // Add back all flags except -march. + if (!Flag.consume_front("-march=")) { NewMultilib.flag(Flag); continue; } @@ -1778,13 +1778,13 @@ RISCVMultilibSelect(const MultilibSet &RISCVMultilibSet, StringRef Arch, // Break down -march into individual extension. llvm::Expected<std::unique_ptr<llvm::RISCVISAInfo>> MLConfigParseResult = llvm::RISCVISAInfo::parseArchString( - Flag.drop_front(7), /*EnableExperimentalExtension=*/true, + Flag, /*EnableExperimentalExtension=*/true, /*ExperimentalExtensionVersionCheck=*/false); if (!MLConfigParseResult) { // Ignore any error here, we assume it will handled in another place. llvm::consumeError(MLConfigParseResult.takeError()); - // We might get parsing error if rv32e in the list, we could just skip + // We might get a parsing error if rv32e in the list, we could just skip // that and process the rest of multi-lib configs. Skip = true; continue; @@ -1797,8 +1797,7 @@ RISCVMultilibSelect(const MultilibSet &RISCVMultilibSet, StringRef Arch, auto ExtName = MLConfigArchExt.first; NewMultilib.flag(Twine("-", ExtName).str()); - if (!AllArchExts.contains(ExtName)) { - AllArchExts.insert(ExtName); + if (AllArchExts.insert(ExtName).second) { addMultilibFlag(ISAInfo->hasExtension(ExtName), Twine("-", ExtName).str(), NewFlags); } @@ -1832,7 +1831,7 @@ RISCVMultilibSelect(const MultilibSet &RISCVMultilibSet, StringRef Arch, if (NewRISCVMultilibs.select(NewFlags, SelectedMultilibs)) for (const Multilib &NewSelectedM : SelectedMultilibs) - for (auto M : RISCVMultilibSet) + for (const auto &M : RISCVMultilibSet) // Look up the corresponding multi-lib entry in original multi-lib set. if (M.gccSuffix() == NewSelectedM.gccSuffix()) return true; @@ -1891,7 +1890,7 @@ static void findRISCVBareMetalMultilibs(const Driver &D, } } - if (RISCVMultilibSelect(RISCVMultilibs, MArch, Flags, + if (selectRISCVMultilib(RISCVMultilibs, MArch, Flags, Result.SelectedMultilibs)) Result.Multilibs = RISCVMultilibs; } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits