From a7e8bfe5ad9a1c1e3f0bba886474f381ebc403a9 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Tue, 28 Jan 2025 15:43:31 -0800 Subject: [PATCH 01/34] [lldb] Fix CommandInterpreter.{h,cpp} formatting (NFC) Fix CommandInterpreter.{h,cpp} formatting in preparation for #125006. --- .../lldb/Interpreter/CommandInterpreter.h | 16 ++-- .../source/Interpreter/CommandInterpreter.cpp | 94 ++++++++++--------- 2 files changed, 56 insertions(+), 54 deletions(-) diff --git a/lldb/include/lldb/Interpreter/CommandInterpreter.h b/lldb/include/lldb/Interpreter/CommandInterpreter.h index 2bafc30cc8e23..910c1d8430335 100644 --- a/lldb/include/lldb/Interpreter/CommandInterpreter.h +++ b/lldb/include/lldb/Interpreter/CommandInterpreter.h @@ -100,8 +100,7 @@ class CommandInterpreterRunOptions { LazyBool stop_on_error, LazyBool stop_on_crash, LazyBool echo_commands, LazyBool echo_comments, LazyBool print_results, LazyBool print_errors, - LazyBool add_to_history, - LazyBool handle_repeats) + LazyBool add_to_history, LazyBool handle_repeats) : m_stop_on_continue(stop_on_continue), m_stop_on_error(stop_on_error), m_stop_on_crash(stop_on_crash), m_echo_commands(echo_commands), m_echo_comment_commands(echo_comments), m_print_results(print_results), @@ -248,13 +247,13 @@ class CommandInterpreter : public Broadcaster, enum CommandTypes { eCommandTypesBuiltin = 0x0001, //< native commands such as "frame" eCommandTypesUserDef = 0x0002, //< scripted commands - eCommandTypesUserMW = 0x0004, //< multiword commands (command containers) + eCommandTypesUserMW = 0x0004, //< multiword commands (command containers) eCommandTypesAliases = 0x0008, //< aliases such as "po" - eCommandTypesHidden = 0x0010, //< commands prefixed with an underscore + eCommandTypesHidden = 0x0010, //< commands prefixed with an underscore eCommandTypesAllThem = 0xFFFF //< all commands }; - // The CommandAlias and CommandInterpreter both have a hand in + // The CommandAlias and CommandInterpreter both have a hand in // substituting for alias commands. They work by writing special tokens // in the template form of the Alias command, and then detecting them when the // command is executed. These are the special tokens: @@ -334,9 +333,8 @@ class CommandInterpreter : public Broadcaster, /// dummy "contains everything MWC, so we return null here, but /// in this case error.Success is true. - CommandObjectMultiword *VerifyUserMultiwordCmdPath(Args &path, - bool leaf_is_command, - Status &result); + CommandObjectMultiword * + VerifyUserMultiwordCmdPath(Args &path, bool leaf_is_command, Status &result); CommandAlias *AddAlias(llvm::StringRef alias_name, lldb::CommandObjectSP &command_obj_sp, @@ -596,7 +594,7 @@ class CommandInterpreter : public Broadcaster, void SetEchoCommentCommands(bool enable); bool GetRepeatPreviousCommand() const; - + bool GetRequireCommandOverwrite() const; const CommandObject::CommandMap &GetUserCommands() const { diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index 764dcfd1903b1..04226af1a1eb8 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -113,7 +113,6 @@ const char *CommandInterpreter::g_no_argument = ""; const char *CommandInterpreter::g_need_argument = ""; const char *CommandInterpreter::g_argument = ""; - #define LLDB_PROPERTIES_interpreter #include "InterpreterProperties.inc" @@ -447,16 +446,17 @@ void CommandInterpreter::Initialize() { CommandAlias *parray_alias = AddAlias("parray", cmd_obj_sp, "--element-count %1 --"); if (parray_alias) { - parray_alias->SetHelp - ("parray -- lldb will evaluate EXPRESSION " - "to get a typed-pointer-to-an-array in memory, and will display " - "COUNT elements of that type from the array."); - parray_alias->SetHelpLong(""); - } - CommandAlias *poarray_alias = AddAlias("poarray", cmd_obj_sp, - "--object-description --element-count %1 --"); + parray_alias->SetHelp( + "parray -- lldb will evaluate EXPRESSION " + "to get a typed-pointer-to-an-array in memory, and will display " + "COUNT elements of that type from the array."); + parray_alias->SetHelpLong(""); + } + CommandAlias *poarray_alias = AddAlias( + "poarray", cmd_obj_sp, "--object-description --element-count %1 --"); if (poarray_alias) { - poarray_alias->SetHelp("poarray -- lldb will " + poarray_alias->SetHelp( + "poarray -- lldb will " "evaluate EXPRESSION to get the address of an array of COUNT " "objects in memory, and will call po on them."); poarray_alias->SetHelpLong(""); @@ -536,9 +536,7 @@ void CommandInterpreter::Initialize() { } } -void CommandInterpreter::Clear() { - m_command_io_handler_sp.reset(); -} +void CommandInterpreter::Clear() { m_command_io_handler_sp.reset(); } const char *CommandInterpreter::ProcessEmbeddedScriptCommands(const char *arg) { // This function has not yet been implemented. @@ -851,9 +849,12 @@ void CommandInterpreter::LoadCommandDictionary() { // now "bt 3" is the preferred form, in line with gdb. if (bt_regex_cmd_up->AddRegexCommand("^([[:digit:]]+)[[:space:]]*$", "thread backtrace -c %1") && - bt_regex_cmd_up->AddRegexCommand("^(-[^[:space:]].*)$", "thread backtrace %1") && - bt_regex_cmd_up->AddRegexCommand("^all[[:space:]]*$", "thread backtrace all") && - bt_regex_cmd_up->AddRegexCommand("^[[:space:]]*$", "thread backtrace")) { + bt_regex_cmd_up->AddRegexCommand("^(-[^[:space:]].*)$", + "thread backtrace %1") && + bt_regex_cmd_up->AddRegexCommand("^all[[:space:]]*$", + "thread backtrace all") && + bt_regex_cmd_up->AddRegexCommand("^[[:space:]]*$", + "thread backtrace")) { CommandObjectSP command_sp(bt_regex_cmd_up.release()); m_command_dict[std::string(command_sp->GetCommandName())] = command_sp; } @@ -954,13 +955,14 @@ int CommandInterpreter::GetCommandNamesMatchingPartialString( return matches.GetSize(); } -CommandObjectMultiword *CommandInterpreter::VerifyUserMultiwordCmdPath( - Args &path, bool leaf_is_command, Status &result) { +CommandObjectMultiword * +CommandInterpreter::VerifyUserMultiwordCmdPath(Args &path, bool leaf_is_command, + Status &result) { result.Clear(); auto get_multi_or_report_error = [&result](CommandObjectSP cmd_sp, - const char *name) -> CommandObjectMultiword * { + const char *name) -> CommandObjectMultiword * { if (!cmd_sp) { result = Status::FromErrorStringWithFormat( "Path component: '%s' not found", name); @@ -1265,8 +1267,8 @@ CommandInterpreter::GetCommandObject(llvm::StringRef cmd_str, // Try to find a match among commands and aliases. Allowing inexact matches, // but perferring exact matches. return GetCommandSP(cmd_str, /*include_aliases=*/true, /*exact=*/false, - matches, descriptions) - .get(); + matches, descriptions) + .get(); } CommandObject *CommandInterpreter::GetUserCommandObject( @@ -1299,8 +1301,8 @@ CommandObject *CommandInterpreter::GetUserCommandObject( StringList tmp_list; StringList *matches_ptr = matches ? matches : &tmp_list; AddNamesMatchingPartialString(GetUserCommands(), cmd_str, *matches_ptr); - AddNamesMatchingPartialString(GetUserMultiwordCommands(), - cmd_str, *matches_ptr); + AddNamesMatchingPartialString(GetUserMultiwordCommands(), cmd_str, + *matches_ptr); return {}; } @@ -1798,8 +1800,7 @@ Status CommandInterpreter::PreprocessCommand(std::string &command) { return error; } -Status -CommandInterpreter::PreprocessToken(std::string &expr_str) { +Status CommandInterpreter::PreprocessToken(std::string &expr_str) { Status error; ExecutionContext exe_ctx(GetExecutionContext()); @@ -1819,9 +1820,8 @@ CommandInterpreter::PreprocessToken(std::string &expr_str) { options.SetTryAllThreads(true); options.SetTimeout(std::nullopt); - ExpressionResults expr_result = - target.EvaluateExpression(expr_str.c_str(), exe_ctx.GetFramePtr(), - expr_result_valobj_sp, options); + ExpressionResults expr_result = target.EvaluateExpression( + expr_str.c_str(), exe_ctx.GetFramePtr(), expr_result_valobj_sp, options); if (expr_result == eExpressionCompleted) { Scalar scalar; @@ -1890,7 +1890,7 @@ bool CommandInterpreter::HandleCommand(const char *command_line, Log *log = GetLog(LLDBLog::Commands); llvm::PrettyStackTraceFormat stack_trace("HandleCommand(command = \"%s\")", - command_line); + command_line); LLDB_LOGF(log, "Processing command: %s", command_line); LLDB_SCOPED_TIMERF("Processing command: %s.", command_line); @@ -2011,7 +2011,8 @@ bool CommandInterpreter::HandleCommand(const char *command_line, // has the command expanded to the full name. For example, if the input was // "br s -n main", command_string is now "breakpoint set -n main". if (log) { - llvm::StringRef command_name = cmd_obj ? cmd_obj->GetCommandName() : ""; + llvm::StringRef command_name = + cmd_obj ? cmd_obj->GetCommandName() : ""; LLDB_LOGF(log, "HandleCommand, cmd_obj : '%s'", command_name.str().c_str()); LLDB_LOGF(log, "HandleCommand, (revised) command_string: '%s'", command_string.c_str()); @@ -2216,11 +2217,15 @@ CommandInterpreter::GetAlias(llvm::StringRef alias_name) const { return nullptr; } -bool CommandInterpreter::HasCommands() const { return (!m_command_dict.empty()); } +bool CommandInterpreter::HasCommands() const { + return (!m_command_dict.empty()); +} bool CommandInterpreter::HasAliases() const { return (!m_alias_dict.empty()); } -bool CommandInterpreter::HasUserCommands() const { return (!m_user_dict.empty()); } +bool CommandInterpreter::HasUserCommands() const { + return (!m_user_dict.empty()); +} bool CommandInterpreter::HasUserMultiwordCommands() const { return (!m_user_mw_dict.empty()); @@ -2578,20 +2583,18 @@ bool CommandInterpreter::DidProcessStopAbnormally() const { return false; } -void -CommandInterpreter::HandleCommands(const StringList &commands, - const ExecutionContext &override_context, - const CommandInterpreterRunOptions &options, - CommandReturnObject &result) { +void CommandInterpreter::HandleCommands( + const StringList &commands, const ExecutionContext &override_context, + const CommandInterpreterRunOptions &options, CommandReturnObject &result) { OverrideExecutionContext(override_context); HandleCommands(commands, options, result); RestoreExecutionContext(); } -void CommandInterpreter::HandleCommands(const StringList &commands, - const CommandInterpreterRunOptions &options, - CommandReturnObject &result) { +void CommandInterpreter::HandleCommands( + const StringList &commands, const CommandInterpreterRunOptions &options, + CommandReturnObject &result) { size_t num_lines = commands.GetSize(); // If we are going to continue past a "continue" then we need to run the @@ -2728,8 +2731,9 @@ void CommandInterpreter::HandleCommandsFromFile( RestoreExecutionContext(); } -void CommandInterpreter::HandleCommandsFromFile(FileSpec &cmd_file, - const CommandInterpreterRunOptions &options, CommandReturnObject &result) { +void CommandInterpreter::HandleCommandsFromFile( + FileSpec &cmd_file, const CommandInterpreterRunOptions &options, + CommandReturnObject &result) { if (!FileSystem::Instance().Exists(cmd_file)) { result.AppendErrorWithFormat( "Error reading commands from file %s - file not found.\n", @@ -3134,9 +3138,9 @@ bool CommandInterpreter::EchoCommandNonInteractive( void CommandInterpreter::IOHandlerInputComplete(IOHandler &io_handler, std::string &line) { - // If we were interrupted, bail out... - if (WasInterrupted()) - return; + // If we were interrupted, bail out... + if (WasInterrupted()) + return; const bool is_interactive = io_handler.GetIsInteractive(); const bool allow_repeats = From c8f4189eeb927247ead2d8b082a6920d5b873aa8 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Thu, 30 Jan 2025 10:15:40 -0800 Subject: [PATCH 02/34] [scudo] Clean up secondary tests. (#124999) Change names to all begin with ScudoSecondary and change tests names appropriately. Move the cache option test to the cache test fixture. Force the allocator test to use the no cached config so that all of the allocations always fully exercise the allocator function and don't skip this by using a previously cached element. --- .../scudo/standalone/tests/secondary_test.cpp | 93 +++++++++---------- 1 file changed, 44 insertions(+), 49 deletions(-) diff --git a/compiler-rt/lib/scudo/standalone/tests/secondary_test.cpp b/compiler-rt/lib/scudo/standalone/tests/secondary_test.cpp index 3638f1c36ddd9..e1471dfdf6807 100644 --- a/compiler-rt/lib/scudo/standalone/tests/secondary_test.cpp +++ b/compiler-rt/lib/scudo/standalone/tests/secondary_test.cpp @@ -32,7 +32,7 @@ template static scudo::Options getOptionsForConfig() { return AO.load(); } -template static void testSecondaryBasic(void) { +template static void testBasic(void) { using SecondaryT = scudo::MapAllocator>; scudo::Options Options = getOptionsForConfig>(); @@ -85,7 +85,7 @@ template static void testSecondaryBasic(void) { L->unmapTestOnly(); } -struct NoCacheConfig { +struct TestNoCacheConfig { static const bool MaySupportMemoryTagging = false; template using TSDRegistryT = void; template using PrimaryT = void; @@ -97,7 +97,7 @@ struct NoCacheConfig { }; }; -struct TestConfig { +struct TestCacheConfig { static const bool MaySupportMemoryTagging = false; template using TSDRegistryT = void; template using PrimaryT = void; @@ -117,15 +117,15 @@ struct TestConfig { }; }; -TEST(ScudoSecondaryTest, SecondaryBasic) { - testSecondaryBasic(); - testSecondaryBasic(); - testSecondaryBasic(); +TEST(ScudoSecondaryTest, Basic) { + testBasic(); + testBasic(); + testBasic(); } -struct MapAllocatorTest : public Test { - using Config = scudo::DefaultConfig; - using LargeAllocator = scudo::MapAllocator>; +struct ScudoSecondaryAllocatorTest : public Test { + using LargeAllocator = + scudo::MapAllocator>; void SetUp() override { Allocator->init(nullptr); } @@ -134,13 +134,13 @@ struct MapAllocatorTest : public Test { std::unique_ptr Allocator = std::make_unique(); scudo::Options Options = - getOptionsForConfig>(); + getOptionsForConfig>(); }; // This exercises a variety of combinations of size and alignment for the // MapAllocator. The size computation done here mimic the ones done by the // combined allocator. -TEST_F(MapAllocatorTest, SecondaryCombinations) { +TEST_F(ScudoSecondaryAllocatorTest, Combinations) { constexpr scudo::uptr MinAlign = FIRST_32_SECOND_64(8, 16); constexpr scudo::uptr HeaderSize = scudo::roundUp(8, MinAlign); for (scudo::uptr SizeLog = 0; SizeLog <= 20; SizeLog++) { @@ -168,7 +168,7 @@ TEST_F(MapAllocatorTest, SecondaryCombinations) { Str.output(); } -TEST_F(MapAllocatorTest, SecondaryIterate) { +TEST_F(ScudoSecondaryAllocatorTest, Iterate) { std::vector V; const scudo::uptr PageSize = scudo::getPageSizeCached(); for (scudo::uptr I = 0; I < 32U; I++) @@ -190,34 +190,8 @@ TEST_F(MapAllocatorTest, SecondaryIterate) { Str.output(); } -TEST_F(MapAllocatorTest, SecondaryCacheOptions) { - if (!Allocator->canCache(0U)) - TEST_SKIP("Secondary Cache disabled"); - - // Attempt to set a maximum number of entries higher than the array size. - EXPECT_TRUE(Allocator->setOption(scudo::Option::MaxCacheEntriesCount, 4096U)); - - // Attempt to set an invalid (negative) number of entries - EXPECT_FALSE(Allocator->setOption(scudo::Option::MaxCacheEntriesCount, -1)); - - // Various valid combinations. - EXPECT_TRUE(Allocator->setOption(scudo::Option::MaxCacheEntriesCount, 4U)); - EXPECT_TRUE( - Allocator->setOption(scudo::Option::MaxCacheEntrySize, 1UL << 20)); - EXPECT_TRUE(Allocator->canCache(1UL << 18)); - EXPECT_TRUE( - Allocator->setOption(scudo::Option::MaxCacheEntrySize, 1UL << 17)); - EXPECT_FALSE(Allocator->canCache(1UL << 18)); - EXPECT_TRUE(Allocator->canCache(1UL << 16)); - EXPECT_TRUE(Allocator->setOption(scudo::Option::MaxCacheEntriesCount, 0U)); - EXPECT_FALSE(Allocator->canCache(1UL << 16)); - EXPECT_TRUE(Allocator->setOption(scudo::Option::MaxCacheEntriesCount, 4U)); - EXPECT_TRUE( - Allocator->setOption(scudo::Option::MaxCacheEntrySize, 1UL << 20)); - EXPECT_TRUE(Allocator->canCache(1UL << 16)); -} - -struct MapAllocatorWithReleaseTest : public MapAllocatorTest { +struct ScudoSecondaryAllocatorWithReleaseTest + : public ScudoSecondaryAllocatorTest { void SetUp() override { Allocator->init(nullptr, /*ReleaseToOsInterval=*/0); } void performAllocations() { @@ -249,11 +223,11 @@ struct MapAllocatorWithReleaseTest : public MapAllocatorTest { bool Ready = false; }; -TEST_F(MapAllocatorWithReleaseTest, SecondaryThreadsRace) { +TEST_F(ScudoSecondaryAllocatorWithReleaseTest, ThreadsRace) { std::thread Threads[16]; for (scudo::uptr I = 0; I < ARRAY_SIZE(Threads); I++) - Threads[I] = - std::thread(&MapAllocatorWithReleaseTest::performAllocations, this); + Threads[I] = std::thread( + &ScudoSecondaryAllocatorWithReleaseTest::performAllocations, this); { std::unique_lock Lock(Mutex); Ready = true; @@ -266,7 +240,7 @@ TEST_F(MapAllocatorWithReleaseTest, SecondaryThreadsRace) { Str.output(); } -struct MapAllocatorCacheTest : public Test { +struct ScudoSecondaryAllocatorCacheTest : public Test { static constexpr scudo::u32 UnmappedMarker = 0xDEADBEEF; static void testUnmapCallback(scudo::MemMapT &MemMap) { @@ -274,7 +248,7 @@ struct MapAllocatorCacheTest : public Test { *Ptr = UnmappedMarker; } - using SecondaryConfig = scudo::SecondaryConfig; + using SecondaryConfig = scudo::SecondaryConfig; using CacheConfig = SecondaryConfig::CacheConfig; using CacheT = scudo::MapAllocatorCache; @@ -315,7 +289,7 @@ struct MapAllocatorCacheTest : public Test { } }; -TEST_F(MapAllocatorCacheTest, CacheOrder) { +TEST_F(ScudoSecondaryAllocatorCacheTest, EntryOrder) { std::vector MemMaps; Cache->setOption(scudo::Option::MaxCacheEntriesCount, CacheConfig::getEntriesArraySize()); @@ -336,7 +310,7 @@ TEST_F(MapAllocatorCacheTest, CacheOrder) { MemMap.unmap(); } -TEST_F(MapAllocatorCacheTest, PartialChunkHeuristicRetrievalTest) { +TEST_F(ScudoSecondaryAllocatorCacheTest, PartialChunkHeuristicRetrievalTest) { const scudo::uptr FragmentedPages = 1 + scudo::CachedBlock::MaxReleasedCachePages; scudo::uptr EntryHeaderPos; @@ -360,7 +334,7 @@ TEST_F(MapAllocatorCacheTest, PartialChunkHeuristicRetrievalTest) { MemMap.unmap(); } -TEST_F(MapAllocatorCacheTest, MemoryLeakTest) { +TEST_F(ScudoSecondaryAllocatorCacheTest, MemoryLeakTest) { std::vector MemMaps; // Fill the cache above MaxEntriesCount to force an eviction // The first cache entry should be evicted (because it is the oldest) @@ -387,3 +361,24 @@ TEST_F(MapAllocatorCacheTest, MemoryLeakTest) { for (auto &MemMap : MemMaps) MemMap.unmap(); } + +TEST_F(ScudoSecondaryAllocatorCacheTest, Options) { + // Attempt to set a maximum number of entries higher than the array size. + EXPECT_TRUE(Cache->setOption(scudo::Option::MaxCacheEntriesCount, 4096U)); + + // Attempt to set an invalid (negative) number of entries + EXPECT_FALSE(Cache->setOption(scudo::Option::MaxCacheEntriesCount, -1)); + + // Various valid combinations. + EXPECT_TRUE(Cache->setOption(scudo::Option::MaxCacheEntriesCount, 4U)); + EXPECT_TRUE(Cache->setOption(scudo::Option::MaxCacheEntrySize, 1UL << 20)); + EXPECT_TRUE(Cache->canCache(1UL << 18)); + EXPECT_TRUE(Cache->setOption(scudo::Option::MaxCacheEntrySize, 1UL << 17)); + EXPECT_FALSE(Cache->canCache(1UL << 18)); + EXPECT_TRUE(Cache->canCache(1UL << 16)); + EXPECT_TRUE(Cache->setOption(scudo::Option::MaxCacheEntriesCount, 0U)); + EXPECT_FALSE(Cache->canCache(1UL << 16)); + EXPECT_TRUE(Cache->setOption(scudo::Option::MaxCacheEntriesCount, 4U)); + EXPECT_TRUE(Cache->setOption(scudo::Option::MaxCacheEntrySize, 1UL << 20)); + EXPECT_TRUE(Cache->canCache(1UL << 16)); +} From 08c76730f35e1dd3c9330b47fc304a35e6d9087e Mon Sep 17 00:00:00 2001 From: Paul Kirth Date: Thu, 30 Jan 2025 10:25:25 -0800 Subject: [PATCH 03/34] [llvm] Enable TLSDESC by default on Fuchsia targets (#124990) Fuchsia uses TLSDESC by default for all target architectures. We also make the comment and check for hasDefaultTLSDESC more accurately reflect its usage. --- clang/test/Driver/tls-dialect.c | 5 +++++ llvm/include/llvm/TargetParser/Triple.h | 7 ++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/clang/test/Driver/tls-dialect.c b/clang/test/Driver/tls-dialect.c index 3471b55b0ebae..9ab79e87353d8 100644 --- a/clang/test/Driver/tls-dialect.c +++ b/clang/test/Driver/tls-dialect.c @@ -10,6 +10,11 @@ /// TLSDESC is not on by default in Linux, even on RISC-V, and is covered above // RUN: %clang -### --target=riscv64-android %s 2>&1 | FileCheck --check-prefix=DESC %s +/// Fuchsia supports TLSDESC by default for all architectures. +// RUN: %clang -### --target=riscv64-unknown-fuchsia %s 2>&1 | FileCheck --check-prefix=DESC %s +// RUN: %clang -### --target=aarch64-unknown-fuchsia %s 2>&1 | FileCheck --check-prefix=DESC %s +// RUN: %clang -### --target=x86_64-unknown-fuchsia %s 2>&1 | FileCheck --check-prefix=DESC %s + /// LTO // RUN: %clang -### --target=loongarch64-linux -flto -mtls-dialect=desc %s 2>&1 | FileCheck --check-prefix=LTO-DESC %s // RUN: %clang -### --target=loongarch64-linux -flto %s 2>&1 | FileCheck --check-prefix=LTO-NODESC %s diff --git a/llvm/include/llvm/TargetParser/Triple.h b/llvm/include/llvm/TargetParser/Triple.h index 7d67966d17256..09c0d223d9b4d 100644 --- a/llvm/include/llvm/TargetParser/Triple.h +++ b/llvm/include/llvm/TargetParser/Triple.h @@ -1123,9 +1123,10 @@ class Triple { isWindowsCygwinEnvironment() || isOHOSFamily(); } - /// True if the target supports both general-dynamic and TLSDESC, and TLSDESC - /// is enabled by default. - bool hasDefaultTLSDESC() const { return isAndroid() && isRISCV64(); } + /// True if the target uses TLSDESC by default. + bool hasDefaultTLSDESC() const { + return isAArch64() || (isAndroid() && isRISCV64()) || isOSFuchsia(); + } /// Tests whether the target uses -data-sections as default. bool hasDefaultDataSections() const { From 74690327c8fb3b1bc8722b8ae40091b268100468 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Tue, 28 Jan 2025 16:10:33 -0800 Subject: [PATCH 04/34] [lldb] Constify methods in CommandReturnObject (NFC) There's no reason these methods cannot be `const`. Currently this prevents us from passing around a const ref. This patch is in preparation for #125006. --- lldb/include/lldb/Interpreter/CommandReturnObject.h | 10 +++++----- lldb/include/lldb/Utility/StreamTee.h | 2 +- lldb/source/Interpreter/CommandReturnObject.cpp | 5 +++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/lldb/include/lldb/Interpreter/CommandReturnObject.h b/lldb/include/lldb/Interpreter/CommandReturnObject.h index 9fef59337016d..f96da34889a32 100644 --- a/lldb/include/lldb/Interpreter/CommandReturnObject.h +++ b/lldb/include/lldb/Interpreter/CommandReturnObject.h @@ -32,9 +32,9 @@ class CommandReturnObject { ~CommandReturnObject() = default; /// Format any inline diagnostics with an indentation of \c indent. - std::string GetInlineDiagnosticString(unsigned indent); + std::string GetInlineDiagnosticString(unsigned indent) const; - llvm::StringRef GetOutputString() { + llvm::StringRef GetOutputString() const { lldb::StreamSP stream_sp(m_out_stream.GetStreamAtIndex(eStreamStringIndex)); if (stream_sp) return std::static_pointer_cast(stream_sp)->GetString(); @@ -46,7 +46,7 @@ class CommandReturnObject { /// If \c with_diagnostics is true, all diagnostics are also /// rendered into the string. Otherwise the expectation is that they /// are fetched with \ref GetInlineDiagnosticString(). - std::string GetErrorString(bool with_diagnostics = true); + std::string GetErrorString(bool with_diagnostics = true) const; StructuredData::ObjectSP GetErrorData(); Stream &GetOutputStream() { @@ -95,11 +95,11 @@ class CommandReturnObject { m_err_stream.SetStreamAtIndex(eImmediateStreamIndex, stream_sp); } - lldb::StreamSP GetImmediateOutputStream() { + lldb::StreamSP GetImmediateOutputStream() const { return m_out_stream.GetStreamAtIndex(eImmediateStreamIndex); } - lldb::StreamSP GetImmediateErrorStream() { + lldb::StreamSP GetImmediateErrorStream() const { return m_err_stream.GetStreamAtIndex(eImmediateStreamIndex); } diff --git a/lldb/include/lldb/Utility/StreamTee.h b/lldb/include/lldb/Utility/StreamTee.h index 5695586171f35..571548e2e23fe 100644 --- a/lldb/include/lldb/Utility/StreamTee.h +++ b/lldb/include/lldb/Utility/StreamTee.h @@ -85,7 +85,7 @@ class StreamTee : public Stream { return result; } - lldb::StreamSP GetStreamAtIndex(uint32_t idx) { + lldb::StreamSP GetStreamAtIndex(uint32_t idx) const { lldb::StreamSP stream_sp; std::lock_guard guard(m_streams_mutex); if (idx < m_streams.size()) diff --git a/lldb/source/Interpreter/CommandReturnObject.cpp b/lldb/source/Interpreter/CommandReturnObject.cpp index b99b2bc7b36ce..0a2948e8e6ca4 100644 --- a/lldb/source/Interpreter/CommandReturnObject.cpp +++ b/lldb/source/Interpreter/CommandReturnObject.cpp @@ -147,7 +147,8 @@ void CommandReturnObject::SetError(llvm::Error error) { } } -std::string CommandReturnObject::GetInlineDiagnosticString(unsigned indent) { +std::string +CommandReturnObject::GetInlineDiagnosticString(unsigned indent) const { StreamString diag_stream(m_colors); RenderDiagnosticDetails(diag_stream, indent, true, m_diagnostics); // Duplex the diagnostics to the secondary stream (but not inlined). @@ -157,7 +158,7 @@ std::string CommandReturnObject::GetInlineDiagnosticString(unsigned indent) { return diag_stream.GetString().str(); } -std::string CommandReturnObject::GetErrorString(bool with_diagnostics) { +std::string CommandReturnObject::GetErrorString(bool with_diagnostics) const { StreamString stream(m_colors); if (with_diagnostics) RenderDiagnosticDetails(stream, std::nullopt, false, m_diagnostics); From 345512cbda296d262a28459afc7f83640b06b6a8 Mon Sep 17 00:00:00 2001 From: Maksim Levental Date: Thu, 30 Jan 2025 14:09:14 -0500 Subject: [PATCH 05/34] Revert "[mlir][llvmir] expose Type(To/From)LLVMIRTranslator C API (#124864)" This reverts commit 7ae964c55b0a2b8dccf076ced9f1ffa8d5487eca. Revert "[mlir] Fix warnings" This reverts commit 0e43b9547d56762d29de9a99c998e7939417a1f3. --- mlir/include/mlir-c/Dialect/LLVM.h | 3 -- mlir/include/mlir-c/Target/LLVMIR.h | 43 ------------------------- mlir/lib/CAPI/Dialect/LLVM.cpp | 4 --- mlir/lib/CAPI/Target/LLVMIR.cpp | 49 ++--------------------------- mlir/test/CAPI/translation.c | 27 ---------------- 5 files changed, 3 insertions(+), 123 deletions(-) diff --git a/mlir/include/mlir-c/Dialect/LLVM.h b/mlir/include/mlir-c/Dialect/LLVM.h index 65b14254e4492..26c4140757c3c 100644 --- a/mlir/include/mlir-c/Dialect/LLVM.h +++ b/mlir/include/mlir-c/Dialect/LLVM.h @@ -52,9 +52,6 @@ MLIR_CAPI_EXPORTED intptr_t mlirLLVMFunctionTypeGetNumInputs(MlirType type); MLIR_CAPI_EXPORTED MlirType mlirLLVMFunctionTypeGetInput(MlirType type, intptr_t pos); -/// Returns the return type of the function type. -MLIR_CAPI_EXPORTED MlirType mlirLLVMFunctionTypeGetReturnType(MlirType type); - /// Returns `true` if the type is an LLVM dialect struct type. MLIR_CAPI_EXPORTED bool mlirTypeIsALLVMStructType(MlirType type); diff --git a/mlir/include/mlir-c/Target/LLVMIR.h b/mlir/include/mlir-c/Target/LLVMIR.h index b5f948961e898..effa74b905ce6 100644 --- a/mlir/include/mlir-c/Target/LLVMIR.h +++ b/mlir/include/mlir-c/Target/LLVMIR.h @@ -16,7 +16,6 @@ #include "mlir-c/IR.h" #include "mlir-c/Support.h" -#include "llvm-c/Core.h" #include "llvm-c/Support.h" #ifdef __cplusplus @@ -33,48 +32,6 @@ extern "C" { MLIR_CAPI_EXPORTED LLVMModuleRef mlirTranslateModuleToLLVMIR(MlirOperation module, LLVMContextRef context); -struct MlirTypeFromLLVMIRTranslator { - void *ptr; -}; - -typedef struct MlirTypeFromLLVMIRTranslator MlirTypeFromLLVMIRTranslator; - -/// Create an LLVM::TypeFromLLVMIRTranslator and transfer ownership to the -/// caller. -MLIR_CAPI_EXPORTED MlirTypeFromLLVMIRTranslator -mlirTypeFromLLVMIRTranslatorCreate(MlirContext ctx); - -/// Takes an LLVM::TypeFromLLVMIRTranslator owned by the caller and destroys it. -/// It is the responsibility of the user to only pass an -/// LLVM::TypeFromLLVMIRTranslator class. -MLIR_CAPI_EXPORTED void -mlirTypeFromLLVMIRTranslatorDestroy(MlirTypeFromLLVMIRTranslator translator); - -/// Translates the given LLVM IR type to the MLIR LLVM dialect. -MLIR_CAPI_EXPORTED MlirType mlirTypeFromLLVMIRTranslatorTranslateType( - MlirTypeFromLLVMIRTranslator translator, LLVMTypeRef llvmType); - -struct MlirTypeToLLVMIRTranslator { - void *ptr; -}; - -typedef struct MlirTypeToLLVMIRTranslator MlirTypeToLLVMIRTranslator; - -/// Create an LLVM::TypeToLLVMIRTranslator and transfer ownership to the -/// caller. -MLIR_CAPI_EXPORTED MlirTypeToLLVMIRTranslator -mlirTypeToLLVMIRTranslatorCreate(LLVMContextRef ctx); - -/// Takes an LLVM::TypeToLLVMIRTranslator owned by the caller and destroys it. -/// It is the responsibility of the user to only pass an -/// LLVM::TypeToLLVMIRTranslator class. -MLIR_CAPI_EXPORTED void -mlirTypeToLLVMIRTranslatorDestroy(MlirTypeToLLVMIRTranslator translator); - -/// Translates the given MLIR LLVM dialect to the LLVM IR type. -MLIR_CAPI_EXPORTED LLVMTypeRef mlirTypeToLLVMIRTranslatorTranslateType( - MlirTypeToLLVMIRTranslator translator, MlirType mlirType); - #ifdef __cplusplus } #endif diff --git a/mlir/lib/CAPI/Dialect/LLVM.cpp b/mlir/lib/CAPI/Dialect/LLVM.cpp index 69c804b7667f3..da450dd3fd8a3 100644 --- a/mlir/lib/CAPI/Dialect/LLVM.cpp +++ b/mlir/lib/CAPI/Dialect/LLVM.cpp @@ -65,10 +65,6 @@ MlirType mlirLLVMFunctionTypeGetInput(MlirType type, intptr_t pos) { .getParamType(static_cast(pos))); } -MlirType mlirLLVMFunctionTypeGetReturnType(MlirType type) { - return wrap(llvm::cast(unwrap(type)).getReturnType()); -} - bool mlirTypeIsALLVMStructType(MlirType type) { return isa(unwrap(type)); } diff --git a/mlir/lib/CAPI/Target/LLVMIR.cpp b/mlir/lib/CAPI/Target/LLVMIR.cpp index 1c1912aec0f2f..dc798372be746 100644 --- a/mlir/lib/CAPI/Target/LLVMIR.cpp +++ b/mlir/lib/CAPI/Target/LLVMIR.cpp @@ -8,15 +8,16 @@ //===----------------------------------------------------------------------===// #include "mlir-c/Target/LLVMIR.h" +#include "llvm-c/Support.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" -#include "llvm/IR/Type.h" +#include #include "mlir/CAPI/IR.h" +#include "mlir/CAPI/Support.h" #include "mlir/CAPI/Wrap.h" #include "mlir/Target/LLVMIR/ModuleTranslation.h" -#include "mlir/Target/LLVMIR/TypeFromLLVM.h" using namespace mlir; @@ -33,47 +34,3 @@ LLVMModuleRef mlirTranslateModuleToLLVMIR(MlirOperation module, return moduleRef; } - -DEFINE_C_API_PTR_METHODS(MlirTypeFromLLVMIRTranslator, - mlir::LLVM::TypeFromLLVMIRTranslator) - -MlirTypeFromLLVMIRTranslator -mlirTypeFromLLVMIRTranslatorCreate(MlirContext ctx) { - MLIRContext *context = unwrap(ctx); - auto *translator = new LLVM::TypeFromLLVMIRTranslator(*context); - return wrap(translator); -} - -void mlirTypeFromLLVMIRTranslatorDestroy( - MlirTypeFromLLVMIRTranslator translator) { - delete static_cast(unwrap(translator)); -} - -MlirType mlirTypeFromLLVMIRTranslatorTranslateType( - MlirTypeFromLLVMIRTranslator translator, LLVMTypeRef llvmType) { - LLVM::TypeFromLLVMIRTranslator *translator_ = unwrap(translator); - mlir::Type type = translator_->translateType(llvm::unwrap(llvmType)); - return wrap(type); -} - -DEFINE_C_API_PTR_METHODS(MlirTypeToLLVMIRTranslator, - mlir::LLVM::TypeToLLVMIRTranslator) - -MlirTypeToLLVMIRTranslator -mlirTypeToLLVMIRTranslatorCreate(LLVMContextRef ctx) { - llvm::LLVMContext *context = llvm::unwrap(ctx); - auto *translator = new LLVM::TypeToLLVMIRTranslator(*context); - return wrap(translator); -} - -void mlirTypeToLLVMIRTranslatorDestroy(MlirTypeToLLVMIRTranslator translator) { - delete static_cast(unwrap(translator)); -} - -LLVMTypeRef -mlirTypeToLLVMIRTranslatorTranslateType(MlirTypeToLLVMIRTranslator translator, - MlirType mlirType) { - LLVM::TypeToLLVMIRTranslator *translator_ = unwrap(translator); - llvm::Type *type = translator_->translateType(unwrap(mlirType)); - return llvm::wrap(type); -} diff --git a/mlir/test/CAPI/translation.c b/mlir/test/CAPI/translation.c index 8891c2a559b7e..c9233d95fd512 100644 --- a/mlir/test/CAPI/translation.c +++ b/mlir/test/CAPI/translation.c @@ -58,38 +58,11 @@ static void testToLLVMIR(MlirContext ctx) { LLVMContextDispose(llvmCtx); } -// CHECK-LABEL: testTypeToFromLLVMIRTranslator -static void testTypeToFromLLVMIRTranslator(MlirContext ctx) { - fprintf(stderr, "testTypeToFromLLVMIRTranslator\n"); - LLVMContextRef llvmCtx = LLVMContextCreate(); - - LLVMTypeRef llvmTy = LLVMInt32TypeInContext(llvmCtx); - MlirTypeFromLLVMIRTranslator fromLLVMTranslator = - mlirTypeFromLLVMIRTranslatorCreate(ctx); - MlirType mlirTy = - mlirTypeFromLLVMIRTranslatorTranslateType(fromLLVMTranslator, llvmTy); - // CHECK: i32 - mlirTypeDump(mlirTy); - - MlirTypeToLLVMIRTranslator toLLVMTranslator = - mlirTypeToLLVMIRTranslatorCreate(llvmCtx); - LLVMTypeRef llvmTy2 = - mlirTypeToLLVMIRTranslatorTranslateType(toLLVMTranslator, mlirTy); - // CHECK: i32 - LLVMDumpType(llvmTy2); - fprintf(stderr, "\n"); - - mlirTypeFromLLVMIRTranslatorDestroy(fromLLVMTranslator); - mlirTypeToLLVMIRTranslatorDestroy(toLLVMTranslator); - LLVMContextDispose(llvmCtx); -} - int main(void) { MlirContext ctx = mlirContextCreate(); mlirDialectHandleRegisterDialect(mlirGetDialectHandle__llvm__(), ctx); mlirContextGetOrLoadDialect(ctx, mlirStringRefCreateFromCString("llvm")); testToLLVMIR(ctx); - testTypeToFromLLVMIRTranslator(ctx); mlirContextDestroy(ctx); return 0; } From 8a20c6459eb955f32bf46afe75cd84d6614cfabc Mon Sep 17 00:00:00 2001 From: Stanislav Mekhanoshin Date: Thu, 30 Jan 2025 11:14:38 -0800 Subject: [PATCH 06/34] [AMDGPU] Create new option for force flush load counter (#124974) In ceratin situations it is beneficial to wait for all outstanding loads regardless of specific load's data we need. This may allow to reduce a number of cache requests. Fixes: SWDEV-511507 --- llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp | 8 ++++ llvm/test/CodeGen/AMDGPU/load-store-cnt.ll | 48 +++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 llvm/test/CodeGen/AMDGPU/load-store-cnt.ll diff --git a/llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp b/llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp index de2095fa60ffd..3d6419778f4b1 100644 --- a/llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp +++ b/llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp @@ -53,6 +53,11 @@ static cl::opt "s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)"), cl::init(false), cl::Hidden); +static cl::opt ForceEmitZeroLoadFlag( + "amdgpu-waitcnt-load-forcezero", + cl::desc("Force all waitcnt load counters to wait until 0"), + cl::init(false), cl::Hidden); + namespace { // Class of object that encapsulates latest instruction counter score // associated with the operand. Used for determining whether @@ -1850,6 +1855,9 @@ bool SIInsertWaitcnts::generateWaitcntInstBefore(MachineInstr &MI, Wait.BvhCnt = 0; } + if (ForceEmitZeroLoadFlag && Wait.LoadCnt != ~0u) + Wait.LoadCnt = 0; + return generateWaitcnt(Wait, MI.getIterator(), *MI.getParent(), ScoreBrackets, OldWaitcntInstr); } diff --git a/llvm/test/CodeGen/AMDGPU/load-store-cnt.ll b/llvm/test/CodeGen/AMDGPU/load-store-cnt.ll new file mode 100644 index 0000000000000..a7fccde416671 --- /dev/null +++ b/llvm/test/CodeGen/AMDGPU/load-store-cnt.ll @@ -0,0 +1,48 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 +; RUN: llc -march=amdgcn -mcpu=gfx1100 < %s | FileCheck --check-prefixes=DEFAULT %s +; RUN: llc -march=amdgcn -mcpu=gfx1100 -amdgpu-waitcnt-load-forcezero < %s | FileCheck --check-prefixes=LDZERO %s + +define amdgpu_kernel void @copy(ptr addrspace(1) noalias nocapture readonly %src1, ptr addrspace(1) noalias nocapture readonly %src2, ptr addrspace(1) noalias nocapture writeonly %dst1, ptr addrspace(1) noalias nocapture writeonly %dst2) { +; DEFAULT-LABEL: copy: +; DEFAULT: ; %bb.0: +; DEFAULT-NEXT: s_load_b256 s[0:7], s[4:5], 0x24 +; DEFAULT-NEXT: v_and_b32_e32 v0, 0x3ff, v0 +; DEFAULT-NEXT: s_delay_alu instid0(VALU_DEP_1) +; DEFAULT-NEXT: v_lshlrev_b32_e32 v0, 2, v0 +; DEFAULT-NEXT: s_waitcnt lgkmcnt(0) +; DEFAULT-NEXT: s_clause 0x1 +; DEFAULT-NEXT: global_load_b32 v1, v0, s[0:1] +; DEFAULT-NEXT: global_load_b32 v2, v0, s[2:3] +; DEFAULT-NEXT: s_waitcnt vmcnt(1) +; DEFAULT-NEXT: global_store_b32 v0, v1, s[4:5] +; DEFAULT-NEXT: s_waitcnt vmcnt(0) +; DEFAULT-NEXT: global_store_b32 v0, v2, s[6:7] +; DEFAULT-NEXT: s_endpgm +; +; LDZERO-LABEL: copy: +; LDZERO: ; %bb.0: +; LDZERO-NEXT: s_load_b256 s[0:7], s[4:5], 0x24 +; LDZERO-NEXT: v_and_b32_e32 v0, 0x3ff, v0 +; LDZERO-NEXT: s_delay_alu instid0(VALU_DEP_1) +; LDZERO-NEXT: v_lshlrev_b32_e32 v0, 2, v0 +; LDZERO-NEXT: s_waitcnt lgkmcnt(0) +; LDZERO-NEXT: s_clause 0x1 +; LDZERO-NEXT: global_load_b32 v1, v0, s[0:1] +; LDZERO-NEXT: global_load_b32 v2, v0, s[2:3] +; LDZERO-NEXT: s_waitcnt vmcnt(0) +; LDZERO-NEXT: s_clause 0x1 +; LDZERO-NEXT: global_store_b32 v0, v1, s[4:5] +; LDZERO-NEXT: global_store_b32 v0, v2, s[6:7] +; LDZERO-NEXT: s_endpgm + %id = tail call i32 @llvm.amdgcn.workitem.id.x() + %idx = zext i32 %id to i64 + %gep.ld1 = getelementptr inbounds nuw float, ptr addrspace(1) %src1, i64 %idx + %v1 = load float, ptr addrspace(1) %gep.ld1, align 4 + %gep.ld2 = getelementptr inbounds nuw float, ptr addrspace(1) %src2, i64 %idx + %v2 = load float, ptr addrspace(1) %gep.ld2, align 4 + %gep.st1 = getelementptr inbounds nuw float, ptr addrspace(1) %dst1, i64 %idx + store float %v1, ptr addrspace(1) %gep.st1, align 4 + %gep.st2 = getelementptr inbounds nuw float, ptr addrspace(1) %dst2, i64 %idx + store float %v2, ptr addrspace(1) %gep.st2, align 4 + ret void +} From b04847b427d6bf6d4415e7f4b4fc983dcdef1720 Mon Sep 17 00:00:00 2001 From: Ben Langmuir Date: Thu, 30 Jan 2025 11:27:43 -0800 Subject: [PATCH 07/34] Revert "Reapply "[ORC] Enable JIT support for the compact-unwind frame..." with fixes." (#125098) This reverts commit d6524c8dfa37634257050ca71d16e117b802181c. This reverts commit b1bd73700a1fb6f450e0f6f9c405a9c8bde2cae7. This was causing bot failures on Darwin https://green.lab.llvm.org/job/llvm.org/job/clang-stage1-cmake-RA-incremental/7315/ Clang.Interpreter.simple-exception.cpp Clang-Unit.Interpreter/ExceptionTests/_/ClangReplInterpreterExceptionTests/0.1 LLVM.ExecutionEngine/OrcLazy.minimal-throw-catch.ll https://green.lab.llvm.org/job/llvm.org/job/clang-stage1-RA/3415/ ORC-x86_64-darwin.TestCases/Darwin/Generic.exceptions.cpp ORC-x86_64-darwin.TestCases/Darwin/x86-64.lljit-ehframe.cpp --- clang/test/Interpreter/simple-exception.cpp | 4 +- compiler-rt/lib/orc/macho_platform.cpp | 6 - .../TestCases/Darwin/Generic/exceptions.cpp | 13 - llvm/include/llvm/ExecutionEngine/Orc/Core.h | 9 +- .../Orc/ExecutorProcessControl.h | 4 - .../ExecutionEngine/Orc/Shared/OrcRTBridge.h | 9 - .../Orc/TargetProcess/UnwindInfoManager.h | 78 --- .../Orc/UnwindInfoRegistrationPlugin.h | 70 -- .../ExecutionEngine/JITLink/CMakeLists.txt | 1 - .../JITLink/CompactUnwindSupport.cpp | 103 --- .../JITLink/CompactUnwindSupport.h | 653 ------------------ .../JITLink/MachOLinkGraphBuilder.cpp | 116 ++++ .../JITLink/MachOLinkGraphBuilder.h | 11 + .../ExecutionEngine/JITLink/MachO_arm64.cpp | 49 +- .../ExecutionEngine/JITLink/MachO_x86_64.cpp | 57 +- llvm/lib/ExecutionEngine/Orc/CMakeLists.txt | 1 - llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp | 3 - llvm/lib/ExecutionEngine/Orc/Core.cpp | 34 +- .../Orc/ExecutorProcessControl.cpp | 7 - llvm/lib/ExecutionEngine/Orc/LLJIT.cpp | 29 +- .../Orc/Shared/OrcRTBridge.cpp | 14 - .../Orc/TargetProcess/CMakeLists.txt | 1 - .../Orc/TargetProcess/UnwindInfoManager.cpp | 188 ----- .../Orc/UnwindInfoRegistrationPlugin.cpp | 238 ------- 24 files changed, 164 insertions(+), 1534 deletions(-) delete mode 100644 compiler-rt/test/orc/TestCases/Darwin/Generic/exceptions.cpp delete mode 100644 llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/UnwindInfoManager.h delete mode 100644 llvm/include/llvm/ExecutionEngine/Orc/UnwindInfoRegistrationPlugin.h delete mode 100644 llvm/lib/ExecutionEngine/JITLink/CompactUnwindSupport.cpp delete mode 100644 llvm/lib/ExecutionEngine/JITLink/CompactUnwindSupport.h delete mode 100644 llvm/lib/ExecutionEngine/Orc/TargetProcess/UnwindInfoManager.cpp delete mode 100644 llvm/lib/ExecutionEngine/Orc/UnwindInfoRegistrationPlugin.cpp diff --git a/clang/test/Interpreter/simple-exception.cpp b/clang/test/Interpreter/simple-exception.cpp index 651e8d9402f89..6749acd6e6bd2 100644 --- a/clang/test/Interpreter/simple-exception.cpp +++ b/clang/test/Interpreter/simple-exception.cpp @@ -1,7 +1,7 @@ // clang-format off // UNSUPPORTED: system-aix -// XFAIL for arm, or running on Windows. -// XFAIL: target=arm-{{.*}}, target=armv{{.*}}, system-windows +// XFAIL for arm and arm64, or running on Windows. +// XFAIL: target=arm{{.*}}, system-windows // RUN: cat %s | clang-repl | FileCheck %s // Incompatible with msan. It passes with -O3 but fail -Oz. Interpreter diff --git a/compiler-rt/lib/orc/macho_platform.cpp b/compiler-rt/lib/orc/macho_platform.cpp index 4b603fd95e316..8ca68587aeb36 100644 --- a/compiler-rt/lib/orc/macho_platform.cpp +++ b/compiler-rt/lib/orc/macho_platform.cpp @@ -557,12 +557,6 @@ Error MachOPlatformRuntimeState::registerObjectPlatformSections( return make_error(ErrStream.str()); } - ORC_RT_DEBUG({ - printdbg(" UnwindInfo: %s, UseCallbackStyleUnwindInfo: %s\n", - UnwindInfo ? "true" : "false", - UseCallbackStyleUnwindInfo ? "true" : "false"); - }); - if (UnwindInfo && UseCallbackStyleUnwindInfo) { ORC_RT_DEBUG({ printdbg(" Registering new-style unwind info for:\n" diff --git a/compiler-rt/test/orc/TestCases/Darwin/Generic/exceptions.cpp b/compiler-rt/test/orc/TestCases/Darwin/Generic/exceptions.cpp deleted file mode 100644 index 7e9c40c724aec..0000000000000 --- a/compiler-rt/test/orc/TestCases/Darwin/Generic/exceptions.cpp +++ /dev/null @@ -1,13 +0,0 @@ -// RUN: %clangxx -c -o %t %s -// RUN: %llvm_jitlink -slab-allocate=20Mb %t -// -// REQUIRES: system-darwin && host-arch-compatible - -int main(int argc, char *argv[]) { - try { - throw 42; - } catch (int E) { - return 42 - E; - } - return 1; -} diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Core.h b/llvm/include/llvm/ExecutionEngine/Orc/Core.h index 3eddaf4c9c59f..db853362f6573 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/Core.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/Core.h @@ -1204,13 +1204,8 @@ class JITDylib : public ThreadSafeRefCountedBase, JITDylib(ExecutionSession &ES, std::string Name); - struct RemoveTrackerResult { - AsynchronousSymbolQuerySet QueriesToFail; - std::shared_ptr FailedSymbols; - std::vector> DefunctMUs; - }; - - RemoveTrackerResult IL_removeTracker(ResourceTracker &RT); + std::pair> + IL_removeTracker(ResourceTracker &RT); void transferTracker(ResourceTracker &DstRT, ResourceTracker &SrcRT); diff --git a/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h b/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h index 86e98e74b7055..dcf5592f1717c 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/ExecutorProcessControl.h @@ -20,7 +20,6 @@ #include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h" #include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h" #include "llvm/ExecutionEngine/Orc/SymbolStringPool.h" -#include "llvm/ExecutionEngine/Orc/TargetProcess/UnwindInfoManager.h" #include "llvm/ExecutionEngine/Orc/TaskDispatch.h" #include "llvm/Support/DynamicLibrary.h" #include "llvm/Support/MSVCErrorWorkarounds.h" @@ -508,9 +507,6 @@ class SelfExecutorProcessControl : public ExecutorProcessControl, SymbolLookupCompleteFn F) override; std::unique_ptr OwnedMemMgr; -#ifdef __APPLE__ - std::unique_ptr UnwindInfoMgr; -#endif // __APPLE__ char GlobalManglingPrefix = 0; }; diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h b/llvm/include/llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h index db5ff135a7164..aed43f6308cba 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h @@ -88,15 +88,6 @@ using SPSRunAsMainSignature = int64_t(shared::SPSExecutorAddr, using SPSRunAsVoidFunctionSignature = int32_t(shared::SPSExecutorAddr); using SPSRunAsIntFunctionSignature = int32_t(shared::SPSExecutorAddr, int32_t); } // end namespace rt - -namespace rt_alt { -extern const char *UnwindInfoManagerInstanceName; -extern const char *UnwindInfoManagerFindSectionsHelperName; -extern const char *UnwindInfoManagerEnableWrapperName; -extern const char *UnwindInfoManagerDisableWrapperName; -extern const char *UnwindInfoManagerRegisterActionName; -extern const char *UnwindInfoManagerDeregisterActionName; -} // end namespace rt_alt } // end namespace orc } // end namespace llvm diff --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/UnwindInfoManager.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/UnwindInfoManager.h deleted file mode 100644 index fc7719f282122..0000000000000 --- a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/UnwindInfoManager.h +++ /dev/null @@ -1,78 +0,0 @@ -//===--- UnwindInfoManager.h -- Register unwind info sections ---*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Utilities for managing eh-frame and compact-unwind registration and lookup -// through libunwind's find_dynamic_unwind_sections mechanism. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_UNWINDINFOMANAGER_H -#define LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_UNWINDINFOMANAGER_H - -#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h" -#include "llvm/ExecutionEngine/Orc/TargetProcess/ExecutorBootstrapService.h" -#include "llvm/Support/Error.h" -#include -#include - -namespace llvm::orc { - -class UnwindInfoManager : public ExecutorBootstrapService { -public: - // This struct's layout should match the unw_dynamic_unwind_sections struct - // from libunwind/src/libunwid_ext.h. - struct UnwindSections { - uintptr_t dso_base; - uintptr_t dwarf_section; - size_t dwarf_section_length; - uintptr_t compact_unwind_section; - size_t compact_unwind_section_length; - }; - - /// If the libunwind find-dynamic-unwind-info callback registration APIs are - /// available then this method will return an UnwindInfoManager instance, - /// otherwise it will return nullptr. - static std::unique_ptr TryCreate(); - - Error shutdown() override; - void addBootstrapSymbols(StringMap &M) override; - - Error enable(void *FindDynamicUnwindSections); - Error disable(void); - - Error registerSections(ArrayRef CodeRanges, - orc::ExecutorAddr DSOBase, - orc::ExecutorAddrRange DWARFEHFrame, - orc::ExecutorAddrRange CompactUnwind); - - Error deregisterSections(ArrayRef CodeRanges); - - int findSections(uintptr_t Addr, UnwindSections *Info); - -private: - UnwindInfoManager(int (*AddFindDynamicUnwindSections)(void *), - int (*RemoveFindDynamicUnwindSections)(void *)) - : AddFindDynamicUnwindSections(AddFindDynamicUnwindSections), - RemoveFindDynamicUnwindSections(RemoveFindDynamicUnwindSections) {} - - static int findSectionsHelper(UnwindInfoManager *Instance, uintptr_t Addr, - UnwindSections *Info); - - std::mutex M; - std::map UWSecs; - - int (*AddFindDynamicUnwindSections)(void *) = nullptr; - int (*RemoveFindDynamicUnwindSections)(void *) = nullptr; - void *FindDynamicUnwindSections = nullptr; - - static const char *AddFnName, *RemoveFnName; -}; - -} // namespace llvm::orc - -#endif // LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_UNWINDINFOMANAGER_H diff --git a/llvm/include/llvm/ExecutionEngine/Orc/UnwindInfoRegistrationPlugin.h b/llvm/include/llvm/ExecutionEngine/Orc/UnwindInfoRegistrationPlugin.h deleted file mode 100644 index eb883a79a93d8..0000000000000 --- a/llvm/include/llvm/ExecutionEngine/Orc/UnwindInfoRegistrationPlugin.h +++ /dev/null @@ -1,70 +0,0 @@ -//===- UnwindInfoRegistrationPlugin.h -- libunwind registration -*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Register eh-frame and compact-unwind sections with libunwind -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_EXECUTIONENGINE_ORC_UNWINDINFOREGISTRATIONPLUGIN_H -#define LLVM_EXECUTIONENGINE_ORC_UNWINDINFOREGISTRATIONPLUGIN_H - -#include "llvm/ExecutionEngine/Orc/LinkGraphLinkingLayer.h" - -namespace llvm::orc { - -class UnwindInfoRegistrationPlugin : public LinkGraphLinkingLayer::Plugin { -public: - static Expected> - Create(IRLayer &IRL, JITDylib &PlatformJD, ExecutorAddr Instance, - ExecutorAddr FindHelper, ExecutorAddr Enable, ExecutorAddr Disable, - ExecutorAddr Register, ExecutorAddr Deregister); - - static Expected> - Create(IRLayer &IRL, JITDylib &PlatformJD); - - ~UnwindInfoRegistrationPlugin(); - - void modifyPassConfig(MaterializationResponsibility &MR, - jitlink::LinkGraph &G, - jitlink::PassConfiguration &PassConfig) override; - - Error notifyEmitted(MaterializationResponsibility &MR) override { - return Error::success(); - } - - Error notifyFailed(MaterializationResponsibility &MR) override { - return Error::success(); - } - - Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override { - return Error::success(); - } - - void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey, - ResourceKey SrcKey) override {} - -private: - UnwindInfoRegistrationPlugin(ExecutionSession &ES, ExecutorAddr Instance, - ExecutorAddr Disable, ExecutorAddr Register, - ExecutorAddr Deregister) - : ES(ES), Instance(Instance), Disable(Disable), Register(Register), - Deregister(Deregister) { - DSOBaseName = ES.intern("__jitlink$libunwind_dso_base"); - } - - static Expected makeBouncerModule(ExecutionSession &ES); - Error addUnwindInfoRegistrationActions(jitlink::LinkGraph &G); - - ExecutionSession &ES; - SymbolStringPtr DSOBaseName; - ExecutorAddr Instance, Disable, Register, Deregister; -}; - -} // namespace llvm::orc - -#endif // LLVM_EXECUTIONENGINE_ORC_UNWINDINFOREGISTRATIONPLUGIN_H diff --git a/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt b/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt index 65dd0c7468ae1..e5f5a99c39bc0 100644 --- a/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt +++ b/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt @@ -3,7 +3,6 @@ tablegen(LLVM COFFOptions.inc -gen-opt-parser-defs) add_public_tablegen_target(JITLinkTableGen) add_llvm_component_library(LLVMJITLink - CompactUnwindSupport.cpp DWARFRecordSectionSplitter.cpp EHFrameSupport.cpp JITLink.cpp diff --git a/llvm/lib/ExecutionEngine/JITLink/CompactUnwindSupport.cpp b/llvm/lib/ExecutionEngine/JITLink/CompactUnwindSupport.cpp deleted file mode 100644 index 51e3d26479ffd..0000000000000 --- a/llvm/lib/ExecutionEngine/JITLink/CompactUnwindSupport.cpp +++ /dev/null @@ -1,103 +0,0 @@ -//=------- CompactUnwindSupport.cpp - Compact Unwind format support -------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Compact Unwind support. -// -//===----------------------------------------------------------------------===// - -#include "CompactUnwindSupport.h" - -#include "llvm/ADT/Sequence.h" - -#define DEBUG_TYPE "jitlink" - -namespace llvm { -namespace jitlink { - -Error splitCompactUnwindBlocks(LinkGraph &G, Section &CompactUnwindSection, - size_t RecordSize) { - - std::vector OriginalBlocks(CompactUnwindSection.blocks().begin(), - CompactUnwindSection.blocks().end()); - LLVM_DEBUG({ - dbgs() << "In " << G.getName() << " splitting compact unwind section " - << CompactUnwindSection.getName() << " containing " - << OriginalBlocks.size() << " initial blocks...\n"; - }); - - while (!OriginalBlocks.empty()) { - auto *B = OriginalBlocks.back(); - OriginalBlocks.pop_back(); - - if (B->getSize() == 0) { - LLVM_DEBUG({ - dbgs() << " Skipping empty block at " - << formatv("{0:x16}", B->getAddress()) << "\n"; - }); - continue; - } - - unsigned NumBlocks = B->getSize() / RecordSize; - - LLVM_DEBUG({ - dbgs() << " Splitting block at " << formatv("{0:x16}", B->getAddress()) - << " into " << NumBlocks << " compact unwind record(s)\n"; - }); - - if (B->getSize() % RecordSize) - return make_error( - "Error splitting compact unwind record in " + G.getName() + - ": block at " + formatv("{0:x}", B->getAddress()) + " has size " + - formatv("{0:x}", B->getSize()) + - " (not a multiple of CU record size of " + - formatv("{0:x}", RecordSize) + ")"); - - auto Blocks = - G.splitBlock(*B, map_range(seq(1U, NumBlocks), [=](Edge::OffsetT Idx) { - return Idx * RecordSize; - })); - - for (auto *CURec : Blocks) { - bool AddedKeepAlive = false; - - for (auto &E : CURec->edges()) { - if (E.getOffset() == 0) { - LLVM_DEBUG({ - dbgs() << " Updating compact unwind record at " - << CURec->getAddress() << " to point to " - << (E.getTarget().hasName() ? *E.getTarget().getName() - : StringRef()) - << " (at " << E.getTarget().getAddress() << ")\n"; - }); - - if (E.getTarget().isExternal()) - return make_error( - "Error adding keep-alive edge for compact unwind record at " + - formatv("{0:x}", CURec->getAddress()) + ": target " + - *E.getTarget().getName() + " is an external symbol"); - auto &TgtBlock = E.getTarget().getBlock(); - auto &CURecSym = - G.addAnonymousSymbol(*CURec, 0, RecordSize, false, false); - TgtBlock.addEdge(Edge::KeepAlive, 0, CURecSym, 0); - AddedKeepAlive = true; - } - } - - if (!AddedKeepAlive) - return make_error( - "Error adding keep-alive edge for compact unwind record at " + - formatv("{0:x}", CURec->getAddress()) + - ": no outgoing target edge at offset 0"); - } - } - - return Error::success(); -} - -} // end namespace jitlink -} // end namespace llvm diff --git a/llvm/lib/ExecutionEngine/JITLink/CompactUnwindSupport.h b/llvm/lib/ExecutionEngine/JITLink/CompactUnwindSupport.h deleted file mode 100644 index dc3ed942aa8ac..0000000000000 --- a/llvm/lib/ExecutionEngine/JITLink/CompactUnwindSupport.h +++ /dev/null @@ -1,653 +0,0 @@ -//===- CompactUnwindSupportImpl.h - Compact Unwind format impl --*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Compact Unwind format support implementation details. -// -//===----------------------------------------------------------------------===// - -#ifndef LIB_EXECUTIONENGINE_JITLINK_COMPACTUNWINDSUPPORTIMPL_H -#define LIB_EXECUTIONENGINE_JITLINK_COMPACTUNWINDSUPPORTIMPL_H - -#include "llvm/ADT/STLExtras.h" -#include "llvm/ExecutionEngine/JITLink/MachO.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/Endian.h" - -#define DEBUG_TYPE "jitlink_cu" - -namespace llvm { -namespace jitlink { - -/// Split blocks in an __LD,__compact_unwind section on record boundaries. -/// When this function returns edges within each record are guaranteed to be -/// sorted by offset. -Error splitCompactUnwindBlocks(LinkGraph &G, Section &CompactUnwindSection, - size_t RecordSize); - -/// CRTP base for compact unwind traits classes. Automatically provides derived -/// constants. -/// -/// FIXME: Passing PtrSize as a template parameter is a hack to work around a -/// bug in older MSVC compilers (until at least MSVC 15) where constexpr -/// fields in the CRTP impl class were not visible to the base class. -/// Once we no longer need to support these compilers the PtrSize -/// template argument should be removed and PointerSize should be -/// defined as a member in the CRTP Impl classes. -template struct CompactUnwindTraits { - static constexpr size_t PointerSize = PtrSize; - static constexpr size_t Size = 3 * PointerSize + 2 * 4; - static constexpr size_t FnFieldOffset = 0; - static constexpr size_t SizeFieldOffset = FnFieldOffset + PointerSize; - static constexpr size_t EncodingFieldOffset = SizeFieldOffset + 4; - static constexpr size_t PersonalityFieldOffset = EncodingFieldOffset + 4; - static constexpr size_t LSDAFieldOffset = - PersonalityFieldOffset + PointerSize; - - static uint32_t readPCRangeSize(ArrayRef RecordContent) { - assert(SizeFieldOffset + 4 <= RecordContent.size() && - "Truncated CU record?"); - return support::endian::read32(RecordContent.data() + - SizeFieldOffset); - } - - static uint32_t readEncoding(ArrayRef RecordContent) { - assert(EncodingFieldOffset + 4 <= RecordContent.size() && - "Truncated CU record?"); - return support::endian::read32(RecordContent.data() + - EncodingFieldOffset); - } -}; - -/// Architecture specific implementation of CompactUnwindManager. -template class CompactUnwindManager { -public: - CompactUnwindManager(StringRef CompactUnwindSectionName, - StringRef UnwindInfoSectionName, - StringRef EHFrameSectionName) - : CompactUnwindSectionName(CompactUnwindSectionName), - UnwindInfoSectionName(UnwindInfoSectionName), - EHFrameSectionName(EHFrameSectionName) {} - - // Split compact unwind records, add keep-alive edges from functions to - // compact unwind records, and from compact unwind records to FDEs where - // needed. - // - // This method must be called *after* __eh_frame has been processed: it - // assumes that eh-frame records have been split up and keep-alive edges have - // been inserted. - Error prepareForPrune(LinkGraph &G) { - Section *CUSec = G.findSectionByName(CompactUnwindSectionName); - if (!CUSec || CUSec->empty()) { - LLVM_DEBUG({ - dbgs() << "Compact unwind: No compact unwind info for " << G.getName() - << "\n"; - }); - return Error::success(); - } - - LLVM_DEBUG({ - dbgs() << "Compact unwind: preparing " << G.getName() << " for prune\n"; - }); - - Section *EHFrameSec = G.findSectionByName(EHFrameSectionName); - - if (auto Err = splitCompactUnwindBlocks(G, *CUSec, CURecTraits::Size)) - return Err; - - LLVM_DEBUG({ - dbgs() << " Preparing " << CUSec->blocks_size() << " blocks in " - << CompactUnwindSectionName << "\n"; - }); - - for (auto *B : CUSec->blocks()) { - - // Find target function edge. - Edge *PCBeginEdge = nullptr; - for (auto &E : B->edges_at(CURecTraits::FnFieldOffset)) { - PCBeginEdge = &E; - break; - } - - if (!PCBeginEdge) - return make_error( - "In " + G.getName() + ", compact unwind record at " + - formatv("{0:x}", B->getAddress()) + " has no pc-begin edge"); - - if (!PCBeginEdge->getTarget().isDefined()) - return make_error( - "In " + G.getName() + ", compact unwind record at " + - formatv("{0:x}", B->getAddress()) + " points at external symbol " + - *PCBeginEdge->getTarget().getName()); - - auto &Fn = PCBeginEdge->getTarget(); - - if (!Fn.isDefined()) { - LLVM_DEBUG({ - dbgs() << "In " << CompactUnwindSectionName << " for " << G.getName() - << " encountered unexpected pc-edge to undefined symbol " - << Fn.getName() << "\n"; - }); - continue; - } else { - LLVM_DEBUG({ - dbgs() << " Found record for function "; - if (Fn.hasName()) - dbgs() << Fn.getName(); - else - dbgs() << "'; - dbgs() << '\n'; - }); - } - - bool NeedsDWARF = CURecTraits::encodingSpecifiesDWARF( - CURecTraits::readEncoding(B->getContent())); - - auto &CURecSym = - G.addAnonymousSymbol(*B, 0, CURecTraits::Size, false, false); - - bool KeepAliveAlreadyPresent = false; - if (EHFrameSec) { - Edge *KeepAliveEdge = nullptr; - for (auto &E : Fn.getBlock().edges_at(0)) { - if (E.getKind() == Edge::KeepAlive && E.getTarget().isDefined() && - &E.getTarget().getBlock().getSection() == EHFrameSec) { - KeepAliveEdge = &E; - break; - } - } - - if (KeepAliveEdge) { - // Found a keep-alive edge to an FDE in the eh-frame. Switch the keep - // alive edge to point to the CU and if the CU needs DWARF then add - // an extra keep-alive edge from the CU to the FDE. - auto &FDE = KeepAliveEdge->getTarget(); - KeepAliveEdge->setTarget(CURecSym); - KeepAliveAlreadyPresent = true; - if (NeedsDWARF) { - LLVM_DEBUG({ - dbgs() << " Needs DWARF: adding keep-alive edge to FDE at " - << FDE.getAddress() << "\n"; - }); - B->addEdge(Edge::KeepAlive, 0, FDE, 0); - } - } else { - if (NeedsDWARF) - return make_error( - "In " + G.getName() + ", compact unwind recard ot " + - formatv("{0:x}", B->getAddress()) + - " needs DWARF, but no FDE was found"); - } - } else { - if (NeedsDWARF) - return make_error( - "In " + G.getName() + ", compact unwind recard ot " + - formatv("{0:x}", B->getAddress()) + " needs DWARF, but no " + - EHFrameSectionName + " section exists"); - } - - if (!KeepAliveAlreadyPresent) { - // No FDE edge. We'll need to add a new edge from the function back - // to the CU record. - Fn.getBlock().addEdge(Edge::KeepAlive, 0, CURecSym, 0); - } - } - - return Error::success(); - } - - /// Process all __compact_unwind records and reserve space for __unwind_info. - Error processAndReserveUnwindInfo(LinkGraph &G) { - // Bail out early if no unwind info. - Section *CUSec = G.findSectionByName(CompactUnwindSectionName); - if (!CUSec) - return Error::success(); - - // The __LD/__compact_unwind section is only used as input for the linker. - // We'll create a new __TEXT,__unwind_info section for unwind info output. - CUSec->setMemLifetime(orc::MemLifetime::NoAlloc); - - // Find / make a mach-header to act as the base for unwind-info offsets - // (and to report the arch / subarch to libunwind). - if (auto Err = getOrCreateCompactUnwindBase(G)) - return Err; - - // Error out if there's already unwind-info in the graph: We have no idea - // how to merge unwind-info sections. - if (G.findSectionByName(UnwindInfoSectionName)) - return make_error("In " + G.getName() + ", " + - UnwindInfoSectionName + - " already exists"); - - // Process the __compact_unwind section to build the Records vector that - // we'll use for writing the __unwind_info section. - if (auto Err = processCompactUnwind(G, *CUSec)) - return Err; - - // Calculate the size of __unwind_info. - size_t UnwindInfoSectionSize = - UnwindInfoSectionHeaderSize + - Personalities.size() * PersonalityEntrySize + - (NumSecondLevelPages + 1) * IndexEntrySize + NumLSDAs * LSDAEntrySize + - NumSecondLevelPages * SecondLevelPageHeaderSize + - Records.size() * SecondLevelPageEntrySize; - - LLVM_DEBUG({ - dbgs() << "In " << G.getName() << ", reserving " - << formatv("{0:x}", UnwindInfoSectionSize) << " bytes for " - << UnwindInfoSectionName << "\n"; - }); - - // Create the __unwind_info section and reserve space for it. - Section &UnwindInfoSec = - G.createSection(UnwindInfoSectionName, orc::MemProt::Read); - - auto UnwindInfoSectionContent = G.allocateBuffer(UnwindInfoSectionSize); - memset(UnwindInfoSectionContent.data(), 0, UnwindInfoSectionContent.size()); - auto &B = G.createMutableContentBlock( - UnwindInfoSec, UnwindInfoSectionContent, orc::ExecutorAddr(), 8, 0); - - // Add Keep-alive edges from the __unwind_info block to all of the target - // functions. - for (auto &R : Records) - B.addEdge(Edge::KeepAlive, 0, *R.Fn, 0); - - return Error::success(); - } - - Error writeUnwindInfo(LinkGraph &G) { - Section *CUSec = G.findSectionByName(CompactUnwindSectionName); - if (!CUSec || CUSec->empty()) - return Error::success(); - - Section *UnwindInfoSec = G.findSectionByName(UnwindInfoSectionName); - if (!UnwindInfoSec) - return make_error("In " + G.getName() + ", " + - UnwindInfoSectionName + - " missing after allocation"); - - if (UnwindInfoSec->blocks_size() != 1) - return make_error( - "In " + G.getName() + ", " + UnwindInfoSectionName + - " contains more than one block post-allocation"); - - LLVM_DEBUG( - { dbgs() << "Writing unwind info for " << G.getName() << "...\n"; }); - - mergeRecords(); - - auto &UnwindInfoBlock = **UnwindInfoSec->blocks().begin(); - auto Content = UnwindInfoBlock.getMutableContent(G); - BinaryStreamWriter Writer( - {reinterpret_cast(Content.data()), Content.size()}, - CURecTraits::Endianness); - - // __unwind_info format, from mach-o/compact_unwind_encoding.h on Darwin: - // - // #define UNWIND_SECTION_VERSION 1 - // struct unwind_info_section_header - // { - // uint32_t version; // UNWIND_SECTION_VERSION - // uint32_t commonEncodingsArraySectionOffset; - // uint32_t commonEncodingsArrayCount; - // uint32_t personalityArraySectionOffset; - // uint32_t personalityArrayCount; - // uint32_t indexSectionOffset; - // uint32_t indexCount; - // // compact_unwind_encoding_t[] - // // uint32_t personalities[] - // // unwind_info_section_header_index_entry[] - // // unwind_info_section_header_lsda_index_entry[] - // }; - - if (auto Err = writeHeader(G, Writer)) - return Err; - - // Skip common encodings: JITLink doesn't use them. - - if (auto Err = writePersonalities(G, Writer)) - return Err; - - // Calculate the offset to the LSDAs. - size_t SectionOffsetToLSDAs = - Writer.getOffset() + (NumSecondLevelPages + 1) * IndexEntrySize; - - // Calculate offset to the 1st second-level page. - size_t SectionOffsetToSecondLevelPages = - SectionOffsetToLSDAs + NumLSDAs * LSDAEntrySize; - - if (auto Err = writeIndexes(G, Writer, SectionOffsetToLSDAs, - SectionOffsetToSecondLevelPages)) - return Err; - - if (auto Err = writeLSDAs(G, Writer)) - return Err; - - if (auto Err = writeSecondLevelPages(G, Writer)) - return Err; - - LLVM_DEBUG({ - dbgs() << " Wrote " << formatv("{0:x}", Writer.getOffset()) - << " bytes of unwind info.\n"; - }); - - return Error::success(); - } - -private: - // Calculate the size of unwind-info. - static constexpr size_t MaxPersonalities = 4; - static constexpr size_t PersonalityShift = 28; - - static constexpr size_t UnwindInfoSectionHeaderSize = 4 * 7; - static constexpr size_t PersonalityEntrySize = 4; - static constexpr size_t IndexEntrySize = 3 * 4; - static constexpr size_t LSDAEntrySize = 2 * 4; - static constexpr size_t SecondLevelPageSize = 4096; - static constexpr size_t SecondLevelPageHeaderSize = 8; - static constexpr size_t SecondLevelPageEntrySize = 8; - static constexpr size_t NumRecordsPerSecondLevelPage = - (SecondLevelPageSize - SecondLevelPageHeaderSize) / - SecondLevelPageEntrySize; - - struct CompactUnwindRecord { - Symbol *Fn = nullptr; - uint32_t Size = 0; - uint32_t Encoding = 0; - Symbol *LSDA = nullptr; - Symbol *FDE = nullptr; - }; - - Error processCompactUnwind(LinkGraph &G, Section &CUSec) { - // TODO: Reset NumLSDAs, Personalities and CompactUnwindRecords if - // processing more than once. - assert(NumLSDAs == 0 && "NumLSDAs should be zero"); - assert(Records.empty() && "CompactUnwindRecords vector should be empty."); - assert(Personalities.empty() && "Personalities vector should be empty."); - - SmallVector NonUniquedRecords; - NonUniquedRecords.reserve(CUSec.blocks_size()); - - // Process __compact_unwind blocks. - for (auto *B : CUSec.blocks()) { - CompactUnwindRecord R; - R.Encoding = CURecTraits::readEncoding(B->getContent()); - for (auto &E : B->edges()) { - switch (E.getOffset()) { - case CURecTraits::FnFieldOffset: - // This could be the function-pointer, or the FDE keep-alive. Check - // the type to decide. - if (E.getKind() == Edge::KeepAlive) - R.FDE = &E.getTarget(); - else - R.Fn = &E.getTarget(); - break; - case CURecTraits::PersonalityFieldOffset: { - // Add the Personality to the Personalities map and update the - // encoding. - size_t PersonalityIdx = 0; - for (; PersonalityIdx != Personalities.size(); ++PersonalityIdx) - if (Personalities[PersonalityIdx] == &E.getTarget()) - break; - if (PersonalityIdx == MaxPersonalities) - return make_error( - "In " + G.getName() + - ", __compact_unwind contains too many personalities (max " + - formatv("{}", MaxPersonalities) + ")"); - if (PersonalityIdx == Personalities.size()) - Personalities.push_back(&E.getTarget()); - - R.Encoding |= (PersonalityIdx + 1) << PersonalityShift; - break; - } - case CURecTraits::LSDAFieldOffset: - ++NumLSDAs; - R.LSDA = &E.getTarget(); - break; - default: - return make_error("In " + G.getName() + - ", compact unwind record at " + - formatv("{0:x}", B->getAddress()) + - " has unrecognized edge at offset " + - formatv("{0:x}", E.getOffset())); - } - } - Records.push_back(R); - } - - // Sort the records into ascending order. - llvm::sort(Records, [](const CompactUnwindRecord &LHS, - const CompactUnwindRecord &RHS) { - return LHS.Fn->getAddress() < RHS.Fn->getAddress(); - }); - - // Calculate the number of second-level pages required. - NumSecondLevelPages = (Records.size() + NumRecordsPerSecondLevelPage - 1) / - NumRecordsPerSecondLevelPage; - - // Convert personality symbols to GOT entry pointers. - typename CURecTraits::GOTManager GOT(G); - for (auto &Personality : Personalities) - Personality = &GOT.getEntryForTarget(G, *Personality); - - LLVM_DEBUG({ - dbgs() << " In " << G.getName() << ", " << CompactUnwindSectionName - << ": raw records = " << Records.size() - << ", personalities = " << Personalities.size() - << ", lsdas = " << NumLSDAs << "\n"; - }); - - return Error::success(); - } - - void mergeRecords() { - SmallVector NonUniqued = std::move(Records); - Records.reserve(NonUniqued.size()); - - Records.push_back(NonUniqued.front()); - for (size_t I = 1; I != NonUniqued.size(); ++I) { - auto &Next = NonUniqued[I]; - auto &Last = Records.back(); - - bool NextNeedsDWARF = CURecTraits::encodingSpecifiesDWARF(Next.Encoding); - bool CannotBeMerged = CURecTraits::encodingCannotBeMerged(Next.Encoding); - if (NextNeedsDWARF || (Next.Encoding != Last.Encoding) || - CannotBeMerged || Next.LSDA || Last.LSDA) - Records.push_back(Next); - } - - // Recalculate derived values that may have changed. - NumSecondLevelPages = (Records.size() + NumRecordsPerSecondLevelPage - 1) / - NumRecordsPerSecondLevelPage; - } - - Error writeHeader(LinkGraph &G, BinaryStreamWriter &W) { - if (!isUInt<32>(NumSecondLevelPages + 1)) - return make_error("In " + G.getName() + ", too many " + - UnwindInfoSectionName + - "second-level pages required"); - - // Write __unwind_info header. - size_t IndexArrayOffset = UnwindInfoSectionHeaderSize + - Personalities.size() * PersonalityEntrySize; - - cantFail(W.writeInteger(1)); - cantFail(W.writeInteger(UnwindInfoSectionHeaderSize)); - cantFail(W.writeInteger(0)); - cantFail(W.writeInteger(UnwindInfoSectionHeaderSize)); - cantFail(W.writeInteger(Personalities.size())); - cantFail(W.writeInteger(IndexArrayOffset)); - cantFail(W.writeInteger(NumSecondLevelPages + 1)); - - return Error::success(); - } - - Error writePersonalities(LinkGraph &G, BinaryStreamWriter &W) { - // Write personalities. - for (auto *PSym : Personalities) { - auto Delta = PSym->getAddress() - CompactUnwindBase->getAddress(); - if (!isUInt<32>(Delta)) - return makePersonalityRangeError(G, *PSym); - cantFail(W.writeInteger(Delta)); - } - return Error::success(); - } - - Error writeIndexes(LinkGraph &G, BinaryStreamWriter &W, - size_t SectionOffsetToLSDAs, - size_t SectionOffsetToSecondLevelPages) { - // Assume that function deltas are ok in this method -- we'll error - // check all of them when we write the second level pages. - - // Write the header index entries. - size_t RecordIdx = 0; - size_t NumPreviousLSDAs = 0; - for (auto &R : Records) { - // If this record marks the start of a new second level page. - if (RecordIdx % NumRecordsPerSecondLevelPage == 0) { - auto FnDelta = R.Fn->getAddress() - CompactUnwindBase->getAddress(); - auto SecondLevelPageOffset = SectionOffsetToSecondLevelPages + - (RecordIdx / NumRecordsPerSecondLevelPage); - auto LSDAOffset = - SectionOffsetToLSDAs + NumPreviousLSDAs * LSDAEntrySize; - - cantFail(W.writeInteger(FnDelta)); - cantFail(W.writeInteger(SecondLevelPageOffset)); - cantFail(W.writeInteger(LSDAOffset)); - } - if (R.LSDA) - ++NumPreviousLSDAs; - ++RecordIdx; - } - - // Write the index array terminator. - { - auto FnEndDelta = - Records.back().Fn->getRange().End - CompactUnwindBase->getAddress(); - - if (LLVM_UNLIKELY(!isUInt<32>(FnEndDelta))) - return make_error( - "In " + G.getName() + " " + UnwindInfoSectionName + - ", delta to end of functions " + - formatv("{0:x}", Records.back().Fn->getRange().End) + - " exceeds 32 bits"); - - cantFail(W.writeInteger(FnEndDelta)); - cantFail(W.writeInteger(0)); - cantFail(W.writeInteger(SectionOffsetToSecondLevelPages)); - } - - return Error::success(); - } - - Error writeLSDAs(LinkGraph &G, BinaryStreamWriter &W) { - // As with writeIndexes, assume that function deltas are ok for now. - for (auto &R : Records) { - if (R.LSDA) { - auto FnDelta = R.Fn->getAddress() - CompactUnwindBase->getAddress(); - auto LSDADelta = R.LSDA->getAddress() - CompactUnwindBase->getAddress(); - - if (LLVM_UNLIKELY(!isUInt<32>(LSDADelta))) - return make_error( - "In " + G.getName() + " " + UnwindInfoSectionName + - ", delta to lsda at " + formatv("{0:x}", R.LSDA->getAddress()) + - " exceeds 32 bits"); - - cantFail(W.writeInteger(FnDelta)); - cantFail(W.writeInteger(LSDADelta)); - } - } - - return Error::success(); - } - - Error writeSecondLevelPages(LinkGraph &G, BinaryStreamWriter &W) { - size_t RecordIdx = 0; - - for (auto &R : Records) { - // When starting a new second-level page, write the page header: - // - // 2 : uint32_t -- UNWIND_SECOND_LEVEL_REGULAR - // 8 : uint16_t -- size of second level page table header - // count : uint16_t -- num entries in this second-level page - if (RecordIdx % NumRecordsPerSecondLevelPage == 0) { - constexpr uint32_t SecondLevelPageHeaderKind = 2; - constexpr uint16_t SecondLevelPageHeaderSize = 8; - uint16_t SecondLevelPageNumEntries = - std::min(Records.size() - RecordIdx, NumRecordsPerSecondLevelPage); - - cantFail(W.writeInteger(SecondLevelPageHeaderKind)); - cantFail(W.writeInteger(SecondLevelPageHeaderSize)); - cantFail(W.writeInteger(SecondLevelPageNumEntries)); - } - - // Write entry. - auto FnDelta = R.Fn->getAddress() - CompactUnwindBase->getAddress(); - - if (LLVM_UNLIKELY(!isUInt<32>(FnDelta))) - return make_error( - "In " + G.getName() + " " + UnwindInfoSectionName + - ", delta to function at " + formatv("{0:x}", R.Fn->getAddress()) + - " exceeds 32 bits"); - - cantFail(W.writeInteger(FnDelta)); - cantFail(W.writeInteger(R.Encoding)); - - ++RecordIdx; - } - - return Error::success(); - } - - Error getOrCreateCompactUnwindBase(LinkGraph &G) { - auto Name = G.intern("__jitlink$libunwind_dso_base"); - CompactUnwindBase = G.findAbsoluteSymbolByName(Name); - if (!CompactUnwindBase) { - if (auto LocalCUBase = getOrCreateLocalMachOHeader(G)) { - CompactUnwindBase = &*LocalCUBase; - auto &B = LocalCUBase->getBlock(); - G.addDefinedSymbol(B, 0, *Name, B.getSize(), Linkage::Strong, - Scope::Local, false, true); - } else - return LocalCUBase.takeError(); - } - CompactUnwindBase->setLive(true); - return Error::success(); - } - - Error makePersonalityRangeError(LinkGraph &G, Symbol &PSym) { - std::string ErrMsg; - { - raw_string_ostream ErrStream(ErrMsg); - ErrStream << "In " << G.getName() << " " << UnwindInfoSectionName - << ", personality "; - if (PSym.hasName()) - ErrStream << PSym.getName() << " "; - ErrStream << "at " << PSym.getAddress() - << " is out of 32-bit delta range of compact-unwind base at " - << CompactUnwindBase->getAddress(); - } - return make_error(std::move(ErrMsg)); - } - - StringRef CompactUnwindSectionName; - StringRef UnwindInfoSectionName; - StringRef EHFrameSectionName; - Symbol *CompactUnwindBase = nullptr; - - size_t NumLSDAs = 0; - size_t NumSecondLevelPages = 0; - SmallVector Personalities; - SmallVector Records; -}; - -} // end namespace jitlink -} // end namespace llvm - -#undef DEBUG_TYPE - -#endif // LIB_EXECUTIONENGINE_JITLINK_COMPACTUNWINDSUPPORTIMPL_H diff --git a/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp b/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp index 179e458c3cd1f..3e757f780b550 100644 --- a/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp @@ -733,5 +733,121 @@ Error MachOLinkGraphBuilder::graphifyCStringSection( return Error::success(); } +Error CompactUnwindSplitter::operator()(LinkGraph &G) { + auto *CUSec = G.findSectionByName(CompactUnwindSectionName); + if (!CUSec) + return Error::success(); + + if (!G.getTargetTriple().isOSBinFormatMachO()) + return make_error( + "Error linking " + G.getName() + + ": compact unwind splitting not supported on non-macho target " + + G.getTargetTriple().str()); + + unsigned CURecordSize = 0; + unsigned PersonalityEdgeOffset = 0; + unsigned LSDAEdgeOffset = 0; + switch (G.getTargetTriple().getArch()) { + case Triple::aarch64: + case Triple::x86_64: + // 64-bit compact-unwind record format: + // Range start: 8 bytes. + // Range size: 4 bytes. + // CU encoding: 4 bytes. + // Personality: 8 bytes. + // LSDA: 8 bytes. + CURecordSize = 32; + PersonalityEdgeOffset = 16; + LSDAEdgeOffset = 24; + break; + default: + return make_error( + "Error linking " + G.getName() + + ": compact unwind splitting not supported on " + + G.getTargetTriple().getArchName()); + } + + std::vector OriginalBlocks(CUSec->blocks().begin(), + CUSec->blocks().end()); + LLVM_DEBUG({ + dbgs() << "In " << G.getName() << " splitting compact unwind section " + << CompactUnwindSectionName << " containing " + << OriginalBlocks.size() << " initial blocks...\n"; + }); + + while (!OriginalBlocks.empty()) { + auto *B = OriginalBlocks.back(); + OriginalBlocks.pop_back(); + + if (B->getSize() == 0) { + LLVM_DEBUG({ + dbgs() << " Skipping empty block at " + << formatv("{0:x16}", B->getAddress()) << "\n"; + }); + continue; + } + + unsigned NumBlocks = B->getSize() / CURecordSize; + + LLVM_DEBUG({ + dbgs() << " Splitting block at " << formatv("{0:x16}", B->getAddress()) + << " into " << NumBlocks << " compact unwind record(s)\n"; + }); + + if (B->getSize() % CURecordSize) + return make_error( + "Error splitting compact unwind record in " + G.getName() + + ": block at " + formatv("{0:x}", B->getAddress()) + " has size " + + formatv("{0:x}", B->getSize()) + + " (not a multiple of CU record size of " + + formatv("{0:x}", CURecordSize) + ")"); + + auto Blocks = + G.splitBlock(*B, map_range(seq(1U, NumBlocks), [=](Edge::OffsetT Idx) { + return Idx * CURecordSize; + })); + + for (auto *CURec : Blocks) { + bool AddedKeepAlive = false; + + for (auto &E : CURec->edges()) { + if (E.getOffset() == 0) { + LLVM_DEBUG({ + dbgs() << " Updating compact unwind record at " + << CURec->getAddress() << " to point to " + << (E.getTarget().hasName() ? *E.getTarget().getName() + : StringRef()) + << " (at " << E.getTarget().getAddress() << ")\n"; + }); + + if (E.getTarget().isExternal()) + return make_error( + "Error adding keep-alive edge for compact unwind record at " + + formatv("{0:x}", CURec->getAddress()) + ": target " + + *E.getTarget().getName() + " is an external symbol"); + auto &TgtBlock = E.getTarget().getBlock(); + auto &CURecSym = + G.addAnonymousSymbol(*CURec, 0, CURecordSize, false, false); + TgtBlock.addEdge(Edge::KeepAlive, 0, CURecSym, 0); + AddedKeepAlive = true; + } else if (E.getOffset() != PersonalityEdgeOffset && + E.getOffset() != LSDAEdgeOffset) + return make_error( + "Unexpected edge at offset " + formatv("{0:x}", E.getOffset()) + + " in compact unwind record at " + + formatv("{0:x}", CURec->getAddress())); + } + + if (!AddedKeepAlive) + return make_error( + "Error adding keep-alive edge for compact unwind record at " + + formatv("{0:x}", CURec->getAddress()) + + ": no outgoing target edge at offset 0"); + } + } + + return Error::success(); +} + } // end namespace jitlink } // end namespace llvm diff --git a/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.h b/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.h index 343218ec9ad18..6afa01250f62d 100644 --- a/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.h +++ b/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.h @@ -236,6 +236,17 @@ class MachOLinkGraphBuilder { StringMap CustomSectionParserFunctions; }; +/// A pass to split up __LD,__compact_unwind sections. +class CompactUnwindSplitter { +public: + CompactUnwindSplitter(StringRef CompactUnwindSectionName) + : CompactUnwindSectionName(CompactUnwindSectionName) {} + Error operator()(LinkGraph &G); + +private: + StringRef CompactUnwindSectionName; +}; + } // end namespace jitlink } // end namespace llvm diff --git a/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp b/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp index f9f2f4ebb2c8c..29061fff9c2ae 100644 --- a/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp @@ -14,7 +14,6 @@ #include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h" #include "llvm/ExecutionEngine/JITLink/aarch64.h" -#include "CompactUnwindSupport.h" #include "DefineExternalSectionStartAndEndSymbols.h" #include "MachOLinkGraphBuilder.h" @@ -626,27 +625,6 @@ static Error applyPACSigningToModInitPointers(LinkGraph &G) { return Error::success(); } -struct CompactUnwindTraits_MachO_arm64 - : public CompactUnwindTraits { - // FIXME: Reinstate once we no longer need the MSVC workaround. See - // FIXME for CompactUnwindTraits in CompactUnwindSupport.h. - // constexpr static size_t PointerSize = 8; - - constexpr static endianness Endianness = endianness::little; - - constexpr static uint32_t EncodingModeMask = 0x0f000000; - - using GOTManager = aarch64::GOTTableManager; - - static bool encodingSpecifiesDWARF(uint32_t Encoding) { - constexpr uint32_t DWARFMode = 0x03000000; - return (Encoding & EncodingModeMask) == DWARFMode; - } - - static bool encodingCannotBeMerged(uint32_t Encoding) { return false; } -}; - void link_MachO_arm64(std::unique_ptr G, std::unique_ptr Ctx) { @@ -659,21 +637,16 @@ void link_MachO_arm64(std::unique_ptr G, else Config.PrePrunePasses.push_back(markAllSymbolsLive); + // Add compact unwind splitter pass. + Config.PrePrunePasses.push_back( + CompactUnwindSplitter("__LD,__compact_unwind")); + // Add eh-frame passes. + // FIXME: Prune eh-frames for which compact-unwind is available once + // we support compact-unwind registration with libunwind. Config.PrePrunePasses.push_back(createEHFrameSplitterPass_MachO_arm64()); Config.PrePrunePasses.push_back(createEHFrameEdgeFixerPass_MachO_arm64()); - // Create a compact-unwind manager for use in passes below. - auto CompactUnwindMgr = - std::make_shared>( - "__LD,__compact_unwind", "__TEXT,__unwind_info", - "__TEXT,__eh_frame"); - - // Add compact unwind prepare pass. - Config.PrePrunePasses.push_back([CompactUnwindMgr](LinkGraph &G) { - return CompactUnwindMgr->prepareForPrune(G); - }); - // Resolve any external section start / end symbols. Config.PostAllocationPasses.push_back( createDefineExternalSectionStartAndEndSymbolsPass( @@ -690,16 +663,6 @@ void link_MachO_arm64(std::unique_ptr G, Config.PreFixupPasses.push_back( aarch64::lowerPointer64AuthEdgesToSigningFunction); } - - // Reserve unwind-info space. - Config.PostPrunePasses.push_back([CompactUnwindMgr](LinkGraph &G) { - return CompactUnwindMgr->processAndReserveUnwindInfo(G); - }); - - // Translate compact-unwind to unwind-info. - Config.PreFixupPasses.push_back([CompactUnwindMgr](LinkGraph &G) { - return CompactUnwindMgr->writeUnwindInfo(G); - }); } if (auto Err = Ctx->modifyPassConfig(*G, Config)) diff --git a/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp b/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp index 218f8ce97ef03..9547266dc9789 100644 --- a/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp @@ -14,7 +14,6 @@ #include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h" #include "llvm/ExecutionEngine/JITLink/x86_64.h" -#include "CompactUnwindSupport.h" #include "DefineExternalSectionStartAndEndSymbols.h" #include "MachOLinkGraphBuilder.h" @@ -501,55 +500,25 @@ Expected> createLinkGraphFromMachOObject_x86_64( .buildGraph(); } -struct CompactUnwindTraits_MachO_x86_64 - : public CompactUnwindTraits { - // FIXME: Reinstate once we no longer need the MSVC workaround. See - // FIXME for CompactUnwindTraits in CompactUnwindSupport.h. - // constexpr static size_t PointerSize = 8; - - constexpr static endianness Endianness = endianness::little; - - constexpr static uint32_t EncodingModeMask = 0x0f000000; - - using GOTManager = x86_64::GOTTableManager; - - static bool encodingSpecifiesDWARF(uint32_t Encoding) { - constexpr uint32_t DWARFMode = 0x04000000; - return (Encoding & EncodingModeMask) == DWARFMode; - } - - static bool encodingCannotBeMerged(uint32_t Encoding) { - constexpr uint32_t StackIndirectMode = 0x03000000; - return (Encoding & EncodingModeMask) == StackIndirectMode; - } -}; - void link_MachO_x86_64(std::unique_ptr G, std::unique_ptr Ctx) { PassConfiguration Config; if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) { - // Add a mark-live pass. - if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple())) - Config.PrePrunePasses.push_back(std::move(MarkLive)); - else - Config.PrePrunePasses.push_back(markAllSymbolsLive); - // Add eh-frame passes. Config.PrePrunePasses.push_back(createEHFrameSplitterPass_MachO_x86_64()); Config.PrePrunePasses.push_back(createEHFrameEdgeFixerPass_MachO_x86_64()); - // Create a compact-unwind manager for use in passes below. - auto CompactUnwindMgr = std::make_shared< - CompactUnwindManager>( - "__LD,__compact_unwind", "__TEXT,__unwind_info", "__TEXT,__eh_frame"); + // Add compact unwind splitter pass. + Config.PrePrunePasses.push_back( + CompactUnwindSplitter("__LD,__compact_unwind")); - // Add compact unwind prepare pass. - Config.PrePrunePasses.push_back([CompactUnwindMgr](LinkGraph &G) { - return CompactUnwindMgr->prepareForPrune(G); - }); + // Add a mark-live pass. + if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple())) + Config.PrePrunePasses.push_back(std::move(MarkLive)); + else + Config.PrePrunePasses.push_back(markAllSymbolsLive); // Resolve any external section start / end symbols. Config.PostAllocationPasses.push_back( @@ -559,16 +528,6 @@ void link_MachO_x86_64(std::unique_ptr G, // Add an in-place GOT/Stubs pass. Config.PostPrunePasses.push_back(buildGOTAndStubs_MachO_x86_64); - // Reserve space for unwind-info. - Config.PostPrunePasses.push_back([CompactUnwindMgr](LinkGraph &G) { - return CompactUnwindMgr->processAndReserveUnwindInfo(G); - }); - - // Translate compact-unwind to unwind-info. - Config.PreFixupPasses.push_back([CompactUnwindMgr](LinkGraph &G) { - return CompactUnwindMgr->writeUnwindInfo(G); - }); - // Add GOT/Stubs optimizer pass. Config.PreFixupPasses.push_back(x86_64::optimizeGOTAndStubAccesses); } diff --git a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt index 8a866294eee25..2ab5d6dd39b63 100644 --- a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt +++ b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt @@ -57,7 +57,6 @@ add_llvm_component_library(LLVMOrcJIT ExecutorProcessControl.cpp TaskDispatch.cpp ThreadSafeModule.cpp - UnwindInfoRegistrationPlugin.cpp RedirectionManager.cpp JITLinkRedirectableSymbolManager.cpp ReOptimizeLayer.cpp diff --git a/llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp b/llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp index c4d65af1b57f8..5d2f3cd4a8be8 100644 --- a/llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp +++ b/llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp @@ -33,9 +33,6 @@ irManglingOptionsFromTargetOptions(const TargetOptions &Opts) { /// Compile a Module to an ObjectFile. Expected SimpleCompiler::operator()(Module &M) { - if (M.getDataLayout().isDefault()) - M.setDataLayout(TM.createDataLayout()); - CompileResult CachedObject = tryToLoadFromObjectCache(M); if (CachedObject) return std::move(CachedObject); diff --git a/llvm/lib/ExecutionEngine/Orc/Core.cpp b/llvm/lib/ExecutionEngine/Orc/Core.cpp index 9f466e725668a..d47eb4416d3c2 100644 --- a/llvm/lib/ExecutionEngine/Orc/Core.cpp +++ b/llvm/lib/ExecutionEngine/Orc/Core.cpp @@ -1251,7 +1251,9 @@ JITDylib::JITDylib(ExecutionSession &ES, std::string Name) LinkOrder.push_back({this, JITDylibLookupFlags::MatchAllSymbols}); } -JITDylib::RemoveTrackerResult JITDylib::IL_removeTracker(ResourceTracker &RT) { +std::pair> +JITDylib::IL_removeTracker(ResourceTracker &RT) { // Note: Should be called under the session lock. assert(State != Closed && "JD is defunct"); @@ -1290,10 +1292,7 @@ JITDylib::RemoveTrackerResult JITDylib::IL_removeTracker(ResourceTracker &RT) { SymbolsToFail.push_back(Sym); } - auto [QueriesToFail, FailedSymbols] = - ES.IL_failSymbols(*this, std::move(SymbolsToFail)); - - std::vector> DefunctMUs; + auto Result = ES.IL_failSymbols(*this, std::move(SymbolsToFail)); // Removed symbols should be taken out of the table altogether. for (auto &Sym : SymbolsToRemove) { @@ -1303,12 +1302,7 @@ JITDylib::RemoveTrackerResult JITDylib::IL_removeTracker(ResourceTracker &RT) { // Remove Materializer if present. if (I->second.hasMaterializerAttached()) { // FIXME: Should this discard the symbols? - auto J = UnmaterializedInfos.find(Sym); - assert(J != UnmaterializedInfos.end() && - "Symbol table indicates MU present, but no UMI record"); - if (J->second->MU) - DefunctMUs.push_back(std::move(J->second->MU)); - UnmaterializedInfos.erase(J); + UnmaterializedInfos.erase(Sym); } else { assert(!UnmaterializedInfos.count(Sym) && "Symbol has materializer attached"); @@ -1319,8 +1313,7 @@ JITDylib::RemoveTrackerResult JITDylib::IL_removeTracker(ResourceTracker &RT) { shrinkMaterializationInfoMemory(); - return {std::move(QueriesToFail), std::move(FailedSymbols), - std::move(DefunctMUs)}; + return Result; } void JITDylib::transferTracker(ResourceTracker &DstRT, ResourceTracker &SrcRT) { @@ -2187,17 +2180,16 @@ Error ExecutionSession::removeResourceTracker(ResourceTracker &RT) { }); std::vector CurrentResourceManagers; - JITDylib::RemoveTrackerResult R; + JITDylib::AsynchronousSymbolQuerySet QueriesToFail; + std::shared_ptr FailedSymbols; runSessionLocked([&] { CurrentResourceManagers = ResourceManagers; RT.makeDefunct(); - R = RT.getJITDylib().IL_removeTracker(RT); + std::tie(QueriesToFail, FailedSymbols) = + RT.getJITDylib().IL_removeTracker(RT); }); - // Release any defunct MaterializationUnits. - R.DefunctMUs.clear(); - Error Err = Error::success(); auto &JD = RT.getJITDylib(); @@ -2205,9 +2197,9 @@ Error ExecutionSession::removeResourceTracker(ResourceTracker &RT) { Err = joinErrors(std::move(Err), L->handleRemoveResources(JD, RT.getKeyUnsafe())); - for (auto &Q : R.QueriesToFail) - Q->handleFailed(make_error(getSymbolStringPool(), - R.FailedSymbols)); + for (auto &Q : QueriesToFail) + Q->handleFailed( + make_error(getSymbolStringPool(), FailedSymbols)); return Err; } diff --git a/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp b/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp index b51fa24be76d1..aa799687e6d5d 100644 --- a/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp +++ b/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp @@ -45,7 +45,6 @@ SelfExecutorProcessControl::SelfExecutorProcessControl( this->DylibMgr = this; this->JDI = {ExecutorAddr::fromPtr(jitDispatchViaWrapperFunctionManager), ExecutorAddr::fromPtr(this)}; - if (this->TargetTriple.isOSBinFormatMachO()) GlobalManglingPrefix = '_'; @@ -53,12 +52,6 @@ SelfExecutorProcessControl::SelfExecutorProcessControl( ExecutorAddr::fromPtr(&llvm_orc_registerEHFrameSectionWrapper); this->BootstrapSymbols[rt::DeregisterEHFrameSectionWrapperName] = ExecutorAddr::fromPtr(&llvm_orc_deregisterEHFrameSectionWrapper); - -#ifdef __APPLE__ - this->UnwindInfoMgr = UnwindInfoManager::TryCreate(); - if (this->UnwindInfoMgr) - this->UnwindInfoMgr->addBootstrapSymbols(this->BootstrapSymbols); -#endif // __APPLE__ } Expected> diff --git a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp index ab7f854187b33..80500d0fdd9bc 100644 --- a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp +++ b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp @@ -21,7 +21,6 @@ #include "llvm/ExecutionEngine/Orc/ObjectTransformLayer.h" #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" #include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h" -#include "llvm/ExecutionEngine/Orc/UnwindInfoRegistrationPlugin.h" #include "llvm/ExecutionEngine/SectionMemoryManager.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/IRBuilder.h" @@ -1221,28 +1220,12 @@ Expected setUpGenericLLVMIRPlatform(LLJIT &J) { if (auto *OLL = dyn_cast(&J.getObjLinkingLayer())) { - bool CompactUnwindInfoSupported = false; - - // Enable compact-unwind support if possible. - if (J.getTargetTriple().isOSDarwin() || - J.getTargetTriple().isOSBinFormatMachO()) { - if (auto UIRP = UnwindInfoRegistrationPlugin::Create( - J.getIRCompileLayer(), PlatformJD)) { - CompactUnwindInfoSupported = true; - OLL->addPlugin(std::move(*UIRP)); - } else - consumeError(UIRP.takeError()); - } - - // Otherwise fall back to standard unwind registration. - if (!CompactUnwindInfoSupported) { - auto &ES = J.getExecutionSession(); - if (auto EHFrameRegistrar = EPCEHFrameRegistrar::Create(ES)) - OLL->addPlugin(std::make_unique( - ES, std::move(*EHFrameRegistrar))); - else - return EHFrameRegistrar.takeError(); - } + auto &ES = J.getExecutionSession(); + if (auto EHFrameRegistrar = EPCEHFrameRegistrar::Create(ES)) + OLL->addPlugin(std::make_unique( + ES, std::move(*EHFrameRegistrar))); + else + return EHFrameRegistrar.takeError(); } J.setPlatformSupport( diff --git a/llvm/lib/ExecutionEngine/Orc/Shared/OrcRTBridge.cpp b/llvm/lib/ExecutionEngine/Orc/Shared/OrcRTBridge.cpp index fef3ff989a52a..54a25c007c589 100644 --- a/llvm/lib/ExecutionEngine/Orc/Shared/OrcRTBridge.cpp +++ b/llvm/lib/ExecutionEngine/Orc/Shared/OrcRTBridge.cpp @@ -64,19 +64,5 @@ const char *RunAsIntFunctionWrapperName = "__llvm_orc_bootstrap_run_as_int_function_wrapper"; } // end namespace rt -namespace rt_alt { -const char *UnwindInfoManagerInstanceName = - "orc_rt_alt_UnwindInfoManager_Instance"; -const char *UnwindInfoManagerFindSectionsHelperName = - "orc_rt_alt_UnwindInfoManager_findSectionsHelper"; -const char *UnwindInfoManagerEnableWrapperName = - "orc_rt_alt_UnwindInfoManager_enable"; -const char *UnwindInfoManagerDisableWrapperName = - "orc_rt_alt_UnwindInfoManager_disable"; -const char *UnwindInfoManagerRegisterActionName = - "orc_rt_alt_UnwindInfoManager_register"; -const char *UnwindInfoManagerDeregisterActionName = - "orc_rt_alt_UnwindInfoManager_deregister"; -} // end namespace rt_alt } // end namespace orc } // end namespace llvm diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt index ffc1bbfa121b3..3d1dfe758c79d 100644 --- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt +++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt @@ -20,7 +20,6 @@ add_llvm_component_library(LLVMOrcTargetProcess SimpleExecutorMemoryManager.cpp SimpleRemoteEPCServer.cpp TargetExecutionUtils.cpp - UnwindInfoManager.cpp ADDITIONAL_HEADER_DIRS ${LLVM_MAIN_INCLUDE_DIR}/llvm/ExecutionEngine/Orc diff --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/UnwindInfoManager.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/UnwindInfoManager.cpp deleted file mode 100644 index 68bba9520c19f..0000000000000 --- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/UnwindInfoManager.cpp +++ /dev/null @@ -1,188 +0,0 @@ -//===------- UnwindInfoManager.cpp - Register unwind info sections --------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/ExecutionEngine/Orc/TargetProcess/UnwindInfoManager.h" -#include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h" -#include "llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h" -#include "llvm/Support/DynamicLibrary.h" - -#define DEBUG_TYPE "orc" - -using namespace llvm; -using namespace llvm::orc; -using namespace llvm::orc::shared; - -static orc::shared::CWrapperFunctionResult -llvm_orc_rt_alt_UnwindInfoManager_enable(const char *Data, uint64_t Size) { - return WrapperFunction::handle( - Data, Size, - [](ExecutorAddr Instance, ExecutorAddr FindFn) { - return Instance.toPtr()->enable( - FindFn.toPtr()); - }) - .release(); -} - -static orc::shared::CWrapperFunctionResult -llvm_orc_rt_alt_UnwindInfoManager_disable(const char *Data, uint64_t Size) { - return WrapperFunction::handle( - Data, Size, - [](ExecutorAddr Instance) { - return Instance.toPtr()->disable(); - }) - .release(); -} - -static orc::shared::CWrapperFunctionResult -llvm_orc_rt_alt_UnwindInfoManager_register(const char *Data, uint64_t Size) { - using SPSSig = - SPSError(SPSExecutorAddr, SPSSequence, - SPSExecutorAddr, SPSExecutorAddrRange, SPSExecutorAddrRange); - - return WrapperFunction::handle( - Data, Size, - [](ExecutorAddr Instance, - std::vector CodeRanges, ExecutorAddr DSOBase, - ExecutorAddrRange DWARFRange, - ExecutorAddrRange CompactUnwindRange) { - return Instance.toPtr()->registerSections( - CodeRanges, DSOBase, DWARFRange, CompactUnwindRange); - }) - .release(); -} - -static orc::shared::CWrapperFunctionResult -llvm_orc_rt_alt_UnwindInfoManager_deregister(const char *Data, uint64_t Size) { - using SPSSig = SPSError(SPSExecutorAddr, SPSSequence); - - return WrapperFunction::handle( - Data, Size, - [](ExecutorAddr Instance, - std::vector CodeRanges) { - return Instance.toPtr()->deregisterSections( - CodeRanges); - }) - .release(); -} - -namespace llvm::orc { - -const char *UnwindInfoManager::AddFnName = - "__unw_add_find_dynamic_unwind_sections"; -const char *UnwindInfoManager::RemoveFnName = - "__unw_remove_find_dynamic_unwind_sections"; - -std::unique_ptr UnwindInfoManager::TryCreate() { - std::string ErrMsg; - auto DL = sys::DynamicLibrary::getPermanentLibrary(nullptr, &ErrMsg); - if (!DL.isValid()) - return nullptr; - - auto AddFindDynamicUnwindSections = - (int (*)(void *))DL.getAddressOfSymbol(AddFnName); - if (!AddFindDynamicUnwindSections) - return nullptr; - - auto RemoveFindDynamicUnwindSections = - (int (*)(void *))DL.getAddressOfSymbol(RemoveFnName); - if (!RemoveFindDynamicUnwindSections) - return nullptr; - - return std::unique_ptr(new UnwindInfoManager( - AddFindDynamicUnwindSections, RemoveFindDynamicUnwindSections)); -} - -Error UnwindInfoManager::shutdown() { return Error::success(); } - -void UnwindInfoManager::addBootstrapSymbols(StringMap &M) { - M[rt_alt::UnwindInfoManagerInstanceName] = ExecutorAddr::fromPtr(this); - M[rt_alt::UnwindInfoManagerFindSectionsHelperName] = - ExecutorAddr::fromPtr(&findSectionsHelper); - M[rt_alt::UnwindInfoManagerEnableWrapperName] = - ExecutorAddr::fromPtr(llvm_orc_rt_alt_UnwindInfoManager_enable); - M[rt_alt::UnwindInfoManagerDisableWrapperName] = - ExecutorAddr::fromPtr(llvm_orc_rt_alt_UnwindInfoManager_disable); - M[rt_alt::UnwindInfoManagerRegisterActionName] = - ExecutorAddr::fromPtr(llvm_orc_rt_alt_UnwindInfoManager_register); - M[rt_alt::UnwindInfoManagerDeregisterActionName] = - ExecutorAddr::fromPtr(llvm_orc_rt_alt_UnwindInfoManager_deregister); -} - -Error UnwindInfoManager::enable(void *FindDynamicUnwindSections) { - LLVM_DEBUG(dbgs() << "Enabling UnwindInfoManager.\n"); - - if (auto Err = AddFindDynamicUnwindSections(FindDynamicUnwindSections)) - return make_error(Twine("Could not register function via ") + - AddFnName + - ", error code = " + Twine(Err), - inconvertibleErrorCode()); - - this->FindDynamicUnwindSections = FindDynamicUnwindSections; - return Error::success(); -} - -Error UnwindInfoManager::disable(void) { - LLVM_DEBUG(dbgs() << "Disabling UnwindInfoManager.\n"); - - if (FindDynamicUnwindSections) - if (auto Err = RemoveFindDynamicUnwindSections(FindDynamicUnwindSections)) - return make_error( - Twine("Could not deregister function via ") + RemoveFnName + - "error code = " + Twine(Err), - inconvertibleErrorCode()); - - FindDynamicUnwindSections = nullptr; - return Error::success(); -} - -Error UnwindInfoManager::registerSections( - ArrayRef CodeRanges, ExecutorAddr DSOBase, - ExecutorAddrRange DWARFEHFrame, ExecutorAddrRange CompactUnwind) { - std::lock_guard Lock(M); - for (auto &R : CodeRanges) - UWSecs[R.Start.getValue()] = UnwindSections{ - static_cast(DSOBase.getValue()), - static_cast(DWARFEHFrame.Start.getValue()), - static_cast(DWARFEHFrame.size()), - static_cast(CompactUnwind.Start.getValue()), - static_cast(CompactUnwind.size())}; - return Error::success(); -} - -Error UnwindInfoManager::deregisterSections( - ArrayRef CodeRanges) { - std::lock_guard Lock(M); - for (auto &R : CodeRanges) { - auto I = UWSecs.find(R.Start.getValue()); - if (I == UWSecs.end()) - return make_error( - "No unwind-info sections registered for range " + - formatv("{0:x} - {1:x}", R.Start, R.End), - inconvertibleErrorCode()); - UWSecs.erase(I); - } - return Error::success(); -} - -int UnwindInfoManager::findSections(uintptr_t Addr, UnwindSections *Info) { - std::lock_guard Lock(M); - auto I = UWSecs.upper_bound(Addr); - if (I == UWSecs.begin()) - return 0; - --I; - *Info = I->second; - return 1; -} - -int UnwindInfoManager::findSectionsHelper(UnwindInfoManager *Instance, - uintptr_t Addr, - UnwindSections *Info) { - return Instance->findSections(Addr, Info); -} - -} // namespace llvm::orc diff --git a/llvm/lib/ExecutionEngine/Orc/UnwindInfoRegistrationPlugin.cpp b/llvm/lib/ExecutionEngine/Orc/UnwindInfoRegistrationPlugin.cpp deleted file mode 100644 index 0073f3daf7f23..0000000000000 --- a/llvm/lib/ExecutionEngine/Orc/UnwindInfoRegistrationPlugin.cpp +++ /dev/null @@ -1,238 +0,0 @@ -//===----- UnwindInfoRegistrationPlugin.cpp - libunwind registration ------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/ExecutionEngine/Orc/UnwindInfoRegistrationPlugin.h" - -#include "llvm/ADT/ScopeExit.h" -#include "llvm/ExecutionEngine/Orc/AbsoluteSymbols.h" -#include "llvm/ExecutionEngine/Orc/Shared/MachOObjectFormat.h" -#include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/Module.h" - -#define DEBUG_TYPE "orc" - -using namespace llvm::jitlink; - -static const char *FindDynamicUnwindSectionsFunctionName = - "_orc_rt_alt_find_dynamic_unwind_sections"; - -namespace llvm::orc { - -Expected> -UnwindInfoRegistrationPlugin::Create(IRLayer &IRL, JITDylib &PlatformJD, - ExecutorAddr Instance, - ExecutorAddr FindHelper, - ExecutorAddr Enable, ExecutorAddr Disable, - ExecutorAddr Register, - ExecutorAddr Deregister) { - - auto &ES = IRL.getExecutionSession(); - - // Build bouncer module. - auto M = makeBouncerModule(ES); - if (!M) - return M.takeError(); - - auto BouncerRT = PlatformJD.createResourceTracker(); - auto RemoveBouncerModule = make_scope_exit([&]() { - if (auto Err = BouncerRT->remove()) - ES.reportError(std::move(Err)); - }); - - if (auto Err = PlatformJD.define(absoluteSymbols( - {{ES.intern(rt_alt::UnwindInfoManagerInstanceName), - ExecutorSymbolDef(Instance, JITSymbolFlags())}, - {ES.intern(rt_alt::UnwindInfoManagerFindSectionsHelperName), - ExecutorSymbolDef(FindHelper, JITSymbolFlags::Callable)}}))) - return std::move(Err); - - if (auto Err = IRL.add(BouncerRT, std::move(*M))) - return Err; - - auto FindUnwindSections = - ES.lookup({&PlatformJD}, FindDynamicUnwindSectionsFunctionName); - if (!FindUnwindSections) - return FindUnwindSections.takeError(); - - using namespace shared; - using SPSEnableSig = SPSError(SPSExecutorAddr, SPSExecutorAddr); - Error CallErr = Error::success(); - if (auto Err = ES.callSPSWrapper( - Enable, CallErr, Instance, FindUnwindSections->getAddress())) { - consumeError(std::move(CallErr)); - return std::move(Err); - } - - if (CallErr) - return std::move(CallErr); - - RemoveBouncerModule.release(); - - return std::shared_ptr( - new UnwindInfoRegistrationPlugin(ES, Instance, Disable, Register, - Deregister)); -} - -Expected> -UnwindInfoRegistrationPlugin::Create(IRLayer &IRL, JITDylib &PlatformJD) { - - ExecutorAddr Instance, FindHelper, Enable, Disable, Register, Deregister; - - auto &EPC = IRL.getExecutionSession().getExecutorProcessControl(); - if (auto Err = EPC.getBootstrapSymbols( - {{Instance, rt_alt::UnwindInfoManagerInstanceName}, - {FindHelper, rt_alt::UnwindInfoManagerFindSectionsHelperName}, - {Enable, rt_alt::UnwindInfoManagerEnableWrapperName}, - {Disable, rt_alt::UnwindInfoManagerDisableWrapperName}, - {Register, rt_alt::UnwindInfoManagerRegisterActionName}, - {Deregister, rt_alt::UnwindInfoManagerDeregisterActionName}})) - return std::move(Err); - - return Create(IRL, PlatformJD, Instance, FindHelper, Enable, Disable, - Register, Deregister); -} - -UnwindInfoRegistrationPlugin::~UnwindInfoRegistrationPlugin() { - using namespace shared; - using SPSDisableSig = SPSError(SPSExecutorAddr); - Error CallErr = Error::success(); - if (auto Err = ES.callSPSWrapper(Disable, CallErr, Instance)) { - consumeError(std::move(CallErr)); - ES.reportError(std::move(Err)); - } - if (CallErr) - ES.reportError(std::move(CallErr)); -} - -void UnwindInfoRegistrationPlugin::modifyPassConfig( - MaterializationResponsibility &MR, LinkGraph &G, - PassConfiguration &PassConfig) { - - PassConfig.PostFixupPasses.push_back( - [this](LinkGraph &G) { return addUnwindInfoRegistrationActions(G); }); -} - -Expected -UnwindInfoRegistrationPlugin::makeBouncerModule(ExecutionSession &ES) { - auto Ctx = std::make_unique(); - auto M = std::make_unique("__libunwind_find_unwind_bouncer", *Ctx); - M->setTargetTriple(ES.getTargetTriple().str()); - - auto EscapeName = [](const char *N) { return std::string("\01") + N; }; - - auto *PtrTy = PointerType::getUnqual(*Ctx); - auto *OpaqueStructTy = StructType::create(*Ctx, "UnwindInfoMgr"); - auto *UnwindMgrInstance = new GlobalVariable( - *M, OpaqueStructTy, true, GlobalValue::ExternalLinkage, nullptr, - EscapeName(rt_alt::UnwindInfoManagerInstanceName)); - - auto *Int64Ty = Type::getInt64Ty(*Ctx); - auto *FindHelperTy = FunctionType::get(Int64Ty, {PtrTy, PtrTy, PtrTy}, false); - auto *FindHelperFn = Function::Create( - FindHelperTy, GlobalValue::ExternalLinkage, - EscapeName(rt_alt::UnwindInfoManagerFindSectionsHelperName), *M); - - auto *FindFnTy = FunctionType::get(Int64Ty, {PtrTy, PtrTy}, false); - auto *FindFn = - Function::Create(FindFnTy, GlobalValue::ExternalLinkage, - EscapeName(FindDynamicUnwindSectionsFunctionName), *M); - auto *EntryBlock = BasicBlock::Create(M->getContext(), StringRef(), FindFn); - IRBuilder<> IB(EntryBlock); - - std::vector FindHelperArgs; - FindHelperArgs.push_back(UnwindMgrInstance); - for (auto &Arg : FindFn->args()) - FindHelperArgs.push_back(&Arg); - - IB.CreateRet(IB.CreateCall(FindHelperFn, FindHelperArgs)); - - return ThreadSafeModule(std::move(M), std::move(Ctx)); -} - -Error UnwindInfoRegistrationPlugin::addUnwindInfoRegistrationActions( - LinkGraph &G) { - ExecutorAddrRange EHFrameRange, UnwindInfoRange; - - std::vector CodeBlocks; - - auto ScanUnwindInfoSection = [&](Section &Sec, ExecutorAddrRange &SecRange) { - if (Sec.empty()) - return; - - SecRange.Start = (*Sec.blocks().begin())->getAddress(); - for (auto *B : Sec.blocks()) { - auto R = B->getRange(); - SecRange.Start = std::min(SecRange.Start, R.Start); - SecRange.End = std::max(SecRange.End, R.End); - for (auto &E : B->edges()) { - if (E.getKind() != Edge::KeepAlive || !E.getTarget().isDefined()) - continue; - auto &TargetBlock = E.getTarget().getBlock(); - auto &TargetSection = TargetBlock.getSection(); - if ((TargetSection.getMemProt() & MemProt::Exec) == MemProt::Exec) - CodeBlocks.push_back(&TargetBlock); - } - } - }; - - if (auto *EHFrame = G.findSectionByName(MachOEHFrameSectionName)) - ScanUnwindInfoSection(*EHFrame, EHFrameRange); - - if (auto *UnwindInfo = G.findSectionByName(MachOCompactUnwindInfoSectionName)) - ScanUnwindInfoSection(*UnwindInfo, UnwindInfoRange); - - if (CodeBlocks.empty()) - return Error::success(); - - if ((EHFrameRange == ExecutorAddrRange() && - UnwindInfoRange == ExecutorAddrRange())) - return Error::success(); - - llvm::sort(CodeBlocks, [](const Block *LHS, const Block *RHS) { - return LHS->getAddress() < RHS->getAddress(); - }); - - SmallVector CodeRanges; - for (auto *B : CodeBlocks) { - if (CodeRanges.empty() || CodeRanges.back().End != B->getAddress()) - CodeRanges.push_back(B->getRange()); - else - CodeRanges.back().End = B->getRange().End; - } - - ExecutorAddr DSOBase; - if (auto *DSOBaseSym = G.findAbsoluteSymbolByName(DSOBaseName)) - DSOBase = DSOBaseSym->getAddress(); - else if (auto *DSOBaseSym = G.findExternalSymbolByName(DSOBaseName)) - DSOBase = DSOBaseSym->getAddress(); - else if (auto *DSOBaseSym = G.findDefinedSymbolByName(DSOBaseName)) - DSOBase = DSOBaseSym->getAddress(); - else - return make_error("In " + G.getName() + - " could not find dso base symbol", - inconvertibleErrorCode()); - - using namespace shared; - using SPSRegisterArgs = - SPSArgList, - SPSExecutorAddr, SPSExecutorAddrRange, SPSExecutorAddrRange>; - using SPSDeregisterArgs = - SPSArgList>; - - G.allocActions().push_back( - {cantFail(WrapperFunctionCall::Create( - Register, Instance, CodeRanges, DSOBase, EHFrameRange, - UnwindInfoRange)), - cantFail(WrapperFunctionCall::Create( - Deregister, Instance, CodeRanges))}); - - return Error::success(); -} - -} // namespace llvm::orc From 12243234f667294fe0059e78be8f001a228d48bd Mon Sep 17 00:00:00 2001 From: LLVM GN Syncbot Date: Thu, 30 Jan 2025 19:27:47 +0000 Subject: [PATCH 08/34] [gn build] Port b04847b427d6 --- .../utils/gn/secondary/llvm/lib/ExecutionEngine/JITLink/BUILD.gn | 1 - llvm/utils/gn/secondary/llvm/lib/ExecutionEngine/Orc/BUILD.gn | 1 - .../llvm/lib/ExecutionEngine/Orc/TargetProcess/BUILD.gn | 1 - 3 files changed, 3 deletions(-) diff --git a/llvm/utils/gn/secondary/llvm/lib/ExecutionEngine/JITLink/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/ExecutionEngine/JITLink/BUILD.gn index 96db1ab43e76e..b9399faa45e2e 100644 --- a/llvm/utils/gn/secondary/llvm/lib/ExecutionEngine/JITLink/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/lib/ExecutionEngine/JITLink/BUILD.gn @@ -22,7 +22,6 @@ static_library("JITLink") { "COFFDirectiveParser.cpp", "COFFLinkGraphBuilder.cpp", "COFF_x86_64.cpp", - "CompactUnwindSupport.cpp", "DWARFRecordSectionSplitter.cpp", "EHFrameSupport.cpp", "ELF.cpp", diff --git a/llvm/utils/gn/secondary/llvm/lib/ExecutionEngine/Orc/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/ExecutionEngine/Orc/BUILD.gn index b0d4d94c6ac80..a13c3cd22e72c 100644 --- a/llvm/utils/gn/secondary/llvm/lib/ExecutionEngine/Orc/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/lib/ExecutionEngine/Orc/BUILD.gn @@ -68,6 +68,5 @@ static_library("Orc") { "Speculation.cpp", "TaskDispatch.cpp", "ThreadSafeModule.cpp", - "UnwindInfoRegistrationPlugin.cpp", ] } diff --git a/llvm/utils/gn/secondary/llvm/lib/ExecutionEngine/Orc/TargetProcess/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/ExecutionEngine/Orc/TargetProcess/BUILD.gn index 49bf1516b2781..d62f5042c9463 100644 --- a/llvm/utils/gn/secondary/llvm/lib/ExecutionEngine/Orc/TargetProcess/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/lib/ExecutionEngine/Orc/TargetProcess/BUILD.gn @@ -16,7 +16,6 @@ static_library("TargetProcess") { "SimpleExecutorMemoryManager.cpp", "SimpleRemoteEPCServer.cpp", "TargetExecutionUtils.cpp", - "UnwindInfoManager.cpp", ] if (current_os == "linux") { libs = [ "rt" ] From 74d7f43b98910a110bc194752fca829eb19c265a Mon Sep 17 00:00:00 2001 From: Nikolas Klauser Date: Thu, 30 Jan 2025 20:34:29 +0100 Subject: [PATCH 09/34] [Clang] Fix __{add,remove}_pointer in Objective-C++ (#123678) This aligns the builtins with how implementations work which don't use the buitins. --- clang/docs/ReleaseNotes.rst | 2 ++ clang/lib/Sema/SemaType.cpp | 6 +++--- clang/test/SemaCXX/remove_pointer.mm | 8 -------- clang/test/SemaObjCXX/type-traits.mm | 17 +++++++++++++++++ 4 files changed, 22 insertions(+), 11 deletions(-) delete mode 100644 clang/test/SemaCXX/remove_pointer.mm create mode 100644 clang/test/SemaObjCXX/type-traits.mm diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 8be1ea2fb0145..8c290437fe16f 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -122,6 +122,8 @@ Bug Fixes in This Version Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +- The behvaiour of ``__add_pointer`` and ``__remove_pointer`` for Objective-C++'s ``id`` and interfaces has been fixed. + Bug Fixes to Attribute Support ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 33d5378944ddb..2781651b5d8f7 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -1826,7 +1826,8 @@ QualType Sema::BuildPointerType(QualType T, if (checkQualifiedFunction(*this, T, Loc, QFK_Pointer)) return QualType(); - assert(!T->isObjCObjectType() && "Should build ObjCObjectPointerType"); + if (T->isObjCObjectType()) + return Context.getObjCObjectPointerType(T); // In ARC, it is forbidden to build pointers to unqualified pointers. if (getLangOpts().ObjCAutoRefCount) @@ -9807,8 +9808,7 @@ QualType Sema::BuiltinAddPointer(QualType BaseType, SourceLocation Loc) { } QualType Sema::BuiltinRemovePointer(QualType BaseType, SourceLocation Loc) { - // We don't want block pointers or ObjectiveC's id type. - if (!BaseType->isAnyPointerType() || BaseType->isObjCIdType()) + if (!BaseType->isAnyPointerType()) return BaseType; return BaseType->getPointeeType(); diff --git a/clang/test/SemaCXX/remove_pointer.mm b/clang/test/SemaCXX/remove_pointer.mm deleted file mode 100644 index d1cf1fa9f4efc..0000000000000 --- a/clang/test/SemaCXX/remove_pointer.mm +++ /dev/null @@ -1,8 +0,0 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s - -// expected-no-diagnostics - -@class X; - -static_assert(__is_same(__remove_pointer(X *), X), ""); -static_assert(__is_same(__remove_pointer(id), id), ""); diff --git a/clang/test/SemaObjCXX/type-traits.mm b/clang/test/SemaObjCXX/type-traits.mm new file mode 100644 index 0000000000000..81b9573b52192 --- /dev/null +++ b/clang/test/SemaObjCXX/type-traits.mm @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=c++17 %s + +// expected-no-diagnostics + +@interface I; +@end + +@class C; + +static_assert(__is_same(__add_pointer(id), id*)); +static_assert(__is_same(__add_pointer(I), I*)); + +static_assert(__is_same(__remove_pointer(C*), C)); +static_assert(!__is_same(__remove_pointer(id), id)); +static_assert(__is_same(__remove_pointer(id*), id)); +static_assert(__is_same(__remove_pointer(__add_pointer(id)), id)); +static_assert(__is_same(__add_pointer(__remove_pointer(id)), id)); From b4d52a9abdad2582d7aafc68448310066526acd8 Mon Sep 17 00:00:00 2001 From: Peter Klausler Date: Thu, 30 Jan 2025 11:41:20 -0800 Subject: [PATCH 10/34] [flang] Repair recent Power build bot breakage (#124950) Add AIX_WARNING expected warnings to a test that is now producing new warnings. Should fix https://lab.llvm.org/buildbot/#/builders/201/builds/2291. --- flang/test/Semantics/kinds04_q10.f90 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/flang/test/Semantics/kinds04_q10.f90 b/flang/test/Semantics/kinds04_q10.f90 index aa5c4abe2f1df..3bec7a386585b 100644 --- a/flang/test/Semantics/kinds04_q10.f90 +++ b/flang/test/Semantics/kinds04_q10.f90 @@ -1,4 +1,5 @@ -! RUN: %python %S/test_errors.py %s %flang_fc1 +! RUN: not %flang_fc1 %s 2>%t.stderr +! RUN: FileCheck %s --input-file=%t.stderr --check-prefixes=PORTABILITY,ERROR,WARNING%if system-aix %{,AIX_WARNING%} ! C716 If both kind-param and exponent-letter appear, exponent-letter ! shall be E. (As an extension we also allow an exponent-letter which matches ! the kind-param) @@ -12,10 +13,12 @@ subroutine s(var) !PORTABILITY: Explicit kind parameter together with non-'E' exponent letter is not standard real :: realvar4 = 4.0D6_8 !WARNING: Explicit kind parameter on real constant disagrees with exponent letter 'q' + !AIX_WARNING: underflow on REAL(10) to REAL(4) conversion real :: realvar5 = 4.0Q6_10 !PORTABILITY: Explicit kind parameter together with non-'E' exponent letter is not standard real :: realvar6 = 4.0Q6_16 real :: realvar7 = 4.0E6_8 + !AIX_WARNING: underflow on REAL(10) to REAL(4) conversion real :: realvar8 = 4.0E6_10 real :: realvar9 = 4.0E6_16 !ERROR: Unsupported REAL(KIND=32) @@ -29,6 +32,7 @@ subroutine s(var) !PORTABILITY: Explicit kind parameter together with non-'E' exponent letter is not standard double precision :: doublevar5 = 4.0Q6_16 double precision :: doublevar6 = 4.0E6_8 + !AIX_WARNING: underflow on REAL(10) to REAL(8) conversion double precision :: doublevar7 = 4.0E6_10 double precision :: doublevar8 = 4.0E6_16 !ERROR: Unsupported REAL(KIND=32) From 0e62c748d440a6d12d190e951c987efe309f40d6 Mon Sep 17 00:00:00 2001 From: Balazs Benics Date: Thu, 30 Jan 2025 20:48:43 +0100 Subject: [PATCH 11/34] [analyzer][NFC] Remove a redundant container lookup (#125064) I found this using my experimental checker present at: https://github.com/steakhal/llvm-project/tree/bb/add-redundant-lookup-checker The idea for looking for redundant container lookups was inspired by #123376 If there is interest, I could think of upstreaming this alpha checker. (For the StaticAnalyzer sources it was the only TP, and I had no FPs from the checker btw.) --- clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp index 55bcb6e220e1e..7b2cccce93cfe 100644 --- a/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp @@ -488,15 +488,17 @@ ExplodedGraph::trim(ArrayRef Sinks, while (!WL2.empty()) { const ExplodedNode *N = WL2.pop_back_val(); + auto [Place, Inserted] = Pass2.try_emplace(N); + // Skip this node if we have already processed it. - if (Pass2.contains(N)) + if (!Inserted) continue; // Create the corresponding node in the new graph and record the mapping // from the old node to the new node. ExplodedNode *NewN = G->createUncachedNode(N->getLocation(), N->State, N->getID(), N->isSink()); - Pass2[N] = NewN; + Place->second = NewN; // Also record the reverse mapping from the new node to the old node. if (InverseMap) (*InverseMap)[NewN] = N; From e058c73526afeb9d4da07f090a73ae47a224fddc Mon Sep 17 00:00:00 2001 From: youngdfb Date: Thu, 30 Jan 2025 14:51:02 -0500 Subject: [PATCH 12/34] Add test for dwarf verification JSON output (#124936) Summary: 6244dfef5cd45f1395c66abbe061c6a7eb002676 LLVM commit added the ability for llvm-dwarfdump to specify --verify-json and get a JSON aggregation of the DWARF errors in a file. This diff improves the testing by ensuring we validate the expected JSON shape. A follow up diff will modify the JSON and this ensures we can verify. Test Plan: ninja check-llvm-tools-llvm-dwarfdump --- ...g-names-verify--completeness-json-output.s | 172 ++++++++++++++++++ .../X86/dwarf-verify-good-json-output.s | 32 ++++ 2 files changed, 204 insertions(+) create mode 100644 llvm/test/tools/llvm-dwarfdump/X86/debug-names-verify--completeness-json-output.s create mode 100644 llvm/test/tools/llvm-dwarfdump/X86/dwarf-verify-good-json-output.s diff --git a/llvm/test/tools/llvm-dwarfdump/X86/debug-names-verify--completeness-json-output.s b/llvm/test/tools/llvm-dwarfdump/X86/debug-names-verify--completeness-json-output.s new file mode 100644 index 0000000000000..c4b7ffe1d2d8e --- /dev/null +++ b/llvm/test/tools/llvm-dwarfdump/X86/debug-names-verify--completeness-json-output.s @@ -0,0 +1,172 @@ +# RUN: llvm-mc -triple x86_64-pc-linux %s -filetype=obj -o - | not llvm-dwarfdump -verify --verify-json=%t.json - +# RUN: FileCheck %s --input-file %t.json + +# CHECK: {"error-categories":{"Name Index DIE entry missing name":{"count":10}},"error-count":10} +# CHECK-NOT: error: Name Index @ 0x0: Entry for DIE @ {{.*}} (DW_TAG_variable) with name var_block_addr missing. + + .section .debug_loc,"",@progbits +.Ldebug_loc0: + .quad 0 + .quad 1 + .short .Lloc0_end-.Lloc0_start # Loc expr size +.Lloc0_start: + .byte 3 # DW_OP_addr + .quad 0x47 +.Lloc0_end: + .quad 0 + .quad 0 + + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .byte 8 # DW_FORM_string + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + + .byte 2 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 8 # DW_FORM_string + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 0 # EOM(1) + .byte 0 # EOM(2) + + .byte 3 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 3 # DW_AT_name + .byte 8 # DW_FORM_string + .byte 110 # DW_AT_linkage_name + .byte 8 # DW_FORM_string + .byte 82 # DW_AT_entry_pc + .byte 1 # DW_FORM_addr + .byte 0 # EOM(1) + .byte 0 # EOM(2) + + .byte 4 # Abbreviation Code + .byte 57 # DW_TAG_namespace + .byte 1 # DW_CHILDREN_yes + .byte 3 # DW_AT_name + .byte 8 # DW_FORM_string + .byte 0 # EOM(1) + .byte 0 # EOM(2) + + .byte 5 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 8 # DW_FORM_string + .byte 2 # DW_AT_location + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + + .byte 6 # Abbreviation Code + .byte 57 # DW_TAG_namespace + .byte 1 # DW_CHILDREN_yes + .byte 0 # EOM(1) + .byte 0 # EOM(2) + + .byte 7 # Abbreviation Code + .byte 29 # DW_TAG_inlined_subroutine + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 8 # DW_FORM_string + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 18 # DW_AT_high_pc + .byte 1 # DW_FORM_addr + .byte 0 # EOM(1) + .byte 0 # EOM(2) + + .byte 8 # Abbreviation Code + .byte 10 # DW_TAG_label + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 8 # DW_FORM_string + .byte 82 # DW_AT_entry_pc + .byte 1 # DW_FORM_addr + .byte 0 # EOM(1) + .byte 0 # EOM(2) + + .byte 0 # EOM(3) + .section .debug_info,"",@progbits + +.Lcu_begin0: + .long .Lcu_end0-.Lcu_start0 # Length of Unit +.Lcu_start0: + .short 4 # DWARF version number + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] DW_TAG_compile_unit + .asciz "hand-written DWARF" # DW_AT_producer + .quad 0x0 # DW_AT_low_pc + .long 0x100 # DW_AT_high_pc + + .byte 4 # Abbrev [4] DW_TAG_namespace + .asciz "namesp" # DW_AT_name + .byte 2 # Abbrev [2] DW_TAG_variable + .asciz "var_block_addr" # DW_AT_name + .byte 9 # DW_AT_location + .byte 3 # DW_OP_addr + .quad 0x47 + .byte 0 # End Of Children Mark + + .byte 6 # Abbrev [6] DW_TAG_namespace + .byte 5 # Abbrev [5] DW_TAG_variable + .asciz "var_loc_addr" # DW_AT_name + .long .Ldebug_loc0 # DW_AT_location + .byte 0 # End Of Children Mark + + .byte 2 # Abbrev [2] DW_TAG_variable + .asciz "var_loc_tls" # DW_AT_name + .byte 1 # DW_AT_location + .byte 0x9b # DW_OP_form_tls_address + + .byte 2 # Abbrev [2] DW_TAG_variable + .asciz "var_loc_gnu_tls" # DW_AT_name + .byte 1 # DW_AT_location + .byte 0xe0 # DW_OP_GNU_push_tls_address + + .byte 3 # Abbrev [3] DW_TAG_subprogram + .asciz "fun_name" # DW_AT_name + .asciz "_Z8fun_name" # DW_AT_linkage_name + .quad 0x47 # DW_AT_entry_pc + .byte 7 # Abbrev [7] DW_TAG_inlined_subroutine + .asciz "fun_inline" # DW_AT_name + .quad 0x48 # DW_AT_low_pc + .quad 0x49 # DW_AT_high_pc + .byte 8 # Abbrev [8] DW_TAG_label + .asciz "label" # DW_AT_name + .quad 0x4a # DW_AT_entry_pc + .byte 0 # End Of Children Mark + + .byte 0 # End Of Children Mark +.Lcu_end0: + + .section .debug_names,"",@progbits + .long .Lnames_end0-.Lnames_start0 # Header: contribution length +.Lnames_start0: + .short 5 # Header: version + .short 0 # Header: padding + .long 1 # Header: compilation unit count + .long 0 # Header: local type unit count + .long 0 # Header: foreign type unit count + .long 0 # Header: bucket count + .long 0 # Header: name count + .long .Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size + .long 0 # Header: augmentation length + .long .Lcu_begin0 # Compilation unit 0 +.Lnames_abbrev_start0: + .byte 0 # End of abbrev list +.Lnames_abbrev_end0: +.Lnames_entries0: +.Lnames_end0: diff --git a/llvm/test/tools/llvm-dwarfdump/X86/dwarf-verify-good-json-output.s b/llvm/test/tools/llvm-dwarfdump/X86/dwarf-verify-good-json-output.s new file mode 100644 index 0000000000000..6f4b1cdedf83a --- /dev/null +++ b/llvm/test/tools/llvm-dwarfdump/X86/dwarf-verify-good-json-output.s @@ -0,0 +1,32 @@ +# RUN: llvm-mc %s -filetype obj -triple x86_64-apple-darwin -o - | llvm-dwarfdump -verify --verify-json=%t.json - +# RUN: FileCheck %s --input-file %t.json + +# CHECK: {"error-categories":{},"error-count":0} + +# This test is meant to verify that the -verify option +# in llvm-dwarfdump doesn't produce any .apple_names related +# output when there's no such section in the object. +# The test was manually modified to exclude the +# .apple_names section from the apple_names_verify_num_atoms.s +# test file in the same directory. + + .section __TEXT,__text,regular,pure_instructions + .file 1 "basic.c" + .comm _i,4,2 ## @i + .comm _j,4,2 ## @j + .section __DWARF,__debug_str,regular,debug +Linfo_string: + .asciz "Apple LLVM version 8.1.0 (clang-802.0.35)" ## string offset=0 + .asciz "basic.c" ## string offset=42 + .asciz "/Users/sgravani/Development/tests" ## string offset=50 + .asciz "i" ## string offset=84 + .asciz "int" ## string offset=86 + .asciz "j" ## string offset=90 + + .section __DWARF,__debug_info,regular,debug +Lsection_info: + +.subsections_via_symbols + .section __DWARF,__debug_line,regular,debug +Lsection_line: +Lline_table_start0: From edc3dc6abd9dec70f03107d1477a2baffe7208f7 Mon Sep 17 00:00:00 2001 From: Peng Liu Date: Thu, 30 Jan 2025 14:55:05 -0500 Subject: [PATCH 13/34] [libc++] Optimize ranges::copy_backward for vector::iterator (#121026) As a follow-up to #121013 (which focused on `std::ranges::copy`), this PR optimizes the performance of `std::ranges::copy_backward` for `vector::iterator`, addressing a subtask outlined in issue #64038. The optimizations yield performance improvements of up to 2000x for aligned copies and 60x for unaligned copies. --- libcxx/docs/ReleaseNotes/21.rst | 2 +- libcxx/include/__algorithm/copy_backward.h | 131 +++++++++++++++++ libcxx/include/__bit_reference | 134 +----------------- libcxx/include/__vector/vector_bool.h | 1 + libcxx/include/bitset | 1 + .../algorithms/copy_backward.bench.cpp | 55 +++++++ .../alg.copy/copy_backward.pass.cpp | 90 +++++++----- .../alg.copy/ranges.copy_backward.pass.cpp | 106 +++++++++----- 8 files changed, 321 insertions(+), 199 deletions(-) create mode 100644 libcxx/test/benchmarks/algorithms/copy_backward.bench.cpp diff --git a/libcxx/docs/ReleaseNotes/21.rst b/libcxx/docs/ReleaseNotes/21.rst index 8a400065376f4..29ecbf3f01c8a 100644 --- a/libcxx/docs/ReleaseNotes/21.rst +++ b/libcxx/docs/ReleaseNotes/21.rst @@ -44,7 +44,7 @@ Implemented Papers Improvements and New Features ----------------------------- -- The ``std::ranges::copy`` and ``std::ranges::copy_n`` algorithms have been optimized for ``std::vector::iterator``\s, +- The ``std::ranges::{copy, copy_n, copy_backward}`` algorithms have been optimized for ``std::vector::iterator``\s, resulting in a performance improvement of up to 2000x. diff --git a/libcxx/include/__algorithm/copy_backward.h b/libcxx/include/__algorithm/copy_backward.h index 48a768f577f55..02ffc14361e6a 100644 --- a/libcxx/include/__algorithm/copy_backward.h +++ b/libcxx/include/__algorithm/copy_backward.h @@ -10,11 +10,14 @@ #define _LIBCPP___ALGORITHM_COPY_BACKWARD_H #include <__algorithm/copy_move_common.h> +#include <__algorithm/copy_n.h> #include <__algorithm/iterator_operations.h> #include <__algorithm/min.h> #include <__config> +#include <__fwd/bit_reference.h> #include <__iterator/iterator_traits.h> #include <__iterator/segmented_iterator.h> +#include <__memory/pointer_traits.h> #include <__type_traits/common_type.h> #include <__type_traits/enable_if.h> #include <__type_traits/is_constructible.h> @@ -34,6 +37,124 @@ template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_InIter, _OutIter> __copy_backward(_InIter __first, _Sent __last, _OutIter __result); +template +_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> __copy_backward_aligned( + __bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, __bit_iterator<_Cp, false> __result) { + using _In = __bit_iterator<_Cp, _IsConst>; + using difference_type = typename _In::difference_type; + using __storage_type = typename _In::__storage_type; + + const int __bits_per_word = _In::__bits_per_word; + difference_type __n = __last - __first; + if (__n > 0) { + // do first word + if (__last.__ctz_ != 0) { + difference_type __dn = std::min(static_cast(__last.__ctz_), __n); + __n -= __dn; + unsigned __clz = __bits_per_word - __last.__ctz_; + __storage_type __m = (~__storage_type(0) << (__last.__ctz_ - __dn)) & (~__storage_type(0) >> __clz); + __storage_type __b = *__last.__seg_ & __m; + *__result.__seg_ &= ~__m; + *__result.__seg_ |= __b; + __result.__ctz_ = static_cast(((-__dn & (__bits_per_word - 1)) + __result.__ctz_) % __bits_per_word); + // __last.__ctz_ = 0 + } + // __last.__ctz_ == 0 || __n == 0 + // __result.__ctz_ == 0 || __n == 0 + // do middle words + __storage_type __nw = __n / __bits_per_word; + __result.__seg_ -= __nw; + __last.__seg_ -= __nw; + std::copy_n(std::__to_address(__last.__seg_), __nw, std::__to_address(__result.__seg_)); + __n -= __nw * __bits_per_word; + // do last word + if (__n > 0) { + __storage_type __m = ~__storage_type(0) << (__bits_per_word - __n); + __storage_type __b = *--__last.__seg_ & __m; + *--__result.__seg_ &= ~__m; + *__result.__seg_ |= __b; + __result.__ctz_ = static_cast(-__n & (__bits_per_word - 1)); + } + } + return __result; +} + +template +_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> __copy_backward_unaligned( + __bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, __bit_iterator<_Cp, false> __result) { + using _In = __bit_iterator<_Cp, _IsConst>; + using difference_type = typename _In::difference_type; + using __storage_type = typename _In::__storage_type; + + const int __bits_per_word = _In::__bits_per_word; + difference_type __n = __last - __first; + if (__n > 0) { + // do first word + if (__last.__ctz_ != 0) { + difference_type __dn = std::min(static_cast(__last.__ctz_), __n); + __n -= __dn; + unsigned __clz_l = __bits_per_word - __last.__ctz_; + __storage_type __m = (~__storage_type(0) << (__last.__ctz_ - __dn)) & (~__storage_type(0) >> __clz_l); + __storage_type __b = *__last.__seg_ & __m; + unsigned __clz_r = __bits_per_word - __result.__ctz_; + __storage_type __ddn = std::min(__dn, static_cast(__result.__ctz_)); + if (__ddn > 0) { + __m = (~__storage_type(0) << (__result.__ctz_ - __ddn)) & (~__storage_type(0) >> __clz_r); + *__result.__seg_ &= ~__m; + if (__result.__ctz_ > __last.__ctz_) + *__result.__seg_ |= __b << (__result.__ctz_ - __last.__ctz_); + else + *__result.__seg_ |= __b >> (__last.__ctz_ - __result.__ctz_); + __result.__ctz_ = static_cast(((-__ddn & (__bits_per_word - 1)) + __result.__ctz_) % __bits_per_word); + __dn -= __ddn; + } + if (__dn > 0) { + // __result.__ctz_ == 0 + --__result.__seg_; + __result.__ctz_ = static_cast(-__dn & (__bits_per_word - 1)); + __m = ~__storage_type(0) << __result.__ctz_; + *__result.__seg_ &= ~__m; + __last.__ctz_ -= __dn + __ddn; + *__result.__seg_ |= __b << (__result.__ctz_ - __last.__ctz_); + } + // __last.__ctz_ = 0 + } + // __last.__ctz_ == 0 || __n == 0 + // __result.__ctz_ != 0 || __n == 0 + // do middle words + unsigned __clz_r = __bits_per_word - __result.__ctz_; + __storage_type __m = ~__storage_type(0) >> __clz_r; + for (; __n >= __bits_per_word; __n -= __bits_per_word) { + __storage_type __b = *--__last.__seg_; + *__result.__seg_ &= ~__m; + *__result.__seg_ |= __b >> __clz_r; + *--__result.__seg_ &= __m; + *__result.__seg_ |= __b << __result.__ctz_; + } + // do last word + if (__n > 0) { + __m = ~__storage_type(0) << (__bits_per_word - __n); + __storage_type __b = *--__last.__seg_ & __m; + __clz_r = __bits_per_word - __result.__ctz_; + __storage_type __dn = std::min(__n, static_cast(__result.__ctz_)); + __m = (~__storage_type(0) << (__result.__ctz_ - __dn)) & (~__storage_type(0) >> __clz_r); + *__result.__seg_ &= ~__m; + *__result.__seg_ |= __b >> (__bits_per_word - __result.__ctz_); + __result.__ctz_ = static_cast(((-__dn & (__bits_per_word - 1)) + __result.__ctz_) % __bits_per_word); + __n -= __dn; + if (__n > 0) { + // __result.__ctz_ == 0 + --__result.__seg_; + __result.__ctz_ = static_cast(-__n & (__bits_per_word - 1)); + __m = ~__storage_type(0) << __result.__ctz_; + *__result.__seg_ &= ~__m; + *__result.__seg_ |= __b << (__result.__ctz_ - (__bits_per_word - __n - __dn)); + } + } + } + return __result; +} + template struct __copy_backward_impl { template @@ -107,6 +228,16 @@ struct __copy_backward_impl { } } + template + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<__bit_iterator<_Cp, _IsConst>, __bit_iterator<_Cp, false> > + operator()(__bit_iterator<_Cp, _IsConst> __first, + __bit_iterator<_Cp, _IsConst> __last, + __bit_iterator<_Cp, false> __result) { + if (__last.__ctz_ == __result.__ctz_) + return std::make_pair(__last, std::__copy_backward_aligned(__first, __last, __result)); + return std::make_pair(__last, std::__copy_backward_unaligned(__first, __last, __result)); + } + // At this point, the iterators have been unwrapped so any `contiguous_iterator` has been unwrapped to a pointer. template ::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_In*, _Out*> diff --git a/libcxx/include/__bit_reference b/libcxx/include/__bit_reference index 46d2b2f7ed948..bb8d4725c3980 100644 --- a/libcxx/include/__bit_reference +++ b/libcxx/include/__bit_reference @@ -11,6 +11,7 @@ #define _LIBCPP___BIT_REFERENCE #include <__algorithm/copy.h> +#include <__algorithm/copy_backward.h> #include <__algorithm/copy_n.h> #include <__algorithm/min.h> #include <__bit/countr.h> @@ -185,134 +186,6 @@ private: __mask_(__m) {} }; -// copy_backward - -template -_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> __copy_backward_aligned( - __bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, __bit_iterator<_Cp, false> __result) { - using _In = __bit_iterator<_Cp, _IsConst>; - using difference_type = typename _In::difference_type; - using __storage_type = typename _In::__storage_type; - - const int __bits_per_word = _In::__bits_per_word; - difference_type __n = __last - __first; - if (__n > 0) { - // do first word - if (__last.__ctz_ != 0) { - difference_type __dn = std::min(static_cast(__last.__ctz_), __n); - __n -= __dn; - unsigned __clz = __bits_per_word - __last.__ctz_; - __storage_type __m = (~__storage_type(0) << (__last.__ctz_ - __dn)) & (~__storage_type(0) >> __clz); - __storage_type __b = *__last.__seg_ & __m; - *__result.__seg_ &= ~__m; - *__result.__seg_ |= __b; - __result.__ctz_ = static_cast(((-__dn & (__bits_per_word - 1)) + __result.__ctz_) % __bits_per_word); - // __last.__ctz_ = 0 - } - // __last.__ctz_ == 0 || __n == 0 - // __result.__ctz_ == 0 || __n == 0 - // do middle words - __storage_type __nw = __n / __bits_per_word; - __result.__seg_ -= __nw; - __last.__seg_ -= __nw; - std::copy_n(std::__to_address(__last.__seg_), __nw, std::__to_address(__result.__seg_)); - __n -= __nw * __bits_per_word; - // do last word - if (__n > 0) { - __storage_type __m = ~__storage_type(0) << (__bits_per_word - __n); - __storage_type __b = *--__last.__seg_ & __m; - *--__result.__seg_ &= ~__m; - *__result.__seg_ |= __b; - __result.__ctz_ = static_cast(-__n & (__bits_per_word - 1)); - } - } - return __result; -} - -template -_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> __copy_backward_unaligned( - __bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, __bit_iterator<_Cp, false> __result) { - using _In = __bit_iterator<_Cp, _IsConst>; - using difference_type = typename _In::difference_type; - using __storage_type = typename _In::__storage_type; - - const int __bits_per_word = _In::__bits_per_word; - difference_type __n = __last - __first; - if (__n > 0) { - // do first word - if (__last.__ctz_ != 0) { - difference_type __dn = std::min(static_cast(__last.__ctz_), __n); - __n -= __dn; - unsigned __clz_l = __bits_per_word - __last.__ctz_; - __storage_type __m = (~__storage_type(0) << (__last.__ctz_ - __dn)) & (~__storage_type(0) >> __clz_l); - __storage_type __b = *__last.__seg_ & __m; - unsigned __clz_r = __bits_per_word - __result.__ctz_; - __storage_type __ddn = std::min(__dn, static_cast(__result.__ctz_)); - if (__ddn > 0) { - __m = (~__storage_type(0) << (__result.__ctz_ - __ddn)) & (~__storage_type(0) >> __clz_r); - *__result.__seg_ &= ~__m; - if (__result.__ctz_ > __last.__ctz_) - *__result.__seg_ |= __b << (__result.__ctz_ - __last.__ctz_); - else - *__result.__seg_ |= __b >> (__last.__ctz_ - __result.__ctz_); - __result.__ctz_ = static_cast(((-__ddn & (__bits_per_word - 1)) + __result.__ctz_) % __bits_per_word); - __dn -= __ddn; - } - if (__dn > 0) { - // __result.__ctz_ == 0 - --__result.__seg_; - __result.__ctz_ = static_cast(-__dn & (__bits_per_word - 1)); - __m = ~__storage_type(0) << __result.__ctz_; - *__result.__seg_ &= ~__m; - __last.__ctz_ -= __dn + __ddn; - *__result.__seg_ |= __b << (__result.__ctz_ - __last.__ctz_); - } - // __last.__ctz_ = 0 - } - // __last.__ctz_ == 0 || __n == 0 - // __result.__ctz_ != 0 || __n == 0 - // do middle words - unsigned __clz_r = __bits_per_word - __result.__ctz_; - __storage_type __m = ~__storage_type(0) >> __clz_r; - for (; __n >= __bits_per_word; __n -= __bits_per_word) { - __storage_type __b = *--__last.__seg_; - *__result.__seg_ &= ~__m; - *__result.__seg_ |= __b >> __clz_r; - *--__result.__seg_ &= __m; - *__result.__seg_ |= __b << __result.__ctz_; - } - // do last word - if (__n > 0) { - __m = ~__storage_type(0) << (__bits_per_word - __n); - __storage_type __b = *--__last.__seg_ & __m; - __clz_r = __bits_per_word - __result.__ctz_; - __storage_type __dn = std::min(__n, static_cast(__result.__ctz_)); - __m = (~__storage_type(0) << (__result.__ctz_ - __dn)) & (~__storage_type(0) >> __clz_r); - *__result.__seg_ &= ~__m; - *__result.__seg_ |= __b >> (__bits_per_word - __result.__ctz_); - __result.__ctz_ = static_cast(((-__dn & (__bits_per_word - 1)) + __result.__ctz_) % __bits_per_word); - __n -= __dn; - if (__n > 0) { - // __result.__ctz_ == 0 - --__result.__seg_; - __result.__ctz_ = static_cast(-__n & (__bits_per_word - 1)); - __m = ~__storage_type(0) << __result.__ctz_; - *__result.__seg_ &= ~__m; - *__result.__seg_ |= __b << (__result.__ctz_ - (__bits_per_word - __n - __dn)); - } - } - } - return __result; -} - -template -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __bit_iterator<_Cp, false> copy_backward( - __bit_iterator<_Cp, _IsConst> __first, __bit_iterator<_Cp, _IsConst> __last, __bit_iterator<_Cp, false> __result) { - if (__last.__ctz_ == __result.__ctz_) - return std::__copy_backward_aligned(__first, __last, __result); - return std::__copy_backward_unaligned(__first, __last, __result); -} - // move template @@ -876,9 +749,8 @@ private: template _LIBCPP_CONSTEXPR_SINCE_CXX20 friend __bit_iterator<_Dp, false> __copy_backward_unaligned( __bit_iterator<_Dp, _IC> __first, __bit_iterator<_Dp, _IC> __last, __bit_iterator<_Dp, false> __result); - template - _LIBCPP_CONSTEXPR_SINCE_CXX20 friend __bit_iterator<_Dp, false> - copy_backward(__bit_iterator<_Dp, _IC> __first, __bit_iterator<_Dp, _IC> __last, __bit_iterator<_Dp, false> __result); + template + friend struct __copy_backward_impl; template friend __bit_iterator<_Cr, false> __swap_ranges_aligned(__bit_iterator<_Cl, false>, __bit_iterator<_Cl, false>, __bit_iterator<_Cr, false>); diff --git a/libcxx/include/__vector/vector_bool.h b/libcxx/include/__vector/vector_bool.h index 8d9257eddfcd2..25e5c42f1dd6f 100644 --- a/libcxx/include/__vector/vector_bool.h +++ b/libcxx/include/__vector/vector_bool.h @@ -10,6 +10,7 @@ #define _LIBCPP___VECTOR_VECTOR_BOOL_H #include <__algorithm/copy.h> +#include <__algorithm/copy_backward.h> #include <__algorithm/fill_n.h> #include <__algorithm/iterator_operations.h> #include <__algorithm/max.h> diff --git a/libcxx/include/bitset b/libcxx/include/bitset index 2914dee3d5292..a20842985b3d5 100644 --- a/libcxx/include/bitset +++ b/libcxx/include/bitset @@ -130,6 +130,7 @@ template struct hash>; # include <__cxx03/bitset> #else # include <__algorithm/copy.h> +# include <__algorithm/copy_backward.h> # include <__algorithm/count.h> # include <__algorithm/fill.h> # include <__algorithm/fill_n.h> diff --git a/libcxx/test/benchmarks/algorithms/copy_backward.bench.cpp b/libcxx/test/benchmarks/algorithms/copy_backward.bench.cpp new file mode 100644 index 0000000000000..c943d9a874b49 --- /dev/null +++ b/libcxx/test/benchmarks/algorithms/copy_backward.bench.cpp @@ -0,0 +1,55 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + +#include +#include +#include + +static void bm_ranges_copy_backward_vb(benchmark::State& state, bool aligned) { + auto n = state.range(); + std::vector in(n, true); + std::vector out(aligned ? n : n + 8); + benchmark::DoNotOptimize(&in); + auto dst = aligned ? out.end() : out.end() - 4; + for (auto _ : state) { + benchmark::DoNotOptimize(std::ranges::copy_backward(in, dst)); + benchmark::DoNotOptimize(&out); + } +} + +static void bm_copy_backward_vb(benchmark::State& state, bool aligned) { + auto n = state.range(); + std::vector in(n, true); + std::vector out(aligned ? n : n + 8); + benchmark::DoNotOptimize(&in); + auto beg = in.begin(); + auto end = in.end(); + auto dst = aligned ? out.end() : out.end() - 4; + for (auto _ : state) { + benchmark::DoNotOptimize(std::copy_backward(beg, end, dst)); + benchmark::DoNotOptimize(&out); + } +} + +static void bm_ranges_copy_backward_vb_aligned(benchmark::State& state) { bm_ranges_copy_backward_vb(state, true); } +static void bm_ranges_copy_backward_vb_unaligned(benchmark::State& state) { bm_ranges_copy_backward_vb(state, false); } + +static void bm_copy_backward_vb_aligned(benchmark::State& state) { bm_copy_backward_vb(state, true); } +static void bm_copy_backward_vb_unaligned(benchmark::State& state) { bm_copy_backward_vb(state, false); } + +// Test std::ranges::copy_backward for vector::iterator +BENCHMARK(bm_ranges_copy_backward_vb_aligned)->Range(8, 1 << 16)->DenseRange(102400, 204800, 4096); +BENCHMARK(bm_ranges_copy_backward_vb_unaligned)->Range(8, 1 << 20); + +// Test std::copy_backward for vector::iterator +BENCHMARK(bm_copy_backward_vb_aligned)->Range(8, 1 << 20); +BENCHMARK(bm_copy_backward_vb_unaligned)->Range(8, 1 << 20); + +BENCHMARK_MAIN(); diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy_backward.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy_backward.pass.cpp index 928903de1ade2..445c7718e1111 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy_backward.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy_backward.pass.cpp @@ -15,6 +15,7 @@ #include #include +#include #include "test_macros.h" #include "test_iterators.h" @@ -36,47 +37,63 @@ class Derived : public PaddedBase { }; template -TEST_CONSTEXPR_CXX20 void -test_copy_backward() -{ +TEST_CONSTEXPR_CXX20 void test_copy_backward() { { const unsigned N = 1000; - int ia[N] = {}; + int ia[N] = {}; for (unsigned i = 0; i < N; ++i) - ia[i] = i; + ia[i] = i; int ib[N] = {0}; - OutIter r = std::copy_backward(InIter(ia), InIter(ia+N), OutIter(ib+N)); + OutIter r = std::copy_backward(InIter(ia), InIter(ia + N), OutIter(ib + N)); assert(base(r) == ib); for (unsigned i = 0; i < N; ++i) - assert(ia[i] == ib[i]); + assert(ia[i] == ib[i]); } } -TEST_CONSTEXPR_CXX20 bool -test() -{ - test_copy_backward, bidirectional_iterator >(); - test_copy_backward, random_access_iterator >(); - test_copy_backward, int*>(); +TEST_CONSTEXPR_CXX20 bool test_vector_bool(std::size_t N) { + std::vector in(N, false); + for (std::size_t i = 0; i < N; i += 2) + in[i] = true; - test_copy_backward, bidirectional_iterator >(); - test_copy_backward, random_access_iterator >(); - test_copy_backward, int*>(); + { // Test copy_backward with aligned bytes + std::vector out(N); + std::copy_backward(in.begin(), in.end(), out.end()); + assert(in == out); + } + { // Test copy_backward with unaligned bytes + std::vector out(N + 8); + std::copy_backward(in.begin(), in.end(), out.end() - 4); + for (std::size_t i = 0; i < N; ++i) + assert(out[i + 4] == in[i]); + } + + return true; +}; - test_copy_backward >(); - test_copy_backward >(); - test_copy_backward(); +TEST_CONSTEXPR_CXX20 bool test() { + test_copy_backward, bidirectional_iterator >(); + test_copy_backward, random_access_iterator >(); + test_copy_backward, int*>(); + + test_copy_backward, bidirectional_iterator >(); + test_copy_backward, random_access_iterator >(); + test_copy_backward, int*>(); + + test_copy_backward >(); + test_copy_backward >(); + test_copy_backward(); #if TEST_STD_VER > 17 - test_copy_backward, bidirectional_iterator>(); - test_copy_backward, random_access_iterator>(); - test_copy_backward, int*>(); - - test_copy_backward, contiguous_iterator>(); - test_copy_backward, contiguous_iterator>(); - test_copy_backward, contiguous_iterator>(); - test_copy_backward>(); + test_copy_backward, bidirectional_iterator>(); + test_copy_backward, random_access_iterator>(); + test_copy_backward, int*>(); + + test_copy_backward, contiguous_iterator>(); + test_copy_backward, contiguous_iterator>(); + test_copy_backward, contiguous_iterator>(); + test_copy_backward>(); #endif { // Make sure that padding bits aren't copied @@ -96,15 +113,24 @@ test() assert(std::equal(a, a + 10, expected)); } - return true; + { // Test vector::iterator optimization + assert(test_vector_bool(8)); + assert(test_vector_bool(19)); + assert(test_vector_bool(32)); + assert(test_vector_bool(49)); + assert(test_vector_bool(64)); + assert(test_vector_bool(199)); + assert(test_vector_bool(256)); + } + + return true; } -int main(int, char**) -{ - test(); +int main(int, char**) { + test(); #if TEST_STD_VER > 17 - static_assert(test()); + static_assert(test()); #endif return 0; diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_backward.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_backward.pass.cpp index 343447446ab2d..a7fa3db23e6ba 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_backward.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_backward.pass.cpp @@ -29,6 +29,7 @@ #include "almost_satisfies_types.h" #include "test_iterators.h" +#include "test_macros.h" template > concept HasCopyBackwardIt = requires(In in, Sent sent, Out out) { std::ranges::copy_backward(in, sent, out); }; @@ -61,16 +62,16 @@ template constexpr void test_iterators() { { // simple test { - std::array in {1, 2, 3, 4}; + std::array in{1, 2, 3, 4}; std::array out; std::same_as> auto ret = - std::ranges::copy_backward(In(in.data()), Sent(In(in.data() + in.size())), Out(out.data() + out.size())); + std::ranges::copy_backward(In(in.data()), Sent(In(in.data() + in.size())), Out(out.data() + out.size())); assert(in == out); assert(base(ret.in) == in.data() + in.size()); assert(base(ret.out) == out.data()); } { - std::array in {1, 2, 3, 4}; + std::array in{1, 2, 3, 4}; std::array out; auto range = std::ranges::subrange(In(in.data()), Sent(In(in.data() + in.size()))); std::same_as> auto ret = @@ -94,7 +95,7 @@ constexpr void test_iterators() { std::array in; std::array out; auto range = std::ranges::subrange(In(in.data()), Sent(In(in.data() + in.size()))); - auto ret = std::ranges::copy_backward(range, Out(out.data())); + auto ret = std::ranges::copy_backward(range, Out(out.data())); assert(base(ret.in) == in.data() + in.size()); assert(base(ret.out) == out.data()); } @@ -104,16 +105,16 @@ constexpr void test_iterators() { template constexpr void test_containers() { { - InContainer in {1, 2, 3, 4}; + InContainer in{1, 2, 3, 4}; OutContainer out(4); std::same_as> auto ret = - std::ranges::copy_backward(In(in.begin()), Sent(In(in.end())), Out(out.end())); + std::ranges::copy_backward(In(in.begin()), Sent(In(in.end())), Out(out.end())); assert(std::ranges::equal(in, out)); assert(base(ret.in) == in.end()); assert(base(ret.out) == out.begin()); } { - InContainer in {1, 2, 3, 4}; + InContainer in{1, 2, 3, 4}; OutContainer out(4); auto range = std::ranges::subrange(In(in.begin()), Sent(In(in.end()))); std::same_as> auto ret = std::ranges::copy_backward(range, Out(out.end())); @@ -125,13 +126,12 @@ constexpr void test_containers() { template constexpr void test_join_view() { - auto to_subranges = std::views::transform([](auto& vec) { - return std::ranges::subrange(Iter(vec.begin()), Sent(Iter(vec.end()))); - }); + auto to_subranges = + std::views::transform([](auto& vec) { return std::ranges::subrange(Iter(vec.begin()), Sent(Iter(vec.end()))); }); { // segmented -> contiguous std::vector> vectors = {}; - auto range = vectors | to_subranges; + auto range = vectors | to_subranges; std::vector> subrange_vector(range.begin(), range.end()); std::array arr; @@ -140,7 +140,7 @@ constexpr void test_join_view() { } { // segmented -> contiguous std::vector> vectors = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10}, {}}; - auto range = vectors | to_subranges; + auto range = vectors | to_subranges; std::vector> subrange_vector(range.begin(), range.end()); std::array arr; @@ -149,7 +149,7 @@ constexpr void test_join_view() { } { // contiguous -> segmented std::vector> vectors = {{0, 0, 0, 0}, {0, 0}, {0, 0, 0, 0}, {}}; - auto range = vectors | to_subranges; + auto range = vectors | to_subranges; std::vector> subrange_vector(range.begin(), range.end()); std::array arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; @@ -158,10 +158,10 @@ constexpr void test_join_view() { } { // segmented -> segmented std::vector> vectors = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10}, {}}; - auto range1 = vectors | to_subranges; + auto range1 = vectors | to_subranges; std::vector> subrange_vector(range1.begin(), range1.end()); std::vector> to_vectors = {{0, 0, 0, 0}, {0, 0, 0, 0}, {}, {0, 0}}; - auto range2 = to_vectors | to_subranges; + auto range2 = to_vectors | to_subranges; std::vector> to_subrange_vector(range2.begin(), range2.end()); std::ranges::copy_backward(subrange_vector | std::views::join, (to_subrange_vector | std::views::join).end()); @@ -224,6 +224,30 @@ constexpr void test_proxy_in_iterators() { test_sentinels(); } +#if TEST_STD_VER >= 23 + +constexpr bool test_vector_bool(std::size_t N) { + std::vector in(N, false); + for (std::size_t i = 0; i < N; i += 2) + in[i] = true; + + { // Test copy_backward with aligned bytes + std::vector out(N); + std::ranges::copy_backward(in, out.end()); + assert(in == out); + } + { // Test copy_backward with unaligned bytes + std::vector out(N + 8); + std::ranges::copy_backward(in, out.end() - 4); + for (std::size_t i = 0; i < N; ++i) + assert(out[i + 4] == in[i]); + } + + return true; +}; + +#endif + constexpr bool test() { test_in_iterators(); test_in_iterators(); @@ -237,13 +261,13 @@ constexpr bool test() { { // check that ranges::dangling is returned std::array out; std::same_as> auto ret = - std::ranges::copy_backward(std::array {1, 2, 3, 4}, out.data() + out.size()); + std::ranges::copy_backward(std::array{1, 2, 3, 4}, out.data() + out.size()); assert(ret.out == out.data()); assert((out == std::array{1, 2, 3, 4})); } { // check that an iterator is returned with a borrowing range - std::array in {1, 2, 3, 4}; + std::array in{1, 2, 3, 4}; std::array out; std::same_as::iterator, int*>> auto ret = std::ranges::copy_backward(std::views::all(in), out.data() + out.size()); @@ -254,8 +278,8 @@ constexpr bool test() { { // check that every element is copied exactly once struct CopyOnce { - bool copied = false; - constexpr CopyOnce() = default; + bool copied = false; + constexpr CopyOnce() = default; constexpr CopyOnce(const CopyOnce& other) = delete; constexpr CopyOnce& operator=(const CopyOnce& other) { assert(!other.copied); @@ -264,16 +288,16 @@ constexpr bool test() { } }; { - std::array in {}; - std::array out {}; + std::array in{}; + std::array out{}; auto ret = std::ranges::copy_backward(in.begin(), in.end(), out.end()); assert(ret.in == in.end()); assert(ret.out == out.begin()); assert(std::all_of(out.begin(), out.end(), [](const auto& e) { return e.copied; })); } { - std::array in {}; - std::array out {}; + std::array in{}; + std::array out{}; auto ret = std::ranges::copy_backward(in, out.end()); assert(ret.in == in.end()); assert(ret.out == out.begin()); @@ -284,8 +308,8 @@ constexpr bool test() { { // check that the range is copied backwards struct OnlyBackwardsCopyable { OnlyBackwardsCopyable* next = nullptr; - bool canCopy = false; - OnlyBackwardsCopyable() = default; + bool canCopy = false; + OnlyBackwardsCopyable() = default; constexpr OnlyBackwardsCopyable& operator=(const OnlyBackwardsCopyable&) { assert(canCopy); if (next != nullptr) @@ -294,12 +318,12 @@ constexpr bool test() { } }; { - std::array in {}; - std::array out {}; - out[1].next = &out[0]; - out[2].next = &out[1]; + std::array in{}; + std::array out{}; + out[1].next = &out[0]; + out[2].next = &out[1]; out[2].canCopy = true; - auto ret = std::ranges::copy_backward(in, out.end()); + auto ret = std::ranges::copy_backward(in, out.end()); assert(ret.in == in.end()); assert(ret.out == out.begin()); assert(out[0].canCopy); @@ -307,12 +331,12 @@ constexpr bool test() { assert(out[2].canCopy); } { - std::array in {}; - std::array out {}; - out[1].next = &out[0]; - out[2].next = &out[1]; + std::array in{}; + std::array out{}; + out[1].next = &out[0]; + out[2].next = &out[1]; out[2].canCopy = true; - auto ret = std::ranges::copy_backward(in.begin(), in.end(), out.end()); + auto ret = std::ranges::copy_backward(in.begin(), in.end(), out.end()); assert(ret.in == in.end()); assert(ret.out == out.begin()); assert(out[0].canCopy); @@ -321,6 +345,18 @@ constexpr bool test() { } } +#if TEST_STD_VER >= 23 + { // Test vector::iterator optimization + assert(test_vector_bool(8)); + assert(test_vector_bool(19)); + assert(test_vector_bool(32)); + assert(test_vector_bool(49)); + assert(test_vector_bool(64)); + assert(test_vector_bool(199)); + assert(test_vector_bool(256)); + } +#endif + return true; } From 439bef9751e1769ccd5a7b4ca4127144912cacfc Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Thu, 30 Jan 2025 15:02:34 -0500 Subject: [PATCH 14/34] [libc++] Refactor the sequence container benchmarks (#119763) Rewrite the sequence container benchmarks to only rely on the actual operations specified in SequenceContainer requirements and add benchmarks for std::list, which is also considered a sequence container. One of the major goals of this refactoring is also to make these container benchmarks run faster so that they can be run more frequently. The existing benchmarks have the significant problem that they take so long to run that they must basically be run overnight. This patch reduces the size of inputs such that the rewritten benchmarks each take at most a minute to run. This patch doesn't touch the string benchmarks, which were not using the generic container benchmark functions previously. --- libcxx/test/benchmarks/GenerateInput.h | 28 + libcxx/test/benchmarks/Utilities.h | 37 -- .../algorithms.partition_point.bench.cpp | 2 +- .../algorithms/lower_bound.bench.cpp | 2 +- .../benchmarks/algorithms/make_heap.bench.cpp | 2 +- .../make_heap_then_sort_heap.bench.cpp | 2 +- .../benchmarks/algorithms/pop_heap.bench.cpp | 2 +- .../algorithms/pstl.stable_sort.bench.cpp | 2 +- .../benchmarks/algorithms/push_heap.bench.cpp | 2 +- .../algorithms/set_intersection.bench.cpp | 2 +- .../test/benchmarks/algorithms/sort.bench.cpp | 2 +- .../benchmarks/algorithms/sort_heap.bench.cpp | 2 +- .../algorithms/stable_sort.bench.cpp | 2 +- .../containers/ContainerBenchmarks.h | 332 ---------- .../containers/container_benchmarks.h | 609 ++++++++++++++++++ .../benchmarks/containers/deque.bench.cpp | 50 +- .../test/benchmarks/containers/list.bench.cpp | 25 + .../benchmarks/containers/string.bench.cpp | 2 +- ...ions.bench.cpp => unordered_set.bench.cpp} | 4 +- .../benchmarks/containers/vector.bench.cpp | 25 + .../containers/vector_operations.bench.cpp | 108 ---- libcxx/test/benchmarks/filesystem.bench.cpp | 2 +- libcxx/test/benchmarks/hash.bench.cpp | 2 +- .../test/benchmarks/variant_visit_1.bench.cpp | 2 +- .../test/benchmarks/variant_visit_2.bench.cpp | 2 +- .../test/benchmarks/variant_visit_3.bench.cpp | 2 +- 26 files changed, 716 insertions(+), 536 deletions(-) delete mode 100644 libcxx/test/benchmarks/Utilities.h delete mode 100644 libcxx/test/benchmarks/containers/ContainerBenchmarks.h create mode 100644 libcxx/test/benchmarks/containers/container_benchmarks.h create mode 100644 libcxx/test/benchmarks/containers/list.bench.cpp rename libcxx/test/benchmarks/containers/{unordered_set_operations.bench.cpp => unordered_set.bench.cpp} (99%) create mode 100644 libcxx/test/benchmarks/containers/vector.bench.cpp delete mode 100644 libcxx/test/benchmarks/containers/vector_operations.bench.cpp diff --git a/libcxx/test/benchmarks/GenerateInput.h b/libcxx/test/benchmarks/GenerateInput.h index 6d5c5167e91ed..081631a32b21d 100644 --- a/libcxx/test/benchmarks/GenerateInput.h +++ b/libcxx/test/benchmarks/GenerateInput.h @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -171,4 +172,31 @@ inline std::vector getRandomCStringInputs(std::size_t N) { return cinputs; } +template +struct Generate { + // When the contents don't matter + static T arbitrary(); + + // Prefer a cheap-to-construct element if possible + static T cheap(); + + // Prefer an expensive-to-construct element if possible + static T expensive(); +}; + +template + requires std::integral +struct Generate { + static T arbitrary() { return 42; } + static T cheap() { return 42; } + static T expensive() { return 42; } +}; + +template <> +struct Generate { + static std::string arbitrary() { return "hello world"; } + static std::string cheap() { return "small"; } + static std::string expensive() { return std::string(256, 'x'); } +}; + #endif // BENCHMARK_GENERATE_INPUT_H diff --git a/libcxx/test/benchmarks/Utilities.h b/libcxx/test/benchmarks/Utilities.h deleted file mode 100644 index fed16ba51f995..0000000000000 --- a/libcxx/test/benchmarks/Utilities.h +++ /dev/null @@ -1,37 +0,0 @@ -// -*- C++ -*- -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef BENCHMARK_UTILITIES_H -#define BENCHMARK_UTILITIES_H - -#include -#include - -#include "benchmark/benchmark.h" - -namespace UtilitiesInternal { -template -auto HaveDataImpl(int) -> decltype((std::declval().data(), std::true_type{})); -template -auto HaveDataImpl(long) -> std::false_type; -template -using HasData = decltype(HaveDataImpl(0)); -} // namespace UtilitiesInternal - -template ::value>* = nullptr> -void DoNotOptimizeData(Container& c) { - benchmark::DoNotOptimize(c.data()); -} - -template ::value>* = nullptr> -void DoNotOptimizeData(Container& c) { - benchmark::DoNotOptimize(&c); -} - -#endif // BENCHMARK_UTILITIES_H diff --git a/libcxx/test/benchmarks/algorithms/algorithms.partition_point.bench.cpp b/libcxx/test/benchmarks/algorithms/algorithms.partition_point.bench.cpp index 0777acbafb5cc..e0bd7e36f78ad 100644 --- a/libcxx/test/benchmarks/algorithms/algorithms.partition_point.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/algorithms.partition_point.bench.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14, c++17 #include #include diff --git a/libcxx/test/benchmarks/algorithms/lower_bound.bench.cpp b/libcxx/test/benchmarks/algorithms/lower_bound.bench.cpp index d9d57969df67a..31fb3597241fc 100644 --- a/libcxx/test/benchmarks/algorithms/lower_bound.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/lower_bound.bench.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14, c++17 #include #include diff --git a/libcxx/test/benchmarks/algorithms/make_heap.bench.cpp b/libcxx/test/benchmarks/algorithms/make_heap.bench.cpp index b7320e17c3e50..64d559620c512 100644 --- a/libcxx/test/benchmarks/algorithms/make_heap.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/make_heap.bench.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14, c++17 #include diff --git a/libcxx/test/benchmarks/algorithms/make_heap_then_sort_heap.bench.cpp b/libcxx/test/benchmarks/algorithms/make_heap_then_sort_heap.bench.cpp index 5991d2846aee4..c6dc136be3ac4 100644 --- a/libcxx/test/benchmarks/algorithms/make_heap_then_sort_heap.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/make_heap_then_sort_heap.bench.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14, c++17 #include diff --git a/libcxx/test/benchmarks/algorithms/pop_heap.bench.cpp b/libcxx/test/benchmarks/algorithms/pop_heap.bench.cpp index 5fef52284239d..e4b96a0ae48c7 100644 --- a/libcxx/test/benchmarks/algorithms/pop_heap.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/pop_heap.bench.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14, c++17 #include diff --git a/libcxx/test/benchmarks/algorithms/pstl.stable_sort.bench.cpp b/libcxx/test/benchmarks/algorithms/pstl.stable_sort.bench.cpp index 10254ac12cf56..a385185ec7fe5 100644 --- a/libcxx/test/benchmarks/algorithms/pstl.stable_sort.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/pstl.stable_sort.bench.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14, c++17 // UNSUPPORTED: libcpp-has-no-incomplete-pstl #include diff --git a/libcxx/test/benchmarks/algorithms/push_heap.bench.cpp b/libcxx/test/benchmarks/algorithms/push_heap.bench.cpp index 89d8122bd1dbe..7dfa0285348bd 100644 --- a/libcxx/test/benchmarks/algorithms/push_heap.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/push_heap.bench.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14, c++17 #include diff --git a/libcxx/test/benchmarks/algorithms/set_intersection.bench.cpp b/libcxx/test/benchmarks/algorithms/set_intersection.bench.cpp index 9bde4bb29dc22..40292179781ee 100644 --- a/libcxx/test/benchmarks/algorithms/set_intersection.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/set_intersection.bench.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14, c++17 #include #include diff --git a/libcxx/test/benchmarks/algorithms/sort.bench.cpp b/libcxx/test/benchmarks/algorithms/sort.bench.cpp index 899272e34795f..7f3ce6ff7a07e 100644 --- a/libcxx/test/benchmarks/algorithms/sort.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/sort.bench.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14, c++17 #include diff --git a/libcxx/test/benchmarks/algorithms/sort_heap.bench.cpp b/libcxx/test/benchmarks/algorithms/sort_heap.bench.cpp index ee4b6bfc7387b..1ce9f1a6df9af 100644 --- a/libcxx/test/benchmarks/algorithms/sort_heap.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/sort_heap.bench.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14, c++17 #include diff --git a/libcxx/test/benchmarks/algorithms/stable_sort.bench.cpp b/libcxx/test/benchmarks/algorithms/stable_sort.bench.cpp index c68f73838c319..26e8de935f5c5 100644 --- a/libcxx/test/benchmarks/algorithms/stable_sort.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/stable_sort.bench.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14, c++17 #include diff --git a/libcxx/test/benchmarks/containers/ContainerBenchmarks.h b/libcxx/test/benchmarks/containers/ContainerBenchmarks.h deleted file mode 100644 index 5fc8981619672..0000000000000 --- a/libcxx/test/benchmarks/containers/ContainerBenchmarks.h +++ /dev/null @@ -1,332 +0,0 @@ -// -*- C++ -*- -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef BENCHMARK_CONTAINER_BENCHMARKS_H -#define BENCHMARK_CONTAINER_BENCHMARKS_H - -#include -#include -#include - -#include "benchmark/benchmark.h" -#include "../Utilities.h" -#include "test_iterators.h" - -namespace ContainerBenchmarks { - -template -void BM_ConstructSize(benchmark::State& st, Container) { - auto size = st.range(0); - for (auto _ : st) { - Container c(size); - DoNotOptimizeData(c); - } -} - -template -void BM_CopyConstruct(benchmark::State& st, Container) { - auto size = st.range(0); - Container c(size); - for (auto _ : st) { - auto v = c; - DoNotOptimizeData(v); - } -} - -template -void BM_Assignment(benchmark::State& st, Container) { - auto size = st.range(0); - Container c1; - Container c2(size); - for (auto _ : st) { - c1 = c2; - DoNotOptimizeData(c1); - DoNotOptimizeData(c2); - } -} - -template -void BM_AssignInputIterIter(benchmark::State& st, Container c, GenInputs gen) { - auto v = gen(1, sz...); - c.resize(st.range(0), v[0]); - auto in = gen(st.range(1), sz...); - benchmark::DoNotOptimize(&in); - benchmark::DoNotOptimize(&c); - for (auto _ : st) { - c.assign(cpp17_input_iterator(in.begin()), cpp17_input_iterator(in.end())); - benchmark::ClobberMemory(); - } -} - -template -void BM_ConstructSizeValue(benchmark::State& st, Container, typename Container::value_type const& val) { - const auto size = st.range(0); - for (auto _ : st) { - Container c(size, val); - DoNotOptimizeData(c); - } -} - -template -void BM_ConstructIterIter(benchmark::State& st, Container, GenInputs gen) { - auto in = gen(st.range(0)); - const auto begin = in.begin(); - const auto end = in.end(); - benchmark::DoNotOptimize(&in); - while (st.KeepRunning()) { - Container c(begin, end); - DoNotOptimizeData(c); - } -} - -template -void BM_ConstructFromRange(benchmark::State& st, Container, GenInputs gen) { - auto in = gen(st.range(0)); - benchmark::DoNotOptimize(&in); - while (st.KeepRunning()) { - Container c(std::from_range, in); - DoNotOptimizeData(c); - } -} - -template -void BM_Pushback_no_grow(benchmark::State& state, Container c) { - int count = state.range(0); - c.reserve(count); - while (state.KeepRunningBatch(count)) { - c.clear(); - for (int i = 0; i != count; ++i) { - c.push_back(i); - } - benchmark::DoNotOptimize(c.data()); - } -} - -template -void BM_InsertValue(benchmark::State& st, Container c, GenInputs gen) { - auto in = gen(st.range(0)); - const auto end = in.end(); - while (st.KeepRunning()) { - c.clear(); - for (auto it = in.begin(); it != end; ++it) { - benchmark::DoNotOptimize(&(*c.insert(*it).first)); - } - benchmark::ClobberMemory(); - } -} - -template -void BM_InsertValueRehash(benchmark::State& st, Container c, GenInputs gen) { - auto in = gen(st.range(0)); - const auto end = in.end(); - while (st.KeepRunning()) { - c.clear(); - c.rehash(16); - for (auto it = in.begin(); it != end; ++it) { - benchmark::DoNotOptimize(&(*c.insert(*it).first)); - } - benchmark::ClobberMemory(); - } -} - -template -void BM_Insert_InputIterIter_NoRealloc(benchmark::State& st, Container c, GenInputs gen) { - auto in = gen(st.range(0)); - DoNotOptimizeData(in); - const auto size = c.size(); - const auto beg = cpp17_input_iterator(in.begin()); - const auto end = cpp17_input_iterator(in.end()); - c.reserve(size + in.size()); // force no reallocation - for (auto _ : st) { - benchmark::DoNotOptimize(&(*c.insert(c.begin(), beg, end))); - st.PauseTiming(); - c.erase(c.begin() + size, c.end()); // avoid the container to grow indefinitely - st.ResumeTiming(); - DoNotOptimizeData(c); - benchmark::ClobberMemory(); - } -} - -template -void BM_Insert_InputIterIter_Realloc_HalfFilled(benchmark::State& st, Container, GenInputs gen) { - const auto size = st.range(0); - Container a = gen(size); - Container in = gen(size + 10); - DoNotOptimizeData(a); - DoNotOptimizeData(in); - const auto beg = cpp17_input_iterator(in.begin()); - const auto end = cpp17_input_iterator(in.end()); - for (auto _ : st) { - st.PauseTiming(); - Container c; - c.reserve(size * 2); // Reallocation with half-filled container - c = a; - st.ResumeTiming(); - benchmark::DoNotOptimize(&(*c.insert(c.begin(), beg, end))); - DoNotOptimizeData(c); - benchmark::ClobberMemory(); - } -} - -template -void BM_Insert_InputIterIter_Realloc_NearFull(benchmark::State& st, Container, GenInputs gen) { - const auto size = st.range(0); - Container a = gen(size); - Container in = gen(10); - DoNotOptimizeData(a); - DoNotOptimizeData(in); - const auto beg = cpp17_input_iterator(in.begin()); - const auto end = cpp17_input_iterator(in.end()); - for (auto _ : st) { - st.PauseTiming(); - Container c; - c.reserve(size + 5); // Reallocation almost-full container - c = a; - st.ResumeTiming(); - benchmark::DoNotOptimize(&(*c.insert(c.begin(), beg, end))); - DoNotOptimizeData(c); - benchmark::ClobberMemory(); - } -} - -template -void BM_InsertDuplicate(benchmark::State& st, Container c, GenInputs gen) { - auto in = gen(st.range(0)); - const auto end = in.end(); - c.insert(in.begin(), in.end()); - benchmark::DoNotOptimize(&c); - benchmark::DoNotOptimize(&in); - while (st.KeepRunning()) { - for (auto it = in.begin(); it != end; ++it) { - benchmark::DoNotOptimize(&(*c.insert(*it).first)); - } - benchmark::ClobberMemory(); - } -} - -template -void BM_EmplaceDuplicate(benchmark::State& st, Container c, GenInputs gen) { - auto in = gen(st.range(0)); - const auto end = in.end(); - c.insert(in.begin(), in.end()); - benchmark::DoNotOptimize(&c); - benchmark::DoNotOptimize(&in); - while (st.KeepRunning()) { - for (auto it = in.begin(); it != end; ++it) { - benchmark::DoNotOptimize(&(*c.emplace(*it).first)); - } - benchmark::ClobberMemory(); - } -} - -template -void BM_erase_iter_in_middle(benchmark::State& st, Container, GenInputs gen) { - auto in = gen(st.range(0)); - Container c(in.begin(), in.end()); - assert(c.size() > 2); - for (auto _ : st) { - auto mid = std::next(c.begin(), c.size() / 2); - auto tmp = *mid; - auto result = c.erase(mid); // erase an element in the middle - benchmark::DoNotOptimize(result); - c.push_back(std::move(tmp)); // and then push it back at the end to avoid needing a new container - } -} - -template -void BM_erase_iter_at_start(benchmark::State& st, Container, GenInputs gen) { - auto in = gen(st.range(0)); - Container c(in.begin(), in.end()); - assert(c.size() > 2); - for (auto _ : st) { - auto it = c.begin(); - auto tmp = *it; - auto result = c.erase(it); // erase the first element - benchmark::DoNotOptimize(result); - c.push_back(std::move(tmp)); // and then push it back at the end to avoid needing a new container - } -} - -template -void BM_Find(benchmark::State& st, Container c, GenInputs gen) { - auto in = gen(st.range(0)); - c.insert(in.begin(), in.end()); - benchmark::DoNotOptimize(&(*c.begin())); - const auto end = in.data() + in.size(); - while (st.KeepRunning()) { - for (auto it = in.data(); it != end; ++it) { - benchmark::DoNotOptimize(&(*c.find(*it))); - } - benchmark::ClobberMemory(); - } -} - -template -void BM_FindRehash(benchmark::State& st, Container c, GenInputs gen) { - c.rehash(8); - auto in = gen(st.range(0)); - c.insert(in.begin(), in.end()); - benchmark::DoNotOptimize(&(*c.begin())); - const auto end = in.data() + in.size(); - while (st.KeepRunning()) { - for (auto it = in.data(); it != end; ++it) { - benchmark::DoNotOptimize(&(*c.find(*it))); - } - benchmark::ClobberMemory(); - } -} - -template -void BM_Rehash(benchmark::State& st, Container c, GenInputs gen) { - auto in = gen(st.range(0)); - c.max_load_factor(3.0); - c.insert(in.begin(), in.end()); - benchmark::DoNotOptimize(c); - const auto bucket_count = c.bucket_count(); - while (st.KeepRunning()) { - c.rehash(bucket_count + 1); - c.rehash(bucket_count); - benchmark::ClobberMemory(); - } -} - -template -void BM_Compare_same_container(benchmark::State& st, Container, GenInputs gen) { - auto in = gen(st.range(0)); - Container c1(in.begin(), in.end()); - Container c2 = c1; - - benchmark::DoNotOptimize(&(*c1.begin())); - benchmark::DoNotOptimize(&(*c2.begin())); - while (st.KeepRunning()) { - bool res = c1 == c2; - benchmark::DoNotOptimize(&res); - benchmark::ClobberMemory(); - } -} - -template -void BM_Compare_different_containers(benchmark::State& st, Container, GenInputs gen) { - auto in1 = gen(st.range(0)); - auto in2 = gen(st.range(0)); - Container c1(in1.begin(), in1.end()); - Container c2(in2.begin(), in2.end()); - - benchmark::DoNotOptimize(&(*c1.begin())); - benchmark::DoNotOptimize(&(*c2.begin())); - while (st.KeepRunning()) { - bool res = c1 == c2; - benchmark::DoNotOptimize(&res); - benchmark::ClobberMemory(); - } -} - -} // namespace ContainerBenchmarks - -#endif // BENCHMARK_CONTAINER_BENCHMARKS_H diff --git a/libcxx/test/benchmarks/containers/container_benchmarks.h b/libcxx/test/benchmarks/containers/container_benchmarks.h new file mode 100644 index 0000000000000..e24bd767177e8 --- /dev/null +++ b/libcxx/test/benchmarks/containers/container_benchmarks.h @@ -0,0 +1,609 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef TEST_BENCHMARKS_CONTAINERS_CONTAINER_BENCHMARKS_H +#define TEST_BENCHMARKS_CONTAINERS_CONTAINER_BENCHMARKS_H + +#include +#include +#include +#include // for std::from_range +#include +#include +#include + +#include "benchmark/benchmark.h" +#include "test_iterators.h" +#include "test_macros.h" +#include "../GenerateInput.h" + +namespace ContainerBenchmarks { + +template +void DoNotOptimizeData(Container& c) { + if constexpr (requires { c.data(); }) { + benchmark::DoNotOptimize(c.data()); + } else { + benchmark::DoNotOptimize(&c); + } +} + +// +// Sequence container operations +// +template +void BM_ctor_size(benchmark::State& st) { + auto size = st.range(0); + + for (auto _ : st) { + Container c(size); // we assume the destructor doesn't dominate the benchmark + DoNotOptimizeData(c); + } +} + +template +void BM_ctor_size_value(benchmark::State& st, Generator gen) { + using ValueType = typename Container::value_type; + const auto size = st.range(0); + ValueType value = gen(); + benchmark::DoNotOptimize(value); + + for (auto _ : st) { + Container c(size, value); // we assume the destructor doesn't dominate the benchmark + DoNotOptimizeData(c); + } +} + +template +void BM_ctor_iter_iter(benchmark::State& st, Generator gen) { + using ValueType = typename Container::value_type; + const auto size = st.range(0); + std::vector in; + std::generate_n(std::back_inserter(in), size, gen); + const auto begin = in.begin(); + const auto end = in.end(); + benchmark::DoNotOptimize(in); + + for (auto _ : st) { + Container c(begin, end); // we assume the destructor doesn't dominate the benchmark + DoNotOptimizeData(c); + } +} + +#if TEST_STD_VER >= 23 +template +void BM_ctor_from_range(benchmark::State& st, Generator gen) { + using ValueType = typename Container::value_type; + const auto size = st.range(0); + std::vector in; + std::generate_n(std::back_inserter(in), size, gen); + benchmark::DoNotOptimize(in); + + for (auto _ : st) { + Container c(std::from_range, in); // we assume the destructor doesn't dominate the benchmark + DoNotOptimizeData(c); + } +} +#endif + +template +void BM_ctor_copy(benchmark::State& st, Generator gen) { + auto size = st.range(0); + Container in; + std::generate_n(std::back_inserter(in), size, gen); + DoNotOptimizeData(in); + + for (auto _ : st) { + Container c(in); // we assume the destructor doesn't dominate the benchmark + DoNotOptimizeData(c); + DoNotOptimizeData(in); + } +} + +template +void BM_assignment(benchmark::State& st, Generator gen) { + auto size = st.range(0); + Container in1, in2; + std::generate_n(std::back_inserter(in1), size, gen); + std::generate_n(std::back_inserter(in2), size, gen); + DoNotOptimizeData(in1); + DoNotOptimizeData(in2); + + // Assign from one of two containers in succession to avoid + // hitting a self-assignment corner-case + Container c(in1); + bool toggle = false; + for (auto _ : st) { + c = toggle ? in1 : in2; + toggle = !toggle; + DoNotOptimizeData(c); + DoNotOptimizeData(in1); + DoNotOptimizeData(in2); + } +} + +// Benchmark Container::assign(input-iter, input-iter) when the container already contains +// the same number of elements that we're assigning. The intent is to check whether the +// implementation basically creates a new container from scratch or manages to reuse the +// pre-existing storage. +template +void BM_assign_input_iter_full(benchmark::State& st, Generator gen) { + using ValueType = typename Container::value_type; + auto size = st.range(0); + std::vector in1, in2; + std::generate_n(std::back_inserter(in1), size, gen); + std::generate_n(std::back_inserter(in2), size, gen); + DoNotOptimizeData(in1); + DoNotOptimizeData(in2); + + Container c(in1.begin(), in1.end()); + bool toggle = false; + for (auto _ : st) { + std::vector& in = toggle ? in1 : in2; + auto first = in.data(); + auto last = in.data() + in.size(); + c.assign(cpp17_input_iterator(first), cpp17_input_iterator(last)); + toggle = !toggle; + DoNotOptimizeData(c); + } +} + +template +void BM_insert_begin(benchmark::State& st, Generator gen) { + using ValueType = typename Container::value_type; + const int size = st.range(0); + std::vector in; + std::generate_n(std::back_inserter(in), size, gen); + DoNotOptimizeData(in); + + Container c(in.begin(), in.end()); + DoNotOptimizeData(c); + + ValueType value = gen(); + benchmark::DoNotOptimize(value); + + for (auto _ : st) { + c.insert(c.begin(), value); + DoNotOptimizeData(c); + + c.erase(std::prev(c.end())); // avoid growing indefinitely + } +} + +template + requires std::random_access_iterator +void BM_insert_middle(benchmark::State& st, Generator gen) { + using ValueType = typename Container::value_type; + const int size = st.range(0); + std::vector in; + std::generate_n(std::back_inserter(in), size, gen); + DoNotOptimizeData(in); + + Container c(in.begin(), in.end()); + DoNotOptimizeData(c); + + ValueType value = gen(); + benchmark::DoNotOptimize(value); + + for (auto _ : st) { + auto mid = c.begin() + (size / 2); // requires random-access iterators in order to make sense + c.insert(mid, value); + DoNotOptimizeData(c); + + c.erase(c.end() - 1); // avoid growing indefinitely + } +} + +// Insert at the start of a vector in a scenario where the vector already +// has enough capacity to hold all the elements we are inserting. +template +void BM_insert_begin_input_iter_with_reserve_no_realloc(benchmark::State& st, Generator gen) { + using ValueType = typename Container::value_type; + const int size = st.range(0); + std::vector in; + std::generate_n(std::back_inserter(in), size, gen); + DoNotOptimizeData(in); + auto first = in.data(); + auto last = in.data() + in.size(); + + const int small = 100; // arbitrary + Container c; + c.reserve(size + small); // ensure no reallocation + std::generate_n(std::back_inserter(c), small, gen); + + for (auto _ : st) { + c.insert(c.begin(), cpp17_input_iterator(first), cpp17_input_iterator(last)); + DoNotOptimizeData(c); + + st.PauseTiming(); + c.erase(c.begin() + small, c.end()); // avoid growing indefinitely + st.ResumeTiming(); + } +} + +// Insert at the start of a vector in a scenario where the vector already +// has almost enough capacity to hold all the elements we are inserting, +// but does need to reallocate. +template +void BM_insert_begin_input_iter_with_reserve_almost_no_realloc(benchmark::State& st, Generator gen) { + using ValueType = typename Container::value_type; + const int size = st.range(0); + std::vector in; + std::generate_n(std::back_inserter(in), size, gen); + DoNotOptimizeData(in); + auto first = in.data(); + auto last = in.data() + in.size(); + + const int overflow = size / 10; // 10% of elements won't fit in the vector when we insert + Container c; + for (auto _ : st) { + st.PauseTiming(); + c = Container(); + c.reserve(size); + std::generate_n(std::back_inserter(c), overflow, gen); + st.ResumeTiming(); + + c.insert(c.begin(), cpp17_input_iterator(first), cpp17_input_iterator(last)); + DoNotOptimizeData(c); + } +} + +// Insert at the start of a vector in a scenario where the vector can fit a few +// more elements, but needs to reallocate almost immediately to fit the remaining +// elements. +template +void BM_insert_begin_input_iter_with_reserve_near_full(benchmark::State& st, Generator gen) { + using ValueType = typename Container::value_type; + const int size = st.range(0); + std::vector in; + std::generate_n(std::back_inserter(in), size, gen); + DoNotOptimizeData(in); + auto first = in.data(); + auto last = in.data() + in.size(); + + const int overflow = 9 * (size / 10); // 90% of elements won't fit in the vector when we insert + Container c; + for (auto _ : st) { + st.PauseTiming(); + c = Container(); + c.reserve(size); + std::generate_n(std::back_inserter(c), overflow, gen); + st.ResumeTiming(); + + c.insert(c.begin(), cpp17_input_iterator(first), cpp17_input_iterator(last)); + DoNotOptimizeData(c); + } +} + +template +void BM_erase_begin(benchmark::State& st, Generator gen) { + using ValueType = typename Container::value_type; + const int size = st.range(0); + std::vector in; + std::generate_n(std::back_inserter(in), size, gen); + DoNotOptimizeData(in); + + Container c(in.begin(), in.end()); + DoNotOptimizeData(c); + + ValueType value = gen(); + benchmark::DoNotOptimize(value); + + for (auto _ : st) { + c.erase(c.begin()); + DoNotOptimizeData(c); + + c.insert(c.end(), value); // re-insert an element at the end to avoid needing a new container + } +} + +template + requires std::random_access_iterator +void BM_erase_middle(benchmark::State& st, Generator gen) { + using ValueType = typename Container::value_type; + const int size = st.range(0); + std::vector in; + std::generate_n(std::back_inserter(in), size, gen); + DoNotOptimizeData(in); + + Container c(in.begin(), in.end()); + DoNotOptimizeData(c); + + ValueType value = gen(); + benchmark::DoNotOptimize(value); + + for (auto _ : st) { + auto mid = c.begin() + (size / 2); + c.erase(mid); + DoNotOptimizeData(c); + + c.insert(c.end(), value); // re-insert an element at the end to avoid needing a new container + } +} + +template +void BM_push_back(benchmark::State& st, Generator gen) { + using ValueType = typename Container::value_type; + const int size = st.range(0); + std::vector in; + std::generate_n(std::back_inserter(in), size, gen); + DoNotOptimizeData(in); + + Container c; + DoNotOptimizeData(c); + while (st.KeepRunningBatch(size)) { + c.clear(); + for (int i = 0; i != size; ++i) { + c.push_back(in[i]); + } + DoNotOptimizeData(c); + } +} + +template +void BM_push_back_with_reserve(benchmark::State& st, Generator gen) { + using ValueType = typename Container::value_type; + const int size = st.range(0); + std::vector in; + std::generate_n(std::back_inserter(in), size, gen); + DoNotOptimizeData(in); + + Container c; + c.reserve(size); + DoNotOptimizeData(c); + while (st.KeepRunningBatch(size)) { + c.clear(); + for (int i = 0; i != size; ++i) { + c.push_back(in[i]); + } + DoNotOptimizeData(c); + } +} + +template +void sequence_container_benchmarks(std::string container) { + using ValueType = typename Container::value_type; + + using Generator = ValueType (*)(); + Generator cheap = [] { return Generate::cheap(); }; + Generator expensive = [] { return Generate::expensive(); }; + auto tostr = [&](Generator gen) { return gen == cheap ? " (cheap elements)" : " (expensive elements)"; }; + std::vector generators; + generators.push_back(cheap); + if constexpr (!std::is_integral_v) { + generators.push_back(expensive); + } + + // constructors + if constexpr (std::is_constructible_v) { + // not all containers provide this one + benchmark::RegisterBenchmark(container + "::ctor(size)", BM_ctor_size)->Arg(1024); + } + for (auto gen : generators) + benchmark::RegisterBenchmark(container + "::ctor(size, value_type)" + tostr(gen), [=](auto& st) { + BM_ctor_size_value(st, gen); + })->Arg(1024); + for (auto gen : generators) + benchmark::RegisterBenchmark(container + "::ctor(Iterator, Iterator)" + tostr(gen), [=](auto& st) { + BM_ctor_iter_iter(st, gen); + })->Arg(1024); +#if TEST_STD_VER >= 23 + for (auto gen : generators) + benchmark::RegisterBenchmark(container + "::ctor(Range)" + tostr(gen), [=](auto& st) { + BM_ctor_from_range(st, gen); + })->Arg(1024); +#endif + for (auto gen : generators) + benchmark::RegisterBenchmark(container + "::ctor(const&)" + tostr(gen), [=](auto& st) { + BM_ctor_copy(st, gen); + })->Arg(1024); + + // assignment + for (auto gen : generators) + benchmark::RegisterBenchmark(container + "::operator=(const&)" + tostr(gen), [=](auto& st) { + BM_assignment(st, gen); + })->Arg(1024); + for (auto gen : generators) + benchmark::RegisterBenchmark(container + "::assign(input-iter, input-iter) (full container)" + tostr(gen), + [=](auto& st) { BM_assign_input_iter_full(st, gen); }) + ->Arg(1024); + + // insert + for (auto gen : generators) + benchmark::RegisterBenchmark(container + "::insert(begin)" + tostr(gen), [=](auto& st) { + BM_insert_begin(st, gen); + })->Arg(1024); + if constexpr (std::random_access_iterator) { + for (auto gen : generators) + benchmark::RegisterBenchmark(container + "::insert(middle)" + tostr(gen), [=](auto& st) { + BM_insert_middle(st, gen); + })->Arg(1024); + } + if constexpr (requires(Container c) { c.reserve(0); }) { + for (auto gen : generators) + benchmark::RegisterBenchmark( + container + "::insert(begin, input-iter, input-iter) (no realloc)" + tostr(gen), + [=](auto& st) { BM_insert_begin_input_iter_with_reserve_no_realloc(st, gen); }) + ->Arg(1024); + for (auto gen : generators) + benchmark::RegisterBenchmark( + container + "::insert(begin, input-iter, input-iter) (half filled)" + tostr(gen), + [=](auto& st) { BM_insert_begin_input_iter_with_reserve_almost_no_realloc(st, gen); }) + ->Arg(1024); + for (auto gen : generators) + benchmark::RegisterBenchmark( + container + "::insert(begin, input-iter, input-iter) (near full)" + tostr(gen), + [=](auto& st) { BM_insert_begin_input_iter_with_reserve_near_full(st, gen); }) + ->Arg(1024); + } + + // erase + for (auto gen : generators) + benchmark::RegisterBenchmark(container + "::erase(begin)" + tostr(gen), [=](auto& st) { + BM_erase_begin(st, gen); + })->Arg(1024); + if constexpr (std::random_access_iterator) { + for (auto gen : generators) + benchmark::RegisterBenchmark(container + "::erase(middle)" + tostr(gen), [=](auto& st) { + BM_erase_middle(st, gen); + })->Arg(1024); + } + + // push_back (optional) + if constexpr (requires(Container c, ValueType v) { c.push_back(v); }) { + for (auto gen : generators) + benchmark::RegisterBenchmark(container + "::push_back()" + tostr(gen), [=](auto& st) { + BM_push_back(st, gen); + })->Arg(1024); + if constexpr (requires(Container c) { c.reserve(0); }) { + for (auto gen : generators) + benchmark::RegisterBenchmark(container + "::push_back() (with reserve)" + tostr(gen), [=](auto& st) { + BM_push_back_with_reserve(st, gen); + })->Arg(1024); + } + } +} + +// +// Misc operations +// +template +void BM_InsertValue(benchmark::State& st, Container c, GenInputs gen) { + auto in = gen(st.range(0)); + const auto end = in.end(); + while (st.KeepRunning()) { + c.clear(); + for (auto it = in.begin(); it != end; ++it) { + benchmark::DoNotOptimize(&(*c.insert(*it).first)); + } + benchmark::ClobberMemory(); + } +} + +template +void BM_InsertValueRehash(benchmark::State& st, Container c, GenInputs gen) { + auto in = gen(st.range(0)); + const auto end = in.end(); + while (st.KeepRunning()) { + c.clear(); + c.rehash(16); + for (auto it = in.begin(); it != end; ++it) { + benchmark::DoNotOptimize(&(*c.insert(*it).first)); + } + benchmark::ClobberMemory(); + } +} + +template +void BM_InsertDuplicate(benchmark::State& st, Container c, GenInputs gen) { + auto in = gen(st.range(0)); + const auto end = in.end(); + c.insert(in.begin(), in.end()); + benchmark::DoNotOptimize(c); + benchmark::DoNotOptimize(in); + while (st.KeepRunning()) { + for (auto it = in.begin(); it != end; ++it) { + benchmark::DoNotOptimize(&(*c.insert(*it).first)); + } + benchmark::ClobberMemory(); + } +} + +template +void BM_EmplaceDuplicate(benchmark::State& st, Container c, GenInputs gen) { + auto in = gen(st.range(0)); + const auto end = in.end(); + c.insert(in.begin(), in.end()); + benchmark::DoNotOptimize(c); + benchmark::DoNotOptimize(in); + while (st.KeepRunning()) { + for (auto it = in.begin(); it != end; ++it) { + benchmark::DoNotOptimize(&(*c.emplace(*it).first)); + } + benchmark::ClobberMemory(); + } +} + +template +void BM_Find(benchmark::State& st, Container c, GenInputs gen) { + auto in = gen(st.range(0)); + c.insert(in.begin(), in.end()); + benchmark::DoNotOptimize(&(*c.begin())); + const auto end = in.data() + in.size(); + while (st.KeepRunning()) { + for (auto it = in.data(); it != end; ++it) { + benchmark::DoNotOptimize(&(*c.find(*it))); + } + benchmark::ClobberMemory(); + } +} + +template +void BM_FindRehash(benchmark::State& st, Container c, GenInputs gen) { + c.rehash(8); + auto in = gen(st.range(0)); + c.insert(in.begin(), in.end()); + benchmark::DoNotOptimize(&(*c.begin())); + const auto end = in.data() + in.size(); + while (st.KeepRunning()) { + for (auto it = in.data(); it != end; ++it) { + benchmark::DoNotOptimize(&(*c.find(*it))); + } + benchmark::ClobberMemory(); + } +} + +template +void BM_Rehash(benchmark::State& st, Container c, GenInputs gen) { + auto in = gen(st.range(0)); + c.max_load_factor(3.0); + c.insert(in.begin(), in.end()); + benchmark::DoNotOptimize(c); + const auto bucket_count = c.bucket_count(); + while (st.KeepRunning()) { + c.rehash(bucket_count + 1); + c.rehash(bucket_count); + benchmark::ClobberMemory(); + } +} + +template +void BM_Compare_same_container(benchmark::State& st, Container, GenInputs gen) { + auto in = gen(st.range(0)); + Container c1(in.begin(), in.end()); + Container c2 = c1; + + benchmark::DoNotOptimize(&(*c1.begin())); + benchmark::DoNotOptimize(&(*c2.begin())); + while (st.KeepRunning()) { + bool res = c1 == c2; + benchmark::DoNotOptimize(&res); + benchmark::ClobberMemory(); + } +} + +template +void BM_Compare_different_containers(benchmark::State& st, Container, GenInputs gen) { + auto in1 = gen(st.range(0)); + auto in2 = gen(st.range(0)); + Container c1(in1.begin(), in1.end()); + Container c2(in2.begin(), in2.end()); + + benchmark::DoNotOptimize(&(*c1.begin())); + benchmark::DoNotOptimize(&(*c2.begin())); + while (st.KeepRunning()) { + bool res = c1 == c2; + benchmark::DoNotOptimize(&res); + benchmark::ClobberMemory(); + } +} + +} // namespace ContainerBenchmarks + +#endif // TEST_BENCHMARKS_CONTAINERS_CONTAINER_BENCHMARKS_H diff --git a/libcxx/test/benchmarks/containers/deque.bench.cpp b/libcxx/test/benchmarks/containers/deque.bench.cpp index 7ff1093a9391c..6a650fa4dce2a 100644 --- a/libcxx/test/benchmarks/containers/deque.bench.cpp +++ b/libcxx/test/benchmarks/containers/deque.bench.cpp @@ -6,50 +6,20 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: c++03, c++11, c++14, c++17 #include #include +#include "container_benchmarks.h" #include "benchmark/benchmark.h" -#include "ContainerBenchmarks.h" -#include "../GenerateInput.h" +int main(int argc, char** argv) { + ContainerBenchmarks::sequence_container_benchmarks>("std::deque"); + ContainerBenchmarks::sequence_container_benchmarks>("std::deque"); -using namespace ContainerBenchmarks; - -constexpr std::size_t TestNumInputs = 1024; - -BENCHMARK_CAPTURE(BM_ConstructSize, deque_byte, std::deque{})->Arg(5140480); - -BENCHMARK_CAPTURE(BM_ConstructSizeValue, deque_byte, std::deque{}, 0)->Arg(5140480); - -BENCHMARK_CAPTURE(BM_ConstructIterIter, deque_char, std::deque{}, getRandomIntegerInputs) - ->Arg(TestNumInputs); - -BENCHMARK_CAPTURE(BM_ConstructIterIter, deque_size_t, std::deque{}, getRandomIntegerInputs) - ->Arg(TestNumInputs); - -BENCHMARK_CAPTURE(BM_ConstructIterIter, deque_string, std::deque{}, getRandomStringInputs) - ->Arg(TestNumInputs); - -BENCHMARK_CAPTURE(BM_ConstructFromRange, deque_char, std::deque{}, getRandomIntegerInputs) - ->Arg(TestNumInputs); - -BENCHMARK_CAPTURE(BM_ConstructFromRange, deque_size_t, std::deque{}, getRandomIntegerInputs) - ->Arg(TestNumInputs); - -BENCHMARK_CAPTURE(BM_ConstructFromRange, deque_string, std::deque{}, getRandomStringInputs) - ->Arg(TestNumInputs); - -BENCHMARK_CAPTURE(BM_erase_iter_in_middle, deque_int, std::deque{}, getRandomIntegerInputs) - ->Range(TestNumInputs, TestNumInputs * 10); -BENCHMARK_CAPTURE(BM_erase_iter_in_middle, deque_string, std::deque{}, getRandomStringInputs) - ->Range(TestNumInputs, TestNumInputs * 10); - -BENCHMARK_CAPTURE(BM_erase_iter_at_start, deque_int, std::deque{}, getRandomIntegerInputs) - ->Range(TestNumInputs, TestNumInputs * 10); -BENCHMARK_CAPTURE(BM_erase_iter_at_start, deque_string, std::deque{}, getRandomStringInputs) - ->Range(TestNumInputs, TestNumInputs * 10); - -BENCHMARK_MAIN(); + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/containers/list.bench.cpp b/libcxx/test/benchmarks/containers/list.bench.cpp new file mode 100644 index 0000000000000..2212affa02ba4 --- /dev/null +++ b/libcxx/test/benchmarks/containers/list.bench.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +#include +#include + +#include "container_benchmarks.h" +#include "benchmark/benchmark.h" + +int main(int argc, char** argv) { + ContainerBenchmarks::sequence_container_benchmarks>("std::list"); + ContainerBenchmarks::sequence_container_benchmarks>("std::list"); + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/containers/string.bench.cpp b/libcxx/test/benchmarks/containers/string.bench.cpp index 0b62c87acf7a2..aeff6ad6f6333 100644 --- a/libcxx/test/benchmarks/containers/string.bench.cpp +++ b/libcxx/test/benchmarks/containers/string.bench.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14, c++17 #include #include diff --git a/libcxx/test/benchmarks/containers/unordered_set_operations.bench.cpp b/libcxx/test/benchmarks/containers/unordered_set.bench.cpp similarity index 99% rename from libcxx/test/benchmarks/containers/unordered_set_operations.bench.cpp rename to libcxx/test/benchmarks/containers/unordered_set.bench.cpp index a8448ef5a0cfb..ad8d0feaa0436 100644 --- a/libcxx/test/benchmarks/containers/unordered_set_operations.bench.cpp +++ b/libcxx/test/benchmarks/containers/unordered_set.bench.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +// UNSUPPORTED: c++03, c++11, c++14, c++17 #include #include @@ -17,7 +17,7 @@ #include "benchmark/benchmark.h" -#include "ContainerBenchmarks.h" +#include "container_benchmarks.h" #include "../GenerateInput.h" #include "test_macros.h" diff --git a/libcxx/test/benchmarks/containers/vector.bench.cpp b/libcxx/test/benchmarks/containers/vector.bench.cpp new file mode 100644 index 0000000000000..eef23d2981642 --- /dev/null +++ b/libcxx/test/benchmarks/containers/vector.bench.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +#include +#include + +#include "container_benchmarks.h" +#include "benchmark/benchmark.h" + +int main(int argc, char** argv) { + ContainerBenchmarks::sequence_container_benchmarks>("std::vector"); + ContainerBenchmarks::sequence_container_benchmarks>("std::vector"); + + benchmark::Initialize(&argc, argv); + benchmark::RunSpecifiedBenchmarks(); + benchmark::Shutdown(); + return 0; +} diff --git a/libcxx/test/benchmarks/containers/vector_operations.bench.cpp b/libcxx/test/benchmarks/containers/vector_operations.bench.cpp deleted file mode 100644 index 1cd754ca7e780..0000000000000 --- a/libcxx/test/benchmarks/containers/vector_operations.bench.cpp +++ /dev/null @@ -1,108 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "benchmark/benchmark.h" -#include "ContainerBenchmarks.h" -#include "../GenerateInput.h" - -using namespace ContainerBenchmarks; - -constexpr std::size_t TestNumInputs = 1024; - -BENCHMARK_CAPTURE(BM_ConstructSize, vector_byte, std::vector{})->Arg(5140480); - -BENCHMARK_CAPTURE(BM_CopyConstruct, vector_int, std::vector{})->Arg(5140480); - -BENCHMARK_CAPTURE(BM_Assignment, vector_int, std::vector{})->Arg(5140480); - -BENCHMARK_CAPTURE(BM_ConstructSizeValue, vector_byte, std::vector{}, 0)->Arg(5140480); - -BENCHMARK_CAPTURE(BM_ConstructIterIter, vector_char, std::vector{}, getRandomIntegerInputs) - ->Arg(TestNumInputs); - -BENCHMARK_CAPTURE(BM_ConstructIterIter, vector_size_t, std::vector{}, getRandomIntegerInputs) - ->Arg(TestNumInputs); - -BENCHMARK_CAPTURE(BM_ConstructIterIter, vector_string, std::vector{}, getRandomStringInputs) - ->Arg(TestNumInputs); - -BENCHMARK_CAPTURE(BM_ConstructFromRange, vector_char, std::vector{}, getRandomIntegerInputs) - ->Arg(TestNumInputs); - -BENCHMARK_CAPTURE(BM_ConstructFromRange, vector_size_t, std::vector{}, getRandomIntegerInputs) - ->Arg(TestNumInputs); - -BENCHMARK_CAPTURE(BM_ConstructFromRange, vector_string, std::vector{}, getRandomStringInputs) - ->Arg(TestNumInputs); - -BENCHMARK_CAPTURE(BM_Pushback_no_grow, vector_int, std::vector{})->Arg(TestNumInputs); - -BENCHMARK_CAPTURE(BM_erase_iter_in_middle, vector_int, std::vector{}, getRandomIntegerInputs) - ->Range(TestNumInputs, TestNumInputs * 10); -BENCHMARK_CAPTURE(BM_erase_iter_in_middle, vector_string, std::vector{}, getRandomStringInputs) - ->Range(TestNumInputs, TestNumInputs * 10); - -BENCHMARK_CAPTURE(BM_erase_iter_at_start, vector_int, std::vector{}, getRandomIntegerInputs) - ->Range(TestNumInputs, TestNumInputs * 10); -BENCHMARK_CAPTURE(BM_erase_iter_at_start, vector_string, std::vector{}, getRandomStringInputs) - ->Range(TestNumInputs, TestNumInputs * 10); - -template -void bm_grow(benchmark::State& state) { - for (auto _ : state) { - std::vector vec; - benchmark::DoNotOptimize(vec); - for (size_t i = 0; i != 2048; ++i) - vec.emplace_back(); - benchmark::DoNotOptimize(vec); - } -} -BENCHMARK(bm_grow); -BENCHMARK(bm_grow); -BENCHMARK(bm_grow>); -BENCHMARK(bm_grow>); - -BENCHMARK_CAPTURE(BM_AssignInputIterIter, vector_int, std::vector{}, getRandomIntegerInputs) - ->Args({TestNumInputs, TestNumInputs}); - -BENCHMARK_CAPTURE( - BM_AssignInputIterIter<32>, vector_string, std::vector{}, getRandomStringInputsWithLength) - ->Args({TestNumInputs, TestNumInputs}); - -BENCHMARK_CAPTURE(BM_AssignInputIterIter<100>, - vector_vector_int, - std::vector>{}, - getRandomIntegerInputsWithLength) - ->Args({TestNumInputs, TestNumInputs}); - -BENCHMARK_CAPTURE(BM_Insert_InputIterIter_NoRealloc, vector_int, std::vector(100, 1), getRandomIntegerInputs) - ->Arg(514048); -BENCHMARK_CAPTURE( - BM_Insert_InputIterIter_Realloc_HalfFilled, vector_int, std::vector{}, getRandomIntegerInputs) - ->Arg(514048); -BENCHMARK_CAPTURE(BM_Insert_InputIterIter_Realloc_NearFull, vector_int, std::vector{}, getRandomIntegerInputs) - ->Arg(514048); -BENCHMARK_CAPTURE( - BM_Insert_InputIterIter_Realloc_HalfFilled, vector_string, std::vector{}, getSSORandomStringInputs) - ->Arg(514048); -BENCHMARK_CAPTURE( - BM_Insert_InputIterIter_Realloc_NearFull, vector_string, std::vector{}, getSSORandomStringInputs) - ->Arg(514048); - -BENCHMARK_MAIN(); diff --git a/libcxx/test/benchmarks/filesystem.bench.cpp b/libcxx/test/benchmarks/filesystem.bench.cpp index 83a87c86d3de0..dc6b0ac537f7e 100644 --- a/libcxx/test/benchmarks/filesystem.bench.cpp +++ b/libcxx/test/benchmarks/filesystem.bench.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14, c++17 #include diff --git a/libcxx/test/benchmarks/hash.bench.cpp b/libcxx/test/benchmarks/hash.bench.cpp index 1e1a0f36ec116..ca958765dc210 100644 --- a/libcxx/test/benchmarks/hash.bench.cpp +++ b/libcxx/test/benchmarks/hash.bench.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03 +// UNSUPPORTED: c++03, c++11, c++14, c++17 #include #include diff --git a/libcxx/test/benchmarks/variant_visit_1.bench.cpp b/libcxx/test/benchmarks/variant_visit_1.bench.cpp index 42b22aabaee04..f1b702530bed3 100644 --- a/libcxx/test/benchmarks/variant_visit_1.bench.cpp +++ b/libcxx/test/benchmarks/variant_visit_1.bench.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14, c++17 #include "benchmark/benchmark.h" diff --git a/libcxx/test/benchmarks/variant_visit_2.bench.cpp b/libcxx/test/benchmarks/variant_visit_2.bench.cpp index 328048cabc443..7dd8d02b358be 100644 --- a/libcxx/test/benchmarks/variant_visit_2.bench.cpp +++ b/libcxx/test/benchmarks/variant_visit_2.bench.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14, c++17 #include "benchmark/benchmark.h" diff --git a/libcxx/test/benchmarks/variant_visit_3.bench.cpp b/libcxx/test/benchmarks/variant_visit_3.bench.cpp index 40f8c1b5fa262..0fe42b0d8e009 100644 --- a/libcxx/test/benchmarks/variant_visit_3.bench.cpp +++ b/libcxx/test/benchmarks/variant_visit_3.bench.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: c++03, c++11, c++14, c++17 #include "benchmark/benchmark.h" From 4f358d75d03b0d412f131a3d38c4781b5f06f584 Mon Sep 17 00:00:00 2001 From: Jon Chesterfield Date: Thu, 30 Jan 2025 20:00:57 +0000 Subject: [PATCH 15/34] [amdgpu][nfc] Post-commit feedback on c39fba209 --- llvm/lib/Target/AMDGPU/SIInstrInfo.cpp | 2 +- llvm/test/CodeGen/AMDGPU/copy-to-reg-frameindex.ll | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp b/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp index a7ac2a3a4c194..35667801c809d 100644 --- a/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp +++ b/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp @@ -2366,7 +2366,7 @@ bool SIInstrInfo::expandPostRAPseudo(MachineInstr &MI) const { assert(ST.useVGPRIndexMode()); Register VecReg = MI.getOperand(0).getReg(); bool IsUndef = MI.getOperand(1).isUndef(); - MachineOperand Idx = MI.getOperand(3); + MachineOperand &Idx = MI.getOperand(3); Register SubReg = MI.getOperand(4).getImm(); MachineInstr *SetOn = BuildMI(MBB, MI, DL, get(AMDGPU::S_SET_GPR_IDX_ON)) diff --git a/llvm/test/CodeGen/AMDGPU/copy-to-reg-frameindex.ll b/llvm/test/CodeGen/AMDGPU/copy-to-reg-frameindex.ll index d86f497aa5e13..9558d9f0bc4c9 100644 --- a/llvm/test/CodeGen/AMDGPU/copy-to-reg-frameindex.ll +++ b/llvm/test/CodeGen/AMDGPU/copy-to-reg-frameindex.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py -; RUN: llc < %s -mtriple=amdgcn -mcpu=gfx90a -verify-machineinstrs | FileCheck %s +; RUN: llc < %s -mtriple=amdgcn -mcpu=gfx90a | FileCheck %s define amdgpu_kernel void @copy_to_reg_frameindex(ptr addrspace(1) %out, i32 %a, i32 %b, i32 %c) { ; CHECK-LABEL: copy_to_reg_frameindex: @@ -20,19 +20,18 @@ define amdgpu_kernel void @copy_to_reg_frameindex(ptr addrspace(1) %out, i32 %a, ; CHECK-NEXT: s_endpgm entry: %B = srem i32 %c, -1 - %alloca = alloca [16 x i32], align 4, addrspace(5) br label %loop loop: + %promotealloca = phi <16 x i32> [ undef, %entry ], [ %0, %loop ] %inc = phi i32 [ 0, %entry ], [ %inc.i, %loop ] - %ptr = getelementptr [16 x i32], ptr addrspace(5) %alloca, i32 0, i32 %inc - store i32 %inc, ptr addrspace(5) %ptr, align 4 + %0 = insertelement <16 x i32> %promotealloca, i32 %inc, i32 %inc %inc.i = add i32 %inc, %B %cnd = icmp uge i32 %inc.i, 16 br i1 %cnd, label %done, label %loop done: - %tmp1 = load i32, ptr addrspace(5) %alloca, align 4 - store i32 %tmp1, ptr addrspace(1) %out, align 4 + %1 = extractelement <16 x i32> %0, i32 0 + store i32 %1, ptr addrspace(1) %out, align 4 ret void } From fcc4ceb331957dc6d1d6d0f4035bd2f48f2945bd Mon Sep 17 00:00:00 2001 From: Nikolas Klauser Date: Thu, 30 Jan 2025 21:10:56 +0100 Subject: [PATCH 16/34] [libc++] Implement N4258(Cleaning-up noexcept in the Library) (#120312) Fixes #99937 --- libcxx/docs/ReleaseNotes/21.rst | 3 +- libcxx/docs/Status/Cxx17Papers.csv | 2 +- libcxx/include/__hash_table | 16 ++-- libcxx/include/__tree | 19 +++-- libcxx/include/deque | 18 +++-- libcxx/include/forward_list | 17 ++-- libcxx/include/list | 18 +++-- .../move_assign_noexcept.compile.pass.cpp | 61 +++++++++++++++ .../map.cons/move_assign_noexcept.pass.cpp | 59 -------------- .../move_assign_noexcept.compile.pass.cpp | 62 +++++++++++++++ .../move_assign_noexcept.pass.cpp | 59 -------------- .../move_assign_noexcept.compile.pass.cpp | 61 +++++++++++++++ .../move_assign_noexcept.pass.cpp | 58 -------------- .../move_assign_noexcept.compile.pass.cpp | 61 +++++++++++++++ .../set.cons/move_assign_noexcept.pass.cpp | 58 -------------- .../move_assign_noexcept.compile.pass.cpp | 49 ++++++++++++ .../deque.cons/move_assign_noexcept.pass.cpp | 57 -------------- .../move_assign_noexcept.compile.pass.cpp | 50 ++++++++++++ .../move_assign_noexcept.pass.cpp | 57 -------------- .../move_assign_noexcept.compile.pass.cpp | 49 ++++++++++++ .../list.cons/move_assign_noexcept.pass.cpp | 57 -------------- .../move_assign_noexcept.compile.pass.cpp | 78 +++++++++++++++++++ .../move_assign_noexcept.pass.cpp | 76 ------------------ .../move_assign_noexcept.compile.pass.cpp | 78 +++++++++++++++++++ .../move_assign_noexcept.pass.cpp | 75 ------------------ .../move_assign_noexcept.compile.pass.cpp | 74 ++++++++++++++++++ .../move_assign_noexcept.pass.cpp | 75 ------------------ .../move_assign_noexcept.compile.pass.cpp | 72 +++++++++++++++++ .../move_assign_noexcept.pass.cpp | 75 ------------------ 29 files changed, 747 insertions(+), 747 deletions(-) create mode 100644 libcxx/test/std/containers/associative/map/map.cons/move_assign_noexcept.compile.pass.cpp delete mode 100644 libcxx/test/std/containers/associative/map/map.cons/move_assign_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/associative/multimap/multimap.cons/move_assign_noexcept.compile.pass.cpp delete mode 100644 libcxx/test/std/containers/associative/multimap/multimap.cons/move_assign_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/associative/multiset/multiset.cons/move_assign_noexcept.compile.pass.cpp delete mode 100644 libcxx/test/std/containers/associative/multiset/multiset.cons/move_assign_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/associative/set/set.cons/move_assign_noexcept.compile.pass.cpp delete mode 100644 libcxx/test/std/containers/associative/set/set.cons/move_assign_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/sequences/deque/deque.cons/move_assign_noexcept.compile.pass.cpp delete mode 100644 libcxx/test/std/containers/sequences/deque/deque.cons/move_assign_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/move_assign_noexcept.compile.pass.cpp delete mode 100644 libcxx/test/std/containers/sequences/forwardlist/forwardlist.cons/move_assign_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/sequences/list/list.cons/move_assign_noexcept.compile.pass.cpp delete mode 100644 libcxx/test/std/containers/sequences/list/list.cons/move_assign_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/move_assign_noexcept.compile.pass.cpp delete mode 100644 libcxx/test/std/containers/unord/unord.map/unord.map.cnstr/move_assign_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/move_assign_noexcept.compile.pass.cpp delete mode 100644 libcxx/test/std/containers/unord/unord.multimap/unord.multimap.cnstr/move_assign_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/unord/unord.multiset/unord.multiset.cnstr/move_assign_noexcept.compile.pass.cpp delete mode 100644 libcxx/test/std/containers/unord/unord.multiset/unord.multiset.cnstr/move_assign_noexcept.pass.cpp create mode 100644 libcxx/test/std/containers/unord/unord.set/unord.set.cnstr/move_assign_noexcept.compile.pass.cpp delete mode 100644 libcxx/test/std/containers/unord/unord.set/unord.set.cnstr/move_assign_noexcept.pass.cpp diff --git a/libcxx/docs/ReleaseNotes/21.rst b/libcxx/docs/ReleaseNotes/21.rst index 29ecbf3f01c8a..82f1de6bad394 100644 --- a/libcxx/docs/ReleaseNotes/21.rst +++ b/libcxx/docs/ReleaseNotes/21.rst @@ -38,8 +38,7 @@ What's New in Libc++ 21.0.0? Implemented Papers ------------------ -- TODO - +- N4258: Cleaning-up noexcept in the Library (`Github `__) Improvements and New Features ----------------------------- diff --git a/libcxx/docs/Status/Cxx17Papers.csv b/libcxx/docs/Status/Cxx17Papers.csv index fbcac452adb8b..24fc7f718c360 100644 --- a/libcxx/docs/Status/Cxx17Papers.csv +++ b/libcxx/docs/Status/Cxx17Papers.csv @@ -3,7 +3,7 @@ "`N4089 `__","Safe conversions in ``unique_ptr``\ .","2014-11 (Urbana)","|Complete|","5","" "`N4169 `__","A proposal to add invoke function template","2014-11 (Urbana)","|Complete|","3.7","" "`N4190 `__","Removing auto_ptr, random_shuffle(), And Old Stuff.","2014-11 (Urbana)","|Complete|","15","" -"`N4258 `__","Cleaning-up noexcept in the Library.","2014-11 (Urbana)","|In Progress|","3.7","" +"`N4258 `__","Cleaning-up noexcept in the Library.","2014-11 (Urbana)","|Complete|","21","" "`N4259 `__","Wording for std::uncaught_exceptions","2014-11 (Urbana)","|Complete|","3.7","``std::uncaught_exception`` is deprecated since LLVM 20" "`N4277 `__","TriviallyCopyable ``reference_wrapper``\ .","2014-11 (Urbana)","|Complete|","3.2","" "`N4279 `__","Improved insertion interface for unique-key maps.","2014-11 (Urbana)","|Complete|","3.7","" diff --git a/libcxx/include/__hash_table b/libcxx/include/__hash_table index 9a82ec51daee7..d7b312f8774fc 100644 --- a/libcxx/include/__hash_table +++ b/libcxx/include/__hash_table @@ -770,9 +770,10 @@ public: _LIBCPP_HIDE_FROM_ABI __hash_table& operator=(const __hash_table& __u); _LIBCPP_HIDE_FROM_ABI __hash_table& operator=(__hash_table&& __u) - _NOEXCEPT_(__node_traits::propagate_on_container_move_assignment::value&& - is_nothrow_move_assignable<__node_allocator>::value&& is_nothrow_move_assignable::value&& - is_nothrow_move_assignable::value); + _NOEXCEPT_(is_nothrow_move_assignable::value&& is_nothrow_move_assignable::value && + ((__node_traits::propagate_on_container_move_assignment::value && + is_nothrow_move_assignable<__node_allocator>::value) || + allocator_traits<__node_allocator>::is_always_equal::value)); template _LIBCPP_HIDE_FROM_ABI void __assign_unique(_InputIterator __first, _InputIterator __last); template @@ -1238,10 +1239,11 @@ void __hash_table<_Tp, _Hash, _Equal, _Alloc>::__move_assign(__hash_table& __u, } template -inline __hash_table<_Tp, _Hash, _Equal, _Alloc>& -__hash_table<_Tp, _Hash, _Equal, _Alloc>::operator=(__hash_table&& __u) _NOEXCEPT_( - __node_traits::propagate_on_container_move_assignment::value&& is_nothrow_move_assignable<__node_allocator>::value&& - is_nothrow_move_assignable::value&& is_nothrow_move_assignable::value) { +inline __hash_table<_Tp, _Hash, _Equal, _Alloc>& __hash_table<_Tp, _Hash, _Equal, _Alloc>::operator=(__hash_table&& __u) + _NOEXCEPT_(is_nothrow_move_assignable::value&& is_nothrow_move_assignable::value && + ((__node_traits::propagate_on_container_move_assignment::value && + is_nothrow_move_assignable<__node_allocator>::value) || + allocator_traits<__node_allocator>::is_always_equal::value)) { __move_assign(__u, integral_constant()); return *this; } diff --git a/libcxx/include/__tree b/libcxx/include/__tree index acad6c33f8782..c627641d5d86f 100644 --- a/libcxx/include/__tree +++ b/libcxx/include/__tree @@ -987,9 +987,12 @@ public: _LIBCPP_HIDE_FROM_ABI __tree(__tree&& __t) _NOEXCEPT_( is_nothrow_move_constructible<__node_allocator>::value&& is_nothrow_move_constructible::value); _LIBCPP_HIDE_FROM_ABI __tree(__tree&& __t, const allocator_type& __a); - _LIBCPP_HIDE_FROM_ABI __tree& operator=(__tree&& __t) _NOEXCEPT_( - __node_traits::propagate_on_container_move_assignment::value&& is_nothrow_move_assignable::value&& - is_nothrow_move_assignable<__node_allocator>::value); + _LIBCPP_HIDE_FROM_ABI __tree& operator=(__tree&& __t) + _NOEXCEPT_(is_nothrow_move_assignable::value && + ((__node_traits::propagate_on_container_move_assignment::value && + is_nothrow_move_assignable<__node_allocator>::value) || + allocator_traits<__node_allocator>::is_always_equal::value)); + _LIBCPP_HIDE_FROM_ABI ~__tree(); _LIBCPP_HIDE_FROM_ABI iterator begin() _NOEXCEPT { return iterator(__begin_node()); } @@ -1520,11 +1523,11 @@ void __tree<_Tp, _Compare, _Allocator>::__move_assign(__tree& __t, false_type) { } template -__tree<_Tp, _Compare, _Allocator>& __tree<_Tp, _Compare, _Allocator>::operator=(__tree&& __t) _NOEXCEPT_( - __node_traits::propagate_on_container_move_assignment::value&& is_nothrow_move_assignable::value&& - is_nothrow_move_assignable<__node_allocator>::value) - -{ +__tree<_Tp, _Compare, _Allocator>& __tree<_Tp, _Compare, _Allocator>::operator=(__tree&& __t) + _NOEXCEPT_(is_nothrow_move_assignable::value && + ((__node_traits::propagate_on_container_move_assignment::value && + is_nothrow_move_assignable<__node_allocator>::value) || + allocator_traits<__node_allocator>::is_always_equal::value)) { __move_assign(__t, integral_constant()); return *this; } diff --git a/libcxx/include/deque b/libcxx/include/deque index df3094cff7f89..95200b4801d7f 100644 --- a/libcxx/include/deque +++ b/libcxx/include/deque @@ -59,9 +59,9 @@ public: deque& operator=(const deque& c); deque& operator=(deque&& c) - noexcept( - allocator_type::propagate_on_container_move_assignment::value && - is_nothrow_move_assignable::value); + noexcept((__alloc_traits::propagate_on_container_move_assignment::value && + is_nothrow_move_assignable::value) || + allocator_traits::is_always_equal::value); deque& operator=(initializer_list il); template @@ -674,9 +674,10 @@ public: _LIBCPP_HIDE_FROM_ABI deque(deque&& __c) noexcept(is_nothrow_move_constructible::value); _LIBCPP_HIDE_FROM_ABI deque(deque&& __c, const __type_identity_t& __a); - _LIBCPP_HIDE_FROM_ABI deque& - operator=(deque&& __c) noexcept(__alloc_traits::propagate_on_container_move_assignment::value && - is_nothrow_move_assignable::value); + _LIBCPP_HIDE_FROM_ABI deque& operator=(deque&& __c) noexcept( + (__alloc_traits::propagate_on_container_move_assignment::value && + is_nothrow_move_assignable::value) || + allocator_traits::is_always_equal::value); _LIBCPP_HIDE_FROM_ABI void assign(initializer_list __il) { assign(__il.begin(), __il.end()); } # endif // _LIBCPP_CXX03_LANG @@ -1379,8 +1380,9 @@ inline deque<_Tp, _Allocator>::deque(deque&& __c, const __type_identity_t inline deque<_Tp, _Allocator>& deque<_Tp, _Allocator>::operator=(deque&& __c) noexcept( - __alloc_traits::propagate_on_container_move_assignment::value && - is_nothrow_move_assignable::value) { + (__alloc_traits::propagate_on_container_move_assignment::value && + is_nothrow_move_assignable::value) || + allocator_traits::is_always_equal::value) { __move_assign(__c, integral_constant()); return *this; } diff --git a/libcxx/include/forward_list b/libcxx/include/forward_list index f3b9617ab2e04..4b6ca8ea8587c 100644 --- a/libcxx/include/forward_list +++ b/libcxx/include/forward_list @@ -58,9 +58,9 @@ public: forward_list& operator=(const forward_list& x); forward_list& operator=(forward_list&& x) - noexcept( - allocator_type::propagate_on_container_move_assignment::value && - is_nothrow_move_assignable::value); + noexcept((__node_traits::propagate_on_container_move_assignment::value && + is_nothrow_move_assignable::value) || + allocator_traits::is_always_equal::value); forward_list& operator=(initializer_list il); template @@ -717,8 +717,9 @@ public: _LIBCPP_HIDE_FROM_ABI forward_list(initializer_list __il, const allocator_type& __a); _LIBCPP_HIDE_FROM_ABI forward_list& operator=(forward_list&& __x) noexcept( - __node_traits::propagate_on_container_move_assignment::value && - is_nothrow_move_assignable::value); + (__node_traits::propagate_on_container_move_assignment::value && + is_nothrow_move_assignable::value) || + allocator_traits::is_always_equal::value); _LIBCPP_HIDE_FROM_ABI forward_list& operator=(initializer_list __il); @@ -1009,8 +1010,10 @@ void forward_list<_Tp, _Alloc>::__move_assign(forward_list& __x, false_type) { } template -inline forward_list<_Tp, _Alloc>& forward_list<_Tp, _Alloc>::operator=(forward_list&& __x) _NOEXCEPT_( - __node_traits::propagate_on_container_move_assignment::value&& is_nothrow_move_assignable::value) { +inline forward_list<_Tp, _Alloc>& forward_list<_Tp, _Alloc>::operator=(forward_list&& __x) noexcept( + (__node_traits::propagate_on_container_move_assignment::value && + is_nothrow_move_assignable::value) || + allocator_traits::is_always_equal::value) { __move_assign(__x, integral_constant()); return *this; } diff --git a/libcxx/include/list b/libcxx/include/list index 5e2fd40d6ee9d..3fcf796ebc03d 100644 --- a/libcxx/include/list +++ b/libcxx/include/list @@ -60,9 +60,9 @@ public: list& operator=(const list& x); list& operator=(list&& x) - noexcept( - allocator_type::propagate_on_container_move_assignment::value && - is_nothrow_move_assignable::value); + noexcept((__node_alloc_traits::propagate_on_container_move_assignment::value && + is_nothrow_move_assignable<__node_allocator>::value) || + allocator_traits::is_always_equal::value); list& operator=(initializer_list); template void assign(Iter first, Iter last); @@ -728,9 +728,10 @@ public: _LIBCPP_HIDE_FROM_ABI list(list&& __c) _NOEXCEPT_(is_nothrow_move_constructible<__node_allocator>::value); _LIBCPP_HIDE_FROM_ABI list(list&& __c, const __type_identity_t& __a); - _LIBCPP_HIDE_FROM_ABI list& operator=(list&& __c) - _NOEXCEPT_(__node_alloc_traits::propagate_on_container_move_assignment::value&& - is_nothrow_move_assignable<__node_allocator>::value); + _LIBCPP_HIDE_FROM_ABI list& operator=(list&& __c) noexcept( + (__node_alloc_traits::propagate_on_container_move_assignment::value && + is_nothrow_move_assignable<__node_allocator>::value) || + allocator_traits::is_always_equal::value); _LIBCPP_HIDE_FROM_ABI list& operator=(initializer_list __il) { assign(__il.begin(), __il.end()); @@ -1067,8 +1068,9 @@ inline list<_Tp, _Alloc>::list(list&& __c, const __type_identity_t inline list<_Tp, _Alloc>& list<_Tp, _Alloc>::operator=(list&& __c) noexcept( - __node_alloc_traits::propagate_on_container_move_assignment::value && - is_nothrow_move_assignable<__node_allocator>::value) { + (__node_alloc_traits::propagate_on_container_move_assignment::value && + is_nothrow_move_assignable<__node_allocator>::value) || + allocator_traits::is_always_equal::value) { __move_assign(__c, integral_constant()); return *this; } diff --git a/libcxx/test/std/containers/associative/map/map.cons/move_assign_noexcept.compile.pass.cpp b/libcxx/test/std/containers/associative/map/map.cons/move_assign_noexcept.compile.pass.cpp new file mode 100644 index 0000000000000..a4c8ef1c5b429 --- /dev/null +++ b/libcxx/test/std/containers/associative/map/map.cons/move_assign_noexcept.compile.pass.cpp @@ -0,0 +1,61 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// map& operator=(map&& c) +// noexcept( +// allocator_type::propagate_on_container_move_assignment::value && +// is_nothrow_move_assignable::value && +// is_nothrow_move_assignable::value); + +// This tests a conforming extension + +// UNSUPPORTED: c++03 + +#include + +#include "test_macros.h" +#include "MoveOnly.h" +#include "test_allocator.h" + +template +struct some_comp { + using value_type = T; + some_comp& operator=(const some_comp&); + bool operator()(const T&, const T&) const { return false; } +}; + +template +struct always_equal_alloc { + using value_type = T; + always_equal_alloc(const always_equal_alloc&); + void allocate(std::size_t); +}; + +template +struct not_always_equal_alloc { + int i; + using value_type = T; + not_always_equal_alloc(const not_always_equal_alloc&); + void allocate(std::size_t); +}; + +template