From 93b9b06f08ca66a6216f019b5609fe81ed0fd963 Mon Sep 17 00:00:00 2001 From: Owen Voorhees Date: Wed, 8 Jan 2020 15:22:55 -0600 Subject: [PATCH 001/286] LLDB updates to support conditionally compiled and multi-pattern catches --- .../Plugins/ExpressionParser/Swift/SwiftASTManipulator.cpp | 2 +- .../Plugins/ExpressionParser/Swift/SwiftASTManipulator.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lldb/source/Plugins/ExpressionParser/Swift/SwiftASTManipulator.cpp b/lldb/source/Plugins/ExpressionParser/Swift/SwiftASTManipulator.cpp index f52a663882d1d..0d286cd35fa81 100644 --- a/lldb/source/Plugins/ExpressionParser/Swift/SwiftASTManipulator.cpp +++ b/lldb/source/Plugins/ExpressionParser/Swift/SwiftASTManipulator.cpp @@ -320,7 +320,7 @@ void SwiftASTManipulatorBase::DoInitialization() { if (do_stmt) { // There should only be one catch: assert(m_do_stmt->getCatches().size() == 1); - swift::CatchStmt *our_catch = m_do_stmt->getCatches().front(); + swift::CaseStmt *our_catch = m_do_stmt->getCatches().front(); if (our_catch) m_catch_stmt = our_catch; } diff --git a/lldb/source/Plugins/ExpressionParser/Swift/SwiftASTManipulator.h b/lldb/source/Plugins/ExpressionParser/Swift/SwiftASTManipulator.h index 9b670a020a52a..c66b4d6d34f73 100644 --- a/lldb/source/Plugins/ExpressionParser/Swift/SwiftASTManipulator.h +++ b/lldb/source/Plugins/ExpressionParser/Swift/SwiftASTManipulator.h @@ -23,7 +23,7 @@ #include "llvm/ADT/SmallVector.h" namespace swift { -class CatchStmt; +class CaseStmt; class DoCatchStmt; class ExtensionDecl; class FuncDecl; @@ -133,7 +133,7 @@ class SwiftASTManipulatorBase { swift::DoCatchStmt *m_do_stmt = nullptr; /// The body of the catch - we patch the assignment there to capture /// any error thrown. - swift::CatchStmt *m_catch_stmt = nullptr; + swift::CaseStmt *m_catch_stmt = nullptr; }; class SwiftASTManipulator : public SwiftASTManipulatorBase { From c7672f2517a42910cc1a9a89dbd7f882563e05e4 Mon Sep 17 00:00:00 2001 From: Raphael Isemann Date: Fri, 10 Jan 2020 19:17:18 +0100 Subject: [PATCH 002/286] [lldb] Remove FieldDecl stealing hack by rerouting indirect imports to the original AST Summary: This is a port of D67803 that was about preventing indirect importing to our scratch context when evaluating expressions. D67803 already has a pretty long explanation of how this works, but the idea is that instead of importing declarations indirectly over the expression AST (i.e., Debug info AST -> Expression AST -> scratch AST) we instead directly import the declaration from the debug info AST to the scratch AST. The difference from D67803 is that here we have to do this in the ASTImporterDelegate (which is our ASTImporter subclass we use in LLDB). It has the same information as the ExternalASTMerger in D67803 as it can access the ClangASTImporter (which also keeps track of where Decls originally came from). With this patch we can also delete the FieldDecl stealing hack in the ClangASTSource (this was only necessary as the indirect imports caused the creation of duplicate Record declarations but we needed the fields in the Record decl we originally found in the scratch ASTContext). This also fixes the current gmodules failures where we fail to find std::vector fields after an indirect import over the expression AST (where it seems even our FieldDecl stealing hack can't save us from). Reviewers: shafik, aprantl Reviewed By: shafik Subscribers: JDevlieghere, lldb-commits, mib, labath, friss Tags: #lldb Differential Revision: https://reviews.llvm.org/D72507 --- .../ExpressionParser/Clang/ClangASTSource.cpp | 14 -------- lldb/source/Symbol/ClangASTImporter.cpp | 33 +++++++++++++++++++ 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp index f6e119902e31d..925c640134d5e 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp @@ -530,20 +530,6 @@ void ClangASTSource::FindExternalLexicalDecls( m_ast_importer_sp->RequireCompleteType(copied_field_type); } - auto decl_context_non_const = const_cast(decl_context); - - // The decl ended up in the wrong DeclContext. Let's fix that so - // the decl we copied will actually be found. - // FIXME: This is a horrible hack that shouldn't be necessary. However - // it seems our current setup sometimes fails to copy decls to the right - // place. See rdar://55129537. - if (copied_decl->getDeclContext() != decl_context) { - assert(copied_decl->getDeclContext()->containsDecl(copied_decl)); - copied_decl->getDeclContext()->removeDecl(copied_decl); - copied_decl->setDeclContext(decl_context_non_const); - assert(!decl_context_non_const->containsDecl(copied_decl)); - decl_context_non_const->addDeclInternal(copied_decl); - } } else { SkippedDecls = true; } diff --git a/lldb/source/Symbol/ClangASTImporter.cpp b/lldb/source/Symbol/ClangASTImporter.cpp index 8feef9d0f284b..d36d06c633798 100644 --- a/lldb/source/Symbol/ClangASTImporter.cpp +++ b/lldb/source/Symbol/ClangASTImporter.cpp @@ -872,6 +872,39 @@ ClangASTImporter::ASTImporterDelegate::ImportImpl(Decl *From) { } } + // Check which ASTContext this declaration originally came from. + DeclOrigin origin = m_master.GetDeclOrigin(From); + // If it originally came from the target ASTContext then we can just + // pretend that the original is the one we imported. This can happen for + // example when inspecting a persistent declaration from the scratch + // ASTContext (which will provide the declaration when parsing the + // expression and then we later try to copy the declaration back to the + // scratch ASTContext to store the result). + // Without this check we would ask the ASTImporter to import a declaration + // into the same ASTContext where it came from (which doesn't make a lot of + // sense). + if (origin.Valid() && origin.ctx == &getToContext()) { + RegisterImportedDecl(From, origin.decl); + return origin.decl; + } + + // This declaration came originally from another ASTContext. Instead of + // copying our potentially incomplete 'From' Decl we instead go to the + // original ASTContext and copy the original to the target. This is not + // only faster than first completing our current decl and then copying it + // to the target, but it also prevents that indirectly copying the same + // declaration to the same target requires the ASTImporter to merge all + // the different decls that appear to come from different ASTContexts (even + // though all these different source ASTContexts just got a copy from + // one source AST). + if (origin.Valid()) { + auto R = m_master.CopyDecl(&getToContext(), origin.decl); + if (R) { + RegisterImportedDecl(From, R); + return R; + } + } + return ASTImporter::ImportImpl(From); } From 61618554acfb1c92fd69abf83479dbdc3ad27ae7 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Mon, 9 Mar 2020 10:40:33 -0700 Subject: [PATCH 003/286] Add a decorator option to skip tests based on a default setting. This patch allows skipping a test based on a default setting, which is useful when running the testsuite in different "modes" based on a default setting. This is a feature I need for the Swift testsuite, but I think it's generally useful. Differential Revision: https://reviews.llvm.org/D75864 (cherry picked from commit 0396aa4c05a4b97101da14b5e813c8ab3a34e9d0) --- .../Python/lldbsuite/test/decorators.py | 14 ++++++--- lldb/test/API/sanity/TestSettingSkipping.py | 29 +++++++++++++++++++ 2 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 lldb/test/API/sanity/TestSettingSkipping.py diff --git a/lldb/packages/Python/lldbsuite/test/decorators.py b/lldb/packages/Python/lldbsuite/test/decorators.py index 39cda3a81954d..7f157149e463f 100644 --- a/lldb/packages/Python/lldbsuite/test/decorators.py +++ b/lldb/packages/Python/lldbsuite/test/decorators.py @@ -158,7 +158,8 @@ def _decorateTest(mode, debug_info=None, swig_version=None, py_version=None, macos_version=None, - remote=None, dwarf_version=None): + remote=None, dwarf_version=None, + setting=None): def fn(self): skip_for_os = _match_decorator_property( lldbplatform.translate(oslist), self.getPlatform()) @@ -196,6 +197,8 @@ def fn(self): skip_for_dwarf_version = (dwarf_version is None) or ( _check_expected_version(dwarf_version[0], dwarf_version[1], self.getDwarfVersion())) + skip_for_setting = (setting is None) or ( + setting in configuration.settings) # For the test to be skipped, all specified (e.g. not None) parameters must be True. # An unspecified parameter means "any", so those are marked skip by default. And we skip @@ -210,7 +213,8 @@ def fn(self): (py_version, skip_for_py_version, "python version"), (macos_version, skip_for_macos_version, "macOS version"), (remote, skip_for_remote, "platform locality (remote/local)"), - (dwarf_version, skip_for_dwarf_version, "dwarf version")] + (dwarf_version, skip_for_dwarf_version, "dwarf version"), + (setting, skip_for_setting, "setting")] reasons = [] final_skip_result = True for this_condition in conditions: @@ -279,7 +283,8 @@ def skipIf(bugnumber=None, debug_info=None, swig_version=None, py_version=None, macos_version=None, - remote=None, dwarf_version=None): + remote=None, dwarf_version=None, + setting=None): return _decorateTest(DecorateMode.Skip, bugnumber=bugnumber, oslist=oslist, hostoslist=hostoslist, @@ -288,7 +293,8 @@ def skipIf(bugnumber=None, debug_info=debug_info, swig_version=swig_version, py_version=py_version, macos_version=macos_version, - remote=remote, dwarf_version=dwarf_version) + remote=remote, dwarf_version=dwarf_version, + setting=setting) def _skip_for_android(reason, api_levels, archs): diff --git a/lldb/test/API/sanity/TestSettingSkipping.py b/lldb/test/API/sanity/TestSettingSkipping.py new file mode 100644 index 0000000000000..10e7144a0068c --- /dev/null +++ b/lldb/test/API/sanity/TestSettingSkipping.py @@ -0,0 +1,29 @@ +""" +This is a sanity check that verifies that test can be sklipped based on settings. +""" + + +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * + + +class SettingSkipSanityTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + NO_DEBUG_INFO_TESTCASE = True + + @skipIf(setting=('target.prefer-dynamic-value', 'no-dynamic-values')) + def testSkip(self): + """This setting is on by default""" + self.assertTrue(False, "This test should not run!") + + @skipIf(setting=('target.prefer-dynamic-value', 'run-target')) + def testNoMatch(self): + self.assertTrue(True, "This test should run!") + + @skipIf(setting=('target.i-made-this-one-up', 'true')) + def testNotExisting(self): + self.assertTrue(True, "This test should run!") + From a7cdbdbdd67827cc6c39c1bc193c563e08053fdc Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Thu, 12 Mar 2020 17:47:27 -0700 Subject: [PATCH 004/286] Convert settings list into a tuple so it can be matched by the decorator. (cherry picked from commit a9682ccb7e70a036bd3acbbe97ed8ab74a7732d3) --- lldb/packages/Python/lldbsuite/test/dotest.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lldb/packages/Python/lldbsuite/test/dotest.py b/lldb/packages/Python/lldbsuite/test/dotest.py index 09a3da95bf07e..1dca928c83dd9 100644 --- a/lldb/packages/Python/lldbsuite/test/dotest.py +++ b/lldb/packages/Python/lldbsuite/test/dotest.py @@ -345,7 +345,8 @@ def parseOptionsAndInitTestdirs(): logging.error('"%s" is not a setting in the form "key=value"', setting[0]) sys.exit(-1) - configuration.settings.append(setting[0].split('=', 1)) + setting_list = setting[0].split('=', 1) + configuration.settings.append((setting_list[0], setting_list[1])) if args.d: sys.stdout.write( From abe1f1d9473ff248d774e200f74ddc353c0fac85 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Thu, 12 Mar 2020 19:25:38 -0700 Subject: [PATCH 005/286] Add support for XFAILing a test based on a setting. This is analogous to the skipping mechanism introduced in https://reviews.llvm.org/D75864 (cherry picked from commit 57da8f720ce18100c5c6fb5c2247109e1ef963b5) --- lldb/packages/Python/lldbsuite/test/decorators.py | 6 ++++-- lldb/test/API/sanity/TestSettingSkipping.py | 8 ++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/lldb/packages/Python/lldbsuite/test/decorators.py b/lldb/packages/Python/lldbsuite/test/decorators.py index 7f157149e463f..302dcd9819e3b 100644 --- a/lldb/packages/Python/lldbsuite/test/decorators.py +++ b/lldb/packages/Python/lldbsuite/test/decorators.py @@ -258,7 +258,8 @@ def expectedFailureAll(bugnumber=None, debug_info=None, swig_version=None, py_version=None, macos_version=None, - remote=None, dwarf_version=None): + remote=None, dwarf_version=None, + setting=None): return _decorateTest(DecorateMode.Xfail, bugnumber=bugnumber, oslist=oslist, hostoslist=hostoslist, @@ -267,7 +268,8 @@ def expectedFailureAll(bugnumber=None, debug_info=debug_info, swig_version=swig_version, py_version=py_version, macos_version=None, - remote=remote,dwarf_version=dwarf_version) + remote=remote,dwarf_version=dwarf_version, + setting=setting) # provide a function to skip on defined oslist, compiler version, and archs diff --git a/lldb/test/API/sanity/TestSettingSkipping.py b/lldb/test/API/sanity/TestSettingSkipping.py index 10e7144a0068c..206c7b4ecd730 100644 --- a/lldb/test/API/sanity/TestSettingSkipping.py +++ b/lldb/test/API/sanity/TestSettingSkipping.py @@ -27,3 +27,11 @@ def testNoMatch(self): def testNotExisting(self): self.assertTrue(True, "This test should run!") + @expectedFailureAll(setting=('target.prefer-dynamic-value', 'no-dynamic-values')) + def testXFAIL(self): + self.assertTrue(False, "This test should run and fail!") + + @expectedFailureAll(setting=('target.prefer-dynamic-value', 'run-target')) + def testNotXFAIL(self): + self.assertTrue(True, "This test should run and succeed!") + From afc11b25fe45282eddd79afb043a31711b35affe Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Fri, 13 Mar 2020 10:21:57 -0700 Subject: [PATCH 006/286] Upstream catalyst support (cherry picked from commit 2de59e58b05a03da39974ad4db489a9ab2d367b3) --- lldb/source/Symbol/SwiftASTContext.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lldb/source/Symbol/SwiftASTContext.cpp b/lldb/source/Symbol/SwiftASTContext.cpp index 0bac8f3d3c157..e5f3fbcbd7885 100644 --- a/lldb/source/Symbol/SwiftASTContext.cpp +++ b/lldb/source/Symbol/SwiftASTContext.cpp @@ -4039,7 +4039,13 @@ swift::ASTContext *SwiftASTContext::GetASTContext() { llvm::Triple triple(GetTriple()); llvm::SmallString<128> prebuiltModuleCachePath = GetResourceDir(triple); StringRef platform; - platform = swift::getPlatformNameForTriple(triple); + if (swift::tripleIsMacCatalystEnvironment(triple)) { + // The prebuilt cache for macCatalyst is the same as the one for macOS, + // not iOS or a separate location of its own. + platform = "macosx"; + } else { + platform = swift::getPlatformNameForTriple(triple); + } llvm::sys::path::append(prebuiltModuleCachePath, platform, "prebuilt-modules"); LOG_PRINTF(LIBLLDB_LOG_TYPES, "Using prebuilt Swift module cache path: %s", From edd876858e02d8be364f72e5a4a40b6ca8c14df3 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Mon, 13 Jan 2020 16:23:33 -0800 Subject: [PATCH 007/286] Add an lldb setting to disable ClangImporter (in favor of DWARFImporter). rdar://problem/57880844 --- lldb/include/lldb/Core/ModuleList.h | 3 ++- lldb/source/Core/CoreProperties.td | 5 ++++- lldb/source/Core/ModuleList.cpp | 10 ++++++++-- lldb/source/Symbol/SwiftASTContext.cpp | 5 ++++- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/lldb/include/lldb/Core/ModuleList.h b/lldb/include/lldb/Core/ModuleList.h index c47317af70439..1b81a9a0aa8a9 100644 --- a/lldb/include/lldb/Core/ModuleList.h +++ b/lldb/include/lldb/Core/ModuleList.h @@ -49,7 +49,8 @@ class ModuleListProperties : public Properties { public: ModuleListProperties(); - bool GetUseDWARFImporter() const; + bool GetUseSwiftClangImporter() const; + bool GetUseSwiftDWARFImporter() const; FileSpec GetClangModulesCachePath() const; bool SetClangModulesCachePath(llvm::StringRef path); SwiftModuleLoadingMode GetSwiftModuleLoadingMode() const; diff --git a/lldb/source/Core/CoreProperties.td b/lldb/source/Core/CoreProperties.td index 91da39bf47c05..c7543873cc597 100644 --- a/lldb/source/Core/CoreProperties.td +++ b/lldb/source/Core/CoreProperties.td @@ -10,7 +10,10 @@ let Definition = "modulelist" in { DefaultStringValue<"">, Desc<"The path to the clang modules cache directory (-fmodules-cache-path).">; // BEGIN SWIFT - def UseDWARFImporter: Property<"use-swift-dwarfimporter", "Boolean">, + def UseSwiftClangImporter: Property<"use-swift-clangimporter", "Boolean">, + DefaultTrue, + Desc<"Reconstruct Clang module dependencies from headers when debugging Swift code">; + def UseSwiftDWARFImporter: Property<"use-swift-dwarfimporter", "Boolean">, DefaultTrue, Desc<"Reconstruct Clang module dependencies from DWARF when debugging Swift code">; def SwiftModuleLoadingMode: Property<"swift-module-loading-mode", "Enum">, diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp index df8610c222523..8ee1846b466d6 100644 --- a/lldb/source/Core/ModuleList.cpp +++ b/lldb/source/Core/ModuleList.cpp @@ -125,8 +125,14 @@ FileSpec ModuleListProperties::GetClangModulesCachePath() const { } // BEGIN SWIFT -bool ModuleListProperties::GetUseDWARFImporter() const { - const uint32_t idx = ePropertyUseDWARFImporter; +bool ModuleListProperties::GetUseSwiftClangImporter() const { + const uint32_t idx = ePropertyUseSwiftClangImporter; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + NULL, idx, g_modulelist_properties[idx].default_uint_value != 0); +} + +bool ModuleListProperties::GetUseSwiftDWARFImporter() const { + const uint32_t idx = ePropertyUseSwiftDWARFImporter; return m_collection_sp->GetPropertyAtIndexAsBoolean( NULL, idx, g_modulelist_properties[idx].default_uint_value != 0); } diff --git a/lldb/source/Symbol/SwiftASTContext.cpp b/lldb/source/Symbol/SwiftASTContext.cpp index 0bac8f3d3c157..41e2151cc68d0 100644 --- a/lldb/source/Symbol/SwiftASTContext.cpp +++ b/lldb/source/Symbol/SwiftASTContext.cpp @@ -3260,6 +3260,9 @@ swift::ClangImporterOptions &SwiftASTContext::GetClangImporterOptions() { if (FileSystem::Instance().Exists(clang_dir_spec)) clang_importer_options.OverrideResourceDir = clang_dir_spec.GetPath(); clang_importer_options.DebuggerSupport = true; + + clang_importer_options.DisableSourceImport = + !props.GetUseSwiftClangImporter(); } return clang_importer_options; } @@ -3990,7 +3993,7 @@ swift::ASTContext *SwiftASTContext::GetASTContext() { if (!clang_importer_options.OverrideResourceDir.empty()) { // Create the DWARFImporterDelegate. auto props = ModuleList::GetGlobalModuleListProperties(); - if (props.GetUseDWARFImporter()) + if (props.GetUseSwiftDWARFImporter()) m_dwarf_importer_delegate_up = std::make_unique(*this); clang_importer_ap = swift::ClangImporter::create( From 150d09ac40599ec735b1536a511189796d99820a Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Thu, 12 Mar 2020 19:25:38 -0700 Subject: [PATCH 008/286] Add support for XFAILing a test based on a setting. This is analogous to the skipping mechanism introduced in https://reviews.llvm.org/D75864 (cherry picked from commit 57da8f720ce18100c5c6fb5c2247109e1ef963b5) --- lldb/packages/Python/lldbsuite/test/decorators.py | 6 ++++-- lldb/test/API/sanity/TestSettingSkipping.py | 8 ++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/lldb/packages/Python/lldbsuite/test/decorators.py b/lldb/packages/Python/lldbsuite/test/decorators.py index cf98cfa2957b2..ba85383125da6 100644 --- a/lldb/packages/Python/lldbsuite/test/decorators.py +++ b/lldb/packages/Python/lldbsuite/test/decorators.py @@ -259,7 +259,8 @@ def expectedFailureAll(bugnumber=None, debug_info=None, swig_version=None, py_version=None, macos_version=None, - remote=None, dwarf_version=None): + remote=None, dwarf_version=None, + setting=None): return _decorateTest(DecorateMode.Xfail, bugnumber=bugnumber, oslist=oslist, hostoslist=hostoslist, @@ -268,7 +269,8 @@ def expectedFailureAll(bugnumber=None, debug_info=debug_info, swig_version=swig_version, py_version=py_version, macos_version=None, - remote=remote,dwarf_version=dwarf_version) + remote=remote,dwarf_version=dwarf_version, + setting=setting) # provide a function to skip on defined oslist, compiler version, and archs diff --git a/lldb/test/API/sanity/TestSettingSkipping.py b/lldb/test/API/sanity/TestSettingSkipping.py index 10e7144a0068c..206c7b4ecd730 100644 --- a/lldb/test/API/sanity/TestSettingSkipping.py +++ b/lldb/test/API/sanity/TestSettingSkipping.py @@ -27,3 +27,11 @@ def testNoMatch(self): def testNotExisting(self): self.assertTrue(True, "This test should run!") + @expectedFailureAll(setting=('target.prefer-dynamic-value', 'no-dynamic-values')) + def testXFAIL(self): + self.assertTrue(False, "This test should run and fail!") + + @expectedFailureAll(setting=('target.prefer-dynamic-value', 'run-target')) + def testNotXFAIL(self): + self.assertTrue(True, "This test should run and succeed!") + From 33f05210aa76292161b4599104b6b6a8bda5994b Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Thu, 12 Mar 2020 14:19:04 -0700 Subject: [PATCH 009/286] Debug Info: Store the SDK in the DICompileUnit. This is another intermediate step for PR44213 (https://bugs.llvm.org/show_bug.cgi?id=44213). This stores the SDK *name* in the debug info, to make it possible to `-fdebug-prefix-map`-replace the sysroot with a recognizable string and allowing the debugger to find a fitting SDK relative to itself, not the machine the executable was compiled on. rdar://problem/51645582 (cherry picked from commit 842ea709e4ed881c2bc59155af5df910eccda9c6) --- clang/lib/CodeGen/CGDebugInfo.cpp | 12 +++++++++--- clang/test/CodeGen/debug-info-sysroot-sdk.c | 16 ++++++++++++++++ clang/test/CodeGen/debug-info-sysroot.c | 15 --------------- 3 files changed, 25 insertions(+), 18 deletions(-) create mode 100644 clang/test/CodeGen/debug-info-sysroot-sdk.c delete mode 100644 clang/test/CodeGen/debug-info-sysroot.c diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index d45dce9e13142..010ba496a628c 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -609,9 +609,15 @@ void CGDebugInfo::CreateCompileUnit() { remapDIPath(MainFileName), remapDIPath(getCurrentDirname()), CSInfo, getSource(SM, SM.getMainFileID())); - StringRef Sysroot; - if (CGM.getCodeGenOpts().getDebuggerTuning() == llvm::DebuggerKind::LLDB) + StringRef Sysroot, SDK; + if (CGM.getCodeGenOpts().getDebuggerTuning() == llvm::DebuggerKind::LLDB) { Sysroot = CGM.getHeaderSearchOpts().Sysroot; + auto B = llvm::sys::path::rbegin(Sysroot); + auto E = llvm::sys::path::rend(Sysroot); + auto It = std::find_if(B, E, [](auto SDK) { return SDK.endswith(".sdk"); }); + if (It != E) + SDK = *It; + } // Create new compile unit. TheCU = DBuilder.createCompileUnit( @@ -623,7 +629,7 @@ void CGDebugInfo::CreateCompileUnit() { ? llvm::DICompileUnit::DebugNameTableKind::None : static_cast( CGOpts.DebugNameTable), - CGOpts.DebugRangesBaseAddress, Sysroot); + CGOpts.DebugRangesBaseAddress, Sysroot, SDK); } llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) { diff --git a/clang/test/CodeGen/debug-info-sysroot-sdk.c b/clang/test/CodeGen/debug-info-sysroot-sdk.c new file mode 100644 index 0000000000000..5c4d201d69047 --- /dev/null +++ b/clang/test/CodeGen/debug-info-sysroot-sdk.c @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -debug-info-kind=limited -triple %itanium_abi_triple \ +// RUN: %s -isysroot /CLANG_SYSROOT/MacOSX.sdk -emit-llvm -o - \ +// RUN: -debugger-tuning=lldb | FileCheck %s --check-prefix=LLDB +// RUN: %clang_cc1 -debug-info-kind=limited -triple %itanium_abi_triple \ +// RUN: %s -isysroot /CLANG_SYSROOT/MacOSX.sdk -emit-llvm -o - \ +// RUN: -debugger-tuning=gdb | FileCheck %s --check-prefix=GDB + +void foo() {} + +// The sysroot and sdk are LLDB-tuning-specific attributes. + +// LLDB: distinct !DICompileUnit({{.*}}sysroot: "/CLANG_SYSROOT/MacOSX.sdk", +// LLDB-SAME: sdk: "MacOSX.sdk" +// GDB: distinct !DICompileUnit( +// GDB-NOT: sysroot: "/CLANG_SYSROOT/MacOSX.sdk" +// GDB-NOT: sdk: "MacOSX.sdk" diff --git a/clang/test/CodeGen/debug-info-sysroot.c b/clang/test/CodeGen/debug-info-sysroot.c deleted file mode 100644 index bb3c0c820cee6..0000000000000 --- a/clang/test/CodeGen/debug-info-sysroot.c +++ /dev/null @@ -1,15 +0,0 @@ -// RUN: %clang_cc1 -debug-info-kind=limited -triple %itanium_abi_triple \ -// RUN: %s -isysroot /CLANG_SYSROOT -emit-llvm -o - \ -// RUN: -debugger-tuning=lldb | FileCheck %s --check-prefix=LLDB -// RUN: %clang_cc1 -debug-info-kind=limited -triple %itanium_abi_triple \ -// RUN: %s -isysroot /CLANG_SYSROOT -emit-llvm -o - \ -// RUN: -debugger-tuning=gdb | FileCheck %s --check-prefix=GDB - -void foo() {} - -// The sysroot is an LLDB-tuning-specific attribute. - -// LLDB: distinct !DICompileUnit({{.*}}sysroot: "/CLANG_SYSROOT" -// GDB: distinct !DICompileUnit( -// GDB-NOT: sysroot: "/CLANG_SYSROOT" - From d5b72b34096890de8b161294552acfe1ea82ca97 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Thu, 12 Mar 2020 19:35:48 -0700 Subject: [PATCH 010/286] Skip/XFAIL tests that do not yet work with ClangImporter disabled. rdar://problem/57880844 --- lldb/packages/Python/lldbsuite/test/dotest.py | 3 ++- .../mtc/swift-property/TestMTCSwiftProperty.py | 2 ++ lldb/test/API/functionalities/mtc/swift/TestMTCSwift.py | 2 ++ .../array_tuple_resilient/TestSwiftArrayTupleResilient.py | 5 ++++- .../swift/bridged_metatype/TestSwiftBridgedMetatype.py | 3 +++ .../TestSwiftBridgingHeaderHeadermap.py | 2 ++ .../clangimporter/config_macros/TestSwiftDedupMacros.py | 2 ++ .../TestSwiftDynamicTypeResolutionImportConflict.py | 2 ++ .../extra_clang_flags/TestSwiftExtraClangFlags.py | 4 ++++ .../headermap_conflict/TestSwiftHeadermapConflict.py | 2 ++ .../include_conflict/TestSwiftIncludeConflict.py | 2 ++ .../clangimporter/macro_conflict/TestSwiftMacroConflict.py | 4 ++++ .../TestSwiftObjCMainConflictingDylibs.py | 2 ++ .../TestSwiftObjCMainConflictingDylibsBridgingHeader.py | 2 ++ .../TestSwiftObjCMainConflictingDylibsFailingImport.py | 2 ++ .../remoteast_import/TestSwiftRemoteASTImport.py | 2 ++ .../rewrite_clang_paths/TestSwiftRewriteClangPaths.py | 4 ++++ .../TestSwiftStaticArchiveTwoSwiftmodules.py | 2 ++ .../swift/deployment_target/TestSwiftDeploymentTarget.py | 4 ++++ lldb/test/API/lang/swift/enum_objc/TestEnumObjC.py | 5 ++++- .../fromobjc/TestSwiftExpressionsInMethodsFromObjc.py | 2 ++ .../first_expr_module_load/TestFirstExprModuleLoad.py | 5 ++++- .../data/TestSwiftFoundationTypeData.py | 6 +++++- .../decimal/TestSwiftFoundationTypeDecimal.py | 5 ++++- .../measurement/TestSwiftFoundationTypeMeasurement.py | 5 ++++- .../notification/TestSwiftFoundationTypeNotification.py | 5 ++++- .../url/TestSwiftFoundationTypeURL.py | 5 ++++- .../main_executable/TestMainExecutable.py | 4 ++++ .../lang/swift/mix_any_object/TestSwiftMixAnyObjectType.py | 2 ++ .../multilang_category/TestMultilangFormatterCategories.py | 2 ++ .../TestSwiftNSArrayCodeRunningFormatter.py | 5 ++++- .../swift/objc_inherited_ivars/TestSwiftAtObjCIvars.py | 2 ++ .../lang/swift/objc_runtime_ivars/TestObjCIvarDiscovery.py | 4 ++++ .../API/lang/swift/optionset/TestSwiftOptionSetType.py | 5 ++++- .../TestProtocolExtensionComputerProperty.py | 7 ++++++- .../class_protocol/TestClassConstrainedProtocolArgument.py | 7 ++++++- .../lang/swift/swiftieformatting/TestSwiftieFormatting.py | 2 ++ .../lang/swift/tagged_pointer/TestSwiftTaggedPointer.py | 5 ++++- .../test/API/lang/swift/{clangimporter => }/union/Makefile | 0 .../swift/{clangimporter => }/union/TestSwiftCUnion.py | 2 ++ .../API/lang/swift/{clangimporter => }/union/main.swift | 0 .../lang/swift/{clangimporter => }/union/module.modulemap | 0 lldb/test/API/lang/swift/{clangimporter => }/union/union.h | 0 .../swift/unknown_reference/TestSwiftUnknownReference.py | 3 +++ .../API/lang/swift/unknown_self/TestSwiftUnknownSelf.py | 6 ++++-- .../TestSwiftDictionaryNSObjectAnyObject.py | 2 ++ .../API/lang/swift/variables/objc/TestObjCImportedTypes.py | 2 ++ .../variables/objc_optionals/TestSwiftObjCOptionals.py | 2 ++ 48 files changed, 135 insertions(+), 16 deletions(-) rename lldb/test/API/lang/swift/{clangimporter => }/union/Makefile (100%) rename lldb/test/API/lang/swift/{clangimporter => }/union/TestSwiftCUnion.py (81%) rename lldb/test/API/lang/swift/{clangimporter => }/union/main.swift (100%) rename lldb/test/API/lang/swift/{clangimporter => }/union/module.modulemap (100%) rename lldb/test/API/lang/swift/{clangimporter => }/union/union.h (100%) diff --git a/lldb/packages/Python/lldbsuite/test/dotest.py b/lldb/packages/Python/lldbsuite/test/dotest.py index bdb20705fe66e..d3452cc8bd854 100644 --- a/lldb/packages/Python/lldbsuite/test/dotest.py +++ b/lldb/packages/Python/lldbsuite/test/dotest.py @@ -352,7 +352,8 @@ def parseOptionsAndInitTestdirs(): logging.error('"%s" is not a setting in the form "key=value"', setting[0]) sys.exit(-1) - configuration.settings.append(setting[0].split('=', 1)) + setting_list = setting[0].split('=', 1) + configuration.settings.append((setting_list[0], setting_list[1])) if args.d: sys.stdout.write( diff --git a/lldb/test/API/functionalities/mtc/swift-property/TestMTCSwiftProperty.py b/lldb/test/API/functionalities/mtc/swift-property/TestMTCSwiftProperty.py index 521d3d130a92c..fa26a727aa3df 100644 --- a/lldb/test/API/functionalities/mtc/swift-property/TestMTCSwiftProperty.py +++ b/lldb/test/API/functionalities/mtc/swift-property/TestMTCSwiftProperty.py @@ -16,6 +16,8 @@ class MTCSwiftPropertyTestCase(TestBase): mydir = TestBase.compute_mydir(__file__) + @expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin def test(self): self.mtc_dylib_path = findMainThreadCheckerDylib() diff --git a/lldb/test/API/functionalities/mtc/swift/TestMTCSwift.py b/lldb/test/API/functionalities/mtc/swift/TestMTCSwift.py index ba1bf3262b95c..5aa3d85f0047e 100644 --- a/lldb/test/API/functionalities/mtc/swift/TestMTCSwift.py +++ b/lldb/test/API/functionalities/mtc/swift/TestMTCSwift.py @@ -16,6 +16,8 @@ class MTCSwiftTestCase(TestBase): mydir = TestBase.compute_mydir(__file__) + @expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin def test(self): self.mtc_dylib_path = findMainThreadCheckerDylib() diff --git a/lldb/test/API/lang/swift/array_tuple_resilient/TestSwiftArrayTupleResilient.py b/lldb/test/API/lang/swift/array_tuple_resilient/TestSwiftArrayTupleResilient.py index fce1c086555d4..96679bbaac78d 100644 --- a/lldb/test/API/lang/swift/array_tuple_resilient/TestSwiftArrayTupleResilient.py +++ b/lldb/test/API/lang/swift/array_tuple_resilient/TestSwiftArrayTupleResilient.py @@ -1,4 +1,7 @@ import lldbsuite.test.lldbinline as lldbinline from lldbsuite.test.decorators import * -lldbinline.MakeInlineTest(__file__, globals(), decorators=[swiftTest, skipUnlessDarwin]) +lldbinline.MakeInlineTest(__file__, globals(), decorators=[swiftTest, skipUnlessDarwin, +expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) +]) diff --git a/lldb/test/API/lang/swift/bridged_metatype/TestSwiftBridgedMetatype.py b/lldb/test/API/lang/swift/bridged_metatype/TestSwiftBridgedMetatype.py index 51433ef657b4d..d9a801d7aaf2e 100644 --- a/lldb/test/API/lang/swift/bridged_metatype/TestSwiftBridgedMetatype.py +++ b/lldb/test/API/lang/swift/bridged_metatype/TestSwiftBridgedMetatype.py @@ -16,6 +16,9 @@ class TestSwiftBridgedMetatype(TestBase): def setUp(self): TestBase.setUp(self) + @expectedFailureAll(bugnumber="rdar://60396797", + oslist=lldbplatform.darwin_all, + setting=('symbols.use-swift-clangimporter', 'false')) @swiftTest def test_swift_bridged_metatype(self): """Test the formatting of bridged Swift metatypes""" diff --git a/lldb/test/API/lang/swift/clangimporter/bridging_header_headermap/TestSwiftBridgingHeaderHeadermap.py b/lldb/test/API/lang/swift/clangimporter/bridging_header_headermap/TestSwiftBridgingHeaderHeadermap.py index e5e5bbb05e77a..535e4787d5fb0 100644 --- a/lldb/test/API/lang/swift/clangimporter/bridging_header_headermap/TestSwiftBridgingHeaderHeadermap.py +++ b/lldb/test/API/lang/swift/clangimporter/bridging_header_headermap/TestSwiftBridgingHeaderHeadermap.py @@ -26,6 +26,8 @@ class TestSwiftBridgingHeaderHeadermap(TestBase): def setUp(self): TestBase.setUp(self) + # Don't run ClangImporter tests if Clangimporter is disabled. + @skipIf(setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test(self): diff --git a/lldb/test/API/lang/swift/clangimporter/config_macros/TestSwiftDedupMacros.py b/lldb/test/API/lang/swift/clangimporter/config_macros/TestSwiftDedupMacros.py index f782d6dd8ba19..a7f6c3157c2fa 100644 --- a/lldb/test/API/lang/swift/clangimporter/config_macros/TestSwiftDedupMacros.py +++ b/lldb/test/API/lang/swift/clangimporter/config_macros/TestSwiftDedupMacros.py @@ -24,6 +24,8 @@ class TestSwiftDedupMacros(TestBase): def setUp(self): TestBase.setUp(self) + # Don't run ClangImporter tests if Clangimporter is disabled. + @skipIf(setting=('symbols.use-swift-clangimporter', 'false')) # NOTE: rdar://44201206 - This test may sporadically segfault. It's likely # that the underlying memory corruption issue has been addressed, but due # to the difficulty of reproducing the crash, we are not sure. If a crash diff --git a/lldb/test/API/lang/swift/clangimporter/dynamic_type_resolution_import_conflict/TestSwiftDynamicTypeResolutionImportConflict.py b/lldb/test/API/lang/swift/clangimporter/dynamic_type_resolution_import_conflict/TestSwiftDynamicTypeResolutionImportConflict.py index cc9484aebd26f..36a9714cf802a 100644 --- a/lldb/test/API/lang/swift/clangimporter/dynamic_type_resolution_import_conflict/TestSwiftDynamicTypeResolutionImportConflict.py +++ b/lldb/test/API/lang/swift/clangimporter/dynamic_type_resolution_import_conflict/TestSwiftDynamicTypeResolutionImportConflict.py @@ -25,6 +25,8 @@ class TestSwiftDynamicTypeResolutionImportConflict(TestBase): def setUp(self): TestBase.setUp(self) + # Don't run ClangImporter tests if Clangimporter is disabled. + @skipIf(setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test(self): diff --git a/lldb/test/API/lang/swift/clangimporter/extra_clang_flags/TestSwiftExtraClangFlags.py b/lldb/test/API/lang/swift/clangimporter/extra_clang_flags/TestSwiftExtraClangFlags.py index d86e559badf65..a7965ae8d5165 100644 --- a/lldb/test/API/lang/swift/clangimporter/extra_clang_flags/TestSwiftExtraClangFlags.py +++ b/lldb/test/API/lang/swift/clangimporter/extra_clang_flags/TestSwiftExtraClangFlags.py @@ -11,6 +11,8 @@ class TestSwiftExtraClangFlags(TestBase): def setUp(self): TestBase.setUp(self) + # Don't run ClangImporter tests if Clangimporter is disabled. + @skipIf(setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test_sanity(self): @@ -20,6 +22,8 @@ def test_sanity(self): self.expect("frame var foo", "sanity check", substrs=['(Foo)']) self.expect("expr FromOverlay(i: 23)", error=True) + # Don't run ClangImporter tests if Clangimporter is disabled. + @skipIf(setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test_extra_clang_flags(self): diff --git a/lldb/test/API/lang/swift/clangimporter/headermap_conflict/TestSwiftHeadermapConflict.py b/lldb/test/API/lang/swift/clangimporter/headermap_conflict/TestSwiftHeadermapConflict.py index d0233276868ae..5e678bc565479 100644 --- a/lldb/test/API/lang/swift/clangimporter/headermap_conflict/TestSwiftHeadermapConflict.py +++ b/lldb/test/API/lang/swift/clangimporter/headermap_conflict/TestSwiftHeadermapConflict.py @@ -25,6 +25,8 @@ class TestSwiftHeadermapConflict(TestBase): def setUp(self): TestBase.setUp(self) + @skipIf(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test(self): diff --git a/lldb/test/API/lang/swift/clangimporter/include_conflict/TestSwiftIncludeConflict.py b/lldb/test/API/lang/swift/clangimporter/include_conflict/TestSwiftIncludeConflict.py index 12dc7a243a4e7..72b7e0014aeac 100644 --- a/lldb/test/API/lang/swift/clangimporter/include_conflict/TestSwiftIncludeConflict.py +++ b/lldb/test/API/lang/swift/clangimporter/include_conflict/TestSwiftIncludeConflict.py @@ -25,6 +25,8 @@ class TestSwiftIncludeConflict(TestBase): def setUp(self): TestBase.setUp(self) + # Don't run ClangImporter tests if Clangimporter is disabled. + @skipIf(setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test(self): diff --git a/lldb/test/API/lang/swift/clangimporter/macro_conflict/TestSwiftMacroConflict.py b/lldb/test/API/lang/swift/clangimporter/macro_conflict/TestSwiftMacroConflict.py index 4073bd220b8c5..c69874d39d30c 100644 --- a/lldb/test/API/lang/swift/clangimporter/macro_conflict/TestSwiftMacroConflict.py +++ b/lldb/test/API/lang/swift/clangimporter/macro_conflict/TestSwiftMacroConflict.py @@ -25,6 +25,8 @@ class TestSwiftMacroConflict(TestBase): def setUp(self): TestBase.setUp(self) + # Don't run ClangImporter tests if Clangimporter is disabled. + @skipIf(setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test(self): @@ -61,6 +63,8 @@ def test(self): self.assertTrue(os.path.isdir(mod_cache), "module cache exists") lldb.SBDebugger.MemoryPressureDetected() + # Don't run ClangImporter tests if Clangimporter is disabled. + @skipIf(setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test_with_dwarfimporter(self): diff --git a/lldb/test/API/lang/swift/clangimporter/objcmain_conflicting_dylibs/TestSwiftObjCMainConflictingDylibs.py b/lldb/test/API/lang/swift/clangimporter/objcmain_conflicting_dylibs/TestSwiftObjCMainConflictingDylibs.py index 9ba124a8454d2..32b045ba76196 100644 --- a/lldb/test/API/lang/swift/clangimporter/objcmain_conflicting_dylibs/TestSwiftObjCMainConflictingDylibs.py +++ b/lldb/test/API/lang/swift/clangimporter/objcmain_conflicting_dylibs/TestSwiftObjCMainConflictingDylibs.py @@ -25,6 +25,8 @@ class TestSwiftObjCMainConflictingDylibs(TestBase): def setUp(self): TestBase.setUp(self) + # Don't run ClangImporter tests if Clangimporter is disabled. + @skipIf(setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test(self): diff --git a/lldb/test/API/lang/swift/clangimporter/objcmain_conflicting_dylibs_bridging_headers/TestSwiftObjCMainConflictingDylibsBridgingHeader.py b/lldb/test/API/lang/swift/clangimporter/objcmain_conflicting_dylibs_bridging_headers/TestSwiftObjCMainConflictingDylibsBridgingHeader.py index 1d8feabea3322..89a66fd060a7d 100644 --- a/lldb/test/API/lang/swift/clangimporter/objcmain_conflicting_dylibs_bridging_headers/TestSwiftObjCMainConflictingDylibsBridgingHeader.py +++ b/lldb/test/API/lang/swift/clangimporter/objcmain_conflicting_dylibs_bridging_headers/TestSwiftObjCMainConflictingDylibsBridgingHeader.py @@ -25,6 +25,8 @@ class TestSwiftObjCMainConflictingDylibsBridgingHeader(TestBase): def setUp(self): TestBase.setUp(self) + # Don't run ClangImporter tests if Clangimporter is disabled. + @skipIf(setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test(self): diff --git a/lldb/test/API/lang/swift/clangimporter/objcmain_conflicting_dylibs_failing_import/TestSwiftObjCMainConflictingDylibsFailingImport.py b/lldb/test/API/lang/swift/clangimporter/objcmain_conflicting_dylibs_failing_import/TestSwiftObjCMainConflictingDylibsFailingImport.py index 3734f5592590a..60026f27394aa 100644 --- a/lldb/test/API/lang/swift/clangimporter/objcmain_conflicting_dylibs_failing_import/TestSwiftObjCMainConflictingDylibsFailingImport.py +++ b/lldb/test/API/lang/swift/clangimporter/objcmain_conflicting_dylibs_failing_import/TestSwiftObjCMainConflictingDylibsFailingImport.py @@ -25,6 +25,8 @@ class TestSwiftObjCMainConflictingDylibsFailingImport(TestBase): def setUp(self): TestBase.setUp(self) + # Don't run ClangImporter tests if Clangimporter is disabled. + @skipIf(setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test(self): diff --git a/lldb/test/API/lang/swift/clangimporter/remoteast_import/TestSwiftRemoteASTImport.py b/lldb/test/API/lang/swift/clangimporter/remoteast_import/TestSwiftRemoteASTImport.py index efbcab8ec6104..0928c9243bf6e 100644 --- a/lldb/test/API/lang/swift/clangimporter/remoteast_import/TestSwiftRemoteASTImport.py +++ b/lldb/test/API/lang/swift/clangimporter/remoteast_import/TestSwiftRemoteASTImport.py @@ -24,6 +24,8 @@ class TestSwiftRemoteASTImport(TestBase): def setUp(self): TestBase.setUp(self) + # Don't run ClangImporter tests if Clangimporter is disabled. + @skipIf(setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def testSwiftRemoteASTImport(self): diff --git a/lldb/test/API/lang/swift/clangimporter/rewrite_clang_paths/TestSwiftRewriteClangPaths.py b/lldb/test/API/lang/swift/clangimporter/rewrite_clang_paths/TestSwiftRewriteClangPaths.py index 52ce620b3859e..f7e54b3885a9c 100644 --- a/lldb/test/API/lang/swift/clangimporter/rewrite_clang_paths/TestSwiftRewriteClangPaths.py +++ b/lldb/test/API/lang/swift/clangimporter/rewrite_clang_paths/TestSwiftRewriteClangPaths.py @@ -25,12 +25,16 @@ class TestSwiftRewriteClangPaths(TestBase): def setUp(self): TestBase.setUp(self) + # Don't run ClangImporter tests if Clangimporter is disabled. + @skipIf(setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest @skipIf(debug_info=no_match(["dsym"])) def testWithRemap(self): self.dotest(True) + # Don't run ClangImporter tests if Clangimporter is disabled. + @skipIf(setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest @skipIf(debug_info=no_match(["dsym"])) diff --git a/lldb/test/API/lang/swift/clangimporter/static_archive/TestSwiftStaticArchiveTwoSwiftmodules.py b/lldb/test/API/lang/swift/clangimporter/static_archive/TestSwiftStaticArchiveTwoSwiftmodules.py index 19d918d5196b9..8fef90151bda6 100644 --- a/lldb/test/API/lang/swift/clangimporter/static_archive/TestSwiftStaticArchiveTwoSwiftmodules.py +++ b/lldb/test/API/lang/swift/clangimporter/static_archive/TestSwiftStaticArchiveTwoSwiftmodules.py @@ -25,6 +25,8 @@ class TestSwiftStaticArchiveTwoSwiftmodules(TestBase): def setUp(self): TestBase.setUp(self) + # Don't run ClangImporter tests if Clangimporter is disabled. + @skipIf(setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test(self): diff --git a/lldb/test/API/lang/swift/deployment_target/TestSwiftDeploymentTarget.py b/lldb/test/API/lang/swift/deployment_target/TestSwiftDeploymentTarget.py index 805407b49b429..62b13e5361aea 100644 --- a/lldb/test/API/lang/swift/deployment_target/TestSwiftDeploymentTarget.py +++ b/lldb/test/API/lang/swift/deployment_target/TestSwiftDeploymentTarget.py @@ -23,6 +23,8 @@ class TestSwiftDeploymentTarget(TestBase): mydir = TestBase.compute_mydir(__file__) + @skipIf(bugnumber="rdar://60396797", # should work but crashes. + setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @skipIfDarwinEmbedded # This test uses macOS triples explicitly. @skipIf(macos_version=["<", "10.11"]) @@ -35,6 +37,8 @@ def test_swift_deployment_target(self): lldb.SBFileSpec('main.swift')) self.expect("p f", substrs=['i = 23']) + @skipIf(bugnumber="rdar://60396797", # should work but crashes. + setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @skipIfDarwinEmbedded # This test uses macOS triples explicitely. @skipIf(macos_version=["<", "10.11"]) diff --git a/lldb/test/API/lang/swift/enum_objc/TestEnumObjC.py b/lldb/test/API/lang/swift/enum_objc/TestEnumObjC.py index e0768afb05784..3765776a47a6d 100644 --- a/lldb/test/API/lang/swift/enum_objc/TestEnumObjC.py +++ b/lldb/test/API/lang/swift/enum_objc/TestEnumObjC.py @@ -1,4 +1,7 @@ import lldbsuite.test.lldbinline as lldbinline from lldbsuite.test.decorators import * -lldbinline.MakeInlineTest(__file__, globals(), decorators=[swiftTest]) +lldbinline.MakeInlineTest(__file__, globals(), decorators=[ + skipIf(bugnumber="rdar://60396797", # should work but crashes. + setting=('symbols.use-swift-clangimporter', 'false')), + swiftTest]) diff --git a/lldb/test/API/lang/swift/expression/classes/fromobjc/TestSwiftExpressionsInMethodsFromObjc.py b/lldb/test/API/lang/swift/expression/classes/fromobjc/TestSwiftExpressionsInMethodsFromObjc.py index 530d848e5ceb7..ea7082247053e 100644 --- a/lldb/test/API/lang/swift/expression/classes/fromobjc/TestSwiftExpressionsInMethodsFromObjc.py +++ b/lldb/test/API/lang/swift/expression/classes/fromobjc/TestSwiftExpressionsInMethodsFromObjc.py @@ -39,6 +39,8 @@ def check_expression(self, expression, expected_result, use_summary=True): expression, expected_result, answer) self.assertTrue(answer == expected_result, report_str) + @skipIf(bugnumber="rdar://60396797", # should work but crashes. + setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test_swift_expressions_from_objc(self): diff --git a/lldb/test/API/lang/swift/first_expr_module_load/TestFirstExprModuleLoad.py b/lldb/test/API/lang/swift/first_expr_module_load/TestFirstExprModuleLoad.py index fce1c086555d4..4b0198aa71da0 100644 --- a/lldb/test/API/lang/swift/first_expr_module_load/TestFirstExprModuleLoad.py +++ b/lldb/test/API/lang/swift/first_expr_module_load/TestFirstExprModuleLoad.py @@ -1,4 +1,7 @@ import lldbsuite.test.lldbinline as lldbinline from lldbsuite.test.decorators import * -lldbinline.MakeInlineTest(__file__, globals(), decorators=[swiftTest, skipUnlessDarwin]) +lldbinline.MakeInlineTest(__file__, globals(), decorators=[swiftTest, skipUnlessDarwin, + skipIf(bugnumber="rdar://60396797", # should work but crashes. + setting=('symbols.use-swift-clangimporter', 'false')) +]) diff --git a/lldb/test/API/lang/swift/foundation_value_types/data/TestSwiftFoundationTypeData.py b/lldb/test/API/lang/swift/foundation_value_types/data/TestSwiftFoundationTypeData.py index ac0e40de886fb..a33c05bfa7621 100644 --- a/lldb/test/API/lang/swift/foundation_value_types/data/TestSwiftFoundationTypeData.py +++ b/lldb/test/API/lang/swift/foundation_value_types/data/TestSwiftFoundationTypeData.py @@ -13,4 +13,8 @@ from lldbsuite.test.decorators import * lldbinline.MakeInlineTest(__file__, globals(), - decorators=[swiftTest,skipUnlessDarwin]) + decorators=[ + swiftTest,skipUnlessDarwin, + skipIf(bugnumber="rdar://60396797", # should work but crashes. + setting=('symbols.use-swift-clangimporter', 'false')) +]) diff --git a/lldb/test/API/lang/swift/foundation_value_types/decimal/TestSwiftFoundationTypeDecimal.py b/lldb/test/API/lang/swift/foundation_value_types/decimal/TestSwiftFoundationTypeDecimal.py index 1048d65fc050a..f761b3c67c24f 100644 --- a/lldb/test/API/lang/swift/foundation_value_types/decimal/TestSwiftFoundationTypeDecimal.py +++ b/lldb/test/API/lang/swift/foundation_value_types/decimal/TestSwiftFoundationTypeDecimal.py @@ -2,4 +2,7 @@ from lldbsuite.test.decorators import * lldbinline.MakeInlineTest(__file__, globals(), - decorators=[swiftTest,skipUnlessDarwin]) + decorators=[swiftTest,skipUnlessDarwin, +expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) +]) diff --git a/lldb/test/API/lang/swift/foundation_value_types/measurement/TestSwiftFoundationTypeMeasurement.py b/lldb/test/API/lang/swift/foundation_value_types/measurement/TestSwiftFoundationTypeMeasurement.py index e437f6658979b..e5a427a50c096 100644 --- a/lldb/test/API/lang/swift/foundation_value_types/measurement/TestSwiftFoundationTypeMeasurement.py +++ b/lldb/test/API/lang/swift/foundation_value_types/measurement/TestSwiftFoundationTypeMeasurement.py @@ -13,4 +13,7 @@ from lldbsuite.test.decorators import * lldbinline.MakeInlineTest(__file__, globals(), - decorators=[swiftTest,skipUnlessDarwin]) + decorators=[swiftTest,skipUnlessDarwin, + expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) +]) diff --git a/lldb/test/API/lang/swift/foundation_value_types/notification/TestSwiftFoundationTypeNotification.py b/lldb/test/API/lang/swift/foundation_value_types/notification/TestSwiftFoundationTypeNotification.py index 12199fb21e44c..dff8c5c16c87f 100644 --- a/lldb/test/API/lang/swift/foundation_value_types/notification/TestSwiftFoundationTypeNotification.py +++ b/lldb/test/API/lang/swift/foundation_value_types/notification/TestSwiftFoundationTypeNotification.py @@ -14,4 +14,7 @@ lldbinline.MakeInlineTest( __file__, globals(), decorators= - [skipUnlessDarwin,swiftTest]) + [skipUnlessDarwin,swiftTest, + expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) +]) diff --git a/lldb/test/API/lang/swift/foundation_value_types/url/TestSwiftFoundationTypeURL.py b/lldb/test/API/lang/swift/foundation_value_types/url/TestSwiftFoundationTypeURL.py index 958c8fac57091..54eb5c2ba5fb5 100644 --- a/lldb/test/API/lang/swift/foundation_value_types/url/TestSwiftFoundationTypeURL.py +++ b/lldb/test/API/lang/swift/foundation_value_types/url/TestSwiftFoundationTypeURL.py @@ -13,4 +13,7 @@ from lldbsuite.test.decorators import * lldbinline.MakeInlineTest(__file__, globals(), - decorators=[swiftTest,skipUnlessDarwin]) + decorators=[swiftTest,skipUnlessDarwin, + expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) +]) diff --git a/lldb/test/API/lang/swift/implementation_only_imports/main_executable/TestMainExecutable.py b/lldb/test/API/lang/swift/implementation_only_imports/main_executable/TestMainExecutable.py index ec0dc06fa7e57..b270013704ce8 100644 --- a/lldb/test/API/lang/swift/implementation_only_imports/main_executable/TestMainExecutable.py +++ b/lldb/test/API/lang/swift/implementation_only_imports/main_executable/TestMainExecutable.py @@ -41,6 +41,8 @@ def launch_info(self): return info + @skipIf(bugnumber="rdar://problem/54322424", # This test is unreliable. + setting=('symbols.use-swift-clangimporter', 'false')) @swiftTest def test_implementation_only_import_main_executable(self): """Test `@_implementationOnly import` in the main executable @@ -64,6 +66,8 @@ def cleanup(): self.expect("e container", substrs=["(main.ContainsTwoInts)", "wrapped = (first = 2, second = 3)", "other = 10"]) self.expect("e TwoInts(4, 5)", substrs=["(SomeLibrary.TwoInts)", "= (first = 4, second = 5)"]) + @skipIf(bugnumber="rdar://problem/54322424", # This test is unreliable. + setting=('symbols.use-swift-clangimporter', 'false')) @swiftTest def test_implementation_only_import_main_executable_no_library_module(self): """Test `@_implementationOnly import` in the main executable, after removing the library's swiftmodule diff --git a/lldb/test/API/lang/swift/mix_any_object/TestSwiftMixAnyObjectType.py b/lldb/test/API/lang/swift/mix_any_object/TestSwiftMixAnyObjectType.py index fb92e3e3fd10b..22206dcb9785f 100644 --- a/lldb/test/API/lang/swift/mix_any_object/TestSwiftMixAnyObjectType.py +++ b/lldb/test/API/lang/swift/mix_any_object/TestSwiftMixAnyObjectType.py @@ -27,6 +27,8 @@ class TestSwiftMixAnyObjectType(TestBase): def setUp(self): TestBase.setUp(self) + @expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test_any_object_type(self): diff --git a/lldb/test/API/lang/swift/multilang_category/TestMultilangFormatterCategories.py b/lldb/test/API/lang/swift/multilang_category/TestMultilangFormatterCategories.py index e7943cdc81072..1083924d9149d 100644 --- a/lldb/test/API/lang/swift/multilang_category/TestMultilangFormatterCategories.py +++ b/lldb/test/API/lang/swift/multilang_category/TestMultilangFormatterCategories.py @@ -15,6 +15,8 @@ class TestMultilangFormatterCategories(TestBase): def setUp(self): TestBase.setUp(self) + @expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) @swiftTest @skipUnlessDarwin def test_multilang_formatter_categories(self): diff --git a/lldb/test/API/lang/swift/nsarray_code_running_formatter/TestSwiftNSArrayCodeRunningFormatter.py b/lldb/test/API/lang/swift/nsarray_code_running_formatter/TestSwiftNSArrayCodeRunningFormatter.py index 1c98a0c0e26e0..3a2b20512cd22 100644 --- a/lldb/test/API/lang/swift/nsarray_code_running_formatter/TestSwiftNSArrayCodeRunningFormatter.py +++ b/lldb/test/API/lang/swift/nsarray_code_running_formatter/TestSwiftNSArrayCodeRunningFormatter.py @@ -13,4 +13,7 @@ from lldbsuite.test.decorators import * lldbinline.MakeInlineTest(__file__, globals(), - decorators=[swiftTest,skipUnlessDarwin]) + decorators=[swiftTest,skipUnlessDarwin, +expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) +]) diff --git a/lldb/test/API/lang/swift/objc_inherited_ivars/TestSwiftAtObjCIvars.py b/lldb/test/API/lang/swift/objc_inherited_ivars/TestSwiftAtObjCIvars.py index 9d2bac2d36d02..d3b8b1bc13a79 100644 --- a/lldb/test/API/lang/swift/objc_inherited_ivars/TestSwiftAtObjCIvars.py +++ b/lldb/test/API/lang/swift/objc_inherited_ivars/TestSwiftAtObjCIvars.py @@ -33,6 +33,8 @@ def check_foo(self, theFoo): lldbutil.check_variable(self, x, False, value='12') lldbutil.check_variable(self, y, False, '"12"') + @expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test_swift_at_objc_ivars(self): diff --git a/lldb/test/API/lang/swift/objc_runtime_ivars/TestObjCIvarDiscovery.py b/lldb/test/API/lang/swift/objc_runtime_ivars/TestObjCIvarDiscovery.py index b9d7ea746ad57..12a868e830ef4 100644 --- a/lldb/test/API/lang/swift/objc_runtime_ivars/TestObjCIvarDiscovery.py +++ b/lldb/test/API/lang/swift/objc_runtime_ivars/TestObjCIvarDiscovery.py @@ -26,6 +26,8 @@ class TestObjCIVarDiscovery(TestBase): mydir = TestBase.compute_mydir(__file__) + @expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @skipIf(debug_info=no_match("dsym")) def test_nodbg(self): @@ -33,6 +35,8 @@ def test_nodbg(self): shutil.rmtree(self.getBuildArtifact("aTestFramework.framework/Versions/A/aTestFramework.dSYM")) self.do_test(False) + @expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @skipIf(debug_info=no_match("dsym")) def test_dbg(self): diff --git a/lldb/test/API/lang/swift/optionset/TestSwiftOptionSetType.py b/lldb/test/API/lang/swift/optionset/TestSwiftOptionSetType.py index dcdf2eebfc01d..e12d83951c722 100644 --- a/lldb/test/API/lang/swift/optionset/TestSwiftOptionSetType.py +++ b/lldb/test/API/lang/swift/optionset/TestSwiftOptionSetType.py @@ -13,4 +13,7 @@ from lldbsuite.test.decorators import * lldbinline.MakeInlineTest(__file__, globals(), - decorators=[swiftTest,skipUnlessDarwin]) + decorators=[swiftTest,skipUnlessDarwin, + expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) +]) diff --git a/lldb/test/API/lang/swift/protocol_extension_computed_property/TestProtocolExtensionComputerProperty.py b/lldb/test/API/lang/swift/protocol_extension_computed_property/TestProtocolExtensionComputerProperty.py index dad5915422c91..37ed3f1358668 100644 --- a/lldb/test/API/lang/swift/protocol_extension_computed_property/TestProtocolExtensionComputerProperty.py +++ b/lldb/test/API/lang/swift/protocol_extension_computed_property/TestProtocolExtensionComputerProperty.py @@ -2,4 +2,9 @@ from lldbsuite.test.decorators import * lldbinline.MakeInlineTest( - __file__, globals(), decorators=[skipUnlessDarwin]) + __file__, globals(), + decorators=[ + swiftTest,skipUnlessDarwin, + skipIf(bugnumber="rdar://60396797", # should work but crashes. + setting=('symbols.use-swift-clangimporter', 'false')) + ]) diff --git a/lldb/test/API/lang/swift/protocols/class_protocol/TestClassConstrainedProtocolArgument.py b/lldb/test/API/lang/swift/protocols/class_protocol/TestClassConstrainedProtocolArgument.py index 6e52c7fabea8b..ba4271dfb6ba5 100644 --- a/lldb/test/API/lang/swift/protocols/class_protocol/TestClassConstrainedProtocolArgument.py +++ b/lldb/test/API/lang/swift/protocols/class_protocol/TestClassConstrainedProtocolArgument.py @@ -6,4 +6,9 @@ from lldbsuite.test.decorators import * lldbinline.MakeInlineTest( - __file__, globals(), decorators=[skipUnlessDarwin]) + __file__, globals(), + decorators=[ + swiftTest,skipUnlessDarwin, + skipIf(bugnumber="rdar://60396797", # should work but crashes. + setting=('symbols.use-swift-clangimporter', 'false')) + ]) diff --git a/lldb/test/API/lang/swift/swiftieformatting/TestSwiftieFormatting.py b/lldb/test/API/lang/swift/swiftieformatting/TestSwiftieFormatting.py index ae2518494dded..2a15f434f3dae 100644 --- a/lldb/test/API/lang/swift/swiftieformatting/TestSwiftieFormatting.py +++ b/lldb/test/API/lang/swift/swiftieformatting/TestSwiftieFormatting.py @@ -27,6 +27,8 @@ class TestSwiftieFormatting(TestBase): def setUp(self): TestBase.setUp(self) + @expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test_swiftie_formatting(self): diff --git a/lldb/test/API/lang/swift/tagged_pointer/TestSwiftTaggedPointer.py b/lldb/test/API/lang/swift/tagged_pointer/TestSwiftTaggedPointer.py index 5d776c004560e..3ab081c71d808 100644 --- a/lldb/test/API/lang/swift/tagged_pointer/TestSwiftTaggedPointer.py +++ b/lldb/test/API/lang/swift/tagged_pointer/TestSwiftTaggedPointer.py @@ -15,4 +15,7 @@ # This test depends on NSObject, so it is not available on non-Darwin # platforms. lldbinline.MakeInlineTest(__file__, globals(), - decorators=[swiftTest,skipUnlessDarwin]) + decorators=[swiftTest,skipUnlessDarwin, + expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) +]) diff --git a/lldb/test/API/lang/swift/clangimporter/union/Makefile b/lldb/test/API/lang/swift/union/Makefile similarity index 100% rename from lldb/test/API/lang/swift/clangimporter/union/Makefile rename to lldb/test/API/lang/swift/union/Makefile diff --git a/lldb/test/API/lang/swift/clangimporter/union/TestSwiftCUnion.py b/lldb/test/API/lang/swift/union/TestSwiftCUnion.py similarity index 81% rename from lldb/test/API/lang/swift/clangimporter/union/TestSwiftCUnion.py rename to lldb/test/API/lang/swift/union/TestSwiftCUnion.py index cfc67659a64d2..f684c9299329f 100644 --- a/lldb/test/API/lang/swift/clangimporter/union/TestSwiftCUnion.py +++ b/lldb/test/API/lang/swift/union/TestSwiftCUnion.py @@ -10,6 +10,8 @@ class TestSwiftAnyType(lldbtest.TestBase): mydir = lldbtest.TestBase.compute_mydir(__file__) + @expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) @swiftTest def test_c_unions(self): self.build() diff --git a/lldb/test/API/lang/swift/clangimporter/union/main.swift b/lldb/test/API/lang/swift/union/main.swift similarity index 100% rename from lldb/test/API/lang/swift/clangimporter/union/main.swift rename to lldb/test/API/lang/swift/union/main.swift diff --git a/lldb/test/API/lang/swift/clangimporter/union/module.modulemap b/lldb/test/API/lang/swift/union/module.modulemap similarity index 100% rename from lldb/test/API/lang/swift/clangimporter/union/module.modulemap rename to lldb/test/API/lang/swift/union/module.modulemap diff --git a/lldb/test/API/lang/swift/clangimporter/union/union.h b/lldb/test/API/lang/swift/union/union.h similarity index 100% rename from lldb/test/API/lang/swift/clangimporter/union/union.h rename to lldb/test/API/lang/swift/union/union.h diff --git a/lldb/test/API/lang/swift/unknown_reference/TestSwiftUnknownReference.py b/lldb/test/API/lang/swift/unknown_reference/TestSwiftUnknownReference.py index 41ef074771239..b53709d817a75 100644 --- a/lldb/test/API/lang/swift/unknown_reference/TestSwiftUnknownReference.py +++ b/lldb/test/API/lang/swift/unknown_reference/TestSwiftUnknownReference.py @@ -29,6 +29,9 @@ def check_class(self, var_self): lldbutil.check_variable(self, m_string, summary='"world"') + @expectedFailureAll(bugnumber="rdar://60396797", + oslist=lldbplatform.darwin_all, + setting=('symbols.use-swift-clangimporter', 'false')) @swiftTest def test_unknown_objc_ref(self): """Test unknown references to Objective-C objects.""" diff --git a/lldb/test/API/lang/swift/unknown_self/TestSwiftUnknownSelf.py b/lldb/test/API/lang/swift/unknown_self/TestSwiftUnknownSelf.py index fc350caf3b02f..6e484a7bac7ef 100644 --- a/lldb/test/API/lang/swift/unknown_self/TestSwiftUnknownSelf.py +++ b/lldb/test/API/lang/swift/unknown_self/TestSwiftUnknownSelf.py @@ -33,8 +33,10 @@ def check_class(self, var_self, broken): self.expect("fr v self", substrs=["hello", "world"]) - @skipIf(archs=['ppc64le']) - # SR-10216 + @expectedFailureAll(bugnumber="rdar://60396797", + oslist=lldbplatform.darwin_all, + setting=('symbols.use-swift-clangimporter', 'false')) + @skipIf(bugnumber="SR-10216", archs=['ppc64le']) @swiftTest def test_unknown_self_objc_ref(self): """Test unknown references to Objective-C objects.""" diff --git a/lldb/test/API/lang/swift/variables/dict_nsobj_anyobj/TestSwiftDictionaryNSObjectAnyObject.py b/lldb/test/API/lang/swift/variables/dict_nsobj_anyobj/TestSwiftDictionaryNSObjectAnyObject.py index bb6c7e3b289ba..17996bdee5c7e 100644 --- a/lldb/test/API/lang/swift/variables/dict_nsobj_anyobj/TestSwiftDictionaryNSObjectAnyObject.py +++ b/lldb/test/API/lang/swift/variables/dict_nsobj_anyobj/TestSwiftDictionaryNSObjectAnyObject.py @@ -27,6 +27,8 @@ class TestDictionaryNSObjectAnyObject(TestBase): def setUp(self): TestBase.setUp(self) + @expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) @skipUnlessDarwin @swiftTest def test_dictionary_nsobject_any_object(self): diff --git a/lldb/test/API/lang/swift/variables/objc/TestObjCImportedTypes.py b/lldb/test/API/lang/swift/variables/objc/TestObjCImportedTypes.py index 0718684def5f7..1fbf3271a7996 100644 --- a/lldb/test/API/lang/swift/variables/objc/TestObjCImportedTypes.py +++ b/lldb/test/API/lang/swift/variables/objc/TestObjCImportedTypes.py @@ -27,6 +27,8 @@ class TestSwiftObjCImportedTypes(TestBase): def setUp(self): TestBase.setUp(self) + @expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) @swiftTest @skipUnlessDarwin def test_swift_objc_imported_types(self): diff --git a/lldb/test/API/lang/swift/variables/objc_optionals/TestSwiftObjCOptionals.py b/lldb/test/API/lang/swift/variables/objc_optionals/TestSwiftObjCOptionals.py index eb7ba3549c59a..53e6e3f275f40 100644 --- a/lldb/test/API/lang/swift/variables/objc_optionals/TestSwiftObjCOptionals.py +++ b/lldb/test/API/lang/swift/variables/objc_optionals/TestSwiftObjCOptionals.py @@ -24,6 +24,8 @@ class TestSwiftObjCOptionalType(TestBase): mydir = TestBase.compute_mydir(__file__) + @expectedFailureAll(bugnumber="rdar://60396797", + setting=('symbols.use-swift-clangimporter', 'false')) @swiftTest @skipUnlessDarwin def test_swift_objc_optional_type(self): From a4da3e344620ef36461f538554a93795ab0e30f7 Mon Sep 17 00:00:00 2001 From: Pavel Labath Date: Fri, 14 Feb 2020 08:33:42 +0100 Subject: [PATCH 011/286] [lldb] Add a test for launch failure and its error message (cherry picked from commit 65e843c9e0b91d5ac156130f61b378bad2e8e2fd) --- .../gdb_remote_client/TestGDBRemoteClient.py | 24 +++++++++++++++++++ .../gdb_remote_client/gdbclientutils.py | 5 ++++ 2 files changed, 29 insertions(+) diff --git a/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py b/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py index 8f0ed9a4933da..238a4559d6fbb 100644 --- a/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py +++ b/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py @@ -50,6 +50,30 @@ def vAttach(self, pid): target.AttachToProcessWithID(lldb.SBListener(), 47, error) self.assertEquals(error_msg, error.GetCString()) + def test_launch_fail(self): + class MyResponder(MockGDBServerResponder): + # Pretend we don't have any process during the initial queries. + def qC(self): + return "E42" + + def qfThreadInfo(self): + return "OK" # No threads. + + # Then, when we are asked to attach, error out. + def A(self, packet): + return "E47" + + self.server.responder = MyResponder() + + target = self.createTarget("a.yaml") + process = self.connect(target) + lldbutil.expect_state_changes(self, self.dbg.GetListener(), process, [lldb.eStateConnected]) + + error = lldb.SBError() + target.Launch(lldb.SBListener(), None, None, None, None, None, + None, 0, True, error) + self.assertEquals("process launch failed: 'A' packet returned an error: 71", error.GetCString()) + def test_read_registers_using_g_packets(self): """Test reading registers using 'g' packets (default behavior)""" self.dbg.HandleCommand( diff --git a/lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py b/lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py index 392aeba5bd688..486485c8e28db 100644 --- a/lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py +++ b/lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py @@ -106,6 +106,8 @@ def respond(self, packet): return self.cont() if packet.startswith("vCont;c"): return self.vCont(packet) + if packet[0] == "A": + return self.A(packet) if packet[0] == "g": return self.readRegisters() if packet[0] == "G": @@ -201,6 +203,9 @@ def cont(self): def vCont(self, packet): raise self.UnexpectedPacketException() + def A(self, packet): + return "" + def readRegisters(self): return "00000000" * self.registerCount From 350a9804bb97052dc35eba2aefbc475ed7f83acb Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Fri, 14 Feb 2020 18:42:38 -0800 Subject: [PATCH 012/286] Remove 'process launch failed:' message prefix in Target::Launch SB API clients can describe the failure message in a more natural way for their UI, this doesn't add information for them. Differential Revision: https://reviews.llvm.org/D74585 (cherry picked from commit 83bea6d99dd17d893b7160e045700aef6173a49d) --- lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp | 2 +- lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp | 2 +- lldb/source/Target/Target.cpp | 5 ----- .../functionalities/gdb_remote_client/TestGDBRemoteClient.py | 2 +- lldb/test/Shell/Process/Windows/launch_failure.yaml | 2 +- 5 files changed, 4 insertions(+), 9 deletions(-) diff --git a/lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp b/lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp index 485ffbe04872f..967119e377917 100644 --- a/lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp +++ b/lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp @@ -367,7 +367,7 @@ PlatformLinux::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, } else LLDB_LOG(log, "not using process STDIO pty"); } else { - LLDB_LOG(log, "process launch failed: {0}", error); + LLDB_LOG(log, "{0}", error); // FIXME figure out appropriate cleanup here. Do we delete the target? Do // we delete the process? Does our caller do that? } diff --git a/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp b/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp index 53f819e6a272c..f3eaffdd3cb75 100644 --- a/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp +++ b/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp @@ -336,7 +336,7 @@ PlatformNetBSD::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, } else LLDB_LOG(log, "not using process STDIO pty"); } else { - LLDB_LOG(log, "process launch failed: {0}", error); + LLDB_LOG(log, "{0}", error); // FIXME figure out appropriate cleanup here. Do we delete the target? Do // we delete the process? Does our caller do that? } diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index 6b205b02216ed..72e5f0281f804 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -2971,11 +2971,6 @@ Status Target::Launch(ProcessLaunchInfo &launch_info, Stream *stream) { } } m_process_sp->RestoreProcessEvents(); - } else { - Status error2; - error2.SetErrorStringWithFormat("process launch failed: %s", - error.AsCString()); - error = error2; } return error; } diff --git a/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py b/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py index 238a4559d6fbb..9de0279bbfad2 100644 --- a/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py +++ b/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py @@ -72,7 +72,7 @@ def A(self, packet): error = lldb.SBError() target.Launch(lldb.SBListener(), None, None, None, None, None, None, 0, True, error) - self.assertEquals("process launch failed: 'A' packet returned an error: 71", error.GetCString()) + self.assertEquals("'A' packet returned an error: 71", error.GetCString()) def test_read_registers_using_g_packets(self): """Test reading registers using 'g' packets (default behavior)""" diff --git a/lldb/test/Shell/Process/Windows/launch_failure.yaml b/lldb/test/Shell/Process/Windows/launch_failure.yaml index be723ef7621d0..88cb0edd9f90e 100644 --- a/lldb/test/Shell/Process/Windows/launch_failure.yaml +++ b/lldb/test/Shell/Process/Windows/launch_failure.yaml @@ -7,7 +7,7 @@ # RUN: yaml2obj %s > %t.exe # RUN: %lldb %t.exe -o run 2>&1 | FileCheck %s -# CHECK: error: process launch failed: unknown error +# CHECK: error: unknown error --- !COFF OptionalHeader: From 002b09222f9d74f1df3fd8132687a8fbaea34680 Mon Sep 17 00:00:00 2001 From: Erik Pilkington Date: Fri, 28 Feb 2020 15:24:23 -0800 Subject: [PATCH 013/286] [Sema] Fix an assert when objc_externally_retained was applied to an unprototyped function rdar://58893199 --- clang/lib/Sema/SemaDeclAttr.cpp | 4 +++- clang/test/SemaObjC/externally-retained.m | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 3607b0d4543c2..d1e71e0d33075 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -7008,7 +7008,9 @@ static void handleObjCExternallyRetainedAttr(Sema &S, Decl *D, // If D is a function-like declaration (method, block, or function), then we // make every parameter psuedo-strong. - for (unsigned I = 0, E = getFunctionOrMethodNumParams(D); I != E; ++I) { + unsigned NumParams = + hasFunctionProto(D) ? getFunctionOrMethodNumParams(D) : 0; + for (unsigned I = 0; I != NumParams; ++I) { auto *PVD = const_cast(getFunctionOrMethodParam(D, I)); QualType Ty = PVD->getType(); diff --git a/clang/test/SemaObjC/externally-retained.m b/clang/test/SemaObjC/externally-retained.m index 24c531ccf7396..f9fbdb0689443 100644 --- a/clang/test/SemaObjC/externally-retained.m +++ b/clang/test/SemaObjC/externally-retained.m @@ -118,3 +118,6 @@ void test13(ObjCTy *first, __weak ObjCTy *second, __unsafe_unretained ObjCTy *th } #pragma clang attribute ext_ret.pop + +__attribute__((objc_externally_retained)) +void unprototyped(); From b3e3a0f7915c6f2a68f8d0ad9e723f373848f818 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Thu, 5 Mar 2020 09:51:40 -0800 Subject: [PATCH 014/286] Correctly identify iOS simulator processes in debugserver. Starting with iOS 13 simulator binaries are identified with an explicit platform in the new LC_BUILD_VERSION load command. On older deployment targets using the LC_VERSION_MIN load commands, this patch detects when an ios process runs on a macOS host and updates the target triple with the "simulator" environment accordingly. (Patch re-applied with bugfix this time). This is part of https://bugs.swift.org/browse/SR-11971 rdar://problem/58438125 Differential Revision: https://reviews.llvm.org/D75696 (cherry picked from commit 000847f8bed4a8624de3e39ff90af721cf8a1e2b) Conflicts: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp --- .../GDBRemoteCommunicationClient.cpp | 26 +++++--- .../gdb_remote_client/TestGDBRemoteClient.py | 1 + .../gdb_remote_client/TestIOSSimulator.py | 63 +++++++++++++++++++ .../debugserver/source/MacOSX/MachProcess.mm | 27 ++++++-- 4 files changed, 101 insertions(+), 16 deletions(-) create mode 100644 lldb/test/API/functionalities/gdb_remote_client/TestIOSSimulator.py diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index b2f1ee527e8b1..1d5f2b60b2dcc 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -1123,6 +1123,20 @@ bool GDBRemoteCommunicationClient::GetDefaultThreadId(lldb::tid_t &tid) { return true; } +static void ParseOSType(llvm::StringRef value, std::string &os_name, + std::string &environment) { + if (value.equals("iossimulator") || value.equals("tvossimulator") || + value.equals("watchossimulator")) { + environment = "simulator"; + os_name = value.drop_back(environment.size()).str(); + } else if (value.equals("maccatalyst")) { + os_name = "ios"; + environment = "macabi"; + } else { + os_name = value.str(); + } +} + bool GDBRemoteCommunicationClient::GetHostInfo(bool force) { Log *log(ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_PROCESS)); @@ -1181,11 +1195,7 @@ bool GDBRemoteCommunicationClient::GetHostInfo(bool force) { extractor.GetHexByteString(m_os_kernel); ++num_keys_decoded; } else if (name.equals("ostype")) { - if (value.equals("maccatalyst")) { - os_name = "ios"; - environment = "macabi"; - } else - os_name = value; + ParseOSType(value, os_name, environment); ++num_keys_decoded; } else if (name.equals("vendor")) { vendor_name = value; @@ -2045,11 +2055,7 @@ bool GDBRemoteCommunicationClient::GetCurrentProcessInfo(bool allow_lazy) { extractor.GetHexByteString(triple); ++num_keys_decoded; } else if (name.equals("ostype")) { - if (value.equals("maccatalyst")) { - os_name = "ios"; - environment = "macabi"; - } else - os_name = value; + ParseOSType(value, os_name, environment); ++num_keys_decoded; } else if (name.equals("vendor")) { vendor_name = value; diff --git a/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py b/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py index 9de0279bbfad2..e5a9ef1da8091 100644 --- a/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py +++ b/lldb/test/API/functionalities/gdb_remote_client/TestGDBRemoteClient.py @@ -63,6 +63,7 @@ def qfThreadInfo(self): def A(self, packet): return "E47" + self.runCmd("log enable gdb-remote packets") self.server.responder = MyResponder() target = self.createTarget("a.yaml") diff --git a/lldb/test/API/functionalities/gdb_remote_client/TestIOSSimulator.py b/lldb/test/API/functionalities/gdb_remote_client/TestIOSSimulator.py new file mode 100644 index 0000000000000..a096a1504fd67 --- /dev/null +++ b/lldb/test/API/functionalities/gdb_remote_client/TestIOSSimulator.py @@ -0,0 +1,63 @@ +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * +from gdbclientutils import * + +class TestIOSSimulator(GDBRemoteTestBase): + """ + Test that an ios simulator process is recognized as such. + """ + + class MyResponder(MockGDBServerResponder): + def __init__(self, host, process): + self.host_ostype = host + self.process_ostype = process + MockGDBServerResponder.__init__(self) + + def respond(self, packet): + if packet == "qProcessInfo": + return self.qProcessInfo() + return MockGDBServerResponder.respond(self, packet) + + def qHostInfo(self): + return "cputype:16777223;cpusubtype:8;ostype:%s;vendor:apple;os_version:10.15.4;maccatalyst_version:13.4;endian:little;ptrsize:8;"%self.host_ostype + def qProcessInfo(self): + return "pid:a860;parent-pid:d2a0;real-uid:1f5;real-gid:14;effective-uid:1f5;effective-gid:14;cputype:1000007;cpusubtype:8;ptrsize:8;ostype:%s;vendor:apple;endian:little;"%self.process_ostype + def vCont(self): + return "vCont;" + + def platform_test(self, host, process, expected_triple): + self.server.responder = self.MyResponder(host, process) + if self.TraceOn(): + self.runCmd("log enable gdb-remote packets") + self.addTearDownHook(lambda: self.runCmd("log disable gdb-remote packets")) + + target = self.dbg.CreateTargetWithFileAndArch(None, None) + process = self.connect(target) + triple = target.GetTriple() + self.assertEqual(triple, expected_triple) + + @skipIfRemote + def test_macos(self): + self.platform_test(host="macosx", process="macosx", + expected_triple="x86_64h-apple-macosx-") + + @skipIfRemote + def test_ios_sim(self): + self.platform_test(host="macosx", process="iossimulator", + expected_triple="x86_64h-apple-ios-simulator") + + @skipIfRemote + def test_catalyst(self): + self.platform_test(host="macosx", process="maccatalyst", + expected_triple="x86_64h-apple-ios-macabi") + + @skipIfRemote + def test_tvos_sim(self): + self.platform_test(host="macosx", process="tvossimulator", + expected_triple="x86_64h-apple-tvos-simulator") + + @skipIfRemote + def test_tvos_sim(self): + self.platform_test(host="macosx", process="watchossimulator", + expected_triple="x86_64h-apple-watchos-simulator") diff --git a/lldb/tools/debugserver/source/MacOSX/MachProcess.mm b/lldb/tools/debugserver/source/MacOSX/MachProcess.mm index e4ec6129f70c5..664c5083f8756 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachProcess.mm +++ b/lldb/tools/debugserver/source/MacOSX/MachProcess.mm @@ -595,6 +595,16 @@ static bool FBSAddEventDataToOptions(NSMutableDictionary *options, plo_pthread_tsd_entry_size); } +/// Determine whether this is running on macOS. +/// Since debugserver runs on the same machine as the process, we can +/// just look at the compilation target. +static bool IsMacOSHost() { +#if TARGET_OS_OSX == 1 + return true; +#else + return false; +#endif +} const char *MachProcess::GetDeploymentInfo(const struct load_command& lc, uint64_t load_command_address, @@ -616,15 +626,17 @@ static bool FBSAddEventDataToOptions(NSMutableDictionary *options, minor_version = (vers_cmd.sdk >> 8) & 0xffu; patch_version = vers_cmd.sdk & 0xffu; + // Handle the older LC_VERSION load commands, which don't + // distinguish between simulator and real hardware. switch (cmd) { case LC_VERSION_MIN_IPHONEOS: - return "ios"; + return IsMacOSHost() ? "iossimulator": "ios"; case LC_VERSION_MIN_MACOSX: return "macosx"; case LC_VERSION_MIN_TVOS: - return "tvos"; + return IsMacOSHost() ? "tvossimulator": "tvos"; case LC_VERSION_MIN_WATCHOS: - return "watchos"; + return IsMacOSHost() ? "watchossimulator" : "watchos"; default: return nullptr; } @@ -646,14 +658,17 @@ static bool FBSAddEventDataToOptions(NSMutableDictionary *options, case PLATFORM_MACCATALYST: return "maccatalyst"; case PLATFORM_IOS: - case PLATFORM_IOSSIMULATOR: return "ios"; + case PLATFORM_IOSSIMULATOR: + return "iossimulator"; case PLATFORM_TVOS: - case PLATFORM_TVOSSIMULATOR: return "tvos"; + case PLATFORM_TVOSSIMULATOR: + return "tvossimulator"; case PLATFORM_WATCHOS: - case PLATFORM_WATCHOSSIMULATOR: return "watchos"; + case PLATFORM_WATCHOSSIMULATOR: + return "watchossimulator"; case PLATFORM_BRIDGEOS: return "bridgeos"; case PLATFORM_DRIVERKIT: From da8f7ff2e7f74a227e6983f2967a9bddfd420eb7 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Wed, 11 Mar 2020 13:35:25 -0700 Subject: [PATCH 015/286] Update for the demotion of TypeChecker --- lldb/source/Symbol/SwiftASTContext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/source/Symbol/SwiftASTContext.cpp b/lldb/source/Symbol/SwiftASTContext.cpp index 9c5ae1e99f333..2efa61ba1bf75 100644 --- a/lldb/source/Symbol/SwiftASTContext.cpp +++ b/lldb/source/Symbol/SwiftASTContext.cpp @@ -3565,7 +3565,7 @@ swift::ASTContext *SwiftASTContext::GetASTContext() { } // Set up the required state for the evaluator in the TypeChecker. - (void)swift::createTypeChecker(*m_ast_context_ap); + m_ast_context_ap->setLegacySemanticQueriesEnabled(); registerIDERequestFunctions(m_ast_context_ap->evaluator); registerParseRequestFunctions(m_ast_context_ap->evaluator); registerTypeCheckerRequestFunctions(m_ast_context_ap->evaluator); From 11877e686a87492692cd7b59b247d55ba7a94a1f Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Tue, 4 Feb 2020 14:22:58 -0800 Subject: [PATCH 016/286] Adjust for apple/swift#29631 --- lldb/source/Symbol/SwiftASTContext.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/source/Symbol/SwiftASTContext.cpp b/lldb/source/Symbol/SwiftASTContext.cpp index 142ab35bce80b..02c5937277f71 100644 --- a/lldb/source/Symbol/SwiftASTContext.cpp +++ b/lldb/source/Symbol/SwiftASTContext.cpp @@ -3551,6 +3551,7 @@ swift::ASTContext *SwiftASTContext::GetASTContext() { registerTypeCheckerRequestFunctions(m_ast_context_ap->evaluator); registerSILGenRequestFunctions(m_ast_context_ap->evaluator); registerTBDGenRequestFunctions(m_ast_context_ap->evaluator); + registerIRGenRequestFunctions(m_ast_context_ap->evaluator); GetASTMap().Insert(m_ast_context_ap.get(), this); From 4a150fe45fdbf83cc5bf595a8685c61aaeb340ed Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Mon, 16 Mar 2020 18:11:36 -0700 Subject: [PATCH 017/286] [DwarfDebug] Fix an assertion error when emitting call site info that combines two DW_OP_stack_values When compiling ``` struct S { float w; }; void f(long w, long b); void g(struct S s) { int w = s.w; f(w, w*4); } ``` I get Assertion failed: ((!CombinedExpr || CombinedExpr->isValid()) && "Combined debug expression is invalid"). That's because we combine two epxressions that both end in DW_OP_stack_value: ``` (lldb) p Expr->dump() !DIExpression(DW_OP_LLVM_convert, 32, DW_ATE_signed, DW_OP_LLVM_convert, 64, DW_ATE_signed, DW_OP_stack_value) (lldb) p Param.Expr->dump() !DIExpression(DW_OP_constu, 4, DW_OP_mul, DW_OP_LLVM_convert, 32, DW_ATE_signed, DW_OP_LLVM_convert, 64, DW_ATE_signed, DW_OP_stack_value) (lldb) p CombinedExpr->isValid() (bool) $0 = false (lldb) p CombinedExpr->dump() !DIExpression(4097, 32, 5, 4097, 64, 5, 16, 4, 30, 4097, 32, 5, 4097, 64, 5, 159, 159) ``` I believe that in this particular case combining two stack values is safe, but I didn't want to sink the special handling into DIExpression::append() because I do want everyone to think about what they are doing. Patch by Adrian Prantl. Fixes PR45181. rdar://problem/60383095 Differential Revision: https://reviews.llvm.org/D76164 (cherry picked from commit 526c51e6fdc834b703e14ca851a8c95c7f1c9b2f) --- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 9 ++- llvm/lib/IR/DebugInfoMetadata.cpp | 4 +- .../MIR/X86/callsite-stack-value.mir | 68 +++++++++++++++++++ 3 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 llvm/test/DebugInfo/MIR/X86/callsite-stack-value.mir diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index bb718fd33647b..f1c98be617371 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -623,12 +623,15 @@ static void addToFwdRegWorklist(FwdRegWorklist &Worklist, unsigned Reg, // instructions we may have already created an expression for the // parameter when walking through the instructions. Append that to the // new expression. + std::vector ParamElts = Param.Expr->getElements().vec(); + // Avoid multiple DW_OP_stack_values. + if (Expr->isImplicit() && Param.Expr->isImplicit()) + erase_if(ParamElts, + [](uint64_t Op) { return Op == dwarf::DW_OP_stack_value; }); const DIExpression *CombinedExpr = (Param.Expr->getNumElements() > 0) - ? DIExpression::append(Expr, Param.Expr->getElements()) + ? DIExpression::append(Expr, ParamElts) : Expr; - assert(CombinedExpr->isValid() && "Combined debug expression is invalid"); - ParamsForFwdReg.push_back({Param.ParamReg, CombinedExpr}); } } diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp index 18bfeff8afa15..46c0b84e3ddcc 100644 --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -1117,7 +1117,9 @@ DIExpression *DIExpression::append(const DIExpression *Expr, } NewOps.append(Ops.begin(), Ops.end()); - return DIExpression::get(Expr->getContext(), NewOps); + auto *result = DIExpression::get(Expr->getContext(), NewOps); + assert(result->isValid() && "concatenated expression is not valid"); + return result; } DIExpression *DIExpression::appendToStack(const DIExpression *Expr, diff --git a/llvm/test/DebugInfo/MIR/X86/callsite-stack-value.mir b/llvm/test/DebugInfo/MIR/X86/callsite-stack-value.mir new file mode 100644 index 0000000000000..5a24bd54cef9b --- /dev/null +++ b/llvm/test/DebugInfo/MIR/X86/callsite-stack-value.mir @@ -0,0 +1,68 @@ +# RUN: llc -start-after=livedebugvalues -mtriple=x86_64-apple-darwin -o - %s -filetype=obj \ +# RUN: | llvm-dwarfdump - | FileCheck %s -implicit-check-not=call_site_parameter + +# CHECK: DW_TAG_formal_parameter +# CHECK-NEXT: DW_AT_location +# CHECK-NEXT: DW_OP_reg17 + +# struct S { +# float w; +# }; +# void f(long w, long b); +# void g(struct S s) { +# int w = s.w; +# f(w, w*4); +# } + +--- | + define void @g(float %s.coerce) local_unnamed_addr !dbg !20 { + entry: + ret void, !dbg !31 + } + declare !dbg !14 void @f(i64, i64) local_unnamed_addr + !llvm.module.flags = !{!6, !7, !8, !9} + !llvm.dbg.cu = !{!10} + !6 = !{i32 7, !"Dwarf Version", i32 4} + !7 = !{i32 2, !"Debug Info Version", i32 3} + !8 = !{i32 1, !"wchar_size", i32 4} + !9 = !{i32 7, !"PIC Level", i32 2} + !10 = distinct !DICompileUnit(language: DW_LANG_ObjC, file: !15, producer: "", isOptimized: true, runtimeVersion: 2, emissionKind: FullDebug, enums: !12, retainedTypes: !13, nameTableKind: None, sysroot: "/") + !12 = !{} + !13 = !{!14} + !14 = !DISubprogram(name: "f", scope: !15, file: !15, line: 4, type: !16, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !12) + !15 = !DIFile(filename: "test.m", directory: "/") + !16 = !DISubroutineType(types: !17) + !17 = !{null, !18, !18} + !18 = !DIBasicType(name: "long int", size: 64, encoding: DW_ATE_signed) + !20 = distinct !DISubprogram(name: "g", scope: !15, file: !15, line: 5, type: !21, scopeLine: 5, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !10, retainedNodes: !27) + !21 = !DISubroutineType(types: !22) + !22 = !{null, !23} + !23 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "S", file: !15, line: 1, size: 32, elements: !24) + !24 = !{!25} + !25 = !DIDerivedType(tag: DW_TAG_member, name: "w", scope: !23, file: !15, line: 2, baseType: !26, size: 32) + !26 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) + !27 = !{!28, !29} + !28 = !DILocalVariable(name: "s", arg: 1, scope: !20, file: !15, line: 5, type: !23) + !29 = !DILocalVariable(name: "w", scope: !20, file: !15, line: 6, type: !30) + !30 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) + !31 = !DILocation(line: 0, scope: !20) +name: g +callSites: + - { bb: 0, offset: 13, fwdArgRegs: + - { arg: 1, reg: '$rsi' } } +body: | + bb.0.entry: + DBG_VALUE $xmm0, $noreg, !28, !DIExpression(), debug-location !31 + DBG_VALUE $xmm0, $noreg, !28, !DIExpression(), debug-location !31 + frame-setup PUSH64r killed $rbp, implicit-def $rsp, implicit $rsp + CFI_INSTRUCTION def_cfa_offset 16 + CFI_INSTRUCTION offset $rbp, -16 + $rbp = frame-setup MOV64rr $rsp + CFI_INSTRUCTION def_cfa_register $rbp + renamable $eax = CVTTSS2SIrr killed renamable $xmm0, implicit $mxcsr, debug-location !31 + DBG_VALUE $eax, $noreg, !29, !DIExpression(), debug-location !31 + renamable $rdi = MOVSX64rr32 killed renamable $eax, debug-location !31 + renamable $eax = LEA64_32r $noreg, 4, renamable $rdi, 0, $noreg, debug-location !31 + renamable $rsi = MOVSX64rr32 killed renamable $eax, debug-location !31 + $rbp = frame-destroy POP64r implicit-def $rsp, implicit $rsp, debug-location !31 + TAILJMPd64 @f, csr_64, implicit $rsp, implicit $ssp, implicit $rsp, implicit $ssp, implicit $rdi, implicit $rsi, debug-location !31 From c84bdb00f27c89eb38edbf731099c7a6ea9e4606 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Tue, 17 Mar 2020 14:28:34 -0700 Subject: [PATCH 018/286] [lldb/PlatformDarwin] Be more robust in computing the SDK path with xcrun The current implementation isn't very resilient when it comes to the output of xcrun. Currently it cannot deal with: - Trailing newlines. - Leading newlines and errors/warnings before the Xcode path. - Xcode not being named Xcode.app. This extract the logic into a helper in PlatformDarwin and fixes those issues. It's also the first step towards removing code duplication between the different platforms and downstream Swift. Differential revision: https://reviews.llvm.org/D76261 (cherry picked from commit 7aa28995e87f6cec2e02608c978885cf01dcc65d) --- .../Platform/MacOSX/PlatformDarwin.cpp | 246 +++++++++++------- .../Plugins/Platform/MacOSX/PlatformDarwin.h | 26 +- .../Platform/MacOSX/PlatformMacOSX.cpp | 92 ++----- .../unittests/Platform/PlatformDarwinTest.cpp | 63 +++++ 4 files changed, 266 insertions(+), 161 deletions(-) diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp index f1abbf2ca1e11..de7733112fee5 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp @@ -1268,76 +1268,6 @@ void PlatformDarwin::CalculateTrapHandlerSymbolNames() { m_trap_handlers.push_back(ConstString("_sigtramp")); } -static const char *const sdk_strings[] = { - "MacOSX", "iPhoneSimulator", "iPhoneOS", -}; - -static FileSpec CheckPathForXcode(const FileSpec &fspec) { - if (FileSystem::Instance().Exists(fspec)) { - const char substr[] = ".app/Contents"; - - std::string path_to_shlib = fspec.GetPath(); - size_t pos = path_to_shlib.rfind(substr); - if (pos != std::string::npos) { - path_to_shlib.erase(pos + strlen(substr)); - FileSpec ret(path_to_shlib); - - FileSpec xcode_binary_path = ret; - xcode_binary_path.AppendPathComponent("MacOS"); - xcode_binary_path.AppendPathComponent("Xcode"); - - if (FileSystem::Instance().Exists(xcode_binary_path)) { - return ret; - } - } - } - return FileSpec(); -} - -static FileSpec GetXcodeContentsPath() { - static FileSpec g_xcode_filespec; - static llvm::once_flag g_once_flag; - llvm::call_once(g_once_flag, []() { - - FileSpec fspec; - - // First get the program file spec. If lldb.so or LLDB.framework is running - // in a program and that program is Xcode, the path returned with be the - // path to Xcode.app/Contents/MacOS/Xcode, so this will be the correct - // Xcode to use. - fspec = HostInfo::GetProgramFileSpec(); - - if (fspec) { - // Ignore the current binary if it is python. - std::string basename_lower = fspec.GetFilename().GetCString(); - std::transform(basename_lower.begin(), basename_lower.end(), - basename_lower.begin(), tolower); - if (basename_lower != "python") { - g_xcode_filespec = CheckPathForXcode(fspec); - } - } - - // Next check DEVELOPER_DIR environment variable - if (!g_xcode_filespec) { - const char *developer_dir_env_var = getenv("DEVELOPER_DIR"); - if (developer_dir_env_var && developer_dir_env_var[0]) { - FileSpec developer_dir_spec = FileSpec(developer_dir_env_var); - FileSystem::Instance().Resolve(developer_dir_spec); - g_xcode_filespec = CheckPathForXcode(developer_dir_spec); - } - - // Fall back to using "xcode-select" to find the selected Xcode - if (!g_xcode_filespec) { - FileSpec xcode_select_path(GetXcodeSelectPath()); - xcode_select_path.RemoveLastPathComponent(); - g_xcode_filespec = CheckPathForXcode(xcode_select_path); - } - } - }); - - return g_xcode_filespec; -} - static FileSpec GetCommandLineToolsLibraryPath() { static FileSpec g_command_line_tools_filespec; @@ -1359,7 +1289,14 @@ bool PlatformDarwin::SDKSupportsModules(SDKType sdk_type, return version >= llvm::VersionTuple(10, 10); case SDKType::iPhoneOS: case SDKType::iPhoneSimulator: + case SDKType::AppleTVOS: + case SDKType::AppleTVSimulator: return version >= llvm::VersionTuple(8); + case SDKType::watchOS: + case SDKType::WatchSimulator: + return version >= llvm::VersionTuple(6); + default: + return false; } return false; @@ -1372,10 +1309,12 @@ bool PlatformDarwin::SDKSupportsModules(SDKType desired_type, if (last_path_component) { const llvm::StringRef sdk_name = last_path_component.GetStringRef(); - if (!sdk_name.startswith(sdk_strings[desired_type])) + const std::string sdk_name_lower = sdk_name.lower(); + const llvm::StringRef sdk_string = GetSDKNameForType(desired_type); + if (!llvm::StringRef(sdk_name_lower).startswith(sdk_string)) return false; - auto version_part = - sdk_name.drop_front(strlen(sdk_strings[desired_type])); + + auto version_part = sdk_name.drop_front(sdk_string.size()); version_part.consume_back(".sdk"); llvm::VersionTuple version; @@ -1427,14 +1366,7 @@ FileSpec PlatformDarwin::FindSDKInXcodeForModules(SDKType sdk_type, } FileSpec PlatformDarwin::GetSDKDirectoryForModules(SDKType sdk_type) { - switch (sdk_type) { - case SDKType::MacOSX: - case SDKType::iPhoneSimulator: - case SDKType::iPhoneOS: - break; - } - - FileSpec sdks_spec = GetXcodeContentsPath(); + FileSpec sdks_spec = GetXcodeContentsDirectory(); sdks_spec.AppendPathComponent("Developer"); sdks_spec.AppendPathComponent("Platforms"); @@ -1448,6 +1380,8 @@ FileSpec PlatformDarwin::GetSDKDirectoryForModules(SDKType sdk_type) { case SDKType::iPhoneOS: sdks_spec.AppendPathComponent("iPhoneOS.platform"); break; + default: + llvm_unreachable("unsupported sdk"); } sdks_spec.AppendPathComponent("Developer"); @@ -1656,6 +1590,8 @@ void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( use_current_os_version = false; #endif break; + default: + break; } llvm::VersionTuple version; @@ -1685,6 +1621,9 @@ void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( case SDKType::MacOSX: minimum_version_option.PutCString("-mmacosx-version-min="); minimum_version_option.PutCString(version.getAsString()); + break; + default: + llvm_unreachable("unsupported sdk"); } options.push_back(minimum_version_option.GetString()); } @@ -1744,8 +1683,7 @@ llvm::VersionTuple PlatformDarwin::GetOSVersion(Process *process) { lldb_private::FileSpec PlatformDarwin::LocateExecutable(const char *basename) { // A collection of SBFileSpec whose SBFileSpec.m_directory members are filled - // in with - // any executable directories that should be searched. + // in with any executable directories that should be searched. static std::vector g_executable_dirs; // Find the global list of directories that we will search for executables @@ -1754,7 +1692,7 @@ lldb_private::FileSpec PlatformDarwin::LocateExecutable(const char *basename) { llvm::call_once(g_once_flag, []() { // When locating executables, trust the DEVELOPER_DIR first if it is set - FileSpec xcode_contents_dir = GetXcodeContentsPath(); + FileSpec xcode_contents_dir = GetXcodeContentsDirectory(); if (xcode_contents_dir) { FileSpec xcode_lldb_resources = xcode_contents_dir; xcode_lldb_resources.AppendPathComponent("SharedFrameworks"); @@ -1816,12 +1754,10 @@ PlatformDarwin::LaunchProcess(lldb_private::ProcessLaunchInfo &launch_info) { return PlatformPOSIX::LaunchProcess(launch_info); } -lldb_private::Status -PlatformDarwin::FindBundleBinaryInExecSearchPaths (const ModuleSpec &module_spec, Process *process, - ModuleSP &module_sp, - const FileSpecList *module_search_paths_ptr, - ModuleSP *old_module_sp_ptr, bool *did_create_ptr) -{ +lldb_private::Status PlatformDarwin::FindBundleBinaryInExecSearchPaths( + const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp, + const FileSpecList *module_search_paths_ptr, ModuleSP *old_module_sp_ptr, + bool *did_create_ptr) { const FileSpec &platform_file = module_spec.GetFileSpec(); // See if the file is present in any of the module_search_paths_ptr // directories. @@ -1892,3 +1828,133 @@ PlatformDarwin::FindBundleBinaryInExecSearchPaths (const ModuleSpec &module_spec } return Status(); } + +std::string +PlatformDarwin::FindXcodeContentsDirectoryInPath(llvm::StringRef path) { + auto begin = llvm::sys::path::begin(path); + auto end = llvm::sys::path::end(path); + + // Iterate over the path components until we find something that ends with + // .app. If the next component is Contents then we've found the Contents + // directory. + for (auto it = begin; it != end; ++it) { + if (it->endswith(".app")) { + auto next = it; + if (++next != end && *next == "Contents") { + llvm::SmallString<128> buffer; + llvm::sys::path::append(buffer, begin, ++next); + return buffer.str().str(); + } + } + } + + return {}; +} + +llvm::StringRef PlatformDarwin::GetSDKNameForType(SDKType type) { + switch (type) { + case MacOSX: + return "macosx"; + case iPhoneSimulator: + return "iphonesimulator"; + case iPhoneOS: + return "iphoneos"; + case AppleTVSimulator: + return "appletvsimulator"; + case AppleTVOS: + return "appletvos"; + case WatchSimulator: + return "watchsimulator"; + case watchOS: + return "watchos"; + case bridgeOS: + return "bridgeos"; + case Linux: + return "linux"; + case numSDKTypes: + case unknown: + return ""; + } + llvm_unreachable("unhandled switch case"); +} + +FileSpec PlatformDarwin::GetXcodeSDK(SDKType type) { + std::string xcrun_cmd = + "xcrun --show-sdk-path --sdk " + GetSDKNameForType(type).str(); + + int status = 0; + int signo = 0; + std::string output_str; + lldb_private::Status error = + Host::RunShellCommand(xcrun_cmd.c_str(), FileSpec(), &status, &signo, + &output_str, std::chrono::seconds(15)); + + // Check that xcrun return something useful. + if (status != 0 || output_str.empty()) + return {}; + + // Convert to a StringRef so we can manipulate the string without modifying + // the underlying data. + llvm::StringRef output(output_str); + + // Remove any trailing newline characters. + output = output.rtrim(); + + // Strip any leading newline characters and everything before them. + const size_t last_newline = output.rfind('\n'); + if (last_newline != llvm::StringRef::npos) + output = output.substr(last_newline + 1); + + // Whatever is left in output should be a valid path. + if (!FileSystem::Instance().Exists(output)) + return {}; + + // Find the contents dir in the xcrun provided path. + std::string xcode_contents_dir = FindXcodeContentsDirectoryInPath(output); + if (xcode_contents_dir.empty()) + return {}; + + return FileSpec(xcode_contents_dir); +} + +FileSpec PlatformDarwin::GetXcodeContentsDirectory() { + static FileSpec g_xcode_contents_path; + static std::once_flag g_once_flag; + std::call_once(g_once_flag, [&]() { + // Try the shlib dir first. + if (FileSpec fspec = HostInfo::GetShlibDir()) { + if (FileSystem::Instance().Exists(fspec)) { + std::string xcode_contents_dir = + FindXcodeContentsDirectoryInPath(fspec.GetPath()); + if (!xcode_contents_dir.empty()) { + g_xcode_contents_path = FileSpec(xcode_contents_dir); + return; + } + } + } + + if (const char *developer_dir_env_var = getenv("DEVELOPER_DIR")) { + FileSpec fspec(developer_dir_env_var); + if (FileSystem::Instance().Exists(fspec)) { + std::string xcode_contents_dir = + FindXcodeContentsDirectoryInPath(fspec.GetPath()); + if (!xcode_contents_dir.empty()) { + g_xcode_contents_path = FileSpec(xcode_contents_dir); + return; + } + } + } + + if (FileSpec fspec = GetXcodeSDK(SDKType::MacOSX)) { + if (FileSystem::Instance().Exists(fspec)) { + std::string xcode_contents_dir = + FindXcodeContentsDirectoryInPath(fspec.GetPath()); + if (!xcode_contents_dir.empty()) { + g_xcode_contents_path = FileSpec(xcode_contents_dir); + return; + } + } + } + }); + return g_xcode_contents_path; +} diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h index d9a0762181bda..56a67e5c6a9ef 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h @@ -80,15 +80,27 @@ class PlatformDarwin : public PlatformPOSIX { static std::tuple ParseVersionBuildDir(llvm::StringRef str); - enum SDKType : unsigned { + enum SDKType : int { MacOSX = 0, iPhoneSimulator, iPhoneOS, + AppleTVSimulator, + AppleTVOS, + WatchSimulator, + watchOS, + bridgeOS, + Linux, + numSDKTypes, + unknown = -1 }; llvm::Expected FetchExtendedCrashInformation(lldb_private::Process &process) override; + static llvm::StringRef GetSDKNameForType(SDKType type); + static lldb_private::FileSpec GetXcodeSDK(SDKType type); + static lldb_private::FileSpec GetXcodeContentsDirectory(); + protected: struct CrashInfoAnnotations { uint64_t version; // unsigned long @@ -155,13 +167,15 @@ class PlatformDarwin : public PlatformPOSIX { const char *GetDeveloperDirectory(); - lldb_private::Status - FindBundleBinaryInExecSearchPaths (const lldb_private::ModuleSpec &module_spec, lldb_private::Process *process, - lldb::ModuleSP &module_sp, const lldb_private::FileSpecList *module_search_paths_ptr, - lldb::ModuleSP *old_module_sp_ptr, bool *did_create_ptr); + lldb_private::Status FindBundleBinaryInExecSearchPaths( + const lldb_private::ModuleSpec &module_spec, + lldb_private::Process *process, lldb::ModuleSP &module_sp, + const lldb_private::FileSpecList *module_search_paths_ptr, + lldb::ModuleSP *old_module_sp_ptr, bool *did_create_ptr); - std::string m_developer_directory; + static std::string FindXcodeContentsDirectoryInPath(llvm::StringRef path); + std::string m_developer_directory; private: DISALLOW_COPY_AND_ASSIGN(PlatformDarwin); diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp index 134a4c7c80759..a5cb449bcbd6e 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp @@ -155,73 +155,35 @@ PlatformMacOSX::~PlatformMacOSX() {} ConstString PlatformMacOSX::GetSDKDirectory(lldb_private::Target &target) { ModuleSP exe_module_sp(target.GetExecutableModule()); - if (exe_module_sp) { - ObjectFile *objfile = exe_module_sp->GetObjectFile(); - if (objfile) { - std::string xcode_contents_path; - std::string default_xcode_sdk; - FileSpec fspec; - llvm::VersionTuple version = objfile->GetSDKVersion(); - if (!version.empty()) { - fspec = HostInfo::GetShlibDir(); - if (fspec) { - std::string path; - xcode_contents_path = fspec.GetPath(); - size_t pos = xcode_contents_path.find("/Xcode.app/Contents/"); - if (pos != std::string::npos) { - // LLDB.framework is inside an Xcode app bundle, we can locate the - // SDK from here - xcode_contents_path.erase(pos + strlen("/Xcode.app/Contents/")); - } else { - xcode_contents_path.clear(); - // Use the selected Xcode - int status = 0; - int signo = 0; - std::string output; - const char *command = "xcrun -sdk macosx --show-sdk-path"; - lldb_private::Status error = RunShellCommand( - command, // shell command to run - FileSpec(), // current working directory - &status, // Put the exit status of the process in here - &signo, // Put the signal that caused the process to exit in - // here - &output, // Get the output from the command and place it in this - // string - std::chrono::seconds(3)); - if (status == 0 && !output.empty()) { - size_t first_non_newline = output.find_last_not_of("\r\n"); - if (first_non_newline != std::string::npos) - output.erase(first_non_newline + 1); - default_xcode_sdk = output; - - pos = default_xcode_sdk.find("/Xcode.app/Contents/"); - if (pos != std::string::npos) - xcode_contents_path = default_xcode_sdk.substr( - 0, pos + strlen("/Xcode.app/Contents/")); - } - } - } - - if (!xcode_contents_path.empty()) { - StreamString sdk_path; - sdk_path.Printf("%sDeveloper/Platforms/MacOSX.platform/Developer/" - "SDKs/MacOSX%u.%u.sdk", - xcode_contents_path.c_str(), version.getMajor(), - version.getMinor().getValue()); - fspec.SetFile(sdk_path.GetString(), FileSpec::Style::native); - if (FileSystem::Instance().Exists(fspec)) - return ConstString(sdk_path.GetString()); - } + if (!exe_module_sp) + return {}; + + ObjectFile *objfile = exe_module_sp->GetObjectFile(); + if (!objfile) + return {}; + + llvm::VersionTuple version = objfile->GetSDKVersion(); + if (version.empty()) + return {}; + + // First try to find an SDK that matches the given SDK version. + if (FileSpec fspec = GetXcodeContentsDirectory()) { + StreamString sdk_path; + sdk_path.Printf("%s/Developer/Platforms/MacOSX.platform/Developer/" + "SDKs/MacOSX%u.%u.sdk", + fspec.GetPath().c_str(), version.getMajor(), + version.getMinor().getValue()); + if (FileSystem::Instance().Exists(fspec)) + return ConstString(sdk_path.GetString()); + } - if (!default_xcode_sdk.empty()) { - fspec.SetFile(default_xcode_sdk, FileSpec::Style::native); - if (FileSystem::Instance().Exists(fspec)) - return ConstString(default_xcode_sdk); - } - } - } + // Use the default SDK as a fallback. + if (FileSpec fspec = GetXcodeSDK(SDKType::MacOSX)) { + if (FileSystem::Instance().Exists(fspec)) + return ConstString(fspec.GetPath()); } - return ConstString(); + + return {}; } Status PlatformMacOSX::GetSymbolFile(const FileSpec &platform_file, diff --git a/lldb/unittests/Platform/PlatformDarwinTest.cpp b/lldb/unittests/Platform/PlatformDarwinTest.cpp index 476848d6881f8..d0c87eb5d30d1 100644 --- a/lldb/unittests/Platform/PlatformDarwinTest.cpp +++ b/lldb/unittests/Platform/PlatformDarwinTest.cpp @@ -18,6 +18,8 @@ using namespace lldb; using namespace lldb_private; struct PlatformDarwinTester : public PlatformDarwin { +public: + using PlatformDarwin::FindXcodeContentsDirectoryInPath; static bool SDKSupportsModules(SDKType desired_type, const lldb_private::FileSpec &sdk_path) { return PlatformDarwin::SDKSupportsModules(desired_type, sdk_path); @@ -69,3 +71,64 @@ TEST(PlatformDarwinTest, TestParseVersionBuildDir) { PlatformDarwin::SDKType::MacOSX, FileSpec(base + "MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk"))); } + +TEST(PlatformDarwinTest, FindXcodeContentsDirectoryInPath) { + std::string standard = + "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/" + "Developer/SDKs/MacOSX.sdk"; + EXPECT_EQ("/Applications/Xcode.app/Contents", + PlatformDarwinTester::FindXcodeContentsDirectoryInPath(standard)); + + std::string standard_version = + "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/" + "Developer/SDKs/MacOSX10.15.sdk"; + EXPECT_EQ( + "/Applications/Xcode.app/Contents", + PlatformDarwinTester::FindXcodeContentsDirectoryInPath(standard_version)); + + std::string beta = "/Applications/Xcode-beta.app/Contents/Developer/" + "Platforms/MacOSX.platform/" + "Developer/SDKs/MacOSX10.15.sdk"; + EXPECT_EQ("/Applications/Xcode-beta.app/Contents", + PlatformDarwinTester::FindXcodeContentsDirectoryInPath(beta)); + + std::string no_app = + "/Applications/Xcode/Contents/Developer/Platforms/MacOSX.platform/" + "Developer/SDKs/MacOSX10.15.sdk"; + EXPECT_EQ("", PlatformDarwinTester::FindXcodeContentsDirectoryInPath(no_app)); + + std::string no_contents = + "/Applications/Xcode.app/Developer/Platforms/MacOSX.platform/" + "Developer/SDKs/MacOSX10.15.sdk"; + EXPECT_EQ( + "", PlatformDarwinTester::FindXcodeContentsDirectoryInPath(no_contents)); + + std::string no_capitalization = + "/Applications/Xcode.app/contents/Developer/Platforms/MacOSX.platform/" + "Developer/SDKs/MacOSX10.15.sdk"; + EXPECT_EQ("", PlatformDarwinTester::FindXcodeContentsDirectoryInPath( + no_capitalization)); +} + +TEST(PlatformDarwinTest, GetSDKNameForType) { + EXPECT_EQ("macosx", + PlatformDarwin::GetSDKNameForType(PlatformDarwin::SDKType::MacOSX)); + EXPECT_EQ("iphonesimulator", PlatformDarwin::GetSDKNameForType( + PlatformDarwin::SDKType::iPhoneSimulator)); + EXPECT_EQ("iphoneos", PlatformDarwin::GetSDKNameForType( + PlatformDarwin::SDKType::iPhoneOS)); + EXPECT_EQ("appletvsimulator", PlatformDarwin::GetSDKNameForType( + PlatformDarwin::SDKType::AppleTVSimulator)); + EXPECT_EQ("appletvos", PlatformDarwin::GetSDKNameForType( + PlatformDarwin::SDKType::AppleTVOS)); + EXPECT_EQ("watchsimulator", PlatformDarwin::GetSDKNameForType( + PlatformDarwin::SDKType::WatchSimulator)); + EXPECT_EQ("watchos", PlatformDarwin::GetSDKNameForType( + PlatformDarwin::SDKType::watchOS)); + EXPECT_EQ("linux", + PlatformDarwin::GetSDKNameForType(PlatformDarwin::SDKType::Linux)); + EXPECT_EQ("", PlatformDarwin::GetSDKNameForType( + PlatformDarwin::SDKType::numSDKTypes)); + EXPECT_EQ( + "", PlatformDarwin::GetSDKNameForType(PlatformDarwin::SDKType::unknown)); +} From 26f33d02526db5451e72bce51a59757b21f7e550 Mon Sep 17 00:00:00 2001 From: Davide Italiano Date: Tue, 17 Mar 2020 17:10:58 -0700 Subject: [PATCH 019/286] [SwiftASTContext] GetFieldAtIndex doesn't really make sense for enums. Also, its implementation is broken. --- lldb/source/Symbol/SwiftASTContext.cpp | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/lldb/source/Symbol/SwiftASTContext.cpp b/lldb/source/Symbol/SwiftASTContext.cpp index de66bac927dee..9686229b3e097 100644 --- a/lldb/source/Symbol/SwiftASTContext.cpp +++ b/lldb/source/Symbol/SwiftASTContext.cpp @@ -6881,22 +6881,8 @@ CompilerType SwiftASTContext::GetFieldAtIndex(void *type, size_t idx, break; case swift::TypeKind::Enum: - case swift::TypeKind::BoundGenericEnum: { - SwiftEnumDescriptor *cached_enum_info = GetCachedEnumInfo(type); - if (cached_enum_info && - idx < cached_enum_info->GetNumElementsWithPayload()) { - const SwiftEnumDescriptor::ElementInfo *enum_element_info = - cached_enum_info->GetElementWithPayloadAtIndex(idx); - name.assign(enum_element_info->name.GetCString()); - if (bit_offset_ptr) - *bit_offset_ptr = 0; - if (bitfield_bit_size_ptr) - *bitfield_bit_size_ptr = 0; - if (is_bitfield_ptr) - *is_bitfield_ptr = false; - return enum_element_info->payload_type; - } - } break; + case swift::TypeKind::BoundGenericEnum: + break; case swift::TypeKind::Tuple: { auto tuple_type = cast(swift_can_type); From 18a720f1c1dae70afc324196125495fa5d762276 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Tue, 17 Mar 2020 16:59:46 -0700 Subject: [PATCH 020/286] [lldb/Bindings] Check that process isn't None before calling is_alive. Make sure that `process` is not None before calling is_alive. Otherwise this might result in an AttributeError: 'NoneType' object has no attribute 'is_alive'. Although lldb.process and friends could already be None in the past, for example after leaving an interactive scripting session, the issue became more prevalent after `fc1fd6bf9fcfac412b10b4193805ec5de0e8df57`. I audited the other interface files for usages of target, process, thread and frame, but this seems the only place where a global is used from an SB class. (cherry picked from commit a11b330418819d9cc9c4f0ecd31acdc2e0bbb703) --- lldb/bindings/interface/SBAddress.i | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/bindings/interface/SBAddress.i b/lldb/bindings/interface/SBAddress.i index 4658534d153ea..de277607d8f5e 100644 --- a/lldb/bindings/interface/SBAddress.i +++ b/lldb/bindings/interface/SBAddress.i @@ -154,7 +154,7 @@ public: def __int__(self): '''Convert an address to a load address if there is a process and that process is alive, or to a file address otherwise.''' - if process.is_alive: + if process and process.is_alive: return self.GetLoadAddress (target) else: return self.GetFileAddress () From 915c19777ab4f940fb5c227e486b264e725e915e Mon Sep 17 00:00:00 2001 From: Bruno Cardoso Lopes Date: Tue, 17 Mar 2020 18:23:28 -0700 Subject: [PATCH 021/286] [Modules] Reapply: Make header inclusion order from umbrella dirs deterministic Sort the headers by name before adding the includes in collectModuleHeaderIncludes. This makes the include order for building umbrellas deterministic across different filesystems and also guarantees that the ASTWriter always dump top headers in the same order. There's currently no good way to test for this behavior. This was first introduced in r289478 and reverted few times because of ASANifed test failures on open source bots (both from LLVM and Swift). Finally reproduced the problem in a Linux machine and use std::sort as a fix, since we are not dealing with POD-like types. rdar://problem/28116411 --- clang/lib/Frontend/FrontendAction.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp index 5195f7c60dc51..204597354282d 100644 --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -364,6 +364,7 @@ static std::error_code collectModuleHeaderIncludes( llvm::sys::path::native(UmbrellaDir.Entry->getName(), DirNative); llvm::vfs::FileSystem &FS = FileMgr.getVirtualFileSystem(); + SmallVector, 8> Headers; for (llvm::vfs::recursive_directory_iterator Dir(FS, DirNative, EC), End; Dir != End && !EC; Dir.increment(EC)) { // Check whether this entry has an extension typically associated with @@ -395,13 +396,25 @@ static std::error_code collectModuleHeaderIncludes( ++It) llvm::sys::path::append(RelativeHeader, *It); - // Include this header as part of the umbrella directory. - Module->addTopHeader(*Header); - addHeaderInclude(RelativeHeader, Includes, LangOpts, Module->IsExternC); + std::string RelName = RelativeHeader.c_str(); + Headers.push_back(std::make_pair(RelName, *Header)); } if (EC) return EC; + + // Sort header paths and make the header inclusion order deterministic + // across different OSs and filesystems. + llvm::sort(Headers.begin(), Headers.end(), []( + const std::pair &LHS, + const std::pair &RHS) { + return LHS.first > RHS.first; + }); + for (auto &H : Headers) { + // Include this header as part of the umbrella directory. + Module->addTopHeader(H.second); + addHeaderInclude(H.first, Includes, LangOpts, Module->IsExternC); + } } // Recurse into submodules. From 526554f71a5665b1e5613d040414bf373231651c Mon Sep 17 00:00:00 2001 From: Med Ismail Bennani Date: Fri, 13 Mar 2020 23:56:35 +0100 Subject: [PATCH 022/286] [lldb/Target] Support more than 2 symbols in StackFrameRecognizer This patch changes the way the StackFrame Recognizers match a certain frame. Until now, recognizers could be registered with a function name but also an alternate symbol. This change is motivated by a test failure for the Assert frame recognizer on Linux. Depending the version of the libc, the abort function (triggered by an assertion), could have more than two signatures (i.e. `raise`, `__GI_raise` and `gsignal`). Instead of only checking the default symbol name and the alternate one, lldb will iterate over a list of symbols to match against. rdar://60386577 Differential Revision: https://reviews.llvm.org/D76188 Signed-off-by: Med Ismail Bennani --- .../lldb/Target/StackFrameRecognizer.h | 14 ++-- .../Python/lldbsuite/test/lldbutil.py | 2 +- lldb/source/Commands/CommandObjectFrame.cpp | 41 ++++++----- lldb/source/Commands/Options.td | 3 +- .../AppleObjCRuntime/AppleObjCRuntimeV2.cpp | 3 +- lldb/source/Target/AssertFrameRecognizer.cpp | 24 +++---- lldb/source/Target/StackFrameRecognizer.cpp | 51 ++++++-------- .../frame/recognizer/TestFrameRecognizer.py | 68 +++++++++++++------ .../test/API/commands/frame/recognizer/main.m | 5 +- .../Target/StackFrameRecognizerTest.cpp | 3 +- 10 files changed, 115 insertions(+), 99 deletions(-) diff --git a/lldb/include/lldb/Target/StackFrameRecognizer.h b/lldb/include/lldb/Target/StackFrameRecognizer.h index 92cfca4227cf5..a21a631f0300b 100644 --- a/lldb/include/lldb/Target/StackFrameRecognizer.h +++ b/lldb/include/lldb/Target/StackFrameRecognizer.h @@ -101,8 +101,8 @@ class ScriptedStackFrameRecognizer : public StackFrameRecognizer { class StackFrameRecognizerManager { public: static void AddRecognizer(lldb::StackFrameRecognizerSP recognizer, - ConstString module, ConstString symbol, - ConstString alternate_symbol, + ConstString module, + llvm::ArrayRef symbols, bool first_instruction_only = true); static void AddRecognizer(lldb::StackFrameRecognizerSP recognizer, @@ -110,11 +110,11 @@ class StackFrameRecognizerManager { lldb::RegularExpressionSP symbol, bool first_instruction_only = true); - static void ForEach( - std::function const - &callback); + static void + ForEach(std::function symbols, + bool regexp)> const &callback); static bool RemoveRecognizerWithID(uint32_t recognizer_id); diff --git a/lldb/packages/Python/lldbsuite/test/lldbutil.py b/lldb/packages/Python/lldbsuite/test/lldbutil.py index 006362a4479c1..98d7b7e13cba0 100644 --- a/lldb/packages/Python/lldbsuite/test/lldbutil.py +++ b/lldb/packages/Python/lldbsuite/test/lldbutil.py @@ -797,7 +797,7 @@ def run_to_breakpoint_do_run(test, target, bkpt, launch_info = None, test.assertEqual(num_threads, 1, "Expected 1 thread to stop at breakpoint, %d did."%(num_threads)) else: test.assertGreater(num_threads, 0, "No threads stopped at breakpoint") - + thread = threads[0] return (target, process, thread, bkpt) diff --git a/lldb/source/Commands/CommandObjectFrame.cpp b/lldb/source/Commands/CommandObjectFrame.cpp index f460b7b05fc77..475a3d660e0e9 100644 --- a/lldb/source/Commands/CommandObjectFrame.cpp +++ b/lldb/source/Commands/CommandObjectFrame.cpp @@ -747,7 +747,7 @@ class CommandObjectFrameRecognizerAdd : public CommandObjectParsed { m_module = std::string(option_arg); break; case 'n': - m_function = std::string(option_arg); + m_symbols.push_back(std::string(option_arg)); break; case 'x': m_regex = true; @@ -761,7 +761,7 @@ class CommandObjectFrameRecognizerAdd : public CommandObjectParsed { void OptionParsingStarting(ExecutionContext *execution_context) override { m_module = ""; - m_function = ""; + m_symbols.clear(); m_class_name = ""; m_regex = false; } @@ -773,7 +773,7 @@ class CommandObjectFrameRecognizerAdd : public CommandObjectParsed { // Instance variables to hold the values for command options. std::string m_class_name; std::string m_module; - std::string m_function; + std::vector m_symbols; bool m_regex; }; @@ -855,9 +855,18 @@ bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command, return false; } - if (m_options.m_function.empty()) { - result.AppendErrorWithFormat("%s needs a function name (-n argument).\n", - m_cmd_name.c_str()); + if (m_options.m_symbols.empty()) { + result.AppendErrorWithFormat( + "%s needs at least one symbol name (-n argument).\n", + m_cmd_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + if (m_options.m_regex && m_options.m_symbols.size() > 1) { + result.AppendErrorWithFormat( + "%s needs only one symbol regular expression (-n argument).\n", + m_cmd_name.c_str()); result.SetStatus(eReturnStatusFailed); return false; } @@ -877,12 +886,13 @@ bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command, auto module = RegularExpressionSP(new RegularExpression(m_options.m_module)); auto func = - RegularExpressionSP(new RegularExpression(m_options.m_function)); + RegularExpressionSP(new RegularExpression(m_options.m_symbols.front())); StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func); } else { auto module = ConstString(m_options.m_module); - auto func = ConstString(m_options.m_function); - StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func, {}); + std::vector symbols(m_options.m_symbols.begin(), + m_options.m_symbols.end()); + StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, symbols); } #endif @@ -959,9 +969,9 @@ class CommandObjectFrameRecognizerList : public CommandObjectParsed { bool DoExecute(Args &command, CommandReturnObject &result) override { bool any_printed = false; StackFrameRecognizerManager::ForEach( - [&result, &any_printed](uint32_t recognizer_id, std::string name, - std::string module, std::string symbol, - std::string alternate_symbol, bool regexp) { + [&result, &any_printed]( + uint32_t recognizer_id, std::string name, std::string module, + llvm::ArrayRef symbols, bool regexp) { Stream &stream = result.GetOutputStream(); if (name.empty()) @@ -970,10 +980,9 @@ class CommandObjectFrameRecognizerList : public CommandObjectParsed { stream << std::to_string(recognizer_id) << ": " << name; if (!module.empty()) stream << ", module " << module; - if (!symbol.empty()) - stream << ", function " << symbol; - if (!alternate_symbol.empty()) - stream << ", symbol " << alternate_symbol; + if (!symbols.empty()) + for (auto &symbol : symbols) + stream << ", symbol " << symbol; if (regexp) stream << " (regexp)"; diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td index 1456630c892f0..5953ed4452234 100644 --- a/lldb/source/Commands/Options.td +++ b/lldb/source/Commands/Options.td @@ -384,7 +384,8 @@ let Command = "frame recognizer add" in { "to.">; def frame_recognizer_function : Option<"function", "n">, Arg<"Name">, Completion<"Symbol">, - Desc<"Name of the function that this recognizer applies to.">; + Desc<"Name of the function that this recognizer applies to. " + "Can be specified more than once except if -x|--regex is provided.">; def frame_recognizer_python_class : Option<"python-class", "l">, Group<2>, Arg<"PythonClass">, Desc<"Give the name of a Python class to use for this frame recognizer.">; diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp index 1840c42caf8e6..5d77082420e60 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp @@ -2721,9 +2721,10 @@ static void RegisterObjCExceptionRecognizer() { FileSpec module; ConstString function; std::tie(module, function) = AppleObjCRuntime::GetExceptionThrowLocation(); + std::vector symbols = {function}; StackFrameRecognizerManager::AddRecognizer( StackFrameRecognizerSP(new ObjCExceptionThrowFrameRecognizer()), - module.GetFilename(), function, /*alternate_symbol*/ {}, + module.GetFilename(), symbols, /*first_instruction_only*/ true); }); } diff --git a/lldb/source/Target/AssertFrameRecognizer.cpp b/lldb/source/Target/AssertFrameRecognizer.cpp index ebeff6c393919..d87459ac2fdd4 100644 --- a/lldb/source/Target/AssertFrameRecognizer.cpp +++ b/lldb/source/Target/AssertFrameRecognizer.cpp @@ -21,8 +21,7 @@ namespace lldb_private { /// name. struct SymbolLocation { FileSpec module_spec; - ConstString symbol_name; - ConstString alternate_symbol_name; + std::vector symbols; }; /// Fetches the abort frame location depending on the current platform. @@ -39,12 +38,13 @@ bool GetAbortLocation(llvm::Triple::OSType os, SymbolLocation &location) { case llvm::Triple::Darwin: case llvm::Triple::MacOSX: location.module_spec = FileSpec("libsystem_kernel.dylib"); - location.symbol_name.SetString("__pthread_kill"); + location.symbols.push_back(ConstString("__pthread_kill")); break; case llvm::Triple::Linux: location.module_spec = FileSpec("libc.so.6"); - location.symbol_name.SetString("raise"); - location.alternate_symbol_name.SetString("__GI_raise"); + location.symbols.push_back(ConstString("raise")); + location.symbols.push_back(ConstString("__GI_raise")); + location.symbols.push_back(ConstString("gsignal")); break; default: Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); @@ -69,12 +69,12 @@ bool GetAssertLocation(llvm::Triple::OSType os, SymbolLocation &location) { case llvm::Triple::Darwin: case llvm::Triple::MacOSX: location.module_spec = FileSpec("libsystem_c.dylib"); - location.symbol_name.SetString("__assert_rtn"); + location.symbols.push_back(ConstString("__assert_rtn")); break; case llvm::Triple::Linux: location.module_spec = FileSpec("libc.so.6"); - location.symbol_name.SetString("__assert_fail"); - location.alternate_symbol_name.SetString("__GI___assert_fail"); + location.symbols.push_back(ConstString("__assert_fail")); + location.symbols.push_back(ConstString("__GI___assert_fail")); break; default: Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); @@ -97,8 +97,7 @@ void RegisterAssertFrameRecognizer(Process *process) { StackFrameRecognizerManager::AddRecognizer( StackFrameRecognizerSP(new AssertFrameRecognizer()), - location.module_spec.GetFilename(), ConstString(location.symbol_name), - ConstString(location.alternate_symbol_name), + location.module_spec.GetFilename(), location.symbols, /*first_instruction_only*/ false); }); } @@ -139,10 +138,7 @@ AssertFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) { ConstString func_name = sym_ctx.GetFunctionName(); - if (func_name == location.symbol_name || - (!location.alternate_symbol_name.IsEmpty() && - func_name == location.alternate_symbol_name)) { - + if (llvm::is_contained(location.symbols, func_name)) { // We go a frame beyond the assert location because the most relevant // frame for the user is the one in which the assert function was called. // If the assert location is the last frame fetched, then it is set as diff --git a/lldb/source/Target/StackFrameRecognizer.cpp b/lldb/source/Target/StackFrameRecognizer.cpp index dfc811da0a507..32b8c94d942c0 100644 --- a/lldb/source/Target/StackFrameRecognizer.cpp +++ b/lldb/source/Target/StackFrameRecognizer.cpp @@ -51,27 +51,25 @@ ScriptedStackFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame) { class StackFrameRecognizerManagerImpl { public: void AddRecognizer(StackFrameRecognizerSP recognizer, ConstString module, - ConstString symbol, ConstString alternate_symbol, + llvm::ArrayRef symbols, bool first_instruction_only) { m_recognizers.push_front({(uint32_t)m_recognizers.size(), false, recognizer, - false, module, RegularExpressionSP(), symbol, - alternate_symbol, RegularExpressionSP(), - first_instruction_only}); + false, module, RegularExpressionSP(), symbols, + RegularExpressionSP(), first_instruction_only}); } void AddRecognizer(StackFrameRecognizerSP recognizer, RegularExpressionSP module, RegularExpressionSP symbol, bool first_instruction_only) { - m_recognizers.push_front({(uint32_t)m_recognizers.size(), false, recognizer, - true, ConstString(), module, ConstString(), - ConstString(), symbol, first_instruction_only}); + m_recognizers.push_front( + {(uint32_t)m_recognizers.size(), false, recognizer, true, ConstString(), + module, std::vector(), symbol, first_instruction_only}); } - void ForEach( - std::function const - &callback) { + void ForEach(std::function< + void(uint32_t recognized_id, std::string recognizer_name, + std::string module, llvm::ArrayRef symbols, + bool regexp)> const &callback) { for (auto entry : m_recognizers) { if (entry.is_regexp) { std::string module_name; @@ -83,16 +81,11 @@ class StackFrameRecognizerManagerImpl { symbol_name = entry.symbol_regexp->GetText().str(); callback(entry.recognizer_id, entry.recognizer->GetName(), module_name, - symbol_name, {}, true); + llvm::makeArrayRef(ConstString(symbol_name)), true); } else { - std::string alternate_symbol; - if (!entry.alternate_symbol.IsEmpty()) - alternate_symbol.append(entry.alternate_symbol.GetCString()); - callback(entry.recognizer_id, entry.recognizer->GetName(), - entry.module.GetCString(), entry.symbol.GetCString(), - alternate_symbol, false); + entry.module.GetCString(), entry.symbols, false); } } } @@ -128,10 +121,8 @@ class StackFrameRecognizerManagerImpl { if (entry.module_regexp) if (!entry.module_regexp->Execute(module_name.GetStringRef())) continue; - if (entry.symbol) - if (entry.symbol != function_name && - (!entry.alternate_symbol || - entry.alternate_symbol != function_name)) + if (!entry.symbols.empty()) + if (!llvm::is_contained(entry.symbols, function_name)) continue; if (entry.symbol_regexp) @@ -160,8 +151,7 @@ class StackFrameRecognizerManagerImpl { bool is_regexp; ConstString module; RegularExpressionSP module_regexp; - ConstString symbol; - ConstString alternate_symbol; + std::vector symbols; RegularExpressionSP symbol_regexp; bool first_instruction_only; }; @@ -176,10 +166,10 @@ StackFrameRecognizerManagerImpl &GetStackFrameRecognizerManagerImpl() { } void StackFrameRecognizerManager::AddRecognizer( - StackFrameRecognizerSP recognizer, ConstString module, ConstString symbol, - ConstString alternate_symbol, bool first_instruction_only) { + StackFrameRecognizerSP recognizer, ConstString module, + llvm::ArrayRef symbols, bool first_instruction_only) { GetStackFrameRecognizerManagerImpl().AddRecognizer( - recognizer, module, symbol, alternate_symbol, first_instruction_only); + recognizer, module, symbols, first_instruction_only); } void StackFrameRecognizerManager::AddRecognizer( @@ -191,9 +181,8 @@ void StackFrameRecognizerManager::AddRecognizer( void StackFrameRecognizerManager::ForEach( std::function const - &callback) { + std::string module, llvm::ArrayRef symbols, + bool regexp)> const &callback) { GetStackFrameRecognizerManagerImpl().ForEach(callback); } diff --git a/lldb/test/API/commands/frame/recognizer/TestFrameRecognizer.py b/lldb/test/API/commands/frame/recognizer/TestFrameRecognizer.py index 3a2faa48e7679..04b940049496e 100644 --- a/lldb/test/API/commands/frame/recognizer/TestFrameRecognizer.py +++ b/lldb/test/API/commands/frame/recognizer/TestFrameRecognizer.py @@ -18,9 +18,7 @@ class FrameRecognizerTestCase(TestBase): @skipUnlessDarwin def test_frame_recognizer_1(self): self.build() - - target = self.dbg.CreateTarget(self.getBuildArtifact("a.out")) - self.assertTrue(target, VALID_TARGET) + exe = self.getBuildArtifact("a.out") # Clear internal & plugins recognizers that get initialized at launch self.runCmd("frame recognizer clear") @@ -33,19 +31,21 @@ def test_frame_recognizer_1(self): self.runCmd("frame recognizer add -l recognizer.MyFrameRecognizer -s a.out -n foo") self.expect("frame recognizer list", - substrs=['0: recognizer.MyFrameRecognizer, module a.out, function foo']) + substrs=['0: recognizer.MyFrameRecognizer, module a.out, symbol foo']) self.runCmd("frame recognizer add -l recognizer.MyOtherFrameRecognizer -s a.out -n bar -x") - self.expect("frame recognizer list", - substrs=['0: recognizer.MyFrameRecognizer, module a.out, function foo', - '1: recognizer.MyOtherFrameRecognizer, module a.out, function bar (regexp)' - ]) + self.expect( + "frame recognizer list", + substrs=[ + '1: recognizer.MyOtherFrameRecognizer, module a.out, symbol bar (regexp)', + '0: recognizer.MyFrameRecognizer, module a.out, symbol foo' + ]) self.runCmd("frame recognizer delete 0") self.expect("frame recognizer list", - substrs=['1: recognizer.MyOtherFrameRecognizer, module a.out, function bar (regexp)']) + substrs=['1: recognizer.MyOtherFrameRecognizer, module a.out, symbol bar (regexp)']) self.runCmd("frame recognizer clear") @@ -54,19 +54,10 @@ def test_frame_recognizer_1(self): self.runCmd("frame recognizer add -l recognizer.MyFrameRecognizer -s a.out -n foo") - lldbutil.run_break_set_by_symbol(self, "foo") - self.runCmd("r") - - self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, - substrs=['stopped', 'stop reason = breakpoint']) - - process = target.GetProcess() - thread = process.GetSelectedThread() + target, process, thread, _ = lldbutil.run_to_name_breakpoint(self, "foo", + exe_name = exe) frame = thread.GetSelectedFrame() - self.assertEqual(frame.GetSymbol().GetName(), "foo") - self.assertFalse(frame.GetLineEntry().IsValid()) - self.expect("frame variable", substrs=['(int) a = 42', '(int) b = 56']) @@ -108,8 +99,9 @@ def test_frame_recognizer_1(self): # FIXME: The following doesn't work yet, but should be fixed. """ - lldbutil.run_break_set_by_symbol(self, "bar") - self.runCmd("c") + target, process, thread, _ = lldbutil.run_to_name_breakpoint(self, "bar", + exe_name = exe) + frame = thread.GetSelectedFrame() self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, substrs=['stopped', 'stop reason = breakpoint']) @@ -120,3 +112,35 @@ def test_frame_recognizer_1(self): self.expect("frame variable -t *a", substrs=['*a = 78']) """ + + @skipUnlessDarwin + def test_frame_recognizer_multi_symbol(self): + self.build() + exe = self.getBuildArtifact("a.out") + + # Clear internal & plugins recognizers that get initialized at launch + self.runCmd("frame recognizer clear") + + self.runCmd("command script import " + os.path.join(self.getSourceDir(), "recognizer.py")) + + self.expect("frame recognizer list", + substrs=['no matching results found.']) + + self.runCmd("frame recognizer add -l recognizer.MyFrameRecognizer -s a.out -n foo -n bar") + + self.expect("frame recognizer list", + substrs=['recognizer.MyFrameRecognizer, module a.out, symbol foo, symbol bar']) + + target, process, thread, _ = lldbutil.run_to_name_breakpoint(self, "foo", + exe_name = exe) + frame = thread.GetSelectedFrame() + + self.expect("frame recognizer info 0", + substrs=['frame 0 is recognized by recognizer.MyFrameRecognizer']) + + target, process, thread, _ = lldbutil.run_to_name_breakpoint(self, "bar", + exe_name = exe) + frame = thread.GetSelectedFrame() + + self.expect("frame recognizer info 0", + substrs=['frame 0 is recognized by recognizer.MyFrameRecognizer']) diff --git a/lldb/test/API/commands/frame/recognizer/main.m b/lldb/test/API/commands/frame/recognizer/main.m index 9c6ce9d210233..a5ef73c43b445 100644 --- a/lldb/test/API/commands/frame/recognizer/main.m +++ b/lldb/test/API/commands/frame/recognizer/main.m @@ -13,10 +13,7 @@ void foo(int a, int b) printf("%d %d\n", a, b); } -void bar(int *ptr) -{ - printf("%d\n", *ptr); -} +void bar(int *ptr) { printf("%d\n", *ptr); } int main (int argc, const char * argv[]) { diff --git a/lldb/unittests/Target/StackFrameRecognizerTest.cpp b/lldb/unittests/Target/StackFrameRecognizerTest.cpp index f7b7829e2bb8d..067a56a19902b 100644 --- a/lldb/unittests/Target/StackFrameRecognizerTest.cpp +++ b/lldb/unittests/Target/StackFrameRecognizerTest.cpp @@ -76,8 +76,7 @@ TEST_F(StackFrameRecognizerTest, NullModuleRegex) { bool any_printed = false; StackFrameRecognizerManager::ForEach( [&any_printed](uint32_t recognizer_id, std::string name, - std::string function, std::string symbol, - std::string alternate_symbol, + std::string function, llvm::ArrayRef symbols, bool regexp) { any_printed = true; }); EXPECT_TRUE(any_printed); From 73f99de9ee51a74d248f364567ace216e951d056 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Tue, 17 Mar 2020 15:03:24 -0700 Subject: [PATCH 023/286] [SwiftASTContext] Share common code with PlatformDarwin. Commit 7aa28995e87f6cec2e02608c978885cf01dcc65d refactored the Xcode resource directory logic and made it possible to have this code shared with SwiftASTContext. --- lldb/source/Symbol/SwiftASTContext.cpp | 182 +++++++++---------------- 1 file changed, 63 insertions(+), 119 deletions(-) diff --git a/lldb/source/Symbol/SwiftASTContext.cpp b/lldb/source/Symbol/SwiftASTContext.cpp index dc55b8853ff58..4b6a910b1d5c5 100644 --- a/lldb/source/Symbol/SwiftASTContext.cpp +++ b/lldb/source/Symbol/SwiftASTContext.cpp @@ -1442,25 +1442,9 @@ ConstString SwiftASTContext::GetPluginName() { uint32_t SwiftASTContext::GetPluginVersion() { return 1; } namespace { -enum SDKType : int { - MacOSX = 0, - iPhoneSimulator, - iPhoneOS, - AppleTVSimulator, - AppleTVOS, - WatchSimulator, - watchOS, - Linux, - numSDKTypes, - unknown = -1 -}; - -const char *const sdk_strings[] = { - "macosx", "iphonesimulator", "iphoneos", "appletvsimulator", - "appletvos", "watchsimulator", "watchos", "linux"}; struct SDKTypeMinVersion { - SDKType sdk_type; + PlatformDarwin::SDKType sdk_type; unsigned min_version_major; unsigned min_version_minor; }; @@ -1474,7 +1458,7 @@ static SDKTypeMinVersion GetSDKType(const llvm::Triple &target, // Only Darwin platforms know the concept of an SDK. auto host_os = host.getOS(); if (host_os != llvm::Triple::OSType::MacOSX) - return {SDKType::unknown, 0, 0}; + return {PlatformDarwin::SDKType::unknown, 0, 0}; auto is_simulator = [&]() -> bool { return target.getEnvironment() == llvm::Triple::Simulator || @@ -1484,74 +1468,24 @@ static SDKTypeMinVersion GetSDKType(const llvm::Triple &target, switch (target.getOS()) { case llvm::Triple::OSType::MacOSX: case llvm::Triple::OSType::Darwin: - return {SDKType::MacOSX, 10, 10}; + return {PlatformDarwin::SDKType::MacOSX, 10, 10}; case llvm::Triple::OSType::IOS: if (is_simulator()) - return {SDKType::iPhoneSimulator, 8, 0}; - return {SDKType::iPhoneOS, 8, 0}; + return {PlatformDarwin::SDKType::iPhoneSimulator, 8, 0}; + return {PlatformDarwin::SDKType::iPhoneOS, 8, 0}; case llvm::Triple::OSType::TvOS: if (is_simulator()) - return {SDKType::AppleTVSimulator, 9, 0}; - return {SDKType::AppleTVOS, 9, 0}; + return {PlatformDarwin::SDKType::AppleTVSimulator, 9, 0}; + return {PlatformDarwin::SDKType::AppleTVOS, 9, 0}; case llvm::Triple::OSType::WatchOS: if (is_simulator()) - return {SDKType::WatchSimulator, 2, 0}; - return {SDKType::watchOS, 2, 0}; + return {PlatformDarwin::SDKType::WatchSimulator, 2, 0}; + return {PlatformDarwin::SDKType::watchOS, 2, 0}; default: - return {SDKType::unknown, 0, 0}; + return {PlatformDarwin::SDKType::unknown, 0, 0}; } } -static StringRef GetXcodeContentsPath() { - static std::once_flag g_once_flag; - static std::string g_xcode_contents_path; - std::call_once(g_once_flag, [&]() { - const char substr[] = ".app/Contents/"; - - // First, try based on the current shlib's location. - if (FileSpec fspec = HostInfo::GetShlibDir()) { - std::string path_to_shlib = fspec.GetPath(); - size_t pos = path_to_shlib.rfind(substr); - if (pos != std::string::npos) { - path_to_shlib.erase(pos + strlen(substr)); - g_xcode_contents_path = path_to_shlib; - return; - } - } - - // Fall back to using xcrun. - if (HostInfo::GetArchitecture().GetTriple().getOS() == - llvm::Triple::MacOSX) { - int status = 0; - int signo = 0; - std::string output; - const char *command = "xcrun -sdk macosx --show-sdk-path"; - lldb_private::Status error = Host::RunShellCommand( - command, // shell command to run - {}, // current working directory - &status, // Put the exit status of the process in here - &signo, // Put the signal that caused the process to exit in here - &output, // Get the output from the command and place it in this - // string - std::chrono::seconds( - 3)); // Timeout in seconds to wait for shell program to finish - if (status == 0 && !output.empty()) { - size_t first_non_newline = output.find_last_not_of("\r\n"); - if (first_non_newline != std::string::npos) { - output.erase(first_non_newline + 1); - } - - size_t pos = output.rfind(substr); - if (pos != std::string::npos) { - output.erase(pos + strlen(substr)); - g_xcode_contents_path = output; - } - } - } - }); - return g_xcode_contents_path; -} - static std::string GetCurrentToolchainPath() { const char substr[] = ".xctoolchain/"; @@ -1591,8 +1525,9 @@ static std::string GetCurrentCLToolsPath() { StringRef SwiftASTContext::GetSwiftStdlibOSDir(const llvm::Triple &target, const llvm::Triple &host) { auto sdk = GetSDKType(target, host); - if (sdk.sdk_type != SDKType::unknown) - return sdk_strings[sdk.sdk_type]; + llvm::StringRef sdk_name = PlatformDarwin::GetSDKNameForType(sdk.sdk_type); + if (!sdk_name.empty()) + return sdk_name; return target.getOSName(); } @@ -1611,10 +1546,10 @@ StringRef SwiftASTContext::GetResourceDir(const llvm::Triple &triple) { if (it != g_resource_dir_cache.end()) return it->getValue(); - auto value = - GetResourceDir(platform_sdk_path, swift_stdlib_os_dir, - GetSwiftResourceDir().GetPath(), GetXcodeContentsPath(), - GetCurrentToolchainPath(), GetCurrentCLToolsPath()); + auto value = GetResourceDir( + platform_sdk_path, swift_stdlib_os_dir, GetSwiftResourceDir().GetPath(), + PlatformDarwin::GetXcodeContentsDirectory().GetPath(), + GetCurrentToolchainPath(), GetCurrentCLToolsPath()); g_resource_dir_cache.insert({key, value}); return g_resource_dir_cache[key]; } @@ -2934,14 +2869,15 @@ namespace { struct SDKEnumeratorInfo { FileSpec found_path; - SDKType sdk_type; + PlatformDarwin::SDKType sdk_type; uint32_t least_major; uint32_t least_minor; }; } // anonymous namespace -static bool SDKSupportsSwift(const FileSpec &sdk_path, SDKType desired_type) { +static bool SDKSupportsSwift(const FileSpec &sdk_path, + PlatformDarwin::SDKType desired_type) { ConstString last_path_component = sdk_path.GetLastPathComponent(); if (last_path_component) { @@ -2951,23 +2887,30 @@ static bool SDKSupportsSwift(const FileSpec &sdk_path, SDKType desired_type) { llvm::StringRef version_part; - SDKType sdk_type = SDKType::unknown; - - if (desired_type == SDKType::unknown) { - for (int i = (int)SDKType::MacOSX; i < SDKType::numSDKTypes; ++i) { - if (sdk_name.startswith(sdk_strings[i])) { - version_part = sdk_name.drop_front(strlen(sdk_strings[i])); - sdk_type = (SDKType)i; + PlatformDarwin::SDKType sdk_type = PlatformDarwin::SDKType::unknown; + + if (desired_type == PlatformDarwin::SDKType::unknown) { + for (int i = (int)PlatformDarwin::SDKType::MacOSX; + i < PlatformDarwin::SDKType::numSDKTypes; ++i) { + PlatformDarwin::SDKType this_type = + static_cast(i); + llvm::StringRef this_sdk_name = + PlatformDarwin::GetSDKNameForType(this_type); + if (sdk_name.startswith(this_sdk_name)) { + version_part = sdk_name.drop_front(this_sdk_name.size()); + sdk_type = this_type; break; } } // For non-Darwin SDKs assume Swift is supported - if (sdk_type == SDKType::unknown) + if (sdk_type == PlatformDarwin::SDKType::unknown) return true; } else { - if (sdk_name.startswith(sdk_strings[desired_type])) { - version_part = sdk_name.drop_front(strlen(sdk_strings[desired_type])); + llvm::StringRef desired_sdk_name = + PlatformDarwin::GetSDKNameForType(desired_type); + if (sdk_name.startswith(desired_sdk_name)) { + version_part = sdk_name.drop_front(desired_sdk_name.size()); sdk_type = desired_type; } else { return false; @@ -2999,26 +2942,26 @@ static bool SDKSupportsSwift(const FileSpec &sdk_path, SDKType desired_type) { return false; switch (sdk_type) { - case SDKType::MacOSX: + case PlatformDarwin::SDKType::MacOSX: if (major > 10 || (major == 10 && minor >= 10)) return true; break; - case SDKType::iPhoneOS: - case SDKType::iPhoneSimulator: + case PlatformDarwin::SDKType::iPhoneOS: + case PlatformDarwin::SDKType::iPhoneSimulator: if (major >= 8) return true; break; - case SDKType::AppleTVSimulator: - case SDKType::AppleTVOS: + case PlatformDarwin::SDKType::AppleTVSimulator: + case PlatformDarwin::SDKType::AppleTVOS: if (major >= 9) return true; break; - case SDKType::WatchSimulator: - case SDKType::watchOS: + case PlatformDarwin::SDKType::WatchSimulator: + case PlatformDarwin::SDKType::watchOS: if (major >= 2) return true; break; - case SDKType::Linux: + case PlatformDarwin::SDKType::Linux: return true; default: return false; @@ -3041,7 +2984,8 @@ DirectoryEnumerator(void *baton, llvm::sys::fs::file_type file_type, return FileSystem::EnumerateDirectoryResult::eEnumerateDirectoryResultNext; }; -static ConstString EnumerateSDKsForVersion(FileSpec sdks_spec, SDKType sdk_type, +static ConstString EnumerateSDKsForVersion(FileSpec sdks_spec, + PlatformDarwin::SDKType sdk_type, uint32_t least_major, uint32_t least_minor) { if (!IsDirectory(sdks_spec)) @@ -3067,22 +3011,23 @@ static ConstString EnumerateSDKsForVersion(FileSpec sdks_spec, SDKType sdk_type, return ConstString(); } -static ConstString GetSDKDirectory(SDKType sdk_type, uint32_t least_major, - uint32_t least_minor) { - if (sdk_type != SDKType::MacOSX) { +static ConstString GetSDKDirectory(PlatformDarwin::SDKType sdk_type, + uint32_t least_major, uint32_t least_minor) { + if (sdk_type != PlatformDarwin::SDKType::MacOSX) { // Look inside Xcode for the required installed iOS SDK version. - std::string sdks_path = GetXcodeContentsPath(); + std::string sdks_path = + PlatformDarwin::GetXcodeContentsDirectory().GetPath(); sdks_path.append("Developer/Platforms"); - if (sdk_type == SDKType::iPhoneSimulator) { + if (sdk_type == PlatformDarwin::SDKType::iPhoneSimulator) { sdks_path.append("/iPhoneSimulator.platform/"); - } else if (sdk_type == SDKType::AppleTVSimulator) { + } else if (sdk_type == PlatformDarwin::SDKType::AppleTVSimulator) { sdks_path.append("/AppleTVSimulator.platform/"); - } else if (sdk_type == SDKType::AppleTVOS) { + } else if (sdk_type == PlatformDarwin::SDKType::AppleTVOS) { sdks_path.append("/AppleTVOS.platform/"); - } else if (sdk_type == SDKType::WatchSimulator) { + } else if (sdk_type == PlatformDarwin::SDKType::WatchSimulator) { sdks_path.append("/WatchSimulator.platform/"); - } else if (sdk_type == SDKType::watchOS) { + } else if (sdk_type == PlatformDarwin::SDKType::watchOS) { // For now, we need to be prepared to handle either capitalization of this // path. std::string WatchOS_candidate_path = sdks_path + "/WatchOS.platform/"; @@ -3137,15 +3082,14 @@ static ConstString GetSDKDirectory(SDKType sdk_type, uint32_t least_major, return pos->second; FileSpec fspec; - std::string xcode_contents_path; - - if (xcode_contents_path.empty()) - xcode_contents_path = GetXcodeContentsPath(); + std::string xcode_contents_path = + PlatformDarwin::GetXcodeContentsDirectory().GetPath(); + ; if (!xcode_contents_path.empty()) { StreamString sdk_path; sdk_path.Printf( - "%sDeveloper/Platforms/MacOSX.platform/Developer/SDKs/MacOSX%u.%u.sdk", + "%s/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX%u.%u.sdk", xcode_contents_path.c_str(), major, minor); fspec.SetFile(sdk_path.GetString(), FileSpec::Style::native); if (FileSystem::Instance().Exists(fspec)) { @@ -3294,7 +3238,7 @@ void SwiftASTContext::InitializeSearchPathOptions( FileSpec platform_sdk(m_platform_sdk_path.c_str()); if (FileSystem::Instance().Exists(platform_sdk) && - SDKSupportsSwift(platform_sdk, SDKType::unknown)) { + SDKSupportsSwift(platform_sdk, PlatformDarwin::SDKType::unknown)) { invocation.setSDKPath(m_platform_sdk_path.c_str()); set_sdk = true; } @@ -3313,7 +3257,7 @@ void SwiftASTContext::InitializeSearchPathOptions( if (!set_sdk) { auto sdk = GetSDKType(triple, HostInfo::GetArchitecture().GetTriple()); // Explicitly leave the SDKPath blank on other platforms. - if (sdk.sdk_type != SDKType::unknown) { + if (sdk.sdk_type != PlatformDarwin::SDKType::unknown) { auto dir = GetSDKDirectory(sdk.sdk_type, sdk.min_version_major, sdk.min_version_minor); // Note that calling setSDKPath() also recomputes all paths that From b9160b1a35902e3657200bff0ee6382a9d64b756 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Wed, 18 Mar 2020 10:04:07 -0700 Subject: [PATCH 024/286] [SwiftASTContext] Use llvm::sys::path for path manipulation Manipulating paths as strings is error prone. This rewrites the SDK findings logic in terms of llvm::sys::path. --- lldb/source/Symbol/SwiftASTContext.cpp | 111 +++++++++++++------------ 1 file changed, 59 insertions(+), 52 deletions(-) diff --git a/lldb/source/Symbol/SwiftASTContext.cpp b/lldb/source/Symbol/SwiftASTContext.cpp index 4b6a910b1d5c5..c8875ca103895 100644 --- a/lldb/source/Symbol/SwiftASTContext.cpp +++ b/lldb/source/Symbol/SwiftASTContext.cpp @@ -3013,41 +3013,43 @@ static ConstString EnumerateSDKsForVersion(FileSpec sdks_spec, static ConstString GetSDKDirectory(PlatformDarwin::SDKType sdk_type, uint32_t least_major, uint32_t least_minor) { + using namespace llvm::sys; if (sdk_type != PlatformDarwin::SDKType::MacOSX) { // Look inside Xcode for the required installed iOS SDK version. - std::string sdks_path = - PlatformDarwin::GetXcodeContentsDirectory().GetPath(); - sdks_path.append("Developer/Platforms"); + llvm::SmallString<256> sdks_path( + PlatformDarwin::GetXcodeContentsDirectory().GetPath()); + path::append(sdks_path, "Developer", "Platforms"); if (sdk_type == PlatformDarwin::SDKType::iPhoneSimulator) { - sdks_path.append("/iPhoneSimulator.platform/"); + path::append(sdks_path, "iPhoneSimulator.platform"); } else if (sdk_type == PlatformDarwin::SDKType::AppleTVSimulator) { - sdks_path.append("/AppleTVSimulator.platform/"); + path::append(sdks_path, "AppleTVSimulator.platform"); } else if (sdk_type == PlatformDarwin::SDKType::AppleTVOS) { - sdks_path.append("/AppleTVOS.platform/"); + path::append(sdks_path, "AppleTVOS.platform"); } else if (sdk_type == PlatformDarwin::SDKType::WatchSimulator) { - sdks_path.append("/WatchSimulator.platform/"); + path::append(sdks_path, "WatchSimulator.platform"); } else if (sdk_type == PlatformDarwin::SDKType::watchOS) { - // For now, we need to be prepared to handle either capitalization of this - // path. - std::string WatchOS_candidate_path = sdks_path + "/WatchOS.platform/"; - if (IsDirectory(FileSpec(WatchOS_candidate_path.c_str()))) { - sdks_path = WatchOS_candidate_path; + // For now, we need to be prepared to handle either capitalization of + // this path. + llvm::SmallString<256> candidate_path = sdks_path; + path::append(candidate_path, "WatchOS.platform"); + if (FileSystem::Instance().Exists(candidate_path)) { + sdks_path = candidate_path; } else { - std::string watchOS_candidate_path = sdks_path + "/watchOS.platform/"; - if (IsDirectory(FileSpec(watchOS_candidate_path.c_str()))) { - sdks_path = watchOS_candidate_path; + // Reset the candidate path. + candidate_path = sdks_path; + path::append(candidate_path, "watchOS.platform"); + if (FileSystem::Instance().Exists(candidate_path)) { + sdks_path = candidate_path; } else { return ConstString(); } } } else { - sdks_path.append("/iPhoneOS.platform/"); + path::append(sdks_path, "iPhoneOS.platform"); } - - sdks_path.append("Developer/SDKs/"); - - FileSpec sdks_spec(sdks_path.c_str()); + path::append(sdks_path, "Developer", "SDKs"); + FileSpec sdks_spec(sdks_path.str()); return EnumerateSDKsForVersion(sdks_spec, sdk_type, least_major, least_major); @@ -3087,45 +3089,50 @@ static ConstString GetSDKDirectory(PlatformDarwin::SDKType sdk_type, ; if (!xcode_contents_path.empty()) { - StreamString sdk_path; - sdk_path.Printf( - "%s/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX%u.%u.sdk", - xcode_contents_path.c_str(), major, minor); - fspec.SetFile(sdk_path.GetString(), FileSpec::Style::native); - if (FileSystem::Instance().Exists(fspec)) { - ConstString path(sdk_path.GetString()); - // Cache results. - g_sdk_cache[major_minor] = path; - return path; - } else if ((least_major != major) || (least_minor != minor)) { - // Try the required SDK. - sdk_path.Clear(); - sdk_path.Printf("%sDeveloper/Platforms/MacOSX.platform/Developer/SDKs/" - "MacOSX%u.%u.sdk", - xcode_contents_path.c_str(), least_major, least_minor); - fspec.SetFile(sdk_path.GetString(), FileSpec::Style::native); + llvm::SmallString<256> sdks_dir( + PlatformDarwin::GetXcodeContentsDirectory().GetPath()); + llvm::sys::path::append(sdks_dir, "Developer", "Platforms", + "MacOSX.platform"); + llvm::sys::path::append(sdks_dir, "Developer", "SDKs"); + + // Try an exact match first. + { + std::string sdk_name = llvm::formatv("MacOSX{0}.{1}.sdk", major, minor); + llvm::SmallString<256> sdk_path = sdks_dir; + llvm::sys::path::append(sdk_path, sdk_name); + fspec.SetFile(sdk_path.str(), FileSpec::Style::native); if (FileSystem::Instance().Exists(fspec)) { - ConstString path(sdk_path.GetString()); + ConstString path(sdk_path.str()); // Cache results. g_sdk_cache[major_minor] = path; return path; - } else { - // Okay, we're going to do an exhaustive search for *any* SDK - // that has an adequate version. - std::string sdks_path = xcode_contents_path; - sdks_path.append("Developer/Platforms/MacOSX.platform/Developer/SDKs"); - - FileSpec sdks_spec(sdks_path.c_str()); - - ConstString sdk_path = EnumerateSDKsForVersion( - sdks_spec, sdk_type, least_major, least_major); + } + } - if (sdk_path) { - g_sdk_cache[major_minor] = sdk_path; - return sdk_path; - } + // Try the minimum required SDK, if it's different from the actual version. + if ((least_major != major) || (least_minor != minor)) { + std::string sdk_name = + llvm::formatv("MacOSX{0}.{1}.sdk", least_major, least_minor); + llvm::SmallString<256> sdk_path = sdks_dir; + llvm::sys::path::append(sdk_path, sdk_name); + fspec.SetFile(sdk_path.str(), FileSpec::Style::native); + if (FileSystem::Instance().Exists(fspec)) { + ConstString path(sdk_path.str()); + // Cache results. + g_sdk_cache[major_minor] = path; + return path; } } + + // Okay, if we haven't found anything yet, we're going to do an exhaustive + // search for *any* SDK that has an adequate version. + ConstString sdk_path = EnumerateSDKsForVersion( + FileSpec(sdks_dir.str()), sdk_type, least_major, least_major); + if (sdk_path) { + // Cache results. + g_sdk_cache[major_minor] = sdk_path; + return sdk_path; + } } // Cache results. From 1e696e381b28c1e1564579e0453bd009557b5db9 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Wed, 18 Mar 2020 10:34:49 -0700 Subject: [PATCH 025/286] rdar://60513353 (lldb-rpc-server crash in SwiftLanguageRuntime::MetadataPromise::FulfillTypePromise) Null-check the GetMetadataPromise result before using it. I checked, all other users of GetMetadataPromise perform the null check already. No test, as I'm not sure how to reproduce the issue. rdar://60513353 --- lldb/source/Plugins/Language/Swift/SwiftMetatype.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lldb/source/Plugins/Language/Swift/SwiftMetatype.cpp b/lldb/source/Plugins/Language/Swift/SwiftMetatype.cpp index 6c8e68c61efcc..f1ade30a41ce3 100644 --- a/lldb/source/Plugins/Language/Swift/SwiftMetatype.cpp +++ b/lldb/source/Plugins/Language/Swift/SwiftMetatype.cpp @@ -43,6 +43,8 @@ bool lldb_private::formatters::swift::SwiftMetatype_SummaryProvider( return false; SwiftLanguageRuntime::MetadataPromiseSP metadata_promise_sp = swift_runtime->GetMetadataPromise(metadata_ptr, valobj); + if (!metadata_promise_sp) + return false; if (CompilerType resolved_type = metadata_promise_sp->FulfillTypePromise()) { stream.Printf("%s", resolved_type.GetDisplayTypeName().AsCString()); From 6cdbe04d7d6849343e682c7bc8612c7a3d8f9699 Mon Sep 17 00:00:00 2001 From: shafik Date: Tue, 17 Mar 2020 10:55:53 -0700 Subject: [PATCH 026/286] [lldb] Remove template parameters from FunctionTemplateDecl names Fix to get the AST we generate for function templates closer to what clang generates and expects. We fix which FuntionDecl we are passing to CreateFunctionTemplateSpecializationInfo and we strip template parameters from the name when creating the FunctionDecl and FunctionTemplateDecl. These two fixes together fix asserts and ambiguous lookup issues for several cases which are added to the already existing small function template test. This fixes issues with overloads, overloads and ADL, variadic function templates and templated operator overloads. Differential Revision: https://reviews.llvm.org/D75761 (cherry picked from commit 9e2715aaacaa3087933b5575d23563751b54843b) --- .../SymbolFile/DWARF/DWARFASTParserClang.cpp | 28 ++++++--- .../TestTemplateFunctions.py | 40 +++++++++--- .../API/lang/cpp/template-function/main.cpp | 62 ++++++++++++++++++- 3 files changed, 114 insertions(+), 16 deletions(-) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index c07ac9bc252ba..e844f331acdc5 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -35,6 +35,8 @@ #include "lldb/Utility/Log.h" #include "lldb/Utility/StreamString.h" +#include "llvm/Demangle/Demangle.h" + #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" @@ -1169,12 +1171,22 @@ TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, } if (!function_decl) { + const char *name = attrs.name.GetCString(); + + // We currently generate function templates with template parameters in + // their name. In order to get closer to the AST that clang generates + // we want to strip these from the name when creating the AST. + if (attrs.mangled_name) { + llvm::ItaniumPartialDemangler D; + if (!D.partialDemangle(attrs.mangled_name)) + name = D.getFunctionBaseName(nullptr, nullptr); + } + // We just have a function that isn't part of a class function_decl = m_ast.CreateFunctionDeclaration( ignore_containing_context ? m_ast.GetTranslationUnitDecl() : containing_decl_ctx, - attrs.name.GetCString(), clang_type, attrs.storage, - attrs.is_inline); + name, clang_type, attrs.storage, attrs.is_inline); if (has_template_params) { TypeSystemClang::TemplateParameterInfos template_param_infos; @@ -1182,14 +1194,14 @@ TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, template_function_decl = m_ast.CreateFunctionDeclaration( ignore_containing_context ? m_ast.GetTranslationUnitDecl() : containing_decl_ctx, - attrs.name.GetCString(), clang_type, attrs.storage, - attrs.is_inline); + name, clang_type, attrs.storage, attrs.is_inline); + clang::FunctionTemplateDecl *func_template_decl = - m_ast.CreateFunctionTemplateDecl( - containing_decl_ctx, template_function_decl, - attrs.name.GetCString(), template_param_infos); + m_ast.CreateFunctionTemplateDecl(containing_decl_ctx, + template_function_decl, name, + template_param_infos); m_ast.CreateFunctionTemplateSpecializationInfo( - function_decl, func_template_decl, template_param_infos); + template_function_decl, func_template_decl, template_param_infos); } lldbassert(function_decl); diff --git a/lldb/test/API/lang/cpp/template-function/TestTemplateFunctions.py b/lldb/test/API/lang/cpp/template-function/TestTemplateFunctions.py index 6c9a0ac35f4fd..0e74185546e84 100644 --- a/lldb/test/API/lang/cpp/template-function/TestTemplateFunctions.py +++ b/lldb/test/API/lang/cpp/template-function/TestTemplateFunctions.py @@ -13,14 +13,40 @@ class TemplateFunctionsTestCase(TestBase): def do_test_template_function(self, add_cast): self.build() - (_, _, thread, _) = lldbutil.run_to_name_breakpoint(self, "main") - frame = thread.GetSelectedFrame() - expr = "foo(42)" + lldbutil.run_to_source_breakpoint(self, '// break here', + lldb.SBFileSpec("main.cpp", False)) + if add_cast: - expr = "(int)" + expr - expr_result = frame.EvaluateExpression(expr) - self.assertTrue(expr_result.IsValid()) - self.assertEqual(expr_result.GetValue(), "42") + self.expect_expr("(int) foo(42)", result_type="int", result_value="42") + else: + self.expect("expr b1 <=> b2", error=True, substrs=["warning: :1:4: '<=>' is a single token in C++20; add a space to avoid a change in behavior"]) + + self.expect_expr("foo(42)", result_type="int", result_value="42") + + # overload with template case + self.expect_expr("h(10)", result_type="int", result_value="10") + + # ADL lookup case + self.expect_expr("f(A::C{})", result_type="int", result_value="4") + + # ADL lookup but no overload + self.expect_expr("g(A::C{})", result_type="int", result_value="4") + + # variadic function cases + self.expect_expr("var(1)", result_type="int", result_value="10") + self.expect_expr("var(1, 2)", result_type="int", result_value="10") + + # Overloaded templated operator case + self.expect_expr("b1 > b2", result_type="bool", result_value="true") + self.expect_expr("b1 >> b2", result_type="bool", result_value="true") + self.expect_expr("b1 << b2", result_type="bool", result_value="true") + self.expect_expr("b1 == b2", result_type="bool", result_value="true") + + # Overloaded operator case + self.expect_expr("d1 > d2", result_type="bool", result_value="true") + self.expect_expr("d1 >> d2", result_type="bool", result_value="true") + self.expect_expr("d1 << d2", result_type="bool", result_value="true") + self.expect_expr("d1 == d2", result_type="bool", result_value="true") @skipIfWindows def test_template_function_with_cast(self): diff --git a/lldb/test/API/lang/cpp/template-function/main.cpp b/lldb/test/API/lang/cpp/template-function/main.cpp index 035e6450cd3e5..47b2c5c1f6e4b 100644 --- a/lldb/test/API/lang/cpp/template-function/main.cpp +++ b/lldb/test/API/lang/cpp/template-function/main.cpp @@ -11,6 +11,66 @@ int foo(T t1) { return int(t1); } +// Some cases to cover ADL, we have two cases: +// +// - f which will have a overload in the global namespace if unqualified lookup +// find f(int) and f(T) is found via ADL. +// +// - g which does not have an overload in the global namespace. +namespace A { +struct C {}; + +template int f(T) { return 4; } + +template int g(T) { return 4; } +} // namespace A + +// Meant to overload A::f(T) which may be found via ADL +int f(int) { return 1; } + +// Regular overloaded functions case h(T) and h(double). +template int h(T x) { return x; } +int h(double d) { return 5; } + +template int var(Us... pargs) { return 10; } + +// Having the templated overloaded operators in a namespace effects the +// mangled name generated in the IR e.g. _ZltRK1BS1_ Vs _ZN1AltERKNS_1BES2_ +// One will be in the symbol table but the other won't. This results in a +// different code path that will result in CPlusPlusNameParser being used. +// This allows us to cover that code as well. +namespace A { +template bool operator<(const T &, const T &) { return true; } + +template bool operator>(const T &, const T &) { return true; } + +template bool operator<<(const T &, const T &) { return true; } + +template bool operator>>(const T &, const T &) { return true; } + +template bool operator==(const T &, const T &) { return true; } + +struct B {}; +} // namespace A + +struct D {}; + +// Make sure we cover more straight forward cases as well. +bool operator<(const D &, const D &) { return true; } +bool operator>(const D &, const D &) { return true; } +bool operator>>(const D &, const D &) { return true; } +bool operator<<(const D &, const D &) { return true; } +bool operator==(const D &, const D &) { return true; } + int main() { - return foo(42); + A::B b1; + A::B b2; + D d1; + D d2; + + bool result_b = b1 < b2 && b1 << b2 && b1 == b2 && b1 > b2 && b1 >> b2; + bool result_c = d1 < d2 && d1 << d2 && d1 == d2 && d1 > d2 && d1 >> d2; + + return foo(42) + result_b + result_c + f(A::C{}) + g(A::C{}) + h(10) + h(1.) + + var(1) + var(1, 2); // break here } From 1e43d4314991859556566643ab29d5e5c8fc64be Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Tue, 17 Mar 2020 15:31:47 -0700 Subject: [PATCH 027/286] [lldb/PlatformDarwin] Return POSIX path from FindXcodeContentsDirectoryInPath Always return a POSIX-style path from FindXcodeContentsDirectoryInPath so that the output is identical on all host platforms. (cherry picked from commit 3829d85cc615ec9a855ce96e4555820e5dd4ae51) --- lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp index de7733112fee5..b3eb933834c74 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp @@ -1842,7 +1842,8 @@ PlatformDarwin::FindXcodeContentsDirectoryInPath(llvm::StringRef path) { auto next = it; if (++next != end && *next == "Contents") { llvm::SmallString<128> buffer; - llvm::sys::path::append(buffer, begin, ++next); + llvm::sys::path::append(buffer, begin, ++next, + llvm::sys::path::Style::posix); return buffer.str().str(); } } From 1283acc8ba90177d4e1c3c588d12b7c15a0c0076 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Wed, 18 Mar 2020 15:07:42 -0700 Subject: [PATCH 028/286] [lldb/PlatformDarwin] Expose current toolchain and CL tools directory Expose two methods to find the current toolchain and the current command line tools directory. These are used by Swift to find the resource directory. (cherry picked from commit 5ffb30fd6c7faff314b01ef0dc75f2683ca85cdf) --- .../Platform/MacOSX/PlatformDarwin.cpp | 27 +++++++++++++++++++ .../Plugins/Platform/MacOSX/PlatformDarwin.h | 9 +++++++ .../unittests/Platform/PlatformDarwinTest.cpp | 18 +++++++++++++ 3 files changed, 54 insertions(+) diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp index b3eb933834c74..906b2bdf4b1d0 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp @@ -1829,6 +1829,21 @@ lldb_private::Status PlatformDarwin::FindBundleBinaryInExecSearchPaths( return Status(); } +std::string PlatformDarwin::FindComponentInPath(llvm::StringRef path, + llvm::StringRef component) { + auto begin = llvm::sys::path::begin(path); + auto end = llvm::sys::path::end(path); + for (auto it = begin; it != end; ++it) { + if (it->contains(component)) { + llvm::SmallString<128> buffer; + llvm::sys::path::append(buffer, begin, ++it, + llvm::sys::path::Style::posix); + return buffer.str().str(); + } + } + return {}; +} + std::string PlatformDarwin::FindXcodeContentsDirectoryInPath(llvm::StringRef path) { auto begin = llvm::sys::path::begin(path); @@ -1959,3 +1974,15 @@ FileSpec PlatformDarwin::GetXcodeContentsDirectory() { }); return g_xcode_contents_path; } + +FileSpec PlatformDarwin::GetCurrentToolchainDirectory() { + if (FileSpec fspec = HostInfo::GetShlibDir()) + return FileSpec(FindComponentInPath(fspec.GetPath(), ".xctoolchain")); + return {}; +} + +FileSpec PlatformDarwin::GetCurrentCommandLineToolsDirectory() { + if (FileSpec fspec = HostInfo::GetShlibDir()) + return FileSpec(FindComponentInPath(fspec.GetPath(), "CommandLineTools")); + return {}; +} diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h index 56a67e5c6a9ef..b90a32c201587 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h @@ -101,6 +101,13 @@ class PlatformDarwin : public PlatformPOSIX { static lldb_private::FileSpec GetXcodeSDK(SDKType type); static lldb_private::FileSpec GetXcodeContentsDirectory(); + /// Return the toolchain directroy the current LLDB instance is located in. + static lldb_private::FileSpec GetCurrentToolchainDirectory(); + + /// Return the command line tools directory the current LLDB instance is + /// located in. + static lldb_private::FileSpec GetCurrentCommandLineToolsDirectory(); + protected: struct CrashInfoAnnotations { uint64_t version; // unsigned long @@ -173,6 +180,8 @@ class PlatformDarwin : public PlatformPOSIX { const lldb_private::FileSpecList *module_search_paths_ptr, lldb::ModuleSP *old_module_sp_ptr, bool *did_create_ptr); + static std::string FindComponentInPath(llvm::StringRef path, + llvm::StringRef component); static std::string FindXcodeContentsDirectoryInPath(llvm::StringRef path); std::string m_developer_directory; diff --git a/lldb/unittests/Platform/PlatformDarwinTest.cpp b/lldb/unittests/Platform/PlatformDarwinTest.cpp index d0c87eb5d30d1..0aea200fe967e 100644 --- a/lldb/unittests/Platform/PlatformDarwinTest.cpp +++ b/lldb/unittests/Platform/PlatformDarwinTest.cpp @@ -19,6 +19,7 @@ using namespace lldb_private; struct PlatformDarwinTester : public PlatformDarwin { public: + using PlatformDarwin::FindComponentInPath; using PlatformDarwin::FindXcodeContentsDirectoryInPath; static bool SDKSupportsModules(SDKType desired_type, const lldb_private::FileSpec &sdk_path) { @@ -132,3 +133,20 @@ TEST(PlatformDarwinTest, GetSDKNameForType) { EXPECT_EQ( "", PlatformDarwin::GetSDKNameForType(PlatformDarwin::SDKType::unknown)); } + +TEST(PlatformDarwinTest, FindComponentInPath) { + EXPECT_EQ("/path/to/foo", + PlatformDarwinTester::FindComponentInPath("/path/to/foo/", "foo")); + + EXPECT_EQ("/path/to/foo", + PlatformDarwinTester::FindComponentInPath("/path/to/foo", "foo")); + + EXPECT_EQ("/path/to/foobar", PlatformDarwinTester::FindComponentInPath( + "/path/to/foobar", "foo")); + + EXPECT_EQ("/path/to/foobar", PlatformDarwinTester::FindComponentInPath( + "/path/to/foobar", "bar")); + + EXPECT_EQ("", + PlatformDarwinTester::FindComponentInPath("/path/to/foo", "bar")); +} From c5f40613f5b24aef1961ab79c065ff2657124a4f Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 19 Mar 2020 10:40:58 -0700 Subject: [PATCH 029/286] Update for the removal of the Legacy Semantic Queries bit --- lldb/source/Symbol/SwiftASTContext.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/lldb/source/Symbol/SwiftASTContext.cpp b/lldb/source/Symbol/SwiftASTContext.cpp index bbc975379c4fd..2e0fff344a617 100644 --- a/lldb/source/Symbol/SwiftASTContext.cpp +++ b/lldb/source/Symbol/SwiftASTContext.cpp @@ -4120,7 +4120,6 @@ swift::ASTContext *SwiftASTContext::GetASTContext() { } // Set up the required state for the evaluator in the TypeChecker. - m_ast_context_ap->setLegacySemanticQueriesEnabled(); registerIDERequestFunctions(m_ast_context_ap->evaluator); registerParseRequestFunctions(m_ast_context_ap->evaluator); registerTypeCheckerRequestFunctions(m_ast_context_ap->evaluator); From 57321fbb220745d5e7343fec6c85f51dce7098a2 Mon Sep 17 00:00:00 2001 From: Fred Riss Date: Fri, 17 Jan 2020 20:49:08 -0800 Subject: [PATCH 030/286] [lldb/testsuite] Modernize 2 test Makefiles Those old Makefiles used completely ad-hoc rules for building files, which means they didn't obey the test harness' variants. They were somewhat tricky to update as they use very peculiar build flags for some files. For this reason I was careful to compare the build commands before and after the change, which is how I found the discrepancy fixed by the previous commit. While some of the make syntax used here might not be easy to grasp for newcomers (per-target variable overrides), it seems better than to have to repliacte the Makefile.rules logic for the test variants and platform support. (cherry picked from commit 546f8f426463c7c22a3a8731803a501ff044ba20) --- .../API/lang/cpp/incomplete-types/Makefile | 41 +++++++------------ lldb/test/API/lang/objc/ivar-IMP/Makefile | 15 +++---- 2 files changed, 20 insertions(+), 36 deletions(-) diff --git a/lldb/test/API/lang/cpp/incomplete-types/Makefile b/lldb/test/API/lang/cpp/incomplete-types/Makefile index 769920c28336c..c39743d999da3 100644 --- a/lldb/test/API/lang/cpp/incomplete-types/Makefile +++ b/lldb/test/API/lang/cpp/incomplete-types/Makefile @@ -1,33 +1,22 @@ -CXX_SOURCES = main.cpp length.cpp a.cpp - -CFLAGS_LIMIT = -c $(CXXFLAGS) -CFLAGS_NO_LIMIT = -c $(CXXFLAGS) - -ifneq (,$(findstring clang,$(CC))) - CFLAGS_LIMIT += -flimit-debug-info - CFLAGS_NO_LIMIT += -fno-limit-debug-info -endif +CXX_SOURCES := length.cpp a.o main.o +EXE := nolimit all: limit nolimit -limit: main.o length_limit.o a.o - $(CXX) main.o length_limit.o a.o -o limit $(LDFLAGS) - -nolimit: main.o length_nolimit.o a.o - $(CXX) main.o length_nolimit.o a.o -o nolimit $(LDFLAGS) - -main.o: main.cpp - $(CXX) $(CFLAGS_LIMIT) $(SRCDIR)/main.cpp -o main.o - -length_limit.o: length.cpp - $(CXX) $(CFLAGS_LIMIT) $(SRCDIR)/length.cpp -o length_limit.o +include Makefile.rules -length_nolimit.o: length.cpp - $(CXX) $(CFLAGS_NO_LIMIT) $(SRCDIR)/length.cpp -o length_nolimit.o +# Force a.cpp to be built with no debug inforamtion +a.o: CFLAGS = $(CFLAGS_NO_DEBUG) -a.o: a.cpp - $(CXX) $(CFLAGS_NO_DEBUG) -c $(SRCDIR)/a.cpp -o a.o +# The default testsuite setup forces -fno-limit-debug-info. Let's not rely on +# CFLAGS_EXTRAS being passed after the default arguments. This rule makes +# sure the variable used by Makefile.rules for this argument is cleared. +main.o: NO_LIMIT_DEBUG_INFO_FLAGS = "" +main.o: CFLAGS_EXTRAS = -flimit-debug-info -clean: OBJECTS += limit nolimit length_limit.o length_nolimit.o length_limit.dwo length_nolimit.dwo +limit: a.o main.o + mkdir -p build_limit + $(MAKE) -C $(BUILDDIR)/build_limit -f $(MAKEFILE_RULES) \ + EXE=../limit CXX_SOURCES="length.cpp ../a.o ../main.o" \ + CFLAGS_EXTRAS=-flimit-debug-info NO_LIMIT_DEBUG_INFO_FLAGS="" -include Makefile.rules diff --git a/lldb/test/API/lang/objc/ivar-IMP/Makefile b/lldb/test/API/lang/objc/ivar-IMP/Makefile index ba7e23acabab1..5d920f4421368 100644 --- a/lldb/test/API/lang/objc/ivar-IMP/Makefile +++ b/lldb/test/API/lang/objc/ivar-IMP/Makefile @@ -1,13 +1,8 @@ -CFLAGS := -g -O0 -CFLAGS_NO_DEBUG = +OBJC_SOURCES := myclass.m repro.m +LD_EXTRAS := -framework Foundation -all: aout - -aout: - $(CC) $(CFLAGS_NO_DEBUG) $(SRCDIR)/myclass.m -c -o myclass.o - $(CC) $(CFLAGS) myclass.o $(SRCDIR)/repro.m -framework Foundation +include Makefile.rules -clean:: - rm -f myclass.o +# Force myclass.m to be compiled without debug info +myclass.o: CFLAGS = $(CFLAGS_NO_DEBUG) -include Makefile.rules From 0317eb998b53fb188fda8bea7e8a4a99e301feb2 Mon Sep 17 00:00:00 2001 From: Fred Riss Date: Tue, 17 Mar 2020 19:50:32 -0700 Subject: [PATCH 031/286] [lldb/MemoryHistoryAsan] Fix address resolution for recorded backtraces Summary: The memory history plugin for Asan creates a HistoryThread with the recorded PC values provided by the Asan runtime. In other cases, thoses PCs are gathered by LLDB directly. The PCs returned by the Asan runtime are the PCs of the calls in the backtrace, not the return addresses you would normally get when unwinding the stack (look for a call to GetPreviousIntructionPc in AsanGetStack). When the above addresses are passed to the unwinder, it will subtract 1 from each address of the non zero frames because it treats them as return addresses. This can lead to the final report referencing the wrong line. This patch fixes this issue by threading a flag through HistoryThread and HistoryUnwinder that tells them to treat every frame like the first one. The Asan MemoryHistory plugin can then use this flag. This fixes running TestMemoryHistory on arm64 devices, although it's hard to guarantee that the test will continue to exhibit the boundary condition that triggers this bug. Reviewers: jasonmolenda, kubamracek Subscribers: kristof.beyls, danielkiss, lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D76341 (cherry picked from commit b40ee7ff1b16982b39582eee04ca82cac5f3d154) --- .../Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp | 7 ++++++- lldb/source/Plugins/Process/Utility/HistoryThread.cpp | 5 +++-- lldb/source/Plugins/Process/Utility/HistoryThread.h | 3 ++- lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp | 11 ++++++++--- lldb/source/Plugins/Process/Utility/HistoryUnwind.h | 6 +++++- 5 files changed, 24 insertions(+), 8 deletions(-) diff --git a/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp b/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp index e0d2c5d0eef8c..87431dd886bd7 100644 --- a/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp +++ b/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp @@ -136,7 +136,12 @@ static void CreateHistoryThreadFromValueObject(ProcessSP process_sp, pcs.push_back(pc); } - HistoryThread *history_thread = new HistoryThread(*process_sp, tid, pcs); + // The ASAN runtime already massages the return addresses into call + // addresses, we don't want LLDB's unwinder to try to locate the previous + // instruction again as this might lead to us reporting a different line. + bool pcs_are_call_addresses = true; + HistoryThread *history_thread = + new HistoryThread(*process_sp, tid, pcs, pcs_are_call_addresses); ThreadSP new_thread_sp(history_thread); std::ostringstream thread_name_with_number; thread_name_with_number << thread_name << " Thread " << tid; diff --git a/lldb/source/Plugins/Process/Utility/HistoryThread.cpp b/lldb/source/Plugins/Process/Utility/HistoryThread.cpp index 295c17e474fba..86d807305e4c3 100644 --- a/lldb/source/Plugins/Process/Utility/HistoryThread.cpp +++ b/lldb/source/Plugins/Process/Utility/HistoryThread.cpp @@ -25,12 +25,13 @@ using namespace lldb_private; // Constructor HistoryThread::HistoryThread(lldb_private::Process &process, lldb::tid_t tid, - std::vector pcs) + std::vector pcs, + bool pcs_are_call_addresses) : Thread(process, tid, true), m_framelist_mutex(), m_framelist(), m_pcs(pcs), m_extended_unwind_token(LLDB_INVALID_ADDRESS), m_queue_name(), m_thread_name(), m_originating_unique_thread_id(tid), m_queue_id(LLDB_INVALID_QUEUE_ID) { - m_unwinder_up.reset(new HistoryUnwind(*this, pcs)); + m_unwinder_up.reset(new HistoryUnwind(*this, pcs, pcs_are_call_addresses)); Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); LLDB_LOGF(log, "%p HistoryThread::HistoryThread", static_cast(this)); } diff --git a/lldb/source/Plugins/Process/Utility/HistoryThread.h b/lldb/source/Plugins/Process/Utility/HistoryThread.h index 1e26586401724..2428e1209d0dc 100644 --- a/lldb/source/Plugins/Process/Utility/HistoryThread.h +++ b/lldb/source/Plugins/Process/Utility/HistoryThread.h @@ -33,7 +33,8 @@ namespace lldb_private { class HistoryThread : public lldb_private::Thread { public: HistoryThread(lldb_private::Process &process, lldb::tid_t tid, - std::vector pcs); + std::vector pcs, + bool pcs_are_call_addresses = false); ~HistoryThread() override; diff --git a/lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp b/lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp index 83fdb011f5a1a..5e07b7593d492 100644 --- a/lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp +++ b/lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp @@ -23,8 +23,10 @@ using namespace lldb_private; // Constructor -HistoryUnwind::HistoryUnwind(Thread &thread, std::vector pcs) - : Unwind(thread), m_pcs(pcs) {} +HistoryUnwind::HistoryUnwind(Thread &thread, std::vector pcs, + bool pcs_are_call_addresses) + : Unwind(thread), m_pcs(pcs), + m_pcs_are_call_addresses(pcs_are_call_addresses) {} // Destructor @@ -59,7 +61,10 @@ bool HistoryUnwind::DoGetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa, if (frame_idx < m_pcs.size()) { cfa = frame_idx; pc = m_pcs[frame_idx]; - behaves_like_zeroth_frame = (frame_idx == 0); + if (m_pcs_are_call_addresses) + behaves_like_zeroth_frame = true; + else + behaves_like_zeroth_frame = (frame_idx == 0); return true; } return false; diff --git a/lldb/source/Plugins/Process/Utility/HistoryUnwind.h b/lldb/source/Plugins/Process/Utility/HistoryUnwind.h index 4d16608bd8c27..ddbee00fc7aa1 100644 --- a/lldb/source/Plugins/Process/Utility/HistoryUnwind.h +++ b/lldb/source/Plugins/Process/Utility/HistoryUnwind.h @@ -18,7 +18,8 @@ namespace lldb_private { class HistoryUnwind : public lldb_private::Unwind { public: - HistoryUnwind(Thread &thread, std::vector pcs); + HistoryUnwind(Thread &thread, std::vector pcs, + bool pcs_are_call_addresses = false); ~HistoryUnwind() override; @@ -35,6 +36,9 @@ class HistoryUnwind : public lldb_private::Unwind { private: std::vector m_pcs; + /// This boolean indicates that the PCs in the non-0 frames are call + /// addresses and not return addresses. + bool m_pcs_are_call_addresses; }; } // namespace lldb_private From e8d7643689ee332e01cac2a586835bd7d4195826 Mon Sep 17 00:00:00 2001 From: Fred Riss Date: Wed, 18 Mar 2020 19:45:34 -0700 Subject: [PATCH 032/286] [lldb/testsuite] Skip TestEmptyStdModule.py if using a remote platform The test runs `platform select host`, so it make no sense to run it when remote debugging. (cherry picked from commit 52b2bae777f2a30d1ed6e87c8812bbffc4f4feeb) --- .../import-std-module/empty-module/TestEmptyStdModule.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/test/API/commands/expression/import-std-module/empty-module/TestEmptyStdModule.py b/lldb/test/API/commands/expression/import-std-module/empty-module/TestEmptyStdModule.py index 76e79df5cd1c8..2b1cb100a3251 100644 --- a/lldb/test/API/commands/expression/import-std-module/empty-module/TestEmptyStdModule.py +++ b/lldb/test/API/commands/expression/import-std-module/empty-module/TestEmptyStdModule.py @@ -15,6 +15,7 @@ class ImportStdModule(TestBase): # but we still add the libc++ category so that this test is only run in # test configurations where libc++ is actually supposed to be tested. @add_test_categories(["libc++"]) + @skipIfRemote @skipIf(compiler=no_match("clang")) def test(self): self.build() From ebcc296d719c29d4d8412b2336a584376e2c0ccb Mon Sep 17 00:00:00 2001 From: Fred Riss Date: Wed, 18 Mar 2020 19:50:18 -0700 Subject: [PATCH 033/286] [lldb/testsuite] Tweak TestBreakpointLocations.py to pass for arm64 The test checks that we correctly set the right number of breakpoints when breaking into an `always_inline` function. The line of this funstion selected for this test was the return statement, but with recent compiler, this return statement doesn't necessarily exist after inlining, even at O0. Switch the breakpoint to a different line of the inline function. (cherry picked from commit c182be211a4d1a79390703ede8f041dcbaaf7947) --- .../functionalities/breakpoint/breakpoint_locations/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lldb/test/API/functionalities/breakpoint/breakpoint_locations/main.c b/lldb/test/API/functionalities/breakpoint/breakpoint_locations/main.c index 7ec3ded67b74f..f6ccb031c7445 100644 --- a/lldb/test/API/functionalities/breakpoint/breakpoint_locations/main.c +++ b/lldb/test/API/functionalities/breakpoint/breakpoint_locations/main.c @@ -14,9 +14,9 @@ func_inlined (void) { static int func_inline_call_count = 0; printf ("Called func_inlined.\n"); - ++func_inline_call_count; + ++func_inline_call_count; // Set break point at this line. printf ("Returning func_inlined call count: %d.\n", func_inline_call_count); - return func_inline_call_count; // Set break point at this line. + return func_inline_call_count; } extern int func_inlined (void); From 19c748a6091921f474789426ee645410f285683a Mon Sep 17 00:00:00 2001 From: Fred Riss Date: Wed, 18 Mar 2020 19:53:28 -0700 Subject: [PATCH 034/286] [lldb/testsuite] Apply @skipIfDarwinEmbedded to part of TestHWBreakMultiThread The comment in the test wrongfully claimed that we support hardware breakpoints on darwin for arm64, but we never did. (cherry picked from commit 127b9d9d774dcc593cfd50eccde307dbe96097a2) --- .../TestHWBreakMultiThread.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lldb/test/API/functionalities/breakpoint/hardware_breakpoints/hardware_breakpoint_on_multiple_threads/TestHWBreakMultiThread.py b/lldb/test/API/functionalities/breakpoint/hardware_breakpoints/hardware_breakpoint_on_multiple_threads/TestHWBreakMultiThread.py index 90d182bfcc89f..5f3ecf564bc8b 100644 --- a/lldb/test/API/functionalities/breakpoint/hardware_breakpoints/hardware_breakpoint_on_multiple_threads/TestHWBreakMultiThread.py +++ b/lldb/test/API/functionalities/breakpoint/hardware_breakpoints/hardware_breakpoint_on_multiple_threads/TestHWBreakMultiThread.py @@ -32,19 +32,21 @@ def test_hw_break_set_disable_multi_thread_linux(self): self.setTearDownCleanup() self.break_multi_thread('disable', False) # llvm.org/PR44659 - # LLDB on darwin supports hardware breakpoints for arm, aarch64, x86_64 and - # i386 architectures. + # LLDB on darwin supports hardware breakpoints for x86_64 and i386 + # architectures. @skipUnlessDarwin @skipIfOutOfTreeDebugserver + @skipIfDarwinEmbedded def test_hw_break_set_delete_multi_thread_macos(self): self.build() self.setTearDownCleanup() self.break_multi_thread('delete') - # LLDB on darwin supports hardware breakpoints for arm, aarch64, x86_64 and - # i386 architectures. + # LLDB on darwin supports hardware breakpoints for x86_64 and i386 + # architectures. @skipUnlessDarwin @skipIfOutOfTreeDebugserver + @skipIfDarwinEmbedded def test_hw_break_set_disable_multi_thread_macos(self): self.build() self.setTearDownCleanup() From ccecfb19afa82218e3cd828a559a00243b318ce4 Mon Sep 17 00:00:00 2001 From: Fred Riss Date: Wed, 18 Mar 2020 20:07:45 -0700 Subject: [PATCH 035/286] [lldb/testsuite] Rewrite TestThreadLocal.py It was an inline test before. Clang stopped emitting line information for the TLS initialization and the inline test didn't have a way to break before it anymore. This rewrites the test as a full-fldeged python test and improves the checking of the error case to verify that the failure we are looking for is related to the TLS setup not being complete. (cherry picked from commit 71db787c4583b5b05b9066509c36eb996924aeda) --- .../lang/cpp/thread_local/TestThreadLocal.py | 51 +++++++++++++++++-- lldb/test/API/lang/cpp/thread_local/main.cpp | 8 +-- 2 files changed, 48 insertions(+), 11 deletions(-) diff --git a/lldb/test/API/lang/cpp/thread_local/TestThreadLocal.py b/lldb/test/API/lang/cpp/thread_local/TestThreadLocal.py index 5152c0010d102..e7cfa1ca14f27 100644 --- a/lldb/test/API/lang/cpp/thread_local/TestThreadLocal.py +++ b/lldb/test/API/lang/cpp/thread_local/TestThreadLocal.py @@ -1,6 +1,49 @@ -from lldbsuite.test import lldbinline from lldbsuite.test import decorators -lldbinline.MakeInlineTest(__file__, globals(), - lldbinline.expectedFailureAll(oslist=[ - "windows", "linux", "netbsd"])) +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil +from lldbsuite.test import lldbtest + + +class PlatformProcessCrashInfoTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @expectedFailureAll(oslist=["windows", "linux", "netbsd"]) + def test_thread_local(self): + # Set a breakpoint on the first instruction of the main function, + # before the TLS initialization has run. + self.build() + exe = self.getBuildArtifact("a.out") + + (target, process, _, _) = \ + lldbutil.run_to_source_breakpoint(self, "Set breakpoint here", + lldb.SBFileSpec("main.cpp")) + self.expect_expr("tl_local_int + 1", + result_type="int", result_value="323") + self.expect_expr("*tl_local_ptr + 2", + result_type="int", result_value="324") + self.expect_expr("tl_global_int", + result_type="int", result_value="123") + self.expect_expr("*tl_global_ptr", + result_type="int", result_value="45") + + # Now see if we emit the correct error when the TLS is not yet + # initialized. Let's set a breakpoint on the first instruction + # of main. + main_module = target.FindModule(lldb.SBFileSpec(exe)) + main_address = main_module.FindSymbol("main").GetStartAddress() + main_bkpt = target.BreakpointCreateBySBAddress(main_address) + + process.Kill() + lldbutil.run_to_breakpoint_do_run(self, target, main_bkpt) + + self.expect("expr tl_local_int", error=True, + substrs=["couldn't get the value of variable tl_local_int", + "No TLS data currently exists for this thread"]) + self.expect("expr *tl_local_ptr", error=True, + substrs=["couldn't get the value of variable tl_local_ptr", + "No TLS data currently exists for this thread"]) + diff --git a/lldb/test/API/lang/cpp/thread_local/main.cpp b/lldb/test/API/lang/cpp/thread_local/main.cpp index 1855b7c5f3441..04c7fc0ed74de 100644 --- a/lldb/test/API/lang/cpp/thread_local/main.cpp +++ b/lldb/test/API/lang/cpp/thread_local/main.cpp @@ -3,15 +3,9 @@ thread_local int tl_global_int = 123; thread_local int *tl_global_ptr = &storage; int main(int argc, char **argv) { - //% self.expect("expr tl_local_int", error=True, substrs=["couldn't get the value of variable tl_local_int"]) - //% self.expect("expr *tl_local_ptr", error=True, substrs=["couldn't get the value of variable tl_local_ptr"]) thread_local int tl_local_int = 321; thread_local int *tl_local_ptr = nullptr; tl_local_ptr = &tl_local_int; tl_local_int++; - //% self.expect("expr tl_local_int + 1", substrs=["int", "= 323"]) - //% self.expect("expr *tl_local_ptr + 2", substrs=["int", "= 324"]) - //% self.expect("expr tl_global_int", substrs=["int", "= 123"]) - //% self.expect("expr *tl_global_ptr", substrs=["int", "= 45"]) - return 0; + return 0; // Set breakpoint here } From c27f2ce14b5b48d422270116d5dccc910040ddd7 Mon Sep 17 00:00:00 2001 From: Fred Riss Date: Wed, 18 Mar 2020 20:12:21 -0700 Subject: [PATCH 036/286] [lldb/testsuite] Slightly rework TestHiddenIvars.py The test was stripping the binaries from the Python code. Unfortunately, if running on darwin embedded in a context that requires code signing, the stripping was invalidating the signature, thus breaking the test. This patch moves the stripping to the Makefile and resigns the stripped binaries if required. (cherry picked from commit acd641c19d687c7117b08cdd568a91a381043ebb) --- lldb/test/API/lang/objc/hidden-ivars/Makefile | 20 +++++++++++++++++++ .../lang/objc/hidden-ivars/TestHiddenIvars.py | 18 ++++------------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/lldb/test/API/lang/objc/hidden-ivars/Makefile b/lldb/test/API/lang/objc/hidden-ivars/Makefile index 0664769456eff..283e8a118fb16 100644 --- a/lldb/test/API/lang/objc/hidden-ivars/Makefile +++ b/lldb/test/API/lang/objc/hidden-ivars/Makefile @@ -4,4 +4,24 @@ OBJC_SOURCES := main.m LD_EXTRAS = -framework Foundation +all: a.out libInternalDefiner.dylib stripped + include Makefile.rules + +ifeq "$(MAKE_DSYM)" "YES" +stripped: a.out.dSYM +endif + +stripped: a.out libInternalDefiner.dylib + mkdir stripped + strip -Sx a.out -o stripped/a.out + strip -Sx libInternalDefiner.dylib -o stripped/libInternalDefiner.dylib +ifneq "$(CODESIGN)" "" + $(CODESIGN) -fs - stripped/a.out +endif +ifneq "$(CODESIGN)" "" + $(CODESIGN) -fs - stripped/libInternalDefiner.dylib +endif +ifeq "$(MAKE_DSYM)" "YES" + cp -r a.out.dSYM stripped/a.out.dSYM +endif diff --git a/lldb/test/API/lang/objc/hidden-ivars/TestHiddenIvars.py b/lldb/test/API/lang/objc/hidden-ivars/TestHiddenIvars.py index 03a325ac49c62..5930ffdc958aa 100644 --- a/lldb/test/API/lang/objc/hidden-ivars/TestHiddenIvars.py +++ b/lldb/test/API/lang/objc/hidden-ivars/TestHiddenIvars.py @@ -80,20 +80,11 @@ def test_frame_variable_across_modules(self): def common_setup(self, strip): if strip: - self.assertTrue(subprocess.call( - ['/usr/bin/strip', '-Sx', - self.getBuildArtifact('libInternalDefiner.dylib')]) == 0, - 'stripping dylib succeeded') - self.assertTrue(subprocess.call( - ['/bin/rm', '-rf', - self.getBuildArtifact('libInternalDefiner.dylib.dSYM')]) == 0, - 'remove dylib dSYM file succeeded') - self.assertTrue(subprocess.call(['/usr/bin/strip', '-Sx', - self.getBuildArtifact("a.out") - ]) == 0, - 'stripping a.out succeeded') + exe = self.getBuildArtifact("stripped/a.out") + else: + exe = self.getBuildArtifact("a.out") # Create a target by the debugger. - target = self.dbg.CreateTarget(self.getBuildArtifact("a.out")) + target = self.dbg.CreateTarget(exe) self.assertTrue(target, VALID_TARGET) # Create the breakpoint inside function 'main'. @@ -110,7 +101,6 @@ def common_setup(self, strip): None, environment, self.get_process_working_directory()) self.assertTrue(process, PROCESS_IS_VALID) - exe = self.getBuildArtifact("a.out") self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) # Break inside the foo function which takes a bar_ptr argument. From 61c326901941671192b7d33bb30397a13edccdde Mon Sep 17 00:00:00 2001 From: Fred Riss Date: Wed, 18 Mar 2020 20:20:42 -0700 Subject: [PATCH 037/286] [lldb/testsuite] Make TestObjCIvarStripped.py working with codesigning This test was stripping a binary generated by Makefile.rules which is potentially codesigned. Stripping invalidates the code signature, so we might need to re-sign after stripping. (cherry picked from commit 59918d3793a1136e7041b1a76f38a42cf8644474) --- lldb/test/API/lang/objc/objc-ivar-stripped/Makefile | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lldb/test/API/lang/objc/objc-ivar-stripped/Makefile b/lldb/test/API/lang/objc/objc-ivar-stripped/Makefile index a218ce37e61df..8b63215d6d9da 100644 --- a/lldb/test/API/lang/objc/objc-ivar-stripped/Makefile +++ b/lldb/test/API/lang/objc/objc-ivar-stripped/Makefile @@ -3,11 +3,10 @@ LD_EXTRAS := -lobjc -framework Foundation all: a.out.stripped +include Makefile.rules + a.out.stripped: a.out.dSYM strip -o a.out.stripped a.out - -clean:: - rm -f a.out.stripped - rm -rf a.out.stripped.dSYM - -include Makefile.rules +ifneq "$(CODESIGN)" "" + $(CODESIGN) -fs - a.out.stripped +endif From bf8cfc6924a802e37f1a17b31eeddcda113a38f4 Mon Sep 17 00:00:00 2001 From: Fred Riss Date: Wed, 18 Mar 2020 21:20:57 -0700 Subject: [PATCH 038/286] [lldb/testsuite] XFail TestBuiltinTrap.py not only on linux Summary: TestBuiltinTrap fail on darwin embedded because the `__builin_trap` builtin doesn't get any line info attached to it by clang when building for arm64. The test was already XFailed for linux arm(64), I presume for the same reasons. This patch just XFails it independently of the platform. Reviewers: labath Subscribers: kristof.beyls, danielkiss, lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D76408 (cherry picked from commit e154cbb124a63057356dede8bca5bdbd2f60d44c) --- lldb/test/API/linux/builtin_trap/TestBuiltinTrap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/test/API/linux/builtin_trap/TestBuiltinTrap.py b/lldb/test/API/linux/builtin_trap/TestBuiltinTrap.py index 22de873e29fad..added4ef508a7 100644 --- a/lldb/test/API/linux/builtin_trap/TestBuiltinTrap.py +++ b/lldb/test/API/linux/builtin_trap/TestBuiltinTrap.py @@ -23,7 +23,7 @@ def setUp(self): # gcc generates incorrect linetable @expectedFailureAll(archs="arm", compiler="gcc", triple=".*-android") - @expectedFailureAll(oslist=['linux'], archs=['arm', 'aarch64']) + @expectedFailureAll(archs=['arm', 'aarch64']) @skipIfWindows def test_with_run_command(self): """Test that LLDB handles a function with __builtin_trap correctly.""" From 4e82212c29b825c05fc075b1a7fb9df635537738 Mon Sep 17 00:00:00 2001 From: Fred Riss Date: Wed, 18 Mar 2020 20:56:42 -0700 Subject: [PATCH 039/286] [lldb/testsuite] Fix TestInlineStepping on arm64 with newer compilers Summary: TestInlineStepping tests LLDB's ability to step in the presence of inline frames. The testcase source has a number of functions and some of them are marked `always_inline`. The test is built around the assumption that the inline function will be fully represented once inlined, but this is not true with the current arm64 code generation. For example: void caller() { always_inline_function(); // Step here } When stppeing into `caller()` above, you might immediatly end up in the inlines frame for `always_inline_function()`, because there might literally be no code associated with `caller()` itself. This patch hacks around the issue by adding an `asm volatile("nop")` on some lines with inlined calls where we expect to be able to step. Like so: void caller() { asm volatile("nop"); always_inline_function(); // Step here } This guarantees there is always going to be one instruction for this line in the caller. Reviewers: labath, jingham Subscribers: kristof.beyls, danielkiss, lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D76406 (cherry picked from commit ecc6c426977f59f69b683d67ceb3157fb694ce09) --- lldb/test/API/functionalities/inline-stepping/calling.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lldb/test/API/functionalities/inline-stepping/calling.cpp b/lldb/test/API/functionalities/inline-stepping/calling.cpp index 9982fbf42734f..49179ce7c9788 100644 --- a/lldb/test/API/functionalities/inline-stepping/calling.cpp +++ b/lldb/test/API/functionalities/inline-stepping/calling.cpp @@ -75,7 +75,7 @@ caller_trivial_1 () void caller_trivial_2 () { - inline_trivial_1 (); // In caller_trivial_2. + asm volatile ("nop"); inline_trivial_1 (); // In caller_trivial_2. inline_value += 1; // At increment in caller_trivial_2. } @@ -88,7 +88,7 @@ called_by_inline_trivial () void inline_trivial_1 () { - inline_trivial_2(); // In inline_trivial_1. + asm volatile ("nop"); inline_trivial_2(); // In inline_trivial_1. inline_value += 1; // At increment in inline_trivial_1. } From 33a8fe74ada202259a627b70c4156d731df5b8e9 Mon Sep 17 00:00:00 2001 From: Fred Riss Date: Thu, 19 Mar 2020 08:17:43 -0700 Subject: [PATCH 040/286] [lldb/testsuite] Skip part of TestProcessCrashInfo.py on Darwin embedded See https://reviews.llvm.org/D76407 for discussion. (cherry picked from commit 8758d02074be7b80b804fad19e8b7de6ebd43c31) --- .../functionalities/process_crash_info/TestProcessCrashInfo.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lldb/test/API/functionalities/process_crash_info/TestProcessCrashInfo.py b/lldb/test/API/functionalities/process_crash_info/TestProcessCrashInfo.py index d0f47de83eea4..6ef5018204fd8 100644 --- a/lldb/test/API/functionalities/process_crash_info/TestProcessCrashInfo.py +++ b/lldb/test/API/functionalities/process_crash_info/TestProcessCrashInfo.py @@ -69,6 +69,8 @@ def test_api(self): self.assertIn("pointer being freed was not allocated", stream.GetData()) + # dyld leaves permanent crash_info records when testing on device. + @skipIfDarwinEmbedded def test_on_sane_process(self): """Test that lldb doesn't fetch the extended crash information dictionnary from a 'sane' stopped process.""" From 7e462eee4d94c25c186bcacc135347bf284d17b0 Mon Sep 17 00:00:00 2001 From: Erik Pilkington Date: Wed, 18 Mar 2020 14:34:55 -0400 Subject: [PATCH 041/286] [Sema] Fix a crash when diagnosing a failed overload due to __ptrauth qualifier rdar://54603814 --- clang/include/clang/Basic/DiagnosticSemaKinds.td | 4 ++++ clang/lib/Sema/SemaOverload.cpp | 11 +++++++++++ clang/test/SemaCXX/ptrauth-qualifier.cpp | 11 +++++++++++ 3 files changed, 26 insertions(+) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index daf581f6dae60..c5a6b466ca79b 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -4130,6 +4130,10 @@ def note_ovl_candidate_bad_ownership : Note< "%select{no|__unsafe_unretained|__strong|__weak|__autoreleasing}4 ownership," " but parameter has %select{no|__unsafe_unretained|__strong|__weak|" "__autoreleasing}5 ownership">; +def note_ovl_candidate_bad_ptrauth : Note< + "candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: " + "%ordinal8 argument (%3) has %select{no ptrauth|%5}4 qualifier," + " but parameter has %select{no ptrauth|%7}6 qualifier">; def note_ovl_candidate_bad_cvr_this : Note< "candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: " "'this' argument has type %3, but method is not marked " diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 83b7f497f99d9..6a066a3f17de1 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -10041,6 +10041,17 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, return; } + if (FromQs.getPointerAuth() != ToQs.getPointerAuth()) { + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_ptrauth) + << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc + << FromTy + << !!FromQs.getPointerAuth() << FromQs.getPointerAuth().getAsString() + << !!ToQs.getPointerAuth() << ToQs.getPointerAuth().getAsString() + << I + 1 << (FromExpr ? FromExpr->getSourceRange() : SourceRange()); + MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); + return; + } + unsigned CVR = FromQs.getCVRQualifiers() & ~ToQs.getCVRQualifiers(); assert(CVR && "unexpected qualifiers mismatch"); diff --git a/clang/test/SemaCXX/ptrauth-qualifier.cpp b/clang/test/SemaCXX/ptrauth-qualifier.cpp index e1fd10121ec84..97448d9d0c5eb 100644 --- a/clang/test/SemaCXX/ptrauth-qualifier.cpp +++ b/clang/test/SemaCXX/ptrauth-qualifier.cpp @@ -1,6 +1,7 @@ // RUN: %clang_cc1 -triple arm64-apple-ios -std=c++11 -fptrauth-calls -fptrauth-intrinsics -verify -fsyntax-only %s #define AQ __ptrauth(1,1,50) +#define AQ2 __ptrauth(1,1,51) #define IQ __ptrauth(1,0,50) struct __attribute__((trivial_abi)) AddrDisc { // expected-warning {{'trivial_abi' cannot be applied to 'AddrDisc'}} @@ -118,3 +119,13 @@ namespace test_union { *x4 = static_cast(*s1); // expected-error {{cannot be assigned because its copy assignment operator is implicitly deleted}} } } + +void test_bad_call_diag(void *AQ* ptr); // expected-note{{candidate function not viable: 1st argument ('void *__ptrauth(1,1,51) *') has __ptrauth(1,1,51) qualifier, but parameter has __ptrauth(1,1,50) qualifier}} expected-note{{candidate function not viable: 1st argument ('void **') has no ptrauth qualifier, but parameter has __ptrauth(1,1,50) qualifier}} +void test_bad_call_diag2(void ** ptr); // expected-note{{1st argument ('void *__ptrauth(1,1,50) *') has __ptrauth(1,1,50) qualifier, but parameter has no ptrauth qualifier}} + +int test_call_diag() { + void *AQ ptr1, *AQ2 ptr2, *ptr3; + test_bad_call_diag(&ptr2); // expected-error {{no matching function for call to 'test_bad_call_diag'}} + test_bad_call_diag(&ptr3); // expected-error {{no matching function for call to 'test_bad_call_diag'}} + test_bad_call_diag2(&ptr1); // expected-error {{no matching function for call to 'test_bad_call_diag2'}} +} From 4a30a6b434772a2d7c6445e6f63729a66c179efd Mon Sep 17 00:00:00 2001 From: Raphael Isemann Date: Thu, 19 Mar 2020 12:20:18 +0100 Subject: [PATCH 042/286] Reland [lldb] Fix string summary of an empty NSPathStore2 (This is D68010 but I also set the new parameter in LibStdcpp.cpp to fix the Debian tests). Summary: Printing a summary for an empty NSPathStore2 string currently prints random bytes behind the empty string pointer from memory (rdar://55575888). It seems the reason for this is that the SourceSize parameter in the `ReadStringAndDumpToStreamOptions` - which is supposed to contain the string length - actually uses the length 0 as a magic value for saying "read as much as possible from the buffer" which is clearly wrong for empty strings. This patch adds another flag that indicates if we have know the string length or not and makes this behaviour dependent on that (which seemingly was the original purpose of this magic value). Reviewers: aprantl, JDevlieghere, shafik Reviewed By: aprantl Subscribers: christof, abidh, lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D68010 (cherry picked from commit 7b2442584e40f97693c38c0d79b83f770d557039) --- .../lldb/DataFormatters/StringPrinter.h | 6 +++++ lldb/source/DataFormatters/StringPrinter.cpp | 22 ++++++++++++------- .../Plugins/Language/CPlusPlus/LibStdcpp.cpp | 2 ++ .../source/Plugins/Language/ObjC/NSString.cpp | 7 ++++++ .../nsstring/TestDataFormatterNSString.py | 6 +++-- .../data-formatter-objc/nsstring/main.m | 2 ++ 6 files changed, 35 insertions(+), 10 deletions(-) diff --git a/lldb/include/lldb/DataFormatters/StringPrinter.h b/lldb/include/lldb/DataFormatters/StringPrinter.h index 67b31f13a3cbd..03035ea934ee9 100644 --- a/lldb/include/lldb/DataFormatters/StringPrinter.h +++ b/lldb/include/lldb/DataFormatters/StringPrinter.h @@ -115,9 +115,15 @@ class StringPrinter { lldb::ProcessSP GetProcessSP() const { return m_process_sp; } + void SetHasSourceSize(bool e) { m_has_source_size = e; } + + bool HasSourceSize() const { return m_has_source_size; } + private: uint64_t m_location = 0; lldb::ProcessSP m_process_sp; + /// True iff we know the source size of the string. + bool m_has_source_size = false; }; class ReadBufferAndDumpToStreamOptions : public DumpToStreamOptions { diff --git a/lldb/source/DataFormatters/StringPrinter.cpp b/lldb/source/DataFormatters/StringPrinter.cpp index f8ff23e1d039d..602710554efe4 100644 --- a/lldb/source/DataFormatters/StringPrinter.cpp +++ b/lldb/source/DataFormatters/StringPrinter.cpp @@ -526,27 +526,33 @@ static bool ReadUTFBufferAndDumpToStream( if (!options.GetStream()) return false; - uint32_t sourceSize = options.GetSourceSize(); + uint32_t sourceSize; bool needs_zero_terminator = options.GetNeedsZeroTermination(); bool is_truncated = false; const auto max_size = process_sp->GetTarget().GetMaximumSizeOfStringSummary(); - if (!sourceSize) { + if (options.HasSourceSize()) { + sourceSize = options.GetSourceSize(); + if (!options.GetIgnoreMaxLength()) { + if (sourceSize > max_size) { + sourceSize = max_size; + is_truncated = true; + } + } + } else { sourceSize = max_size; needs_zero_terminator = true; - } else if (!options.GetIgnoreMaxLength()) { - if (sourceSize > max_size) { - sourceSize = max_size; - is_truncated = true; - } } const int bufferSPSize = sourceSize * type_width; lldb::DataBufferSP buffer_sp(new DataBufferHeap(bufferSPSize, 0)); - if (!buffer_sp->GetBytes()) + // Check if we got bytes. We never get any bytes if we have an empty + // string, but we still continue so that we end up actually printing + // an empty string (""). + if (sourceSize != 0 && !buffer_sp->GetBytes()) return false; Status error; diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp index 7db201822c8bd..61ac6a796beec 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp @@ -259,6 +259,7 @@ bool lldb_private::formatters::LibStdcppStringSummaryProvider( if (error.Fail()) return false; options.SetSourceSize(size_of_data); + options.SetHasSourceSize(true); if (!StringPrinter::ReadStringAndDumpToStream< StringPrinter::StringElementType::UTF8>(options)) { @@ -319,6 +320,7 @@ bool lldb_private::formatters::LibStdcppWStringSummaryProvider( if (error.Fail()) return false; options.SetSourceSize(size_of_data); + options.SetHasSourceSize(true); options.SetPrefixToken("L"); switch (wchar_size) { diff --git a/lldb/source/Plugins/Language/ObjC/NSString.cpp b/lldb/source/Plugins/Language/ObjC/NSString.cpp index bfbc8cd847980..92e31db517e22 100644 --- a/lldb/source/Plugins/Language/ObjC/NSString.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSString.cpp @@ -171,6 +171,7 @@ bool lldb_private::formatters::NSStringSummaryProvider( options.SetStream(&stream); options.SetQuote('"'); options.SetSourceSize(explicit_length); + options.SetHasSourceSize(has_explicit_length); options.SetNeedsZeroTermination(false); options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); @@ -183,6 +184,7 @@ bool lldb_private::formatters::NSStringSummaryProvider( options.SetProcessSP(process_sp); options.SetStream(&stream); options.SetSourceSize(explicit_length); + options.SetHasSourceSize(has_explicit_length); options.SetNeedsZeroTermination(false); options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); @@ -200,6 +202,7 @@ bool lldb_private::formatters::NSStringSummaryProvider( options.SetStream(&stream); options.SetQuote('"'); options.SetSourceSize(explicit_length); + options.SetHasSourceSize(has_explicit_length); options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); options.SetLanguage(summary_options.GetLanguage()); @@ -222,6 +225,7 @@ bool lldb_private::formatters::NSStringSummaryProvider( options.SetStream(&stream); options.SetQuote('"'); options.SetSourceSize(explicit_length); + options.SetHasSourceSize(has_explicit_length); options.SetNeedsZeroTermination(!has_explicit_length); options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); @@ -242,6 +246,7 @@ bool lldb_private::formatters::NSStringSummaryProvider( options.SetStream(&stream); options.SetQuote('"'); options.SetSourceSize(explicit_length); + options.SetHasSourceSize(has_explicit_length); options.SetNeedsZeroTermination(!has_explicit_length); options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); @@ -264,6 +269,7 @@ bool lldb_private::formatters::NSStringSummaryProvider( options.SetProcessSP(process_sp); options.SetStream(&stream); options.SetSourceSize(explicit_length); + options.SetHasSourceSize(has_explicit_length); options.SetNeedsZeroTermination(!has_explicit_length); options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); @@ -287,6 +293,7 @@ bool lldb_private::formatters::NSStringSummaryProvider( options.SetProcessSP(process_sp); options.SetStream(&stream); options.SetSourceSize(explicit_length); + options.SetHasSourceSize(has_explicit_length); options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); options.SetLanguage(summary_options.GetLanguage()); diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-objc/nsstring/TestDataFormatterNSString.py b/lldb/test/API/functionalities/data-formatter/data-formatter-objc/nsstring/TestDataFormatterNSString.py index 6480025e2e17d..5b323f5614b21 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-objc/nsstring/TestDataFormatterNSString.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-objc/nsstring/TestDataFormatterNSString.py @@ -76,8 +76,8 @@ def rdar11106605_commands(self): self.expect('frame variable hebrew', substrs=['לילה טוב']) def nsstring_data_formatter_commands(self): - self.expect('frame variable str0 str1 str2 str3 str4 str5 str6 str8 str9 str10 str11 label1 label2 processName str12', - substrs=['(NSString *) str1 = ', ' @"A rather short ASCII NSString object is here"', + self.expect('frame variable empty str0 str1 str2 str3 str4 str5 str6 str8 str9 str10 str11 label1 label2 processName str12', + substrs=['(NSString *) empty = ', ' @""', # '(NSString *) str0 = ',' @"255"', '(NSString *) str1 = ', ' @"A rather short ASCII NSString object is here"', '(NSString *) str2 = ', ' @"A rather short UTF8 NSString object is here"', @@ -104,6 +104,8 @@ def nsstring_data_formatter_commands(self): self.expect('expr -d run-target -- path', substrs=['usr/blah/stuff']) self.expect('frame variable path', substrs=['usr/blah/stuff']) + self.expect('expr -d run-target -- empty_path', substrs=['@""']) + self.expect('frame variable empty_path', substrs=['@""']) def nsstring_withNULs_commands(self): """Check that the NSString formatter supports embedded NULs in the text""" diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-objc/nsstring/main.m b/lldb/test/API/functionalities/data-formatter/data-formatter-objc/nsstring/main.m index b0d926fd54ef6..e5a365605b231 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-objc/nsstring/main.m +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-objc/nsstring/main.m @@ -25,6 +25,7 @@ int main (int argc, const char * argv[]) NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + NSString *empty = @""; NSString *str0 = [[NSNumber numberWithUnsignedLongLong:0xFF] stringValue]; NSString *str1 = [NSString stringWithCString:"A rather short ASCII NSString object is here" encoding:NSASCIIStringEncoding]; NSString *str2 = [NSString stringWithUTF8String:"A rather short UTF8 NSString object is here"]; @@ -77,6 +78,7 @@ int main (int argc, const char * argv[]) NSArray *components = @[@"usr", @"blah", @"stuff"]; NSString *path = [NSString pathWithComponents: components]; + NSString *empty_path = [empty stringByDeletingPathExtension]; const unichar someOfTheseAreNUL[] = {'a',' ', 'v','e','r','y',' ', 'm','u','c','h',' ','b','o','r','i','n','g',' ','t','a','s','k', From e6b96f93820bd0375be0cd5668114388496e1ee5 Mon Sep 17 00:00:00 2001 From: Raphael Isemann Date: Fri, 20 Mar 2020 11:22:23 +0100 Subject: [PATCH 043/286] [lldb] Check for "C++2a" instead of "C++20" in TestTemplateFunction.py When backporting D75761 the error message wasn't adapted to 'C++2a' from 'C++20'. --- .../API/lang/cpp/template-function/TestTemplateFunctions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/test/API/lang/cpp/template-function/TestTemplateFunctions.py b/lldb/test/API/lang/cpp/template-function/TestTemplateFunctions.py index 0e74185546e84..aa98b3c4d29de 100644 --- a/lldb/test/API/lang/cpp/template-function/TestTemplateFunctions.py +++ b/lldb/test/API/lang/cpp/template-function/TestTemplateFunctions.py @@ -19,7 +19,7 @@ def do_test_template_function(self, add_cast): if add_cast: self.expect_expr("(int) foo(42)", result_type="int", result_value="42") else: - self.expect("expr b1 <=> b2", error=True, substrs=["warning: :1:4: '<=>' is a single token in C++20; add a space to avoid a change in behavior"]) + self.expect("expr b1 <=> b2", error=True, substrs=["warning: :1:4: '<=>' is a single token in C++2a; add a space to avoid a change in behavior"]) self.expect_expr("foo(42)", result_type="int", result_value="42") From 361b74018a5e15f7253dd8ec3fec4fbcb791e837 Mon Sep 17 00:00:00 2001 From: Raphael Isemann Date: Thu, 19 Mar 2020 12:20:18 +0100 Subject: [PATCH 044/286] Reland [lldb] Fix string summary of an empty NSPathStore2 (This is D68010 but I also set the new parameter in LibStdcpp.cpp to fix the Debian tests). Summary: Printing a summary for an empty NSPathStore2 string currently prints random bytes behind the empty string pointer from memory (rdar://55575888). It seems the reason for this is that the SourceSize parameter in the `ReadStringAndDumpToStreamOptions` - which is supposed to contain the string length - actually uses the length 0 as a magic value for saying "read as much as possible from the buffer" which is clearly wrong for empty strings. This patch adds another flag that indicates if we have know the string length or not and makes this behaviour dependent on that (which seemingly was the original purpose of this magic value). Reviewers: aprantl, JDevlieghere, shafik Reviewed By: aprantl Subscribers: christof, abidh, lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D68010 (cherry picked from commit 7b2442584e40f97693c38c0d79b83f770d557039) --- .../lldb/DataFormatters/StringPrinter.h | 6 +++++ lldb/source/DataFormatters/StringPrinter.cpp | 22 ++++++++++++------- .../Plugins/Language/CPlusPlus/LibStdcpp.cpp | 2 ++ .../source/Plugins/Language/ObjC/NSString.cpp | 7 ++++++ .../nsstring/TestDataFormatterNSString.py | 6 +++-- .../data-formatter-objc/nsstring/main.m | 2 ++ 6 files changed, 35 insertions(+), 10 deletions(-) diff --git a/lldb/include/lldb/DataFormatters/StringPrinter.h b/lldb/include/lldb/DataFormatters/StringPrinter.h index 67b31f13a3cbd..03035ea934ee9 100644 --- a/lldb/include/lldb/DataFormatters/StringPrinter.h +++ b/lldb/include/lldb/DataFormatters/StringPrinter.h @@ -115,9 +115,15 @@ class StringPrinter { lldb::ProcessSP GetProcessSP() const { return m_process_sp; } + void SetHasSourceSize(bool e) { m_has_source_size = e; } + + bool HasSourceSize() const { return m_has_source_size; } + private: uint64_t m_location = 0; lldb::ProcessSP m_process_sp; + /// True iff we know the source size of the string. + bool m_has_source_size = false; }; class ReadBufferAndDumpToStreamOptions : public DumpToStreamOptions { diff --git a/lldb/source/DataFormatters/StringPrinter.cpp b/lldb/source/DataFormatters/StringPrinter.cpp index f8ff23e1d039d..602710554efe4 100644 --- a/lldb/source/DataFormatters/StringPrinter.cpp +++ b/lldb/source/DataFormatters/StringPrinter.cpp @@ -526,27 +526,33 @@ static bool ReadUTFBufferAndDumpToStream( if (!options.GetStream()) return false; - uint32_t sourceSize = options.GetSourceSize(); + uint32_t sourceSize; bool needs_zero_terminator = options.GetNeedsZeroTermination(); bool is_truncated = false; const auto max_size = process_sp->GetTarget().GetMaximumSizeOfStringSummary(); - if (!sourceSize) { + if (options.HasSourceSize()) { + sourceSize = options.GetSourceSize(); + if (!options.GetIgnoreMaxLength()) { + if (sourceSize > max_size) { + sourceSize = max_size; + is_truncated = true; + } + } + } else { sourceSize = max_size; needs_zero_terminator = true; - } else if (!options.GetIgnoreMaxLength()) { - if (sourceSize > max_size) { - sourceSize = max_size; - is_truncated = true; - } } const int bufferSPSize = sourceSize * type_width; lldb::DataBufferSP buffer_sp(new DataBufferHeap(bufferSPSize, 0)); - if (!buffer_sp->GetBytes()) + // Check if we got bytes. We never get any bytes if we have an empty + // string, but we still continue so that we end up actually printing + // an empty string (""). + if (sourceSize != 0 && !buffer_sp->GetBytes()) return false; Status error; diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp index 7db201822c8bd..61ac6a796beec 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp @@ -259,6 +259,7 @@ bool lldb_private::formatters::LibStdcppStringSummaryProvider( if (error.Fail()) return false; options.SetSourceSize(size_of_data); + options.SetHasSourceSize(true); if (!StringPrinter::ReadStringAndDumpToStream< StringPrinter::StringElementType::UTF8>(options)) { @@ -319,6 +320,7 @@ bool lldb_private::formatters::LibStdcppWStringSummaryProvider( if (error.Fail()) return false; options.SetSourceSize(size_of_data); + options.SetHasSourceSize(true); options.SetPrefixToken("L"); switch (wchar_size) { diff --git a/lldb/source/Plugins/Language/ObjC/NSString.cpp b/lldb/source/Plugins/Language/ObjC/NSString.cpp index bfbc8cd847980..92e31db517e22 100644 --- a/lldb/source/Plugins/Language/ObjC/NSString.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSString.cpp @@ -171,6 +171,7 @@ bool lldb_private::formatters::NSStringSummaryProvider( options.SetStream(&stream); options.SetQuote('"'); options.SetSourceSize(explicit_length); + options.SetHasSourceSize(has_explicit_length); options.SetNeedsZeroTermination(false); options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); @@ -183,6 +184,7 @@ bool lldb_private::formatters::NSStringSummaryProvider( options.SetProcessSP(process_sp); options.SetStream(&stream); options.SetSourceSize(explicit_length); + options.SetHasSourceSize(has_explicit_length); options.SetNeedsZeroTermination(false); options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); @@ -200,6 +202,7 @@ bool lldb_private::formatters::NSStringSummaryProvider( options.SetStream(&stream); options.SetQuote('"'); options.SetSourceSize(explicit_length); + options.SetHasSourceSize(has_explicit_length); options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); options.SetLanguage(summary_options.GetLanguage()); @@ -222,6 +225,7 @@ bool lldb_private::formatters::NSStringSummaryProvider( options.SetStream(&stream); options.SetQuote('"'); options.SetSourceSize(explicit_length); + options.SetHasSourceSize(has_explicit_length); options.SetNeedsZeroTermination(!has_explicit_length); options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); @@ -242,6 +246,7 @@ bool lldb_private::formatters::NSStringSummaryProvider( options.SetStream(&stream); options.SetQuote('"'); options.SetSourceSize(explicit_length); + options.SetHasSourceSize(has_explicit_length); options.SetNeedsZeroTermination(!has_explicit_length); options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); @@ -264,6 +269,7 @@ bool lldb_private::formatters::NSStringSummaryProvider( options.SetProcessSP(process_sp); options.SetStream(&stream); options.SetSourceSize(explicit_length); + options.SetHasSourceSize(has_explicit_length); options.SetNeedsZeroTermination(!has_explicit_length); options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); @@ -287,6 +293,7 @@ bool lldb_private::formatters::NSStringSummaryProvider( options.SetProcessSP(process_sp); options.SetStream(&stream); options.SetSourceSize(explicit_length); + options.SetHasSourceSize(has_explicit_length); options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped); options.SetLanguage(summary_options.GetLanguage()); diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-objc/nsstring/TestDataFormatterNSString.py b/lldb/test/API/functionalities/data-formatter/data-formatter-objc/nsstring/TestDataFormatterNSString.py index 6480025e2e17d..5b323f5614b21 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-objc/nsstring/TestDataFormatterNSString.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-objc/nsstring/TestDataFormatterNSString.py @@ -76,8 +76,8 @@ def rdar11106605_commands(self): self.expect('frame variable hebrew', substrs=['לילה טוב']) def nsstring_data_formatter_commands(self): - self.expect('frame variable str0 str1 str2 str3 str4 str5 str6 str8 str9 str10 str11 label1 label2 processName str12', - substrs=['(NSString *) str1 = ', ' @"A rather short ASCII NSString object is here"', + self.expect('frame variable empty str0 str1 str2 str3 str4 str5 str6 str8 str9 str10 str11 label1 label2 processName str12', + substrs=['(NSString *) empty = ', ' @""', # '(NSString *) str0 = ',' @"255"', '(NSString *) str1 = ', ' @"A rather short ASCII NSString object is here"', '(NSString *) str2 = ', ' @"A rather short UTF8 NSString object is here"', @@ -104,6 +104,8 @@ def nsstring_data_formatter_commands(self): self.expect('expr -d run-target -- path', substrs=['usr/blah/stuff']) self.expect('frame variable path', substrs=['usr/blah/stuff']) + self.expect('expr -d run-target -- empty_path', substrs=['@""']) + self.expect('frame variable empty_path', substrs=['@""']) def nsstring_withNULs_commands(self): """Check that the NSString formatter supports embedded NULs in the text""" diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-objc/nsstring/main.m b/lldb/test/API/functionalities/data-formatter/data-formatter-objc/nsstring/main.m index b0d926fd54ef6..e5a365605b231 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-objc/nsstring/main.m +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-objc/nsstring/main.m @@ -25,6 +25,7 @@ int main (int argc, const char * argv[]) NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + NSString *empty = @""; NSString *str0 = [[NSNumber numberWithUnsignedLongLong:0xFF] stringValue]; NSString *str1 = [NSString stringWithCString:"A rather short ASCII NSString object is here" encoding:NSASCIIStringEncoding]; NSString *str2 = [NSString stringWithUTF8String:"A rather short UTF8 NSString object is here"]; @@ -77,6 +78,7 @@ int main (int argc, const char * argv[]) NSArray *components = @[@"usr", @"blah", @"stuff"]; NSString *path = [NSString pathWithComponents: components]; + NSString *empty_path = [empty stringByDeletingPathExtension]; const unichar someOfTheseAreNUL[] = {'a',' ', 'v','e','r','y',' ', 'm','u','c','h',' ','b','o','r','i','n','g',' ','t','a','s','k', From 5513b44ed08169b31bd00e1a805f81dab10a9835 Mon Sep 17 00:00:00 2001 From: Raphael Isemann Date: Fri, 20 Mar 2020 11:22:23 +0100 Subject: [PATCH 045/286] [lldb] Check for "C++2a" instead of "C++20" in TestTemplateFunction.py When backporting D75761 the error message wasn't adapted to 'C++2a' from 'C++20'. (cherry picked from commit e6b96f93820bd0375be0cd5668114388496e1ee5) --- .../API/lang/cpp/template-function/TestTemplateFunctions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/test/API/lang/cpp/template-function/TestTemplateFunctions.py b/lldb/test/API/lang/cpp/template-function/TestTemplateFunctions.py index 0e74185546e84..aa98b3c4d29de 100644 --- a/lldb/test/API/lang/cpp/template-function/TestTemplateFunctions.py +++ b/lldb/test/API/lang/cpp/template-function/TestTemplateFunctions.py @@ -19,7 +19,7 @@ def do_test_template_function(self, add_cast): if add_cast: self.expect_expr("(int) foo(42)", result_type="int", result_value="42") else: - self.expect("expr b1 <=> b2", error=True, substrs=["warning: :1:4: '<=>' is a single token in C++20; add a space to avoid a change in behavior"]) + self.expect("expr b1 <=> b2", error=True, substrs=["warning: :1:4: '<=>' is a single token in C++2a; add a space to avoid a change in behavior"]) self.expect_expr("foo(42)", result_type="int", result_value="42") From 2b1e511a9d502a43210c2fb3bc27f0d104f2d6a9 Mon Sep 17 00:00:00 2001 From: Fred Riss Date: Fri, 20 Mar 2020 17:18:47 -0700 Subject: [PATCH 046/286] [lldb/Swift] Adapt Swift string formatters after upstream change https://github.com/llvm/llvm-project/commit/7b2442584e40f97693c38c0d79b83f770d557039 Swift formatters also needed to call SetHasSourceSize. --- lldb/source/Plugins/Language/Swift/SwiftFormatters.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lldb/source/Plugins/Language/Swift/SwiftFormatters.cpp b/lldb/source/Plugins/Language/Swift/SwiftFormatters.cpp index 9457317e91348..2df321c693d89 100644 --- a/lldb/source/Plugins/Language/Swift/SwiftFormatters.cpp +++ b/lldb/source/Plugins/Language/Swift/SwiftFormatters.cpp @@ -81,6 +81,7 @@ static bool readStringFromAddress( read_options.SetProcessSP(process); read_options.SetStream(&stream); read_options.SetSourceSize(length); + read_options.SetHasSourceSize(true); read_options.SetNeedsZeroTermination(false); read_options.SetIgnoreMaxLength(summary_options.GetCapping() == lldb::eTypeSummaryUncapped); @@ -413,6 +414,7 @@ bool lldb_private::formatters::swift::StaticString_SummaryProvider( read_options.SetProcessSP(process_sp); read_options.SetLocation(start_ptr); read_options.SetSourceSize(size); + read_options.SetHasSourceSize(true); read_options.SetBinaryZeroIsTerminator(false); read_options.SetNeedsZeroTermination(false); read_options.SetStream(&stream); From 5fcd8fd100fb17f7c52ab0b57c1644ac294fea13 Mon Sep 17 00:00:00 2001 From: Raphael Isemann Date: Fri, 20 Mar 2020 15:06:30 +0100 Subject: [PATCH 047/286] [lldb][swift] Test fun->func completion in REPL completion test Test for rdar://problem/60076884 The Hashable completion was just picked by me at random, but we can test the exact crash for that radar for free if we change it to 'fun'->'func'. --- .../API/lang/swift/completion/TestSwiftREPLCompletion.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lldb/test/API/lang/swift/completion/TestSwiftREPLCompletion.py b/lldb/test/API/lang/swift/completion/TestSwiftREPLCompletion.py index eb776440fbb6d..6a5eb84e6f3b3 100644 --- a/lldb/test/API/lang/swift/completion/TestSwiftREPLCompletion.py +++ b/lldb/test/API/lang/swift/completion/TestSwiftREPLCompletion.py @@ -23,9 +23,9 @@ def test_basic_completion(self): # pexpect is not recognized as a interactive terminal by pexpect it seems. self.child.send("\t\t\t") - # Try completing something that only has one result "Hasabl" -> "Hashable". - self.child.send("Hashabl\t") - self.child.expect_exact("Hashable") + # Try completing something that only has one result "fun" -> "func". + self.child.send("fun\t") + self.child.expect_exact("func") self.child.sendline("") # Try completing something that has multiple completions. From 502baccfa5f6765ed8c45219dc0ab5dbc4f4f1b3 Mon Sep 17 00:00:00 2001 From: David Stenberg Date: Wed, 18 Mar 2020 11:32:03 +0100 Subject: [PATCH 048/286] [DebugInfo] Fix multi-byte entry values in call site values Summary: In D67768/D67492 I added support for entry values having blocks larger than one byte, but I now noticed that the DIE implementation I added there was broken. The takeNodes() function, that moves the entry value block from a temporary buffer to the output buffer, would destroy the input iterator when transferring the first node, meaning that only that node was moved. In practice, this meant that when emitting a call site value using a DW_OP_entry_value operation with a DWARF register number larger than 31, that multi-byte DW_OP_regx expression would be truncated. Reviewers: djtodoro, aprantl, vsk Reviewed By: djtodoro Subscribers: llvm-commits Tags: #debug-info, #llvm Differential Revision: https://reviews.llvm.org/D76279 (cherry picked from commit a0a3a9c5a83192254eae442654e65dd3eb724713) --- llvm/include/llvm/CodeGen/DIE.h | 19 +++++-- .../AArch64/dbgcall-site-float-entry-value.ll | 49 +++++++++++++++++++ 2 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 llvm/test/DebugInfo/AArch64/dbgcall-site-float-entry-value.ll diff --git a/llvm/include/llvm/CodeGen/DIE.h b/llvm/include/llvm/CodeGen/DIE.h index 40f6b041e9b30..150c30df9dd72 100644 --- a/llvm/include/llvm/CodeGen/DIE.h +++ b/llvm/include/llvm/CodeGen/DIE.h @@ -551,10 +551,21 @@ template class IntrusiveBackList : IntrusiveBackListBase { } void takeNodes(IntrusiveBackList &Other) { - for (auto &N : Other) { - N.Next.setPointerAndInt(&N, true); - push_back(N); - } + if (Other.empty()) + return; + + T *FirstNode = static_cast(Other.Last->Next.getPointer()); + T *IterNode = FirstNode; + do { + // Keep a pointer to the node and increment the iterator. + T *TmpNode = IterNode; + IterNode = static_cast(IterNode->Next.getPointer()); + + // Unlink the node and push it back to this list. + TmpNode->Next.setPointerAndInt(TmpNode, true); + push_back(*TmpNode); + } while (IterNode != FirstNode); + Other.Last = nullptr; } diff --git a/llvm/test/DebugInfo/AArch64/dbgcall-site-float-entry-value.ll b/llvm/test/DebugInfo/AArch64/dbgcall-site-float-entry-value.ll new file mode 100644 index 0000000000000..27c6fb3f8ff0c --- /dev/null +++ b/llvm/test/DebugInfo/AArch64/dbgcall-site-float-entry-value.ll @@ -0,0 +1,49 @@ +; RUN: llc -mtriple aarch64-linux-gnu -debug-entry-values -filetype=obj -o - %s | llvm-dwarfdump - | FileCheck %s + +; Based on the following C reproducer: +; +; extern void callee(float); +; +; void foo(float param) { +; callee(param); +; } + +; Verify that a call site value using DW_OP_GNU_entry_value(DW_OP_regx B0) is +; emitted for the float parameter. Previously the entry value's multi-byte +; DW_OP_regx expression would be truncated. + +; CHECK: DW_TAG_GNU_call_site_parameter +; CHECK-NEXT: DW_AT_location (DW_OP_regx B0) +; CHECK-NEXT: DW_AT_GNU_call_site_value (DW_OP_GNU_entry_value(DW_OP_regx B0) + +target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" +target triple = "aarch64" + +; Function Attrs: nounwind +define dso_local void @foo(float %param) local_unnamed_addr !dbg !12 { +entry: + tail call void @callee(float %param), !dbg !13 + ret void, !dbg !14 +} + +declare !dbg !4 dso_local void @callee(float) local_unnamed_addr + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!8, !9, !10} +!llvm.ident = !{!11} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 11.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "float.c", directory: "/") +!2 = !{} +!3 = !{!4} +!4 = !DISubprogram(name: "callee", scope: !1, file: !1, line: 1, type: !5, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2) +!5 = !DISubroutineType(types: !6) +!6 = !{null, !7} +!7 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float) +!8 = !{i32 7, !"Dwarf Version", i32 4} +!9 = !{i32 2, !"Debug Info Version", i32 3} +!10 = !{i32 1, !"wchar_size", i32 4} +!11 = !{!"clang version 11.0.0 "} +!12 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 3, type: !5, scopeLine: 3, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2) +!13 = !DILocation(line: 4, scope: !12) +!14 = !DILocation(line: 5, scope: !12) From 0a03464f2e7ac9799b9ed864be6835b793a13d3e Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Fri, 20 Mar 2020 11:12:01 -0700 Subject: [PATCH 049/286] PR45181: Fix another invalid DIExpression combination The original test case from PR45181 triggers a DIExpression combination that wasn't fixed in D76164. (cherry picked from commit 636665331bbd4c369a9f33c4d35fb9a863c94646) --- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 27 +- llvm/test/DebugInfo/X86/pr45181.ll | 306 +++++++++++++++++++++ 2 files changed, 321 insertions(+), 12 deletions(-) create mode 100644 llvm/test/DebugInfo/X86/pr45181.ll diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index f1c98be617371..63583471977e3 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -572,6 +572,18 @@ struct FwdRegParamInfo { /// Register worklist for finding call site values. using FwdRegWorklist = MapVector>; +/// Append the expression \p Addition to \p Original and return the result. +static const DIExpression *combineDIExpressions(const DIExpression *Original, + const DIExpression *Addition) { + std::vector Elts = Addition->getElements().vec(); + // Avoid multiple DW_OP_stack_values. + if (Original->isImplicit() && Addition->isImplicit()) + erase_if(Elts, [](uint64_t Op) { return Op == dwarf::DW_OP_stack_value; }); + const DIExpression *CombinedExpr = + (Elts.size() > 0) ? DIExpression::append(Original, Elts) : Original; + return CombinedExpr; +} + /// Emit call site parameter entries that are described by the given value and /// debug expression. template @@ -591,9 +603,8 @@ static void finishCallSiteParams(ValT Val, const DIExpression *Expr, // parameter when walking through the instructions. Append that to the // base expression. const DIExpression *CombinedExpr = - ShouldCombineExpressions - ? DIExpression::append(Expr, Param.Expr->getElements()) - : Expr; + ShouldCombineExpressions ? combineDIExpressions(Expr, Param.Expr) + : Expr; assert((!CombinedExpr || CombinedExpr->isValid()) && "Combined debug expression is invalid"); @@ -623,15 +634,7 @@ static void addToFwdRegWorklist(FwdRegWorklist &Worklist, unsigned Reg, // instructions we may have already created an expression for the // parameter when walking through the instructions. Append that to the // new expression. - std::vector ParamElts = Param.Expr->getElements().vec(); - // Avoid multiple DW_OP_stack_values. - if (Expr->isImplicit() && Param.Expr->isImplicit()) - erase_if(ParamElts, - [](uint64_t Op) { return Op == dwarf::DW_OP_stack_value; }); - const DIExpression *CombinedExpr = - (Param.Expr->getNumElements() > 0) - ? DIExpression::append(Expr, ParamElts) - : Expr; + const DIExpression *CombinedExpr = combineDIExpressions(Expr, Param.Expr); ParamsForFwdReg.push_back({Param.ParamReg, CombinedExpr}); } } diff --git a/llvm/test/DebugInfo/X86/pr45181.ll b/llvm/test/DebugInfo/X86/pr45181.ll new file mode 100644 index 0000000000000..ececeabdfd89d --- /dev/null +++ b/llvm/test/DebugInfo/X86/pr45181.ll @@ -0,0 +1,306 @@ +; RUN: llc -O1 -filetype=obj -debug-entry-values -o - < %s | llvm-dwarfdump -verify - -o /dev/null + +; TODO: This test should be made more targeted by converting to MIR and reducing, +; however at the moment conversion to MIR fails with: +; Assertion failed: (!NameRef.empty() && "Normal symbols cannot be unnamed!") + +target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.14.0" + +%struct.e = type opaque +%"class.aa::aq" = type { i8 } +%"class.aa::ah" = type { i8 } +%"class.aa::y" = type { i8 } +%"class.aa::y.0" = type { i8 } +%struct.j = type opaque +%struct.h = type opaque +%struct.r = type opaque + +@o = local_unnamed_addr global i32 0, align 4, !dbg !0 +@p = local_unnamed_addr global %struct.e* null, align 8, !dbg !42 + +; Function Attrs: optsize ssp uwtable +define void @_ZN2aa2aq2arEv(%"class.aa::aq"* %this) local_unnamed_addr #0 align 2 !dbg !50 { +entry: + call void @llvm.dbg.value(metadata %"class.aa::aq"* %this, metadata !71, metadata !DIExpression()), !dbg !75 + %0 = bitcast %"class.aa::aq"* %this to %"class.aa::ah"*, !dbg !76 + tail call void @_ZN2aa2ah2aiEiib(%"class.aa::ah"* %0, i32 undef, i32 undef, i1 zeroext true) #5, !dbg !76 + ret void, !dbg !77 +} + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 + +; Function Attrs: argmemonly nounwind willreturn +declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #2 + +; Function Attrs: optsize ssp uwtable +define linkonce_odr void @_ZN2aa2ah2aiEiib(%"class.aa::ah"* %this, i32 %aj, i32 %0, i1 zeroext %1) local_unnamed_addr #0 align 2 personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) !dbg !78 { +entry: + %ao = alloca %"class.aa::y", align 1 + %ap = alloca %"class.aa::y.0", align 1 + call void @llvm.dbg.value(metadata %"class.aa::ah"* %this, metadata !80, metadata !DIExpression()), !dbg !126 + call void @llvm.dbg.value(metadata i32 %aj, metadata !82, metadata !DIExpression()), !dbg !126 + call void @llvm.dbg.value(metadata i32 %0, metadata !83, metadata !DIExpression()), !dbg !126 + call void @llvm.dbg.value(metadata i1 %1, metadata !84, metadata !DIExpression()), !dbg !126 + call void @llvm.dbg.value(metadata i32 %aj, metadata !85, metadata !DIExpression()), !dbg !126 + %2 = getelementptr inbounds %"class.aa::y", %"class.aa::y"* %ao, i64 0, i32 0, !dbg !127 + call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %2) #6, !dbg !127 + call void @llvm.dbg.declare(metadata %"class.aa::y"* %ao, metadata !91, metadata !DIExpression()), !dbg !128 + %call = tail call %struct.j* @_Z1mPvS_lPFvS_PKvlE(i8* undef, i8* undef, i64 0, void (i8*, i8*, i64)* nonnull @_ZN2aa12_GLOBAL__N_12agEPvPKvl) #5, !dbg !129 + call void @_ZN2aa1yIP1jNS_2ac1zI1eEEEC1ES2_(%"class.aa::y"* nonnull %ao, %struct.j* %call) #5, !dbg !128 + %3 = getelementptr inbounds %"class.aa::y.0", %"class.aa::y.0"* %ap, i64 0, i32 0, !dbg !130 + call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull %3) #6, !dbg !130 + call void @llvm.dbg.declare(metadata %"class.aa::y.0"* %ap, metadata !110, metadata !DIExpression()), !dbg !131 + %4 = load %struct.e*, %struct.e** @p, align 8, !dbg !132, !tbaa !133 + %call3 = invoke %struct.h* @_Z1qP1e(%struct.e* %4) #5 + to label %invoke.cont unwind label %lpad, !dbg !137 + +invoke.cont: ; preds = %entry + invoke void @_ZN2aa1yIP1hNS_2ac1zI1eEEEC1ES2_(%"class.aa::y.0"* nonnull %ap, %struct.h* %call3) #5 + to label %invoke.cont4 unwind label %lpad, !dbg !131 + +invoke.cont4: ; preds = %invoke.cont + %conv = sext i32 %aj to i64, !dbg !138 + %mul = shl nsw i32 %aj, 2, !dbg !139 + %conv6 = sext i32 %mul to i64, !dbg !140 + %call9 = invoke %struct.h* @_ZN2aa1yIP1hNS_2ac1zI1eEEE2abEv(%"class.aa::y.0"* nonnull %ap) #5 + to label %invoke.cont8 unwind label %lpad7, !dbg !141 + +invoke.cont8: ; preds = %invoke.cont4 + %call11 = invoke %struct.j* @_ZN2aa1yIP1jNS_2ac1zI1eEEE2abEv(%"class.aa::y"* nonnull %ao) #5 + to label %invoke.cont10 unwind label %lpad7, !dbg !142 + +invoke.cont10: ; preds = %invoke.cont8 + %5 = load i32, i32* @o, align 4, !dbg !143, !tbaa !144 + %call13 = invoke %struct.r* @_Z1vlllllP1hiP1jPdb1n(i64 %conv, i64 0, i64 8, i64 2, i64 %conv6, %struct.h* %call9, i32 0, %struct.j* %call11, double* null, i1 zeroext false, i32 %5) #5 + to label %invoke.cont12 unwind label %lpad7, !dbg !146 + +invoke.cont12: ; preds = %invoke.cont10 + unreachable, !dbg !146 + +lpad: ; preds = %invoke.cont, %entry + %6 = landingpad { i8*, i32 } + cleanup, !dbg !147 + %7 = extractvalue { i8*, i32 } %6, 0, !dbg !147 + %8 = extractvalue { i8*, i32 } %6, 1, !dbg !147 + br label %ehcleanup, !dbg !147 + +lpad7: ; preds = %invoke.cont10, %invoke.cont8, %invoke.cont4 + %9 = landingpad { i8*, i32 } + cleanup, !dbg !147 + %10 = extractvalue { i8*, i32 } %9, 0, !dbg !147 + %11 = extractvalue { i8*, i32 } %9, 1, !dbg !147 + call void @_ZN2aa1yIP1hNS_2ac1zI1eEEED1Ev(%"class.aa::y.0"* nonnull %ap) #7, !dbg !147 + br label %ehcleanup, !dbg !147 + +ehcleanup: ; preds = %lpad7, %lpad + %exn.slot.0 = phi i8* [ %10, %lpad7 ], [ %7, %lpad ], !dbg !147 + %ehselector.slot.0 = phi i32 [ %11, %lpad7 ], [ %8, %lpad ], !dbg !147 + call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull %3) #6, !dbg !147 + call void @_ZN2aa1yIP1jNS_2ac1zI1eEEED1Ev(%"class.aa::y"* nonnull %ao) #7, !dbg !147 + call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull %2) #6, !dbg !147 + %lpad.val = insertvalue { i8*, i32 } undef, i8* %exn.slot.0, 0, !dbg !147 + %lpad.val19 = insertvalue { i8*, i32 } %lpad.val, i32 %ehselector.slot.0, 1, !dbg !147 + resume { i8*, i32 } %lpad.val19, !dbg !147 +} + +; Function Attrs: argmemonly nounwind willreturn +declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #2 + +; Function Attrs: optsize +declare !dbg !11 %struct.j* @_Z1mPvS_lPFvS_PKvlE(i8*, i8*, i64, void (i8*, i8*, i64)*) local_unnamed_addr #3 + +; Function Attrs: optsize +declare void @_ZN2aa12_GLOBAL__N_12agEPvPKvl(i8*, i8*, i64) #3 + +; Function Attrs: optsize +declare void @_ZN2aa1yIP1jNS_2ac1zI1eEEEC1ES2_(%"class.aa::y"*, %struct.j*) unnamed_addr #3 + +; Function Attrs: optsize +declare !dbg !24 %struct.h* @_Z1qP1e(%struct.e*) local_unnamed_addr #3 + +declare i32 @__gxx_personality_v0(...) + +; Function Attrs: optsize +declare void @_ZN2aa1yIP1hNS_2ac1zI1eEEEC1ES2_(%"class.aa::y.0"*, %struct.h*) unnamed_addr #3 + +; Function Attrs: optsize +declare !dbg !31 %struct.r* @_Z1vlllllP1hiP1jPdb1n(i64, i64, i64, i64, i64, %struct.h*, i32, %struct.j*, double*, i1 zeroext, i32) local_unnamed_addr #3 + +; Function Attrs: optsize +declare %struct.h* @_ZN2aa1yIP1hNS_2ac1zI1eEEE2abEv(%"class.aa::y.0"*) local_unnamed_addr #3 + +; Function Attrs: optsize +declare %struct.j* @_ZN2aa1yIP1jNS_2ac1zI1eEEE2abEv(%"class.aa::y"*) local_unnamed_addr #3 + +; Function Attrs: nounwind optsize +declare void @_ZN2aa1yIP1hNS_2ac1zI1eEEED1Ev(%"class.aa::y.0"*) unnamed_addr #4 + +; Function Attrs: nounwind optsize +declare void @_ZN2aa1yIP1jNS_2ac1zI1eEEED1Ev(%"class.aa::y"*) unnamed_addr #4 + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +attributes #0 = { optsize ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone speculatable willreturn } +attributes #2 = { argmemonly nounwind willreturn } +attributes #3 = { optsize "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #4 = { nounwind optsize "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="all" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #5 = { optsize } +attributes #6 = { nounwind } +attributes #7 = { nounwind optsize } + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!45, !46, !47, !48} +!llvm.ident = !{!49} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "o", scope: !2, file: !6, line: 11, type: !40, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 11.0.0 (git@github.com:llvm/llvm-project.git 0fecdcd1628999a1900d9cf84cd33dacf1319fa6)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !10, globals: !41, nameTableKind: None, sysroot: "/") +!3 = !DIFile(filename: "/Users/vsk/tmp/x.cc", directory: "/Users/vsk/src/llvm-backup-master") +!4 = !{!5} +!5 = !DICompositeType(tag: DW_TAG_enumeration_type, file: !6, line: 16, baseType: !7, size: 32, elements: !8) +!6 = !DIFile(filename: "tmp/x.cc", directory: "/Users/vsk") +!7 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!8 = !{!9} +!9 = !DIEnumerator(name: "u", value: 0, isUnsigned: true) +!10 = !{!11, !24, !31} +!11 = !DISubprogram(name: "m", linkageName: "_Z1mPvS_lPFvS_PKvlE", scope: !6, file: !6, line: 10, type: !12, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !23) +!12 = !DISubroutineType(types: !13) +!13 = !{!14, !16, !16, !17, !18} +!14 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !15, size: 64) +!15 = !DICompositeType(tag: DW_TAG_structure_type, name: "j", file: !6, line: 8, flags: DIFlagFwdDecl, identifier: "_ZTS1j") +!16 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) +!17 = !DIBasicType(name: "long int", size: 64, encoding: DW_ATE_signed) +!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !19, size: 64) +!19 = !DISubroutineType(types: !20) +!20 = !{null, !16, !21, !17} +!21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !22, size: 64) +!22 = !DIDerivedType(tag: DW_TAG_const_type, baseType: null) +!23 = !{} +!24 = !DISubprogram(name: "q", linkageName: "_Z1qP1e", scope: !6, file: !6, line: 13, type: !25, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !23) +!25 = !DISubroutineType(types: !26) +!26 = !{!27, !29} +!27 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !28, size: 64) +!28 = !DICompositeType(tag: DW_TAG_structure_type, name: "h", file: !6, line: 7, flags: DIFlagFwdDecl, identifier: "_ZTS1h") +!29 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !30, size: 64) +!30 = !DICompositeType(tag: DW_TAG_structure_type, name: "e", file: !6, line: 5, flags: DIFlagFwdDecl, identifier: "_ZTS1e") +!31 = !DISubprogram(name: "v", linkageName: "_Z1vlllllP1hiP1jPdb1n", scope: !6, file: !6, line: 17, type: !32, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !23) +!32 = !DISubroutineType(types: !33) +!33 = !{!34, !17, !17, !17, !17, !17, !27, !36, !14, !37, !39, !40} +!34 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !35, size: 64) +!35 = !DICompositeType(tag: DW_TAG_structure_type, name: "r", file: !6, line: 14, flags: DIFlagFwdDecl, identifier: "_ZTS1r") +!36 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!37 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !38, size: 64) +!38 = !DIBasicType(name: "double", size: 64, encoding: DW_ATE_float) +!39 = !DIBasicType(name: "bool", size: 8, encoding: DW_ATE_boolean) +!40 = !DICompositeType(tag: DW_TAG_enumeration_type, name: "n", file: !6, line: 11, size: 32, flags: DIFlagFwdDecl, identifier: "_ZTS1n") +!41 = !{!0, !42} +!42 = !DIGlobalVariableExpression(var: !43, expr: !DIExpression()) +!43 = distinct !DIGlobalVariable(name: "p", scope: !2, file: !6, line: 12, type: !44, isLocal: false, isDefinition: true) +!44 = !DIDerivedType(tag: DW_TAG_typedef, name: "f", file: !6, line: 5, baseType: !29) +!45 = !{i32 7, !"Dwarf Version", i32 4} +!46 = !{i32 2, !"Debug Info Version", i32 3} +!47 = !{i32 1, !"wchar_size", i32 4} +!48 = !{i32 7, !"PIC Level", i32 2} +!49 = !{!"clang version 11.0.0 (git@github.com:llvm/llvm-project.git 0fecdcd1628999a1900d9cf84cd33dacf1319fa6)"} +!50 = distinct !DISubprogram(name: "ar", linkageName: "_ZN2aa2aq2arEv", scope: !51, file: !6, line: 48, type: !67, scopeLine: 48, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, declaration: !66, retainedNodes: !70) +!51 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "aq", scope: !52, file: !6, line: 45, size: 8, flags: DIFlagTypePassByValue, elements: !53, identifier: "_ZTSN2aa2aqE") +!52 = !DINamespace(name: "aa", scope: null) +!53 = !{!54, !66} +!54 = !DIDerivedType(tag: DW_TAG_inheritance, scope: !51, baseType: !55, extraData: i32 0) +!55 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "ah", scope: !52, file: !6, line: 34, size: 8, flags: DIFlagTypePassByValue, elements: !56, identifier: "_ZTSN2aa2ahE") +!56 = !{!57} +!57 = !DISubprogram(name: "ai", linkageName: "_ZN2aa2ah2aiEiib", scope: !55, file: !6, line: 36, type: !58, scopeLine: 36, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagOptimized) +!58 = !DISubroutineType(types: !59) +!59 = !{!60, !64, !65, !65, !39} +!60 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "af", scope: !52, file: !6, line: 30, size: 8, flags: DIFlagTypePassByValue, elements: !23, templateParams: !61, identifier: "_ZTSN2aa2afI1wEE") +!61 = !{!62} +!62 = !DITemplateTypeParameter(type: !63) +!63 = !DICompositeType(tag: DW_TAG_class_type, name: "w", file: !6, line: 18, flags: DIFlagFwdDecl, identifier: "_ZTS1w") +!64 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !55, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!65 = !DIDerivedType(tag: DW_TAG_typedef, name: "b", file: !6, line: 2, baseType: !36) +!66 = !DISubprogram(name: "ar", linkageName: "_ZN2aa2aq2arEv", scope: !51, file: !6, line: 46, type: !67, scopeLine: 46, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized) +!67 = !DISubroutineType(types: !68) +!68 = !{null, !69} +!69 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !51, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!70 = !{!71, !73, !74} +!71 = !DILocalVariable(name: "this", arg: 1, scope: !50, type: !72, flags: DIFlagArtificial | DIFlagObjectPointer) +!72 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !51, size: 64) +!73 = !DILocalVariable(name: "aj", scope: !50, file: !6, line: 49, type: !65) +!74 = !DILocalVariable(name: "am", scope: !50, file: !6, line: 50, type: !65) +!75 = !DILocation(line: 0, scope: !50) +!76 = !DILocation(line: 51, column: 3, scope: !50) +!77 = !DILocation(line: 52, column: 1, scope: !50) +!78 = distinct !DISubprogram(name: "ai", linkageName: "_ZN2aa2ah2aiEiib", scope: !55, file: !6, line: 36, type: !58, scopeLine: 36, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, declaration: !57, retainedNodes: !79) +!79 = !{!80, !82, !83, !84, !85, !86, !87, !91, !110} +!80 = !DILocalVariable(name: "this", arg: 1, scope: !78, type: !81, flags: DIFlagArtificial | DIFlagObjectPointer) +!81 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !55, size: 64) +!82 = !DILocalVariable(name: "aj", arg: 2, scope: !78, file: !6, line: 36, type: !65) +!83 = !DILocalVariable(arg: 3, scope: !78, file: !6, line: 36, type: !65) +!84 = !DILocalVariable(arg: 4, scope: !78, file: !6, line: 36, type: !39) +!85 = !DILocalVariable(name: "ak", scope: !78, file: !6, line: 37, type: !65) +!86 = !DILocalVariable(name: "al", scope: !78, file: !6, line: 38, type: !65) +!87 = !DILocalVariable(name: "an", scope: !78, file: !6, line: 39, type: !88) +!88 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !89, size: 64) +!89 = !DIDerivedType(tag: DW_TAG_typedef, name: "c", file: !6, line: 3, baseType: !90) +!90 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!91 = !DILocalVariable(name: "ao", scope: !78, file: !6, line: 40, type: !92) +!92 = !DIDerivedType(tag: DW_TAG_typedef, name: "ae", scope: !52, file: !6, line: 29, baseType: !93) +!93 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "y >", scope: !52, file: !6, line: 20, size: 8, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !94, templateParams: !105, identifier: "_ZTSN2aa1yIP1jNS_2ac1zI1eEEEE") +!94 = !{!95, !99, !102} +!95 = !DISubprogram(name: "y", scope: !93, file: !6, line: 22, type: !96, scopeLine: 22, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagOptimized) +!96 = !DISubroutineType(types: !97) +!97 = !{null, !98, !14} +!98 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !93, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!99 = !DISubprogram(name: "~y", scope: !93, file: !6, line: 23, type: !100, scopeLine: 23, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagOptimized) +!100 = !DISubroutineType(types: !101) +!101 = !{null, !98} +!102 = !DISubprogram(name: "ab", linkageName: "_ZN2aa1yIP1jNS_2ac1zI1eEEE2abEv", scope: !93, file: !6, line: 24, type: !103, scopeLine: 24, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagOptimized) +!103 = !DISubroutineType(types: !104) +!104 = !{!14, !98} +!105 = !{!106, !107} +!106 = !DITemplateTypeParameter(name: "x", type: !14) +!107 = !DITemplateTypeParameter(type: !108) +!108 = !DICompositeType(tag: DW_TAG_structure_type, name: "z", scope: !109, file: !6, line: 27, flags: DIFlagFwdDecl, identifier: "_ZTSN2aa2ac1zI1eEE") +!109 = !DINamespace(name: "ac", scope: !52) +!110 = !DILocalVariable(name: "ap", scope: !78, file: !6, line: 41, type: !111) +!111 = !DIDerivedType(tag: DW_TAG_typedef, name: "ae", scope: !52, file: !6, line: 29, baseType: !112) +!112 = distinct !DICompositeType(tag: DW_TAG_class_type, name: "y >", scope: !52, file: !6, line: 20, size: 8, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !113, templateParams: !124, identifier: "_ZTSN2aa1yIP1hNS_2ac1zI1eEEEE") +!113 = !{!114, !118, !121} +!114 = !DISubprogram(name: "y", scope: !112, file: !6, line: 22, type: !115, scopeLine: 22, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagOptimized) +!115 = !DISubroutineType(types: !116) +!116 = !{null, !117, !27} +!117 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !112, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer) +!118 = !DISubprogram(name: "~y", scope: !112, file: !6, line: 23, type: !119, scopeLine: 23, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagOptimized) +!119 = !DISubroutineType(types: !120) +!120 = !{null, !117} +!121 = !DISubprogram(name: "ab", linkageName: "_ZN2aa1yIP1hNS_2ac1zI1eEEE2abEv", scope: !112, file: !6, line: 24, type: !122, scopeLine: 24, flags: DIFlagPublic | DIFlagPrototyped, spFlags: DISPFlagOptimized) +!122 = !DISubroutineType(types: !123) +!123 = !{!27, !117} +!124 = !{!125, !107} +!125 = !DITemplateTypeParameter(name: "x", type: !27) +!126 = !DILocation(line: 0, scope: !78) +!127 = !DILocation(line: 40, column: 5, scope: !78) +!128 = !DILocation(line: 40, column: 11, scope: !78) +!129 = !DILocation(line: 40, column: 14, scope: !78) +!130 = !DILocation(line: 41, column: 5, scope: !78) +!131 = !DILocation(line: 41, column: 11, scope: !78) +!132 = !DILocation(line: 41, column: 16, scope: !78) +!133 = !{!134, !134, i64 0} +!134 = !{!"any pointer", !135, i64 0} +!135 = !{!"omnipotent char", !136, i64 0} +!136 = !{!"Simple C++ TBAA"} +!137 = !DILocation(line: 41, column: 14, scope: !78) +!138 = !DILocation(line: 42, column: 7, scope: !78) +!139 = !DILocation(line: 42, column: 23, scope: !78) +!140 = !DILocation(line: 42, column: 21, scope: !78) +!141 = !DILocation(line: 42, column: 32, scope: !78) +!142 = !DILocation(line: 42, column: 44, scope: !78) +!143 = !DILocation(line: 42, column: 70, scope: !78) +!144 = !{!145, !145, i64 0} +!145 = !{!"_ZTS1n", !135, i64 0} +!146 = !DILocation(line: 42, column: 5, scope: !78) +!147 = !DILocation(line: 43, column: 3, scope: !78) From 66b141c1a4472610c862256213d77098bed45348 Mon Sep 17 00:00:00 2001 From: Simon Pilgrim Date: Sat, 29 Feb 2020 19:24:21 +0000 Subject: [PATCH 050/286] Fix Wdocumentation warning - use tparam for template parameters. NFC. (cherry picked from commit 259238baa659f85d57d6f9bb07a166b6dcf041dd) --- llvm/include/llvm/ADT/CoalescingBitVector.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/include/llvm/ADT/CoalescingBitVector.h b/llvm/include/llvm/ADT/CoalescingBitVector.h index 21b3bbbe2ff27..6fc81b3126450 100644 --- a/llvm/include/llvm/ADT/CoalescingBitVector.h +++ b/llvm/include/llvm/ADT/CoalescingBitVector.h @@ -33,8 +33,8 @@ namespace llvm { /// Compared to SparseBitVector, CoalescingBitVector offers more predictable /// performance for non-sequential find() operations. /// -/// \param IndexT - The type of the index into the bitvector. -/// \param N - The first N coalesced intervals of set bits are stored in-place +/// \tparam IndexT - The type of the index into the bitvector. +/// \tparam N - The first N coalesced intervals of set bits are stored in-place /// (in the initial heap allocation). template class CoalescingBitVector { static_assert(std::is_unsigned::value, From 0f582f5d8538197dcb0cea5ead697589779c13c5 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Thu, 19 Mar 2020 16:21:52 -0700 Subject: [PATCH 051/286] [ADT] CoalescingBitVector: Avoid initial heap allocation, NFC Avoid making a heap allocation when constructing a CoalescingBitVector. This reduces time spent in LiveDebugValues when compiling sqlite3 by 700ms (0.5% of the total User Time). rdar://60046261 Differential Revision: https://reviews.llvm.org/D76465 (cherry picked from commit 4716ebb823e4a3953d7ea803db1949ff699b96c8) --- llvm/include/llvm/ADT/CoalescingBitVector.h | 60 ++++++++----------- llvm/lib/CodeGen/LiveDebugValues.cpp | 20 ++++--- .../unittests/ADT/CoalescingBitVectorTest.cpp | 11 ---- 3 files changed, 38 insertions(+), 53 deletions(-) diff --git a/llvm/include/llvm/ADT/CoalescingBitVector.h b/llvm/include/llvm/ADT/CoalescingBitVector.h index 6fc81b3126450..34352daeea156 100644 --- a/llvm/include/llvm/ADT/CoalescingBitVector.h +++ b/llvm/include/llvm/ADT/CoalescingBitVector.h @@ -21,7 +21,6 @@ #include #include -#include namespace llvm { @@ -34,8 +33,7 @@ namespace llvm { /// performance for non-sequential find() operations. /// /// \tparam IndexT - The type of the index into the bitvector. -/// \tparam N - The first N coalesced intervals of set bits are stored in-place -/// (in the initial heap allocation). +/// \tparam N - The first N coalesced intervals of set bits are stored in-place. template class CoalescingBitVector { static_assert(std::is_unsigned::value, "Index must be an unsigned integer."); @@ -55,13 +53,13 @@ template class CoalescingBitVector { /// Construct by passing in a CoalescingBitVector::Allocator /// reference. CoalescingBitVector(Allocator &Alloc) - : Alloc(&Alloc), Intervals(std::make_unique(Alloc)) {} + : Alloc(&Alloc), Intervals(Alloc) {} /// \name Copy/move constructors and assignment operators. /// @{ CoalescingBitVector(const ThisT &Other) - : Alloc(Other.Alloc), Intervals(std::make_unique(*Other.Alloc)) { + : Alloc(Other.Alloc), Intervals(*Other.Alloc) { set(Other); } @@ -71,27 +69,21 @@ template class CoalescingBitVector { return *this; } - CoalescingBitVector(ThisT &&Other) - : Alloc(Other.Alloc), Intervals(std::move(Other.Intervals)) {} - - ThisT &operator=(ThisT &&Other) { - Alloc = Other.Alloc; - Intervals = std::move(Other.Intervals); - return *this; - } + CoalescingBitVector(ThisT &&Other) = delete; + ThisT &operator=(ThisT &&Other) = delete; /// @} /// Clear all the bits. - void clear() { Intervals->clear(); } + void clear() { Intervals.clear(); } /// Check whether no bits are set. - bool empty() const { return Intervals->empty(); } + bool empty() const { return Intervals.empty(); } /// Count the number of set bits. unsigned count() const { unsigned Bits = 0; - for (auto It = Intervals->begin(), End = Intervals->end(); It != End; ++It) + for (auto It = Intervals.begin(), End = Intervals.end(); It != End; ++It) Bits += 1 + It.stop() - It.start(); return Bits; } @@ -112,7 +104,7 @@ template class CoalescingBitVector { /// This method does /not/ support setting already-set bits, see \ref set /// for the rationale. For a safe set union operation, use \ref operator|=. void set(const ThisT &Other) { - for (auto It = Other.Intervals->begin(), End = Other.Intervals->end(); + for (auto It = Other.Intervals.begin(), End = Other.Intervals.end(); It != End; ++It) insert(It.start(), It.stop()); } @@ -125,8 +117,8 @@ template class CoalescingBitVector { /// Check whether the bit at \p Index is set. bool test(IndexT Index) const { - const auto It = Intervals->find(Index); - if (It == Intervals->end()) + const auto It = Intervals.find(Index); + if (It == Intervals.end()) return false; assert(It.stop() >= Index && "Interval must end after Index"); return It.start() <= Index; @@ -140,8 +132,8 @@ template class CoalescingBitVector { /// Reset the bit at \p Index. Supports resetting an already-unset bit. void reset(IndexT Index) { - auto It = Intervals->find(Index); - if (It == Intervals->end()) + auto It = Intervals.find(Index); + if (It == Intervals.end()) return; // Split the interval containing Index into up to two parts: one from @@ -169,7 +161,7 @@ template class CoalescingBitVector { getOverlaps(RHS, Overlaps); // Insert the non-overlapping parts of all the intervals from RHS. - for (auto It = RHS.Intervals->begin(), End = RHS.Intervals->end(); + for (auto It = RHS.Intervals.begin(), End = RHS.Intervals.end(); It != End; ++It) { IndexT Start = It.start(); IndexT Stop = It.stop(); @@ -205,7 +197,7 @@ template class CoalescingBitVector { IndexT OlapStart, OlapStop; std::tie(OlapStart, OlapStop) = Overlap; - auto It = Intervals->find(OlapStart); + auto It = Intervals.find(OlapStart); IndexT CurrStart = It.start(); IndexT CurrStop = It.stop(); assert(CurrStart <= OlapStart && OlapStop <= CurrStop && @@ -227,14 +219,14 @@ template class CoalescingBitVector { // We cannot just use std::equal because it checks the dereferenced values // of an iterator pair for equality, not the iterators themselves. In our // case that results in comparison of the (unused) IntervalMap values. - auto ItL = Intervals->begin(); - auto ItR = RHS.Intervals->begin(); - while (ItL != Intervals->end() && ItR != RHS.Intervals->end() && + auto ItL = Intervals.begin(); + auto ItR = RHS.Intervals.begin(); + while (ItL != Intervals.end() && ItR != RHS.Intervals.end() && ItL.start() == ItR.start() && ItL.stop() == ItR.stop()) { ++ItL; ++ItR; } - return ItL == Intervals->end() && ItR == RHS.Intervals->end(); + return ItL == Intervals.end() && ItR == RHS.Intervals.end(); } bool operator!=(const ThisT &RHS) const { return !operator==(RHS); } @@ -324,15 +316,15 @@ template class CoalescingBitVector { } }; - const_iterator begin() const { return const_iterator(Intervals->begin()); } + const_iterator begin() const { return const_iterator(Intervals.begin()); } const_iterator end() const { return const_iterator(); } /// Return an iterator pointing to the first set bit AT, OR AFTER, \p Index. /// If no such set bit exists, return end(). This is like std::lower_bound. const_iterator find(IndexT Index) const { - auto UnderlyingIt = Intervals->find(Index); - if (UnderlyingIt == Intervals->end()) + auto UnderlyingIt = Intervals.find(Index); + if (UnderlyingIt == Intervals.end()) return end(); auto It = const_iterator(UnderlyingIt); It.advanceTo(Index); @@ -341,7 +333,7 @@ template class CoalescingBitVector { void print(raw_ostream &OS) const { OS << "{"; - for (auto It = Intervals->begin(), End = Intervals->end(); It != End; + for (auto It = Intervals.begin(), End = Intervals.end(); It != End; ++It) { OS << "[" << It.start(); if (It.start() != It.stop()) @@ -362,13 +354,13 @@ template class CoalescingBitVector { #endif private: - void insert(IndexT Start, IndexT End) { Intervals->insert(Start, End, 0); } + void insert(IndexT Start, IndexT End) { Intervals.insert(Start, End, 0); } /// Record the overlaps between \p this and \p Other in \p Overlaps. Return /// true if there is any overlap. bool getOverlaps(const ThisT &Other, SmallVectorImpl &Overlaps) const { - for (IntervalMapOverlaps I(*Intervals, *Other.Intervals); + for (IntervalMapOverlaps I(Intervals, Other.Intervals); I.valid(); ++I) Overlaps.emplace_back(I.start(), I.stop()); assert(std::is_sorted(Overlaps.begin(), Overlaps.end(), @@ -409,7 +401,7 @@ template class CoalescingBitVector { } Allocator *Alloc; - std::unique_ptr Intervals; + MapT Intervals; }; } // namespace llvm diff --git a/llvm/lib/CodeGen/LiveDebugValues.cpp b/llvm/lib/CodeGen/LiveDebugValues.cpp index a013c419b7c79..89c3bcf52cddf 100644 --- a/llvm/lib/CodeGen/LiveDebugValues.cpp +++ b/llvm/lib/CodeGen/LiveDebugValues.cpp @@ -482,7 +482,8 @@ class LiveDebugValues : public MachineFunctionPass { } }; - using VarLocInMBB = SmallDenseMap; + using VarLocInMBB = + SmallDenseMap>; struct TransferDebugPair { MachineInstr *TransferInst; ///< Instruction where this transfer occurs. LocIndex LocationID; ///< Location number for the transfer dest. @@ -573,15 +574,17 @@ class LiveDebugValues : public MachineFunctionPass { SmallVectorImpl &UsedRegs) const; VarLocSet &getVarLocsInMBB(const MachineBasicBlock *MBB, VarLocInMBB &Locs) { - auto Result = Locs.try_emplace(MBB, Alloc); - return Result.first->second; + std::unique_ptr &VLS = Locs[MBB]; + if (!VLS) + VLS = std::make_unique(Alloc); + return *VLS.get(); } const VarLocSet &getVarLocsInMBB(const MachineBasicBlock *MBB, const VarLocInMBB &Locs) const { auto It = Locs.find(MBB); assert(It != Locs.end() && "MBB not in map"); - return It->second; + return *It->second.get(); } /// Tests whether this instruction is a spill to a stack location. @@ -1479,10 +1482,11 @@ bool LiveDebugValues::join( // Just copy over the Out locs to incoming locs for the first visited // predecessor, and for all other predecessors join the Out locs. + VarLocSet &OutLocVLS = *OL->second.get(); if (!NumVisited) - InLocsT = OL->second; + InLocsT = OutLocVLS; else - InLocsT &= OL->second; + InLocsT &= OutLocVLS; LLVM_DEBUG({ if (!InLocsT.empty()) { @@ -1554,7 +1558,7 @@ void LiveDebugValues::flushPendingLocs(VarLocInMBB &PendingInLocs, for (auto &Iter : PendingInLocs) { // Map is keyed on a constant pointer, unwrap it so we can insert insts. auto &MBB = const_cast(*Iter.first); - VarLocSet &Pending = Iter.second; + VarLocSet &Pending = *Iter.second.get(); for (uint64_t ID : Pending) { // The ID location is live-in to MBB -- work out what kind of machine @@ -1703,7 +1707,7 @@ bool LiveDebugValues::ExtendRanges(MachineFunction &MF) { // Initialize per-block structures and scan for fragment overlaps. for (auto &MBB : MF) { - PendingInLocs.try_emplace(&MBB, Alloc); + PendingInLocs[&MBB] = std::make_unique(Alloc); for (auto &MI : MBB) { if (MI.isDebugValue()) diff --git a/llvm/unittests/ADT/CoalescingBitVectorTest.cpp b/llvm/unittests/ADT/CoalescingBitVectorTest.cpp index 02a5bde2bfacd..9536efe742a27 100644 --- a/llvm/unittests/ADT/CoalescingBitVectorTest.cpp +++ b/llvm/unittests/ADT/CoalescingBitVectorTest.cpp @@ -77,17 +77,6 @@ TEST(CoalescingBitVector, Copy) { EXPECT_TRUE(elementsMatch(BV2, {0})); } -TEST(CoalescingBitVector, Move) { - UBitVec::Allocator Alloc; - UBitVec BV1(Alloc); - BV1.set(0); - UBitVec BV2 = std::move(BV1); - EXPECT_TRUE(elementsMatch(BV2, {0})); - BV2.set(5); - BV1 = std::move(BV2); - EXPECT_TRUE(elementsMatch(BV1, {0, 5})); -} - TEST(CoalescingBitVectorTest, Iterators) { UBitVec::Allocator Alloc; UBitVec BV(Alloc); From c539f3e62b5fd03de3b741d1a742d238e9f39c92 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Thu, 19 Mar 2020 16:40:58 -0700 Subject: [PATCH 052/286] [ADT] CoalescingBitVector: Add advanceToLowerBound iterator operation advanceToLowerBound moves an iterator to the first bit set at, or after, the given index. This can be faster than doing IntervalMap::find. rdar://60046261 Differential Revision: https://reviews.llvm.org/D76466 (cherry picked from commit a3fd1a1c744f4fa0bdefc77f5ec00141fb1f6d2a) --- llvm/include/llvm/ADT/CoalescingBitVector.h | 25 +++++++++++- .../unittests/ADT/CoalescingBitVectorTest.cpp | 38 +++++++++++++++++++ 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/llvm/include/llvm/ADT/CoalescingBitVector.h b/llvm/include/llvm/ADT/CoalescingBitVector.h index 34352daeea156..8ef6f4fac0a1b 100644 --- a/llvm/include/llvm/ADT/CoalescingBitVector.h +++ b/llvm/include/llvm/ADT/CoalescingBitVector.h @@ -266,9 +266,9 @@ template class CoalescingBitVector { } /// Advance the iterator to \p Index, if it is contained within the current - /// interval. + /// interval. The public-facing method which supports advancing past the + /// current interval is \ref advanceToLowerBound. void advanceTo(IndexT Index) { - assert(OffsetIntoMapIterator == 0 && "Not implemented"); assert(Index <= CachedStop && "Cannot advance to OOB index"); if (Index < CachedStart) // We're already past this index. @@ -314,6 +314,25 @@ template class CoalescingBitVector { operator++(); return tmp; } + + /// Advance the iterator to the first set bit AT, OR AFTER, \p Index. If + /// no such set bit exists, advance to end(). This is like std::lower_bound. + /// This is useful if \p Index is close to the current iterator position. + /// However, unlike \ref find(), this has worst-case O(n) performance. + void advanceToLowerBound(IndexT Index) { + if (OffsetIntoMapIterator == kIteratorAtTheEndOffset) + return; + + // Advance to the first interval containing (or past) Index, or to end(). + while (Index > CachedStop) { + ++MapIterator; + resetCache(); + if (OffsetIntoMapIterator == kIteratorAtTheEndOffset) + return; + } + + advanceTo(Index); + } }; const_iterator begin() const { return const_iterator(Intervals.begin()); } @@ -322,6 +341,8 @@ template class CoalescingBitVector { /// Return an iterator pointing to the first set bit AT, OR AFTER, \p Index. /// If no such set bit exists, return end(). This is like std::lower_bound. + /// This has worst-case logarithmic performance (roughly O(log(gaps between + /// contiguous ranges))). const_iterator find(IndexT Index) const { auto UnderlyingIt = Intervals.find(Index); if (UnderlyingIt == Intervals.end()) diff --git a/llvm/unittests/ADT/CoalescingBitVectorTest.cpp b/llvm/unittests/ADT/CoalescingBitVectorTest.cpp index 9536efe742a27..06ac5df721bed 100644 --- a/llvm/unittests/ADT/CoalescingBitVectorTest.cpp +++ b/llvm/unittests/ADT/CoalescingBitVectorTest.cpp @@ -453,6 +453,44 @@ TEST(CoalescingBitVectorTest, FindLowerBound) { EXPECT_EQ(*BV.find(3), 3u); } +TEST(CoalescingBitVectorTest, AdvanceToLowerBound) { + U64BitVec::Allocator Alloc; + U64BitVec BV(Alloc); + uint64_t BigNum1 = uint64_t(1) << 32; + uint64_t BigNum2 = (uint64_t(1) << 33) + 1; + + auto advFromBegin = [&](uint64_t To) -> U64BitVec::const_iterator { + auto It = BV.begin(); + It.advanceToLowerBound(To); + return It; + }; + + EXPECT_TRUE(advFromBegin(BigNum1) == BV.end()); + BV.set(BigNum1); + auto Find1 = advFromBegin(BigNum1); + EXPECT_EQ(*Find1, BigNum1); + BV.set(BigNum2); + auto Find2 = advFromBegin(BigNum1); + EXPECT_EQ(*Find2, BigNum1); + auto Find3 = advFromBegin(BigNum2); + EXPECT_EQ(*Find3, BigNum2); + BV.reset(BigNum1); + auto Find4 = advFromBegin(BigNum1); + EXPECT_EQ(*Find4, BigNum2); + + BV.clear(); + BV.set({1, 2, 3}); + EXPECT_EQ(*advFromBegin(2), 2u); + EXPECT_EQ(*advFromBegin(3), 3u); + auto It = BV.begin(); + It.advanceToLowerBound(0); + EXPECT_EQ(*It, 1u); + It.advanceToLowerBound(100); + EXPECT_TRUE(It == BV.end()); + It.advanceToLowerBound(100); + EXPECT_TRUE(It == BV.end()); +} + TEST(CoalescingBitVectorTest, Print) { std::string S; { From 8a4252707c1795c16610801d428fbe6ba6b6c1fc Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Thu, 19 Mar 2020 16:43:40 -0700 Subject: [PATCH 053/286] [LiveDebugValues] Speed up collectIDsForRegs, NFC Use the advanceToLowerBound operation available on CoalescingBitVector iterators to speed up collection of variables which reside within some set of registers. The speedup comes from avoiding repeated top-down traversals in IntervalMap::find. The linear scan forward from one register interval to the next is unlikely to be as expensive as a full IntervalMap search starting from the root. This reduces time spent in LiveDebugValues when compiling sqlite3 by 200ms (about 0.1% - 0.2% of the total User Time). Depends on D76466. rdar://60046261 Differential Revision: https://reviews.llvm.org/D76467 (cherry picked from commit a24594335513f1ecf07a785a6633f9d3956c0ad2) --- llvm/lib/CodeGen/LiveDebugValues.cpp | 63 ++++++++++++++++++---------- 1 file changed, 41 insertions(+), 22 deletions(-) diff --git a/llvm/lib/CodeGen/LiveDebugValues.cpp b/llvm/lib/CodeGen/LiveDebugValues.cpp index 89c3bcf52cddf..9816bd8f97ec5 100644 --- a/llvm/lib/CodeGen/LiveDebugValues.cpp +++ b/llvm/lib/CodeGen/LiveDebugValues.cpp @@ -110,7 +110,10 @@ static bool isRegOtherThanSPAndFP(const MachineOperand &Op, namespace { +// Max out the number of statically allocated elements in DefinedRegsSet, as +// this prevents fallback to std::set::count() operations. using DefinedRegsSet = SmallSet; + using VarLocSet = CoalescingBitVector; /// A type-checked pair of {Register Location (or 0), Index}, used to index @@ -563,10 +566,11 @@ class LiveDebugValues : public MachineFunctionPass { } }; - /// Collect all VarLoc IDs from \p CollectFrom for VarLocs which are located - /// in \p Reg, of kind RegisterKind. Insert collected IDs in \p Collected. - void collectIDsForReg(VarLocSet &Collected, uint32_t Reg, - const VarLocSet &CollectFrom) const; + /// Collect all VarLoc IDs from \p CollectFrom for VarLocs of kind + /// RegisterKind which are located in any reg in \p Regs. Insert collected IDs + /// into \p Collected. + void collectIDsForRegs(VarLocSet &Collected, const DefinedRegsSet &Regs, + const VarLocSet &CollectFrom) const; /// Get the registers which are used by VarLocs of kind RegisterKind tracked /// by \p CollectFrom. @@ -773,16 +777,30 @@ LiveDebugValues::OpenRangesSet::getEntryValueBackup(DebugVariable Var) { return llvm::None; } -void LiveDebugValues::collectIDsForReg(VarLocSet &Collected, uint32_t Reg, - const VarLocSet &CollectFrom) const { - // The half-open interval [FirstIndexForReg, FirstInvalidIndex) contains all - // possible VarLoc IDs for VarLocs of kind RegisterKind which live in Reg. - uint64_t FirstIndexForReg = LocIndex::rawIndexForReg(Reg); - uint64_t FirstInvalidIndex = LocIndex::rawIndexForReg(Reg + 1); - // Iterate through that half-open interval and collect all the set IDs. - for (auto It = CollectFrom.find(FirstIndexForReg), End = CollectFrom.end(); - It != End && *It < FirstInvalidIndex; ++It) - Collected.set(*It); +void LiveDebugValues::collectIDsForRegs(VarLocSet &Collected, + const DefinedRegsSet &Regs, + const VarLocSet &CollectFrom) const { + assert(!Regs.empty() && "Nothing to collect"); + SmallVector SortedRegs; + for (Register Reg : Regs) + SortedRegs.push_back(Reg); + array_pod_sort(SortedRegs.begin(), SortedRegs.end()); + auto It = CollectFrom.find(LocIndex::rawIndexForReg(SortedRegs.front())); + auto End = CollectFrom.end(); + for (uint32_t Reg : SortedRegs) { + // The half-open interval [FirstIndexForReg, FirstInvalidIndex) contains all + // possible VarLoc IDs for VarLocs of kind RegisterKind which live in Reg. + uint64_t FirstIndexForReg = LocIndex::rawIndexForReg(Reg); + uint64_t FirstInvalidIndex = LocIndex::rawIndexForReg(Reg + 1); + It.advanceToLowerBound(FirstIndexForReg); + + // Iterate through that half-open interval and collect all the set IDs. + for (; It != End && *It < FirstInvalidIndex; ++It) + Collected.set(*It); + + if (It == End) + return; + } } void LiveDebugValues::getUsedRegs(const VarLocSet &CollectFrom, @@ -803,7 +821,7 @@ void LiveDebugValues::getUsedRegs(const VarLocSet &CollectFrom, // even if there aren't any VarLocs living in `FoundReg+1`, we're still // guaranteed to move on to the next register (or to end()). uint64_t NextRegIndex = LocIndex::rawIndexForReg(FoundReg + 1); - It = CollectFrom.find(NextRegIndex); + It.advanceToLowerBound(NextRegIndex); } } @@ -1076,9 +1094,7 @@ void LiveDebugValues::transferRegisterDef( unsigned SP = TLI->getStackPointerRegisterToSaveRestore(); // Find the regs killed by MI, and find regmasks of preserved regs. - // Max out the number of statically allocated elements in `DeadRegs`, as this - // prevents fallback to std::set::count() operations. - SmallSet DeadRegs; + DefinedRegsSet DeadRegs; SmallVector RegMasks; for (const MachineOperand &MO : MI.operands()) { // Determine whether the operand is a register def. @@ -1097,9 +1113,6 @@ void LiveDebugValues::transferRegisterDef( // Erase VarLocs which reside in one of the dead registers. For performance // reasons, it's critical to not iterate over the full set of open VarLocs. // Iterate over the set of dying/used regs instead. - VarLocSet KillSet(Alloc); - for (uint32_t DeadReg : DeadRegs) - collectIDsForReg(KillSet, DeadReg, OpenRanges.getVarLocs()); if (!RegMasks.empty()) { SmallVector UsedRegs; getUsedRegs(OpenRanges.getVarLocs(), UsedRegs); @@ -1121,9 +1134,15 @@ void LiveDebugValues::transferRegisterDef( return MachineOperand::clobbersPhysReg(RegMask, Reg); }); if (AnyRegMaskKillsReg) - collectIDsForReg(KillSet, Reg, OpenRanges.getVarLocs()); + DeadRegs.insert(Reg); } } + + if (DeadRegs.empty()) + return; + + VarLocSet KillSet(Alloc); + collectIDsForRegs(KillSet, DeadRegs, OpenRanges.getVarLocs()); OpenRanges.erase(KillSet, VarLocIDs); if (auto *TPC = getAnalysisIfAvailable()) { From 985aabf4eae9fa6d9dda553b3a0d6ea2acacf07a Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Fri, 20 Mar 2020 12:37:58 -0700 Subject: [PATCH 054/286] unittest: Work around build failure on MSVC builders MSVC insists on using the deleted move constructor instead of the copy constructor: http://lab.llvm.org:8011/builders/lld-x86_64-win7/builds/41203 C:\ps4-buildslave2\lld-x86_64-win7\llvm-project\llvm\unittests\ADT\CoalescingBitVectorTest.cpp(193): error C2280: 'llvm::CoalescingBitVector::CoalescingBitVector(llvm::CoalescingBitVector &&)': attempting to reference a deleted function (cherry picked from commit 7ec24448801c30bb0b2127f2c7b7ac10c1a009fc) --- .../unittests/ADT/CoalescingBitVectorTest.cpp | 27 ++++++++----------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/llvm/unittests/ADT/CoalescingBitVectorTest.cpp b/llvm/unittests/ADT/CoalescingBitVectorTest.cpp index 06ac5df721bed..4f87bf415bebb 100644 --- a/llvm/unittests/ADT/CoalescingBitVectorTest.cpp +++ b/llvm/unittests/ADT/CoalescingBitVectorTest.cpp @@ -183,14 +183,12 @@ TEST(CoalescingBitVectorTest, Comparison) { // A simple implementation of set union, used to double-check the human // "expected" answer. -UBitVec simpleUnion(UBitVec::Allocator &Alloc, const UBitVec &LHS, +void simpleUnion(UBitVec &Union, const UBitVec &LHS, const UBitVec &RHS) { - UBitVec Union(Alloc); for (unsigned Bit : LHS) Union.test_and_set(Bit); for (unsigned Bit : RHS) Union.test_and_set(Bit); - return Union; } TEST(CoalescingBitVectorTest, Union) { @@ -204,7 +202,8 @@ TEST(CoalescingBitVectorTest, Union) { BV1.set(LHS); UBitVec BV2(Alloc); BV2.set(RHS); - const UBitVec &DoubleCheckedExpected = simpleUnion(Alloc, BV1, BV2); + UBitVec DoubleCheckedExpected(Alloc); + simpleUnion(DoubleCheckedExpected, BV1, BV2); ASSERT_TRUE(elementsMatch(DoubleCheckedExpected, Expected)); BV1 |= BV2; ASSERT_TRUE(elementsMatch(BV1, Expected)); @@ -277,13 +276,11 @@ TEST(CoalescingBitVectorTest, Union) { // A simple implementation of set intersection, used to double-check the // human "expected" answer. -UBitVec simpleIntersection(UBitVec::Allocator &Alloc, const UBitVec &LHS, - const UBitVec &RHS) { - UBitVec Intersection(Alloc); +void simpleIntersection(UBitVec &Intersection, const UBitVec &LHS, + const UBitVec &RHS) { for (unsigned Bit : LHS) if (RHS.test(Bit)) Intersection.set(Bit); - return Intersection; } TEST(CoalescingBitVectorTest, Intersection) { @@ -297,7 +294,8 @@ TEST(CoalescingBitVectorTest, Intersection) { BV1.set(LHS); UBitVec BV2(Alloc); BV2.set(RHS); - const UBitVec &DoubleCheckedExpected = simpleIntersection(Alloc, BV1, BV2); + UBitVec DoubleCheckedExpected(Alloc); + simpleIntersection(DoubleCheckedExpected, BV1, BV2); ASSERT_TRUE(elementsMatch(DoubleCheckedExpected, Expected)); BV1 &= BV2; ASSERT_TRUE(elementsMatch(BV1, Expected)); @@ -356,14 +354,11 @@ TEST(CoalescingBitVectorTest, Intersection) { // A simple implementation of set intersection-with-complement, used to // double-check the human "expected" answer. -UBitVec simpleIntersectionWithComplement(UBitVec::Allocator &Alloc, - const UBitVec &LHS, - const UBitVec &RHS) { - UBitVec Intersection(Alloc); +void simpleIntersectionWithComplement(UBitVec &Intersection, const UBitVec &LHS, + const UBitVec &RHS) { for (unsigned Bit : LHS) if (!RHS.test(Bit)) Intersection.set(Bit); - return Intersection; } TEST(CoalescingBitVectorTest, IntersectWithComplement) { @@ -378,8 +373,8 @@ TEST(CoalescingBitVectorTest, IntersectWithComplement) { BV1.set(LHS); UBitVec BV2(Alloc); BV2.set(RHS); - const UBitVec &DoubleCheckedExpected = - simpleIntersectionWithComplement(Alloc, BV1, BV2); + UBitVec DoubleCheckedExpected(Alloc); + simpleIntersectionWithComplement(DoubleCheckedExpected, BV1, BV2); ASSERT_TRUE(elementsMatch(DoubleCheckedExpected, Expected)); BV1.intersectWithComplement(BV2); ASSERT_TRUE(elementsMatch(BV1, Expected)); From b3b3dfa7365227441ce5ed04f6655844c889ac1c Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Fri, 20 Mar 2020 17:00:22 -0700 Subject: [PATCH 055/286] [lldb/SwiftASTContext] Use PlatformDarwin::GetCurrent.*Directory()' Use GetCurrentToolchainDirectory and GetCurrentCommandLineToolsDirectory from PlatformDarwin. --- lldb/source/Symbol/SwiftASTContext.cpp | 37 ++------------------------ 1 file changed, 2 insertions(+), 35 deletions(-) diff --git a/lldb/source/Symbol/SwiftASTContext.cpp b/lldb/source/Symbol/SwiftASTContext.cpp index 74b47b9c5cff5..96f127b301104 100644 --- a/lldb/source/Symbol/SwiftASTContext.cpp +++ b/lldb/source/Symbol/SwiftASTContext.cpp @@ -1486,40 +1486,6 @@ static SDKTypeMinVersion GetSDKType(const llvm::Triple &target, } } -static std::string GetCurrentToolchainPath() { - const char substr[] = ".xctoolchain/"; - - { - if (FileSpec fspec = HostInfo::GetShlibDir()) { - std::string path_to_shlib = fspec.GetPath(); - size_t pos = path_to_shlib.rfind(substr); - if (pos != std::string::npos) { - path_to_shlib.erase(pos + strlen(substr)); - return path_to_shlib; - } - } - } - - return {}; -} - -static std::string GetCurrentCLToolsPath() { - const char substr[] = "/CommandLineTools/"; - - { - if (FileSpec fspec = HostInfo::GetShlibDir()) { - std::string path_to_shlib = fspec.GetPath(); - size_t pos = path_to_shlib.rfind(substr); - if (pos != std::string::npos) { - path_to_shlib.erase(pos + strlen(substr)); - return path_to_shlib; - } - } - } - - return {}; -} - /// Return the name of the OS-specific subdirectory containing the /// Swift stdlib needed for \p target. StringRef SwiftASTContext::GetSwiftStdlibOSDir(const llvm::Triple &target, @@ -1549,7 +1515,8 @@ StringRef SwiftASTContext::GetResourceDir(const llvm::Triple &triple) { auto value = GetResourceDir( platform_sdk_path, swift_stdlib_os_dir, GetSwiftResourceDir().GetPath(), PlatformDarwin::GetXcodeContentsDirectory().GetPath(), - GetCurrentToolchainPath(), GetCurrentCLToolsPath()); + PlatformDarwin::GetCurrentToolchainDirectory().GetPath(), + PlatformDarwin::GetCurrentCommandLineToolsDirectory().GetPath()); g_resource_dir_cache.insert({key, value}); return g_resource_dir_cache[key]; } From 0e97b1a50a477acad46d2510b6cebaa2dadcfc1d Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 18 Mar 2020 15:46:31 -0700 Subject: [PATCH 056/286] Fix -fsanitize=array-bound to treat T[0] union members as flexible array members regardless of whether they're the last member of the union. (cherry picked from commit f18233dad4669eaf59ca996dca79beae8d364247) --- clang/lib/CodeGen/CGExpr.cpp | 8 ++++++++ clang/test/CodeGen/bounds-checking.c | 22 ++++++++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 6ed796046ef29..575df186e2cd2 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -860,8 +860,12 @@ void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, static bool isFlexibleArrayMemberExpr(const Expr *E) { // For compatibility with existing code, we treat arrays of length 0 or // 1 as flexible array members. + // FIXME: This is inconsistent with the warning code in SemaChecking. Unify + // the two mechanisms. const ArrayType *AT = E->getType()->castAsArrayTypeUnsafe(); if (const auto *CAT = dyn_cast(AT)) { + // FIXME: Sema doesn't treat [1] as a flexible array member if the bound + // was produced by macro expansion. if (CAT->getSize().ugt(1)) return false; } else if (!isa(AT)) @@ -874,6 +878,10 @@ static bool isFlexibleArrayMemberExpr(const Expr *E) { // FIXME: If the base type of the member expr is not FD->getParent(), // this should not be treated as a flexible array member access. if (const auto *FD = dyn_cast(ME->getMemberDecl())) { + // FIXME: Sema doesn't treat a T[1] union member as a flexible array + // member, only a T[0] or T[] member gets that treatment. + if (FD->getParent()->isUnion()) + return true; RecordDecl::field_iterator FI( DeclContext::decl_iterator(const_cast(FD))); return ++FI == FD->getParent()->field_end(); diff --git a/clang/test/CodeGen/bounds-checking.c b/clang/test/CodeGen/bounds-checking.c index 2e6a08650dd97..15cef8c007a55 100644 --- a/clang/test/CodeGen/bounds-checking.c +++ b/clang/test/CodeGen/bounds-checking.c @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -fsanitize=local-bounds -emit-llvm -triple x86_64-apple-darwin10 %s -o - | FileCheck %s // RUN: %clang_cc1 -fsanitize=local-bounds -fexperimental-new-pass-manager -emit-llvm -triple x86_64-apple-darwin10 %s -o - | FileCheck %s -// RUN: %clang_cc1 -fsanitize=array-bounds -O -fsanitize-trap=array-bounds -emit-llvm -triple x86_64-apple-darwin10 -DNO_DYNAMIC %s -o - | FileCheck %s -// RUN: %clang_cc1 -fsanitize=array-bounds -O -fsanitize-trap=array-bounds -fexperimental-new-pass-manager -emit-llvm -triple x86_64-apple-darwin10 -DNO_DYNAMIC %s -o - | FileCheck %s +// RUN: %clang_cc1 -fsanitize=array-bounds -O -fsanitize-trap=array-bounds -emit-llvm -triple x86_64-apple-darwin10 -DNO_DYNAMIC %s -o - | FileCheck %s --check-prefixes=CHECK,NONLOCAL +// RUN: %clang_cc1 -fsanitize=array-bounds -O -fsanitize-trap=array-bounds -fexperimental-new-pass-manager -emit-llvm -triple x86_64-apple-darwin10 -DNO_DYNAMIC %s -o - | FileCheck %s --check-prefixes=CHECK,NONLOCAL // // REQUIRES: x86-registered-target @@ -31,3 +31,21 @@ void f3() { // CHECK: call {{.*}} @llvm.trap a[2] = 1; } + +union U { int a[0]; int b[1]; int c[2]; }; + +// CHECK-LABEL: define {{.*}} @f4 +int f4(union U *u, int i) { + // a and b are treated as flexible array members. + // CHECK-NOT: @llvm.trap + return u->a[i] + u->b[i]; + // CHECK: } +} + +// CHECK-LABEL: define {{.*}} @f5 +int f5(union U *u, int i) { + // c is not a flexible array member. + // NONLOCAL: call {{.*}} @llvm.trap + return u->c[i]; + // CHECK: } +} From b6a9124bf4ced4b66a46ea4de903eeb6e1524cbf Mon Sep 17 00:00:00 2001 From: Elizabeth Andrews Date: Wed, 12 Feb 2020 11:30:02 -0800 Subject: [PATCH 057/286] Fix type-dependency of bitfields in templates This patch is a follow up to 878a24ee244a24. Name of bitfields with value-dependent width should be set as type-dependent. This patch adds the required value-dependency check and sets the type-dependency accordingly. Patch fixes PR44886 Differential revision: https://reviews.llvm.org/D72242 --- clang/lib/AST/Expr.cpp | 5 +++++ clang/test/SemaTemplate/enum-argument.cpp | 3 ++- .../SemaTemplate/value-dependent-bitfield-cond.cpp | 13 +++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 clang/test/SemaTemplate/value-dependent-bitfield-cond.cpp diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 73ddbc62482dd..d39e437e3bcfa 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1685,6 +1685,11 @@ MemberExpr *MemberExpr::Create( CXXRecordDecl *RD = dyn_cast_or_null(DC); if (RD && RD->isDependentContext() && RD->isCurrentInstantiation(DC)) E->setTypeDependent(T->isDependentType()); + + // Bitfield with value-dependent width is type-dependent. + FieldDecl *FD = dyn_cast(MemberDecl); + if (FD && FD->isBitField() && FD->getBitWidth()->isValueDependent()) + E->setTypeDependent(true); } if (HasQualOrFound) { diff --git a/clang/test/SemaTemplate/enum-argument.cpp b/clang/test/SemaTemplate/enum-argument.cpp index a79ed8403e9f4..7ff4196139901 100644 --- a/clang/test/SemaTemplate/enum-argument.cpp +++ b/clang/test/SemaTemplate/enum-argument.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s +// expected-no-diagnostics enum Enum { val = 1 }; template struct C { @@ -30,7 +31,7 @@ namespace rdar8020920 { unsigned long long bitfield : e0; void f(int j) { - bitfield + j; // expected-warning {{expression result unused}} + bitfield + j; } }; } diff --git a/clang/test/SemaTemplate/value-dependent-bitfield-cond.cpp b/clang/test/SemaTemplate/value-dependent-bitfield-cond.cpp new file mode 100644 index 0000000000000..873e4d48e8374 --- /dev/null +++ b/clang/test/SemaTemplate/value-dependent-bitfield-cond.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// expected-no-diagnostics + +template +class A { + int c : b; + +public: + void f() { + if (c) + ; + } +}; From f020ba604f3df6357edd02449c141fd36482811d Mon Sep 17 00:00:00 2001 From: Fred Riss Date: Wed, 11 Mar 2020 10:26:03 -0700 Subject: [PATCH 058/286] [lldb/Target] Initialize new targets environment variables from target.env-vars Summary: The TargetProperties constructor invokes a series of callbacks to prime the properties from the default ones. The one callback in charge of updating the inferior environment was commented out because it crashed. The reason for the crash is that TargetProperties is a parent class of Target and the callbacks were invoked using a Target that was not fully initialized. This patch moves the initial callback invocations to a separate function that can be called at the end the Target constructor, thus preventing the crash. One existing test had to be modified, because the initialization of the environment properties now take place at the time the target is created, not at the first use of the environment (usually launch time). The added test checks that the LaunchInfo object returned by the target has been primed with the values from the settings. Reviewers: jingham, labath Subscribers: lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D76009 (cherry picked from commit 9228a9efc6c57a932d936ebb214f6ff5bafe79ff) --- lldb/include/lldb/Target/Target.h | 2 ++ lldb/source/Target/Target.cpp | 26 +++++++++--------- .../API/commands/settings/TestSettings.py | 27 ++++++++++++------- 3 files changed, 34 insertions(+), 21 deletions(-) diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index 377baf9f4fbda..ade6cce844d5e 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -229,6 +229,8 @@ class TargetProperties : public Properties { bool GetRequireHardwareBreakpoints() const; + void UpdateLaunchInfoFromProperties(); + private: // Callbacks for m_launch_info. static void Arg0ValueChangedCallback(void *target_property_ptr, diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index 55259ab602922..81bd284935fc1 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -117,6 +117,8 @@ Target::Target(Debugger &debugger, const ArchSpec &target_arch, target_arch.GetArchitectureName(), target_arch.GetTriple().getTriple().c_str()); } + + UpdateLaunchInfoFromProperties(); } Target::~Target() { @@ -3799,18 +3801,6 @@ TargetProperties::TargetProperties(Target *target) ConstString("Experimental settings - setting these won't produce " "errors if the setting is not present."), true, m_experimental_properties_up->GetValueProperties()); - - // Update m_launch_info once it was created - Arg0ValueChangedCallback(this, nullptr); - RunArgsValueChangedCallback(this, nullptr); - // EnvVarsValueChangedCallback(this, nullptr); // FIXME: cause segfault in - // Target::GetPlatform() - InputPathValueChangedCallback(this, nullptr); - OutputPathValueChangedCallback(this, nullptr); - ErrorPathValueChangedCallback(this, nullptr); - DetachOnErrorValueChangedCallback(this, nullptr); - DisableASLRValueChangedCallback(this, nullptr); - DisableSTDIOValueChangedCallback(this, nullptr); } else { m_collection_sp = std::make_shared(ConstString("target")); @@ -3829,6 +3819,18 @@ TargetProperties::TargetProperties(Target *target) TargetProperties::~TargetProperties() = default; +void TargetProperties::UpdateLaunchInfoFromProperties() { + Arg0ValueChangedCallback(this, nullptr); + RunArgsValueChangedCallback(this, nullptr); + EnvVarsValueChangedCallback(this, nullptr); + InputPathValueChangedCallback(this, nullptr); + OutputPathValueChangedCallback(this, nullptr); + ErrorPathValueChangedCallback(this, nullptr); + DetachOnErrorValueChangedCallback(this, nullptr); + DisableASLRValueChangedCallback(this, nullptr); + DisableSTDIOValueChangedCallback(this, nullptr); +} + bool TargetProperties::GetInjectLocalVariables( ExecutionContext *exe_ctx) const { const Property *exp_property = m_collection_sp->GetPropertyAtIndex( diff --git a/lldb/test/API/commands/settings/TestSettings.py b/lldb/test/API/commands/settings/TestSettings.py index 1130821bac0f4..0e862aac47524 100644 --- a/lldb/test/API/commands/settings/TestSettings.py +++ b/lldb/test/API/commands/settings/TestSettings.py @@ -219,6 +219,15 @@ def test_run_args_and_env_vars(self): self.addTearDownHook( lambda: self.runCmd("settings clear target.env-vars")) + launch_info = self.dbg.GetTargetAtIndex(0).GetLaunchInfo() + found_env_var = False + for i in range(0, launch_info.GetNumEnvironmentEntries()): + if launch_info.GetEnvironmentEntryAtIndex(i) == "MY_ENV_VAR=YES": + found_env_var = True + break + self.assertTrue(found_env_var, + "MY_ENV_VAR was not set in LunchInfo object") + self.runCmd("process launch --working-dir '{0}'".format(self.get_process_working_directory()), RUN_SUCCEEDED) @@ -239,15 +248,6 @@ def test_pass_host_env_vars(self): """Test that the host env vars are passed to the launched process.""" self.build() - exe = self.getBuildArtifact("a.out") - self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) - - # By default, inherit-env is 'true'. - self.expect( - 'settings show target.inherit-env', - "Default inherit-env is 'true'", - startstr="target.inherit-env (boolean) = true") - # Set some host environment variables now. os.environ["MY_HOST_ENV_VAR1"] = "VAR1" os.environ["MY_HOST_ENV_VAR2"] = "VAR2" @@ -257,6 +257,15 @@ def unset_env_variables(): os.environ.pop("MY_HOST_ENV_VAR1") os.environ.pop("MY_HOST_ENV_VAR2") + exe = self.getBuildArtifact("a.out") + self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) + + # By default, inherit-env is 'true'. + self.expect( + 'settings show target.inherit-env', + "Default inherit-env is 'true'", + startstr="target.inherit-env (boolean) = true") + self.addTearDownHook(unset_env_variables) self.runCmd("process launch --working-dir '{0}'".format(self.get_process_working_directory()), RUN_SUCCEEDED) From e17be10fefdf5ca090e2a77623f8bb96406912df Mon Sep 17 00:00:00 2001 From: Fred Riss Date: Wed, 11 Mar 2020 22:09:11 -0700 Subject: [PATCH 059/286] [lldb/API] Make Launch(Simple) use args and env from target properties Summary: When no arguments or environment is provided to SBTarget::LaunchSimple, make it use the values surrently set in the target properties. You can get the current behavior back by passing an empty array instead. It seems like using the target defaults is a much more intuitive behavior for those APIs. It's unllikely that anyone passed NULL/None to this API after having set properties in order to explicitely ignore them. One direct application of this change is within the testsuite. We have plenty of tests calling LaunchSimple and passing None as environment. If you passed --inferior-env to dotest.py to, for example, set (DY)LD_LIBRARY_PATH, it wouldn't be taken into account. Reviewers: jingham, labath, #libc_abi! Subscribers: libcxx-commits, lldb-commits Tags: #lldb, #libc_abi Differential Revision: https://reviews.llvm.org/D76045 (cherry picked from commit cd7b45057ca9bc72b99a0abc6c9be25e0f72fbcf) --- lldb/include/lldb/API/SBTarget.h | 8 +++++-- lldb/source/API/SBTarget.cpp | 13 +++++++++-- .../API/commands/settings/TestSettings.py | 22 +++++++++++++++---- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h index da2246f7a4eb3..cc6b5a23bb2b9 100644 --- a/lldb/include/lldb/API/SBTarget.h +++ b/lldb/include/lldb/API/SBTarget.h @@ -127,7 +127,9 @@ class LLDB_API SBTarget { /// The argument array. /// /// \param[in] envp - /// The environment array. + /// The environment array. If this is null, the default + /// environment values (provided through `settings set + /// target.env-vars`) will be used. /// /// \param[in] stdin_path /// The path to use when re-directing the STDIN of the new @@ -175,7 +177,9 @@ class LLDB_API SBTarget { /// The argument array. /// /// \param[in] envp - /// The environment array. + /// The environment array. If this isn't provided, the default + /// environment values (provided through `settings set + /// target.env-vars`) will be used. /// /// \param[in] working_directory /// The working directory to have the child process run in diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp index 8e19aeb16bc3e..dcfc0677262ce 100644 --- a/lldb/source/API/SBTarget.cpp +++ b/lldb/source/API/SBTarget.cpp @@ -376,10 +376,19 @@ SBProcess SBTarget::Launch(SBListener &listener, char const **argv, Module *exe_module = target_sp->GetExecutableModulePointer(); if (exe_module) launch_info.SetExecutableFile(exe_module->GetPlatformFileSpec(), true); - if (argv) + if (argv) { launch_info.GetArguments().AppendArguments(argv); - if (envp) + } else { + auto default_launch_info = target_sp->GetProcessLaunchInfo(); + launch_info.GetArguments().AppendArguments( + default_launch_info.GetArguments()); + } + if (envp) { launch_info.GetEnvironment() = Environment(envp); + } else { + auto default_launch_info = target_sp->GetProcessLaunchInfo(); + launch_info.GetEnvironment() = default_launch_info.GetEnvironment(); + } if (listener.IsValid()) launch_info.SetListener(listener.GetSP()); diff --git a/lldb/test/API/commands/settings/TestSettings.py b/lldb/test/API/commands/settings/TestSettings.py index 0e862aac47524..e9d6ff0076509 100644 --- a/lldb/test/API/commands/settings/TestSettings.py +++ b/lldb/test/API/commands/settings/TestSettings.py @@ -205,10 +205,15 @@ def test_disassembler_settings(self): @skipIfDarwinEmbedded # debugserver on ios etc can't write files def test_run_args_and_env_vars(self): + self.do_test_run_args_and_env_vars(use_launchsimple=False) + + @skipIfDarwinEmbedded # debugserver on ios etc can't write files + def test_launchsimple_args_and_env_vars(self): + self.do_test_run_args_and_env_vars(use_launchsimple=True) + + def do_test_run_args_and_env_vars(self, use_launchsimple): """Test that run-args and env-vars are passed to the launched process.""" self.build() - exe = self.getBuildArtifact("a.out") - self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) # Set the run-args and the env-vars. # And add hooks to restore the settings during tearDown(). @@ -219,7 +224,11 @@ def test_run_args_and_env_vars(self): self.addTearDownHook( lambda: self.runCmd("settings clear target.env-vars")) - launch_info = self.dbg.GetTargetAtIndex(0).GetLaunchInfo() + exe = self.getBuildArtifact("a.out") + self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) + + target = self.dbg.GetTargetAtIndex(0) + launch_info = target.GetLaunchInfo() found_env_var = False for i in range(0, launch_info.GetNumEnvironmentEntries()): if launch_info.GetEnvironmentEntryAtIndex(i) == "MY_ENV_VAR=YES": @@ -228,7 +237,12 @@ def test_run_args_and_env_vars(self): self.assertTrue(found_env_var, "MY_ENV_VAR was not set in LunchInfo object") - self.runCmd("process launch --working-dir '{0}'".format(self.get_process_working_directory()), + wd = self.get_process_working_directory() + if use_launchsimple: + process = target.LaunchSimple(None, None, wd) + self.assertTrue(process) + else: + self.runCmd("process launch --working-dir '{0}'".format(wd), RUN_SUCCEEDED) # Read the output file produced by running the program. From e4be9592c9ad7fab07f75a3f9472637b2407cc04 Mon Sep 17 00:00:00 2001 From: Raphael Isemann Date: Fri, 6 Mar 2020 18:42:20 -0800 Subject: [PATCH 060/286] [lldb][NFC] Make TestStats.py not an inline test There is still the bug that empty lines seem to skip any following expressions and it makes it harder to commend between all the comments. Let's make this a normal test instead which is just slightly more verbose but can be properly formatted. (cherry picked from commit 6bbdecc5cf8096148df4726245f3bc60e464c76b) --- .../API/commands/statistics/basic/Makefile | 2 ++ .../commands/statistics/basic/TestStats.py | 35 ++++++++++++++++--- .../test/API/commands/statistics/basic/main.c | 13 +------ 3 files changed, 34 insertions(+), 16 deletions(-) create mode 100644 lldb/test/API/commands/statistics/basic/Makefile diff --git a/lldb/test/API/commands/statistics/basic/Makefile b/lldb/test/API/commands/statistics/basic/Makefile new file mode 100644 index 0000000000000..c9319d6e6888a --- /dev/null +++ b/lldb/test/API/commands/statistics/basic/Makefile @@ -0,0 +1,2 @@ +C_SOURCES := main.c +include Makefile.rules diff --git a/lldb/test/API/commands/statistics/basic/TestStats.py b/lldb/test/API/commands/statistics/basic/TestStats.py index 9f5c7172a65b9..4809adf9060f5 100644 --- a/lldb/test/API/commands/statistics/basic/TestStats.py +++ b/lldb/test/API/commands/statistics/basic/TestStats.py @@ -1,5 +1,32 @@ -from lldbsuite.test import lldbinline -from lldbsuite.test import decorators +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil -lldbinline.MakeInlineTest( - __file__, globals(), [decorators.no_debug_info_test]) +class TestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + def test(self): + self.build() + lldbutil.run_to_source_breakpoint(self, "// break here", lldb.SBFileSpec("main.c")) + + self.expect("statistics disable", substrs=['need to enable statistics before disabling'], error=True) + + # 'expression' should change the statistics. + self.expect("statistics enable") + self.expect("statistics enable", substrs=['already enabled'], error=True) + self.expect("expr patatino", substrs=['27']) + self.expect("statistics disable") + self.expect("statistics dump", substrs=['expr evaluation successes : 1', + 'expr evaluation failures : 0']) + + # 'frame var' with disabled statistics shouldn't change stats. + self.expect("frame var", substrs=['27']) + + self.expect("statistics enable") + # 'frame var' with enabled statistics will change stats. + self.expect("frame var", substrs=['27']) + self.expect("statistics disable") + self.expect("statistics dump", substrs=['frame var successes : 1', + 'frame var failures : 0']) diff --git a/lldb/test/API/commands/statistics/basic/main.c b/lldb/test/API/commands/statistics/basic/main.c index 9adb3a09a0806..2c5b4f5f098ee 100644 --- a/lldb/test/API/commands/statistics/basic/main.c +++ b/lldb/test/API/commands/statistics/basic/main.c @@ -2,17 +2,6 @@ int main(void) { int patatino = 27; - //%self.expect("statistics disable", substrs=['need to enable statistics before disabling'], error=True) - //%self.expect("statistics enable") - //%self.expect("statistics enable", substrs=['already enabled'], error=True) - //%self.expect("expr patatino", substrs=['27']) - //%self.expect("statistics disable") - //%self.expect("statistics dump", substrs=['expr evaluation successes : 1', 'expr evaluation failures : 0']) - //%self.expect("frame var", substrs=['27']) - //%self.expect("statistics enable") - //%self.expect("frame var", substrs=['27']) - //%self.expect("statistics disable") - //%self.expect("statistics dump", substrs=['frame var successes : 1', 'frame var failures : 0']) - return 0; + return 0; // break here } From 7d1bb0364326da5fb3ecbfc6c396d42085651820 Mon Sep 17 00:00:00 2001 From: Raphael Isemann Date: Tue, 17 Mar 2020 14:11:35 +0100 Subject: [PATCH 061/286] [lldb] Tighten checks in TestStats.py Just adding trailing newlines that "...: 1" doesn't match "...: 10". (cherry picked from commit f95541839cb25c883dc530928232105af87c75dc) --- lldb/test/API/commands/statistics/basic/TestStats.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lldb/test/API/commands/statistics/basic/TestStats.py b/lldb/test/API/commands/statistics/basic/TestStats.py index 4809adf9060f5..76bc224338488 100644 --- a/lldb/test/API/commands/statistics/basic/TestStats.py +++ b/lldb/test/API/commands/statistics/basic/TestStats.py @@ -18,8 +18,8 @@ def test(self): self.expect("statistics enable", substrs=['already enabled'], error=True) self.expect("expr patatino", substrs=['27']) self.expect("statistics disable") - self.expect("statistics dump", substrs=['expr evaluation successes : 1', - 'expr evaluation failures : 0']) + self.expect("statistics dump", substrs=['expr evaluation successes : 1\n', + 'expr evaluation failures : 0\n']) # 'frame var' with disabled statistics shouldn't change stats. self.expect("frame var", substrs=['27']) @@ -28,5 +28,5 @@ def test(self): # 'frame var' with enabled statistics will change stats. self.expect("frame var", substrs=['27']) self.expect("statistics disable") - self.expect("statistics dump", substrs=['frame var successes : 1', - 'frame var failures : 0']) + self.expect("statistics dump", substrs=['frame var successes : 1\n', + 'frame var failures : 0\n']) From c717127b734c52c0f4c2ee6da943813d4d7106c0 Mon Sep 17 00:00:00 2001 From: Raphael Isemann Date: Fri, 6 Mar 2020 18:27:46 -0800 Subject: [PATCH 062/286] [lldb][NFC] Refactor our option generation out of EvaluateExpression (cherry picked from commit 8f7c911b58813908da7fa99c7c1a8e7ca1a58213) --- .../Commands/CommandObjectExpression.cpp | 44 ++++++++++--------- .../source/Commands/CommandObjectExpression.h | 6 +++ 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp index db90dde98eff5..d18c9e5d9c5c4 100644 --- a/lldb/source/Commands/CommandObjectExpression.cpp +++ b/lldb/source/Commands/CommandObjectExpression.cpp @@ -357,29 +357,13 @@ CanBeUsedForElementCountPrinting(ValueObject &valobj) { return Status(); } -bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr, - Stream *output_stream, - Stream *error_stream, - CommandReturnObject *result) { - // Don't use m_exe_ctx as this might be called asynchronously after the - // command object DoExecute has finished when doing multi-line expression - // that use an input reader... - ExecutionContext exe_ctx(m_interpreter.GetExecutionContext()); - - Target *target = exe_ctx.GetTargetPtr(); - - if (!target) - target = &GetDummyTarget(); - - lldb::ValueObjectSP result_valobj_sp; - bool keep_in_memory = true; - StackFrame *frame = exe_ctx.GetFramePtr(); - +EvaluateExpressionOptions +CommandObjectExpression::GetEvalOptions(const Target &target) { EvaluateExpressionOptions options; options.SetCoerceToId(m_varobj_options.use_objc); options.SetUnwindOnError(m_command_options.unwind_on_error); options.SetIgnoreBreakpoints(m_command_options.ignore_breakpoints); - options.SetKeepInMemory(keep_in_memory); + options.SetKeepInMemory(true); options.SetUseDynamic(m_varobj_options.use_dynamic); options.SetTryAllThreads(m_command_options.try_all_threads); options.SetDebug(m_command_options.debug); @@ -391,7 +375,7 @@ bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr, bool auto_apply_fixits; if (m_command_options.auto_apply_fixits == eLazyBoolCalculate) - auto_apply_fixits = target->GetEnableAutoApplyFixIts(); + auto_apply_fixits = target.GetEnableAutoApplyFixIts(); else auto_apply_fixits = m_command_options.auto_apply_fixits == eLazyBoolYes; @@ -410,7 +394,27 @@ bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr, options.SetTimeout(std::chrono::microseconds(m_command_options.timeout)); else options.SetTimeout(llvm::None); + return options; +} + +bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr, + Stream *output_stream, + Stream *error_stream, + CommandReturnObject *result) { + // Don't use m_exe_ctx as this might be called asynchronously after the + // command object DoExecute has finished when doing multi-line expression + // that use an input reader... + ExecutionContext exe_ctx(m_interpreter.GetExecutionContext()); + + Target *target = exe_ctx.GetTargetPtr(); + + if (!target) + target = &GetDummyTarget(); + + lldb::ValueObjectSP result_valobj_sp; + StackFrame *frame = exe_ctx.GetFramePtr(); + const EvaluateExpressionOptions options = GetEvalOptions(*target); ExpressionResults success = target->EvaluateExpression( expr, frame, result_valobj_sp, options, &m_fixed_expression); diff --git a/lldb/source/Commands/CommandObjectExpression.h b/lldb/source/Commands/CommandObjectExpression.h index de159863b43a2..20841ebaee874 100644 --- a/lldb/source/Commands/CommandObjectExpression.h +++ b/lldb/source/Commands/CommandObjectExpression.h @@ -14,7 +14,9 @@ #include "lldb/Interpreter/OptionGroupBoolean.h" #include "lldb/Interpreter/OptionGroupFormat.h" #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h" +#include "lldb/Target/Target.h" #include "lldb/lldb-private-enumerations.h" + namespace lldb_private { class CommandObjectExpression : public CommandObjectRaw, @@ -65,6 +67,10 @@ class CommandObjectExpression : public CommandObjectRaw, bool DoExecute(llvm::StringRef command, CommandReturnObject &result) override; + /// Return the appropriate expression options used for evaluating the + /// expression in the given target. + EvaluateExpressionOptions GetEvalOptions(const Target &target); + bool EvaluateExpression(llvm::StringRef expr, Stream *output_stream, Stream *error_stream, CommandReturnObject *result = nullptr); From c414651946fae4b11a0310787342931234f5f8f3 Mon Sep 17 00:00:00 2001 From: Raphael Isemann Date: Tue, 17 Mar 2020 12:57:32 +0100 Subject: [PATCH 063/286] [lldb] Ptrs->refs in CommandObjectExpression::EvaluateExpression parameters The error_stream and result parameter were inconsistently checked for being null, so we might as well make them references instead of crashing in case someone passes a nullptr and hits one of the code paths that are currently not doing a nullptr check on those parameters. Also change output_stream for consistency. (cherry picked from commit 7c6e52ac0ce5a6879331bc3c322dd20bfec3bf14) --- .../Commands/CommandObjectExpression.cpp | 45 +++++++++---------- .../source/Commands/CommandObjectExpression.h | 5 +-- 2 files changed, 23 insertions(+), 27 deletions(-) diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp index d18c9e5d9c5c4..2a94db7dc900b 100644 --- a/lldb/source/Commands/CommandObjectExpression.cpp +++ b/lldb/source/Commands/CommandObjectExpression.cpp @@ -398,9 +398,9 @@ CommandObjectExpression::GetEvalOptions(const Target &target) { } bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr, - Stream *output_stream, - Stream *error_stream, - CommandReturnObject *result) { + Stream &output_stream, + Stream &error_stream, + CommandReturnObject &result) { // Don't use m_exe_ctx as this might be called asynchronously after the // command object DoExecute has finished when doing multi-line expression // that use an input reader... @@ -420,11 +420,10 @@ bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr, // We only tell you about the FixIt if we applied it. The compiler errors // will suggest the FixIt if it parsed. - if (error_stream && !m_fixed_expression.empty() && - target->GetEnableNotifyAboutFixIts()) { + if (!m_fixed_expression.empty() && target->GetEnableNotifyAboutFixIts()) { if (success == eExpressionCompleted) - error_stream->Printf(" Fix-it applied, fixed expression was: \n %s\n", - m_fixed_expression.c_str()); + error_stream.Printf(" Fix-it applied, fixed expression was: \n %s\n", + m_fixed_expression.c_str()); } if (result_valobj_sp) { @@ -438,10 +437,10 @@ bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr, if (m_varobj_options.elem_count > 0) { Status error(CanBeUsedForElementCountPrinting(*result_valobj_sp)); if (error.Fail()) { - result->AppendErrorWithFormat( + result.AppendErrorWithFormat( "expression cannot be used with --element-count %s\n", error.AsCString("")); - result->SetStatus(eReturnStatusFailed); + result.SetStatus(eReturnStatusFailed); return false; } } @@ -451,36 +450,33 @@ bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr, options.SetVariableFormatDisplayLanguage( result_valobj_sp->GetPreferredDisplayLanguage()); - result_valobj_sp->Dump(*output_stream, options); + result_valobj_sp->Dump(output_stream, options); - if (result) - result->SetStatus(eReturnStatusSuccessFinishResult); + result.SetStatus(eReturnStatusSuccessFinishResult); } } else { if (result_valobj_sp->GetError().GetError() == UserExpression::kNoResult) { if (format != eFormatVoid && GetDebugger().GetNotifyVoid()) { - error_stream->PutCString("(void)\n"); + error_stream.PutCString("(void)\n"); } - if (result) - result->SetStatus(eReturnStatusSuccessFinishResult); + result.SetStatus(eReturnStatusSuccessFinishResult); } else { const char *error_cstr = result_valobj_sp->GetError().AsCString(); if (error_cstr && error_cstr[0]) { const size_t error_cstr_len = strlen(error_cstr); const bool ends_with_newline = error_cstr[error_cstr_len - 1] == '\n'; if (strstr(error_cstr, "error:") != error_cstr) - error_stream->PutCString("error: "); - error_stream->Write(error_cstr, error_cstr_len); + error_stream.PutCString("error: "); + error_stream.Write(error_cstr, error_cstr_len); if (!ends_with_newline) - error_stream->EOL(); + error_stream.EOL(); } else { - error_stream->PutCString("error: unknown error\n"); + error_stream.PutCString("error: unknown error\n"); } - if (result) - result->SetStatus(eReturnStatusFailed); + result.SetStatus(eReturnStatusFailed); } } } @@ -497,7 +493,8 @@ void CommandObjectExpression::IOHandlerInputComplete(IOHandler &io_handler, StreamFileSP output_sp = io_handler.GetOutputStreamFileSP(); StreamFileSP error_sp = io_handler.GetErrorStreamFileSP(); - EvaluateExpression(line.c_str(), output_sp.get(), error_sp.get()); + CommandReturnObject return_obj; + EvaluateExpression(line.c_str(), *output_sp, *error_sp, return_obj); if (output_sp) output_sp->Flush(); if (error_sp) @@ -647,8 +644,8 @@ bool CommandObjectExpression::DoExecute(llvm::StringRef command, } Target &target = GetSelectedOrDummyTarget(); - if (EvaluateExpression(expr, &(result.GetOutputStream()), - &(result.GetErrorStream()), &result)) { + if (EvaluateExpression(expr, result.GetOutputStream(), + result.GetErrorStream(), result)) { if (!m_fixed_expression.empty() && target.GetEnableNotifyAboutFixIts()) { CommandHistory &history = m_interpreter.GetCommandHistory(); diff --git a/lldb/source/Commands/CommandObjectExpression.h b/lldb/source/Commands/CommandObjectExpression.h index 20841ebaee874..50111619f6fd8 100644 --- a/lldb/source/Commands/CommandObjectExpression.h +++ b/lldb/source/Commands/CommandObjectExpression.h @@ -71,9 +71,8 @@ class CommandObjectExpression : public CommandObjectRaw, /// expression in the given target. EvaluateExpressionOptions GetEvalOptions(const Target &target); - bool EvaluateExpression(llvm::StringRef expr, Stream *output_stream, - Stream *error_stream, - CommandReturnObject *result = nullptr); + bool EvaluateExpression(llvm::StringRef expr, Stream &output_stream, + Stream &error_stream, CommandReturnObject &result); void GetMultilineExpression(); From 1db4442b32657a0f45d27785530de37b6410b166 Mon Sep 17 00:00:00 2001 From: Raphael Isemann Date: Mon, 23 Mar 2020 15:25:51 +0100 Subject: [PATCH 064/286] [lldb] Mark expressions that couldn't be parsed or executed as failed expressions Summary: LLDB keeps statistics of how many expression evaluations are 'successful' and 'failed' which are updated after each expression evaluation (assuming statistics are enabled). From what I understand the idea is that this could be used to define how well LLDB's expression evaluator is working. Currently all expressions are considered successful unless the user passes an explicit positive element counting to the expression command (with the `-Z` flag) and then passes an expression that successfully evaluates to a type that doesn't support element counting. Expressions that fail to parse, execute or any other outcome are considered successful at the moment which means we nearly always have a 100% expression evaluation success rate. This patch makes that expressions that fail to parse or execute to count as failed expressions. We can't know whether the expression failed because of an user error of because LLDB couldn't correctly parse/compile it, but I would argue that this is still an improvement. Assuming that the percentage of valid user expressions stays mostly constant over time (which seems like a reasonable assumption), then this way we can still see if we are doing relatively better/worse from release to release. Reviewers: davide, aprantl, JDevlieghere Reviewed By: aprantl Subscribers: abidh Differential Revision: https://reviews.llvm.org/D76280 (cherry picked from commit 6a4905ae2d65a2883112bf8cbf83c35c0c03f410) --- lldb/source/Commands/CommandObjectExpression.cpp | 3 ++- lldb/source/Commands/CommandObjectExpression.h | 10 ++++++++++ .../API/commands/statistics/basic/TestStats.py | 14 ++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp index 2a94db7dc900b..28dc22f72f382 100644 --- a/lldb/source/Commands/CommandObjectExpression.cpp +++ b/lldb/source/Commands/CommandObjectExpression.cpp @@ -481,7 +481,8 @@ bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr, } } - return true; + return (success != eExpressionSetupError && + success != eExpressionParseError); } void CommandObjectExpression::IOHandlerInputComplete(IOHandler &io_handler, diff --git a/lldb/source/Commands/CommandObjectExpression.h b/lldb/source/Commands/CommandObjectExpression.h index 50111619f6fd8..96c6881a12ef7 100644 --- a/lldb/source/Commands/CommandObjectExpression.h +++ b/lldb/source/Commands/CommandObjectExpression.h @@ -71,6 +71,16 @@ class CommandObjectExpression : public CommandObjectRaw, /// expression in the given target. EvaluateExpressionOptions GetEvalOptions(const Target &target); + /// Evaluates the given expression. + /// \param output_stream The stream to which the evaluation result will be + /// printed. + /// \param error_stream Contains error messages that should be displayed to + /// the user in case the evaluation fails. + /// \param result A CommandReturnObject which status will be set to the + /// appropriate value depending on evaluation success and + /// whether the expression produced any result. + /// \return Returns true iff the expression was successfully evaluated, + /// executed and the result could be printed to the output stream. bool EvaluateExpression(llvm::StringRef expr, Stream &output_stream, Stream &error_stream, CommandReturnObject &result); diff --git a/lldb/test/API/commands/statistics/basic/TestStats.py b/lldb/test/API/commands/statistics/basic/TestStats.py index 76bc224338488..be028199fade1 100644 --- a/lldb/test/API/commands/statistics/basic/TestStats.py +++ b/lldb/test/API/commands/statistics/basic/TestStats.py @@ -21,6 +21,20 @@ def test(self): self.expect("statistics dump", substrs=['expr evaluation successes : 1\n', 'expr evaluation failures : 0\n']) + self.expect("statistics enable") + # Doesn't parse. + self.expect("expr doesnt_exist", error=True, + substrs=["undeclared identifier 'doesnt_exist'"]) + # Doesn't successfully execute. + self.expect("expr int *i = nullptr; *i", error=True) + # Interpret an integer as an array with 3 elements is also a failure. + self.expect("expr -Z 3 -- 1", error=True, + substrs=["expression cannot be used with --element-count"]) + self.expect("statistics disable") + # We should have gotten 3 new failures and the previous success. + self.expect("statistics dump", substrs=['expr evaluation successes : 1\n', + 'expr evaluation failures : 3\n']) + # 'frame var' with disabled statistics shouldn't change stats. self.expect("frame var", substrs=['27']) From 6a6818e089ee4c49691dbac0049c135636ef2d70 Mon Sep 17 00:00:00 2001 From: Fred Riss Date: Thu, 19 Mar 2020 18:02:05 -0700 Subject: [PATCH 065/286] [lldb/Target] Rework the way the inferior environment is created Summary: The interactions between the environment settings (`target.env-vars`, `target.inherit-env`) and the inferior life-cycle are non-obvious today. For example, if `target.inherit-env` is set, the `target.env-vars` setting will be augmented with the contents of the host environment the first time the launch environment is queried (usually at launch). After that point, toggling `target.inherit-env` will have no effect as there's no tracking of what comes from the host and what is a user setting. This patch computes the environment every time it is queried rather than updating the contents of the `target.env-vars` property. This means that toggling the `target.inherit-env` property later will now have the intended effect. This patch also adds a `target.unset-env-vars` settings that one can use to remove variables from the launch environment. Using this, you can inherit all but a few of the host environment. The way the launch environment is constructed is: 1/ if `target.inherit-env` is set, then read the host environment into the launch environment. 2/ Remove for the environment the variables listed in `target.unset-env`. 3/ Augment the launch environment with the contents of `target.env-vars`. This overrides any common values with the host environment. The one functional difference here that could be seen as a regression is that `target.env-vars` will not contain the inferior environment after launch. The patch implements a better alternative in the `target show-launch-environment` command which will return the environment computed through the above rules. Reviewers: labath, jingham Subscribers: lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D76470 (cherry picked from commit b4a6e63ea12309bf667d1569a20ec5b081cbf2a4) --- lldb/include/lldb/Target/Target.h | 3 + lldb/source/Commands/CommandObjectTarget.cpp | 38 ++++++++ lldb/source/Target/Target.cpp | 95 ++++++++----------- lldb/source/Target/TargetProperties.td | 5 +- .../API/commands/settings/TestSettings.py | 90 +++++++++++++++++- 5 files changed, 176 insertions(+), 55 deletions(-) diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index ade6cce844d5e..7525bc3e81cef 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -254,9 +254,12 @@ class TargetProperties : public Properties { static void DisableSTDIOValueChangedCallback(void *target_property_ptr, OptionValue *); + Environment ComputeEnvironment() const; + // Member variables. ProcessLaunchInfo m_launch_info; std::unique_ptr m_experimental_properties_up; + Target *m_target; }; class EvaluateExpressionOptions { diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp index 8a5f75ab4d4cc..957bc81037f5c 100644 --- a/lldb/source/Commands/CommandObjectTarget.cpp +++ b/lldb/source/Commands/CommandObjectTarget.cpp @@ -682,6 +682,41 @@ class CommandObjectTargetDelete : public CommandObjectParsed { OptionGroupBoolean m_cleanup_option; }; +class CommandObjectTargetShowLaunchEnvironment : public CommandObjectParsed { +public: + CommandObjectTargetShowLaunchEnvironment(CommandInterpreter &interpreter) + : CommandObjectParsed( + interpreter, "target show-launch-environment", + "Shows the environment being passed to the process when launched, " + "taking info account 3 settings: target.env-vars, " + "target.inherit-env and target.unset-env-vars.", + nullptr, eCommandRequiresTarget) {} + + ~CommandObjectTargetShowLaunchEnvironment() override = default; + +protected: + bool DoExecute(Args &args, CommandReturnObject &result) override { + Target *target = m_exe_ctx.GetTargetPtr(); + Environment env = target->GetEnvironment(); + + std::vector env_vector; + env_vector.reserve(env.size()); + for (auto &KV : env) + env_vector.push_back(&KV); + std::sort(env_vector.begin(), env_vector.end(), + [](Environment::value_type *a, Environment::value_type *b) { + return a->first() < b->first(); + }); + + auto &strm = result.GetOutputStream(); + for (auto &KV : env_vector) + strm.Format("{0}={1}\n", KV->first(), KV->second); + + result.SetStatus(eReturnStatusSuccessFinishResult); + return result.Succeeded(); + } +}; + #pragma mark CommandObjectTargetVariable // "target variable" @@ -4885,6 +4920,9 @@ CommandObjectMultiwordTarget::CommandObjectMultiwordTarget( CommandObjectSP(new CommandObjectTargetList(interpreter))); LoadSubCommand("select", CommandObjectSP(new CommandObjectTargetSelect(interpreter))); + LoadSubCommand("show-launch-environment", + CommandObjectSP(new CommandObjectTargetShowLaunchEnvironment( + interpreter))); LoadSubCommand( "stop-hook", CommandObjectSP(new CommandObjectMultiwordTargetStopHooks(interpreter))); diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index 81bd284935fc1..25345238b982f 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -3670,16 +3670,13 @@ enum { class TargetOptionValueProperties : public OptionValueProperties { public: - TargetOptionValueProperties(ConstString name) - : OptionValueProperties(name), m_target(nullptr), m_got_host_env(false) {} + TargetOptionValueProperties(ConstString name) : OptionValueProperties(name) {} // This constructor is used when creating TargetOptionValueProperties when it // is part of a new lldb_private::Target instance. It will copy all current // global property values as needed - TargetOptionValueProperties(Target *target, - const TargetPropertiesSP &target_properties_sp) - : OptionValueProperties(*target_properties_sp->GetValueProperties()), - m_target(target), m_got_host_env(false) {} + TargetOptionValueProperties(const TargetPropertiesSP &target_properties_sp) + : OptionValueProperties(*target_properties_sp->GetValueProperties()) {} const Property *GetPropertyAtIndex(const ExecutionContext *exe_ctx, bool will_modify, @@ -3687,9 +3684,6 @@ class TargetOptionValueProperties : public OptionValueProperties { // When getting the value for a key from the target options, we will always // try and grab the setting from the current target if there is one. Else // we just use the one from this instance. - if (idx == ePropertyEnvVars) - GetHostEnvironmentIfNeeded(); - if (exe_ctx) { Target *target = exe_ctx->GetTargetPtr(); if (target) { @@ -3702,41 +3696,6 @@ class TargetOptionValueProperties : public OptionValueProperties { } return ProtectedGetPropertyAtIndex(idx); } - - lldb::TargetSP GetTargetSP() { return m_target->shared_from_this(); } - -protected: - void GetHostEnvironmentIfNeeded() const { - if (!m_got_host_env) { - if (m_target) { - m_got_host_env = true; - const uint32_t idx = ePropertyInheritEnv; - if (GetPropertyAtIndexAsBoolean( - nullptr, idx, g_target_properties[idx].default_uint_value != 0)) { - PlatformSP platform_sp(m_target->GetPlatform()); - if (platform_sp) { - Environment env = platform_sp->GetEnvironment(); - OptionValueDictionary *env_dict = - GetPropertyAtIndexAsOptionValueDictionary(nullptr, - ePropertyEnvVars); - if (env_dict) { - const bool can_replace = false; - for (const auto &KV : env) { - // Don't allow existing keys to be replaced with ones we get - // from the platform environment - env_dict->SetValueForKey( - ConstString(KV.first()), - OptionValueSP(new OptionValueString(KV.second.c_str())), - can_replace); - } - } - } - } - } - } - } - Target *m_target; - mutable bool m_got_host_env; }; // TargetProperties @@ -3763,10 +3722,10 @@ TargetExperimentalProperties::TargetExperimentalProperties() // TargetProperties TargetProperties::TargetProperties(Target *target) - : Properties(), m_launch_info() { + : Properties(), m_launch_info(), m_target(target) { if (target) { m_collection_sp = std::make_shared( - target, Target::GetGlobalProperties()); + Target::GetGlobalProperties()); // Set callbacks to update launch_info whenever "settins set" updated any // of these properties @@ -3776,6 +3735,12 @@ TargetProperties::TargetProperties(Target *target) ePropertyRunArgs, TargetProperties::RunArgsValueChangedCallback, this); m_collection_sp->SetValueChangedCallback( ePropertyEnvVars, TargetProperties::EnvVarsValueChangedCallback, this); + m_collection_sp->SetValueChangedCallback( + ePropertyUnsetEnvVars, TargetProperties::EnvVarsValueChangedCallback, + this); + m_collection_sp->SetValueChangedCallback( + ePropertyInheritEnv, TargetProperties::EnvVarsValueChangedCallback, + this); m_collection_sp->SetValueChangedCallback( ePropertyInputPath, TargetProperties::InputPathValueChangedCallback, this); @@ -3984,19 +3949,43 @@ void TargetProperties::SetRunArguments(const Args &args) { m_launch_info.GetArguments() = args; } +Environment TargetProperties::ComputeEnvironment() const { + Environment env; + + if (m_target && + m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, ePropertyInheritEnv, + g_target_properties[ePropertyInheritEnv].default_uint_value != 0)) { + if (auto platform_sp = m_target->GetPlatform()) { + Environment platform_env = platform_sp->GetEnvironment(); + for (const auto &KV : platform_env) + env[KV.first()] = KV.second; + } + } + + Args property_unset_env; + m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, ePropertyUnsetEnvVars, + property_unset_env); + for (const auto &var : property_unset_env) + env.erase(var.ref()); + + Args property_env; + m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, ePropertyEnvVars, + property_env); + for (const auto &KV : Environment(property_env)) + env[KV.first()] = KV.second; + + return env; +} + Environment TargetProperties::GetEnvironment() const { - // TODO: Get rid of the Args intermediate step - Args env; - const uint32_t idx = ePropertyEnvVars; - m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, idx, env); - return Environment(env); + return ComputeEnvironment(); } void TargetProperties::SetEnvironment(Environment env) { // TODO: Get rid of the Args intermediate step const uint32_t idx = ePropertyEnvVars; m_collection_sp->SetPropertyAtIndexFromArgs(nullptr, idx, Args(env)); - m_launch_info.GetEnvironment() = std::move(env); } bool TargetProperties::GetSkipPrologue() const { @@ -4356,7 +4345,7 @@ void TargetProperties::EnvVarsValueChangedCallback(void *target_property_ptr, OptionValue *) { TargetProperties *this_ = static_cast(target_property_ptr); - this_->m_launch_info.GetEnvironment() = this_->GetEnvironment(); + this_->m_launch_info.GetEnvironment() = this_->ComputeEnvironment(); } void TargetProperties::InputPathValueChangedCallback(void *target_property_ptr, diff --git a/lldb/source/Target/TargetProperties.td b/lldb/source/Target/TargetProperties.td index 1f20484363afe..ecaded656e0b0 100644 --- a/lldb/source/Target/TargetProperties.td +++ b/lldb/source/Target/TargetProperties.td @@ -83,7 +83,10 @@ let Definition = "target" in { Desc<"A list containing all the arguments to be passed to the executable when it is run. Note that this does NOT include the argv[0] which is in target.arg0.">; def EnvVars: Property<"env-vars", "Dictionary">, DefaultUnsignedValue<16>, - Desc<"A list of all the environment variables to be passed to the executable's environment, and their values.">; + Desc<"A list of user provided environment variables to be passed to the executable's environment, and their values.">; + def UnsetEnvVars: Property<"unset-env-vars", "Array">, + DefaultUnsignedValue<16>, + Desc<"A list of environment variable names to be unset in the inferior's environment. This is most useful to unset some host environment variables when target.inherit-env is true. target.env-vars takes precedence over target.unset-env-vars.">; def InheritEnv: Property<"inherit-env", "Boolean">, DefaultTrue, Desc<"Inherit the environment from the process that is running LLDB.">; diff --git a/lldb/test/API/commands/settings/TestSettings.py b/lldb/test/API/commands/settings/TestSettings.py index e9d6ff0076509..23f4de05ea0cb 100644 --- a/lldb/test/API/commands/settings/TestSettings.py +++ b/lldb/test/API/commands/settings/TestSettings.py @@ -237,6 +237,10 @@ def do_test_run_args_and_env_vars(self, use_launchsimple): self.assertTrue(found_env_var, "MY_ENV_VAR was not set in LunchInfo object") + self.expect( + 'target show-launch-environment', + substrs=["MY_ENV_VAR=YES"]) + wd = self.get_process_working_directory() if use_launchsimple: process = target.LaunchSimple(None, None, wd) @@ -257,6 +261,31 @@ def do_test_run_args_and_env_vars(self, use_launchsimple): "argv[3] matches", "Environment variable 'MY_ENV_VAR' successfully passed."]) + # Check that env-vars overrides unset-env-vars. + self.runCmd('settings set target.unset-env-vars MY_ENV_VAR') + + self.expect( + 'target show-launch-environment', + 'env-vars overrides unset-env-vars', + substrs=["MY_ENV_VAR=YES"]) + + wd = self.get_process_working_directory() + if use_launchsimple: + process = target.LaunchSimple(None, None, wd) + self.assertTrue(process) + else: + self.runCmd("process launch --working-dir '{0}'".format(wd), + RUN_SUCCEEDED) + + # Read the output file produced by running the program. + output = lldbutil.read_file_from_process_wd(self, "output2.txt") + + self.expect( + output, + exe=False, + substrs=[ + "Environment variable 'MY_ENV_VAR' successfully passed."]) + @skipIfRemote # it doesn't make sense to send host env to remote target def test_pass_host_env_vars(self): """Test that the host env vars are passed to the launched process.""" @@ -270,6 +299,7 @@ def test_pass_host_env_vars(self): def unset_env_variables(): os.environ.pop("MY_HOST_ENV_VAR1") os.environ.pop("MY_HOST_ENV_VAR2") + self.addTearDownHook(unset_env_variables) exe = self.getBuildArtifact("a.out") self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) @@ -280,7 +310,33 @@ def unset_env_variables(): "Default inherit-env is 'true'", startstr="target.inherit-env (boolean) = true") - self.addTearDownHook(unset_env_variables) + self.expect( + 'target show-launch-environment', + 'Host environment is passed correctly', + substrs=['MY_HOST_ENV_VAR1=VAR1', 'MY_HOST_ENV_VAR2=VAR2']) + self.runCmd("process launch --working-dir '{0}'".format(self.get_process_working_directory()), + RUN_SUCCEEDED) + + # Read the output file produced by running the program. + output = lldbutil.read_file_from_process_wd(self, "output1.txt") + + self.expect( + output, + exe=False, + substrs=[ + "The host environment variable 'MY_HOST_ENV_VAR1' successfully passed.", + "The host environment variable 'MY_HOST_ENV_VAR2' successfully passed."]) + + # Now test that we can prevent the inferior from inheriting the + # environment. + self.runCmd('settings set target.inherit-env false') + + self.expect( + 'target show-launch-environment', + 'target.inherit-env affects `target show-launch-environment`', + matching=False, + substrs = ['MY_HOST_ENV_VAR1=VAR1', 'MY_HOST_ENV_VAR2=VAR2']) + self.runCmd("process launch --working-dir '{0}'".format(self.get_process_working_directory()), RUN_SUCCEEDED) @@ -290,10 +346,42 @@ def unset_env_variables(): self.expect( output, exe=False, + matching=False, substrs=[ "The host environment variable 'MY_HOST_ENV_VAR1' successfully passed.", "The host environment variable 'MY_HOST_ENV_VAR2' successfully passed."]) + # Now test that we can unset variables from the inherited environment. + self.runCmd('settings set target.inherit-env true') + self.runCmd('settings set target.unset-env-vars MY_HOST_ENV_VAR1') + self.runCmd("process launch --working-dir '{0}'".format(self.get_process_working_directory()), + RUN_SUCCEEDED) + + # Read the output file produced by running the program. + output = lldbutil.read_file_from_process_wd(self, "output1.txt") + + self.expect( + 'target show-launch-environment', + 'MY_HOST_ENV_VAR1 is unset, it shouldn\'t be in `target show-launch-environment`', + matching=False, + substrs = ['MY_HOST_ENV_VAR1=VAR1']) + self.expect( + 'target show-launch-environment', + 'MY_HOST_ENV_VAR2 shouldn be in `target show-launch-environment`', + substrs = ['MY_HOST_ENV_VAR2=VAR2']) + + self.expect( + output, + exe=False, + matching=False, + substrs=[ + "The host environment variable 'MY_HOST_ENV_VAR1' successfully passed."]) + self.expect( + output, + exe=False, + substrs=[ + "The host environment variable 'MY_HOST_ENV_VAR2' successfully passed."]) + @skipIfDarwinEmbedded # debugserver on ios etc can't write files def test_set_error_output_path(self): """Test that setting target.error/output-path for the launched process works.""" From 480db6fadf678f7e0956b37fa371bd6023de0d36 Mon Sep 17 00:00:00 2001 From: Fred Riss Date: Mon, 23 Mar 2020 11:54:45 -0700 Subject: [PATCH 066/286] [lldb/testsuite] Pass the correct Swift library path to tests Also remove the --swift-library option to dotest which looks unused. --- lldb/packages/Python/lldbsuite/test/dotest.py | 5 ----- lldb/packages/Python/lldbsuite/test/dotest_args.py | 4 ---- lldb/test/API/CMakeLists.txt | 3 +-- 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/lldb/packages/Python/lldbsuite/test/dotest.py b/lldb/packages/Python/lldbsuite/test/dotest.py index d3452cc8bd854..7315820561eda 100644 --- a/lldb/packages/Python/lldbsuite/test/dotest.py +++ b/lldb/packages/Python/lldbsuite/test/dotest.py @@ -333,9 +333,6 @@ def parseOptionsAndInitTestdirs(): if args.swiftcompiler: configuration.swiftCompiler = args.swiftcompiler - if args.swiftlibrary: - configuration.swiftLibrary = args.swiftlibrary - cflags_extras = "" if args.E: os.environ['CFLAGS_EXTRAS'] = args.E @@ -1100,8 +1097,6 @@ def run_suite(): os.environ["CC"] = configuration.compiler if configuration.swiftCompiler: os.environ["SWIFTC"] = configuration.swiftCompiler - if configuration.swiftLibrary: - os.environ["USERSWIFTLIBRARY"] = configuration.swiftLibrary configString = "arch=%s compiler=%s" % (configuration.arch, configuration.compiler) diff --git a/lldb/packages/Python/lldbsuite/test/dotest_args.py b/lldb/packages/Python/lldbsuite/test/dotest_args.py index 84885a6fafbde..30537befdcad9 100644 --- a/lldb/packages/Python/lldbsuite/test/dotest_args.py +++ b/lldb/packages/Python/lldbsuite/test/dotest_args.py @@ -44,10 +44,6 @@ def create_parser(): '--swift-compiler', dest='swiftcompiler', help='The path to a valid Swift compiler') - group.add_argument( - '--swift-library', - dest='swiftlibrary', - help='The path to a folder that contains valid Swift library files') if sys.platform == 'darwin': group.add_argument('--apple-sdk', metavar='apple_sdk', dest='apple_sdk', default="macosx", help=textwrap.dedent( '''Specify the name of the Apple SDK (macosx, macosx.internal, iphoneos, iphoneos.internal, or path to SDK) and use the appropriate tools from that SDK's toolchain.''')) diff --git a/lldb/test/API/CMakeLists.txt b/lldb/test/API/CMakeLists.txt index e4015f3a05159..e08a377e4f463 100644 --- a/lldb/test/API/CMakeLists.txt +++ b/lldb/test/API/CMakeLists.txt @@ -31,10 +31,9 @@ option(LLDB_TEST_SWIFT "Use in-tree swift when testing lldb" On) if(LLDB_TEST_SWIFT) set(LLDB_SWIFTC ${SWIFT_BINARY_DIR}/bin/swiftc CACHE STRING "Path to swift compiler") - set(LLDB_SWIFT_LIBS ${SWIFT_LIBRARY_DIR}/swift CACHE STRING "Path to swift libraries") + set(LLDB_SWIFT_LIBS ${SWIFT_LIBRARY_DIR}/swift/macosx CACHE STRING "Path to swift libraries") set(SWIFT_TEST_ARGS --swift-compiler ${LLDB_SWIFTC} - --swift-library ${LLDB_SWIFT_LIBS} --inferior-env "DYLD_LIBRARY_PATH=\\\"${LLDB_SWIFT_LIBS}\\\"" --inferior-env "LD_LIBRARY_PATH=\\\"${LLDB_SWIFT_LIBS}\\\"" --inferior-env "SIMCTL_CHILD_DYLD_LIBRARY_PATH=\\\"${LLDB_SWIFT_LIBS}\\\"" From dd4ee984edbf6bc44e92feffa251af1da63e1fef Mon Sep 17 00:00:00 2001 From: Fred Riss Date: Wed, 11 Mar 2020 10:26:03 -0700 Subject: [PATCH 067/286] [lldb/Target] Initialize new targets environment variables from target.env-vars Summary: The TargetProperties constructor invokes a series of callbacks to prime the properties from the default ones. The one callback in charge of updating the inferior environment was commented out because it crashed. The reason for the crash is that TargetProperties is a parent class of Target and the callbacks were invoked using a Target that was not fully initialized. This patch moves the initial callback invocations to a separate function that can be called at the end the Target constructor, thus preventing the crash. One existing test had to be modified, because the initialization of the environment properties now take place at the time the target is created, not at the first use of the environment (usually launch time). The added test checks that the LaunchInfo object returned by the target has been primed with the values from the settings. Reviewers: jingham, labath Subscribers: lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D76009 (cherry picked from commit 9228a9efc6c57a932d936ebb214f6ff5bafe79ff) --- lldb/include/lldb/Target/Target.h | 2 ++ lldb/source/Target/Target.cpp | 26 +++++++++--------- .../API/commands/settings/TestSettings.py | 27 ++++++++++++------- 3 files changed, 34 insertions(+), 21 deletions(-) diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index 6f8d60731acf5..ae440e2600bc3 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -207,6 +207,8 @@ class TargetProperties : public Properties { bool GetRequireHardwareBreakpoints() const; + void UpdateLaunchInfoFromProperties(); + private: // Callbacks for m_launch_info. static void Arg0ValueChangedCallback(void *target_property_ptr, diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index 72e5f0281f804..93aae5d993f9a 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -114,6 +114,8 @@ Target::Target(Debugger &debugger, const ArchSpec &target_arch, target_arch.GetArchitectureName(), target_arch.GetTriple().getTriple().c_str()); } + + UpdateLaunchInfoFromProperties(); } Target::~Target() { @@ -3486,18 +3488,6 @@ TargetProperties::TargetProperties(Target *target) ConstString("Experimental settings - setting these won't produce " "errors if the setting is not present."), true, m_experimental_properties_up->GetValueProperties()); - - // Update m_launch_info once it was created - Arg0ValueChangedCallback(this, nullptr); - RunArgsValueChangedCallback(this, nullptr); - // EnvVarsValueChangedCallback(this, nullptr); // FIXME: cause segfault in - // Target::GetPlatform() - InputPathValueChangedCallback(this, nullptr); - OutputPathValueChangedCallback(this, nullptr); - ErrorPathValueChangedCallback(this, nullptr); - DetachOnErrorValueChangedCallback(this, nullptr); - DisableASLRValueChangedCallback(this, nullptr); - DisableSTDIOValueChangedCallback(this, nullptr); } else { m_collection_sp = std::make_shared(ConstString("target")); @@ -3516,6 +3506,18 @@ TargetProperties::TargetProperties(Target *target) TargetProperties::~TargetProperties() = default; +void TargetProperties::UpdateLaunchInfoFromProperties() { + Arg0ValueChangedCallback(this, nullptr); + RunArgsValueChangedCallback(this, nullptr); + EnvVarsValueChangedCallback(this, nullptr); + InputPathValueChangedCallback(this, nullptr); + OutputPathValueChangedCallback(this, nullptr); + ErrorPathValueChangedCallback(this, nullptr); + DetachOnErrorValueChangedCallback(this, nullptr); + DisableASLRValueChangedCallback(this, nullptr); + DisableSTDIOValueChangedCallback(this, nullptr); +} + bool TargetProperties::GetInjectLocalVariables( ExecutionContext *exe_ctx) const { const Property *exp_property = m_collection_sp->GetPropertyAtIndex( diff --git a/lldb/test/API/commands/settings/TestSettings.py b/lldb/test/API/commands/settings/TestSettings.py index 1130821bac0f4..0e862aac47524 100644 --- a/lldb/test/API/commands/settings/TestSettings.py +++ b/lldb/test/API/commands/settings/TestSettings.py @@ -219,6 +219,15 @@ def test_run_args_and_env_vars(self): self.addTearDownHook( lambda: self.runCmd("settings clear target.env-vars")) + launch_info = self.dbg.GetTargetAtIndex(0).GetLaunchInfo() + found_env_var = False + for i in range(0, launch_info.GetNumEnvironmentEntries()): + if launch_info.GetEnvironmentEntryAtIndex(i) == "MY_ENV_VAR=YES": + found_env_var = True + break + self.assertTrue(found_env_var, + "MY_ENV_VAR was not set in LunchInfo object") + self.runCmd("process launch --working-dir '{0}'".format(self.get_process_working_directory()), RUN_SUCCEEDED) @@ -239,15 +248,6 @@ def test_pass_host_env_vars(self): """Test that the host env vars are passed to the launched process.""" self.build() - exe = self.getBuildArtifact("a.out") - self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) - - # By default, inherit-env is 'true'. - self.expect( - 'settings show target.inherit-env', - "Default inherit-env is 'true'", - startstr="target.inherit-env (boolean) = true") - # Set some host environment variables now. os.environ["MY_HOST_ENV_VAR1"] = "VAR1" os.environ["MY_HOST_ENV_VAR2"] = "VAR2" @@ -257,6 +257,15 @@ def unset_env_variables(): os.environ.pop("MY_HOST_ENV_VAR1") os.environ.pop("MY_HOST_ENV_VAR2") + exe = self.getBuildArtifact("a.out") + self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) + + # By default, inherit-env is 'true'. + self.expect( + 'settings show target.inherit-env', + "Default inherit-env is 'true'", + startstr="target.inherit-env (boolean) = true") + self.addTearDownHook(unset_env_variables) self.runCmd("process launch --working-dir '{0}'".format(self.get_process_working_directory()), RUN_SUCCEEDED) From 3f8d1cd8d4c68310a642e35114c76e07a6a09c45 Mon Sep 17 00:00:00 2001 From: Fred Riss Date: Wed, 11 Mar 2020 22:09:11 -0700 Subject: [PATCH 068/286] [lldb/API] Make Launch(Simple) use args and env from target properties Summary: When no arguments or environment is provided to SBTarget::LaunchSimple, make it use the values surrently set in the target properties. You can get the current behavior back by passing an empty array instead. It seems like using the target defaults is a much more intuitive behavior for those APIs. It's unllikely that anyone passed NULL/None to this API after having set properties in order to explicitely ignore them. One direct application of this change is within the testsuite. We have plenty of tests calling LaunchSimple and passing None as environment. If you passed --inferior-env to dotest.py to, for example, set (DY)LD_LIBRARY_PATH, it wouldn't be taken into account. Reviewers: jingham, labath, #libc_abi! Subscribers: libcxx-commits, lldb-commits Tags: #lldb, #libc_abi Differential Revision: https://reviews.llvm.org/D76045 (cherry picked from commit cd7b45057ca9bc72b99a0abc6c9be25e0f72fbcf) --- lldb/include/lldb/API/SBTarget.h | 8 +++++-- lldb/source/API/SBTarget.cpp | 13 +++++++++-- .../API/commands/settings/TestSettings.py | 22 +++++++++++++++---- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h index 89f6450edc52d..520f7453c0cd9 100644 --- a/lldb/include/lldb/API/SBTarget.h +++ b/lldb/include/lldb/API/SBTarget.h @@ -127,7 +127,9 @@ class LLDB_API SBTarget { /// The argument array. /// /// \param[in] envp - /// The environment array. + /// The environment array. If this is null, the default + /// environment values (provided through `settings set + /// target.env-vars`) will be used. /// /// \param[in] stdin_path /// The path to use when re-directing the STDIN of the new @@ -175,7 +177,9 @@ class LLDB_API SBTarget { /// The argument array. /// /// \param[in] envp - /// The environment array. + /// The environment array. If this isn't provided, the default + /// environment values (provided through `settings set + /// target.env-vars`) will be used. /// /// \param[in] working_directory /// The working directory to have the child process run in diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp index 7b5d3f8ea0ebb..54d2fd41f2bd1 100644 --- a/lldb/source/API/SBTarget.cpp +++ b/lldb/source/API/SBTarget.cpp @@ -371,10 +371,19 @@ SBProcess SBTarget::Launch(SBListener &listener, char const **argv, Module *exe_module = target_sp->GetExecutableModulePointer(); if (exe_module) launch_info.SetExecutableFile(exe_module->GetPlatformFileSpec(), true); - if (argv) + if (argv) { launch_info.GetArguments().AppendArguments(argv); - if (envp) + } else { + auto default_launch_info = target_sp->GetProcessLaunchInfo(); + launch_info.GetArguments().AppendArguments( + default_launch_info.GetArguments()); + } + if (envp) { launch_info.GetEnvironment() = Environment(envp); + } else { + auto default_launch_info = target_sp->GetProcessLaunchInfo(); + launch_info.GetEnvironment() = default_launch_info.GetEnvironment(); + } if (listener.IsValid()) launch_info.SetListener(listener.GetSP()); diff --git a/lldb/test/API/commands/settings/TestSettings.py b/lldb/test/API/commands/settings/TestSettings.py index 0e862aac47524..e9d6ff0076509 100644 --- a/lldb/test/API/commands/settings/TestSettings.py +++ b/lldb/test/API/commands/settings/TestSettings.py @@ -205,10 +205,15 @@ def test_disassembler_settings(self): @skipIfDarwinEmbedded # debugserver on ios etc can't write files def test_run_args_and_env_vars(self): + self.do_test_run_args_and_env_vars(use_launchsimple=False) + + @skipIfDarwinEmbedded # debugserver on ios etc can't write files + def test_launchsimple_args_and_env_vars(self): + self.do_test_run_args_and_env_vars(use_launchsimple=True) + + def do_test_run_args_and_env_vars(self, use_launchsimple): """Test that run-args and env-vars are passed to the launched process.""" self.build() - exe = self.getBuildArtifact("a.out") - self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) # Set the run-args and the env-vars. # And add hooks to restore the settings during tearDown(). @@ -219,7 +224,11 @@ def test_run_args_and_env_vars(self): self.addTearDownHook( lambda: self.runCmd("settings clear target.env-vars")) - launch_info = self.dbg.GetTargetAtIndex(0).GetLaunchInfo() + exe = self.getBuildArtifact("a.out") + self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) + + target = self.dbg.GetTargetAtIndex(0) + launch_info = target.GetLaunchInfo() found_env_var = False for i in range(0, launch_info.GetNumEnvironmentEntries()): if launch_info.GetEnvironmentEntryAtIndex(i) == "MY_ENV_VAR=YES": @@ -228,7 +237,12 @@ def test_run_args_and_env_vars(self): self.assertTrue(found_env_var, "MY_ENV_VAR was not set in LunchInfo object") - self.runCmd("process launch --working-dir '{0}'".format(self.get_process_working_directory()), + wd = self.get_process_working_directory() + if use_launchsimple: + process = target.LaunchSimple(None, None, wd) + self.assertTrue(process) + else: + self.runCmd("process launch --working-dir '{0}'".format(wd), RUN_SUCCEEDED) # Read the output file produced by running the program. From 6f04e9af8ca2142d0c45e75aa9016e48e995e711 Mon Sep 17 00:00:00 2001 From: Fred Riss Date: Thu, 19 Mar 2020 18:02:05 -0700 Subject: [PATCH 069/286] [lldb/Target] Rework the way the inferior environment is created Summary: The interactions between the environment settings (`target.env-vars`, `target.inherit-env`) and the inferior life-cycle are non-obvious today. For example, if `target.inherit-env` is set, the `target.env-vars` setting will be augmented with the contents of the host environment the first time the launch environment is queried (usually at launch). After that point, toggling `target.inherit-env` will have no effect as there's no tracking of what comes from the host and what is a user setting. This patch computes the environment every time it is queried rather than updating the contents of the `target.env-vars` property. This means that toggling the `target.inherit-env` property later will now have the intended effect. This patch also adds a `target.unset-env-vars` settings that one can use to remove variables from the launch environment. Using this, you can inherit all but a few of the host environment. The way the launch environment is constructed is: 1/ if `target.inherit-env` is set, then read the host environment into the launch environment. 2/ Remove for the environment the variables listed in `target.unset-env`. 3/ Augment the launch environment with the contents of `target.env-vars`. This overrides any common values with the host environment. The one functional difference here that could be seen as a regression is that `target.env-vars` will not contain the inferior environment after launch. The patch implements a better alternative in the `target show-launch-environment` command which will return the environment computed through the above rules. Reviewers: labath, jingham Subscribers: lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D76470 (cherry picked from commit b4a6e63ea12309bf667d1569a20ec5b081cbf2a4) --- lldb/include/lldb/Target/Target.h | 3 + lldb/source/Commands/CommandObjectTarget.cpp | 38 ++++++++ lldb/source/Target/Target.cpp | 95 ++++++++----------- lldb/source/Target/TargetProperties.td | 5 +- .../API/commands/settings/TestSettings.py | 90 +++++++++++++++++- 5 files changed, 176 insertions(+), 55 deletions(-) diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index ae440e2600bc3..4dd340e483742 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -232,9 +232,12 @@ class TargetProperties : public Properties { static void DisableSTDIOValueChangedCallback(void *target_property_ptr, OptionValue *); + Environment ComputeEnvironment() const; + // Member variables. ProcessLaunchInfo m_launch_info; std::unique_ptr m_experimental_properties_up; + Target *m_target; }; class EvaluateExpressionOptions { diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp index 8a5f75ab4d4cc..957bc81037f5c 100644 --- a/lldb/source/Commands/CommandObjectTarget.cpp +++ b/lldb/source/Commands/CommandObjectTarget.cpp @@ -682,6 +682,41 @@ class CommandObjectTargetDelete : public CommandObjectParsed { OptionGroupBoolean m_cleanup_option; }; +class CommandObjectTargetShowLaunchEnvironment : public CommandObjectParsed { +public: + CommandObjectTargetShowLaunchEnvironment(CommandInterpreter &interpreter) + : CommandObjectParsed( + interpreter, "target show-launch-environment", + "Shows the environment being passed to the process when launched, " + "taking info account 3 settings: target.env-vars, " + "target.inherit-env and target.unset-env-vars.", + nullptr, eCommandRequiresTarget) {} + + ~CommandObjectTargetShowLaunchEnvironment() override = default; + +protected: + bool DoExecute(Args &args, CommandReturnObject &result) override { + Target *target = m_exe_ctx.GetTargetPtr(); + Environment env = target->GetEnvironment(); + + std::vector env_vector; + env_vector.reserve(env.size()); + for (auto &KV : env) + env_vector.push_back(&KV); + std::sort(env_vector.begin(), env_vector.end(), + [](Environment::value_type *a, Environment::value_type *b) { + return a->first() < b->first(); + }); + + auto &strm = result.GetOutputStream(); + for (auto &KV : env_vector) + strm.Format("{0}={1}\n", KV->first(), KV->second); + + result.SetStatus(eReturnStatusSuccessFinishResult); + return result.Succeeded(); + } +}; + #pragma mark CommandObjectTargetVariable // "target variable" @@ -4885,6 +4920,9 @@ CommandObjectMultiwordTarget::CommandObjectMultiwordTarget( CommandObjectSP(new CommandObjectTargetList(interpreter))); LoadSubCommand("select", CommandObjectSP(new CommandObjectTargetSelect(interpreter))); + LoadSubCommand("show-launch-environment", + CommandObjectSP(new CommandObjectTargetShowLaunchEnvironment( + interpreter))); LoadSubCommand( "stop-hook", CommandObjectSP(new CommandObjectMultiwordTargetStopHooks(interpreter))); diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index 93aae5d993f9a..3b2a5bbc6d906 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -3357,16 +3357,13 @@ enum { class TargetOptionValueProperties : public OptionValueProperties { public: - TargetOptionValueProperties(ConstString name) - : OptionValueProperties(name), m_target(nullptr), m_got_host_env(false) {} + TargetOptionValueProperties(ConstString name) : OptionValueProperties(name) {} // This constructor is used when creating TargetOptionValueProperties when it // is part of a new lldb_private::Target instance. It will copy all current // global property values as needed - TargetOptionValueProperties(Target *target, - const TargetPropertiesSP &target_properties_sp) - : OptionValueProperties(*target_properties_sp->GetValueProperties()), - m_target(target), m_got_host_env(false) {} + TargetOptionValueProperties(const TargetPropertiesSP &target_properties_sp) + : OptionValueProperties(*target_properties_sp->GetValueProperties()) {} const Property *GetPropertyAtIndex(const ExecutionContext *exe_ctx, bool will_modify, @@ -3374,9 +3371,6 @@ class TargetOptionValueProperties : public OptionValueProperties { // When getting the value for a key from the target options, we will always // try and grab the setting from the current target if there is one. Else // we just use the one from this instance. - if (idx == ePropertyEnvVars) - GetHostEnvironmentIfNeeded(); - if (exe_ctx) { Target *target = exe_ctx->GetTargetPtr(); if (target) { @@ -3389,41 +3383,6 @@ class TargetOptionValueProperties : public OptionValueProperties { } return ProtectedGetPropertyAtIndex(idx); } - - lldb::TargetSP GetTargetSP() { return m_target->shared_from_this(); } - -protected: - void GetHostEnvironmentIfNeeded() const { - if (!m_got_host_env) { - if (m_target) { - m_got_host_env = true; - const uint32_t idx = ePropertyInheritEnv; - if (GetPropertyAtIndexAsBoolean( - nullptr, idx, g_target_properties[idx].default_uint_value != 0)) { - PlatformSP platform_sp(m_target->GetPlatform()); - if (platform_sp) { - Environment env = platform_sp->GetEnvironment(); - OptionValueDictionary *env_dict = - GetPropertyAtIndexAsOptionValueDictionary(nullptr, - ePropertyEnvVars); - if (env_dict) { - const bool can_replace = false; - for (const auto &KV : env) { - // Don't allow existing keys to be replaced with ones we get - // from the platform environment - env_dict->SetValueForKey( - ConstString(KV.first()), - OptionValueSP(new OptionValueString(KV.second.c_str())), - can_replace); - } - } - } - } - } - } - } - Target *m_target; - mutable bool m_got_host_env; }; // TargetProperties @@ -3450,10 +3409,10 @@ TargetExperimentalProperties::TargetExperimentalProperties() // TargetProperties TargetProperties::TargetProperties(Target *target) - : Properties(), m_launch_info() { + : Properties(), m_launch_info(), m_target(target) { if (target) { m_collection_sp = std::make_shared( - target, Target::GetGlobalProperties()); + Target::GetGlobalProperties()); // Set callbacks to update launch_info whenever "settins set" updated any // of these properties @@ -3463,6 +3422,12 @@ TargetProperties::TargetProperties(Target *target) ePropertyRunArgs, TargetProperties::RunArgsValueChangedCallback, this); m_collection_sp->SetValueChangedCallback( ePropertyEnvVars, TargetProperties::EnvVarsValueChangedCallback, this); + m_collection_sp->SetValueChangedCallback( + ePropertyUnsetEnvVars, TargetProperties::EnvVarsValueChangedCallback, + this); + m_collection_sp->SetValueChangedCallback( + ePropertyInheritEnv, TargetProperties::EnvVarsValueChangedCallback, + this); m_collection_sp->SetValueChangedCallback( ePropertyInputPath, TargetProperties::InputPathValueChangedCallback, this); @@ -3659,19 +3624,43 @@ void TargetProperties::SetRunArguments(const Args &args) { m_launch_info.GetArguments() = args; } +Environment TargetProperties::ComputeEnvironment() const { + Environment env; + + if (m_target && + m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, ePropertyInheritEnv, + g_target_properties[ePropertyInheritEnv].default_uint_value != 0)) { + if (auto platform_sp = m_target->GetPlatform()) { + Environment platform_env = platform_sp->GetEnvironment(); + for (const auto &KV : platform_env) + env[KV.first()] = KV.second; + } + } + + Args property_unset_env; + m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, ePropertyUnsetEnvVars, + property_unset_env); + for (const auto &var : property_unset_env) + env.erase(var.ref()); + + Args property_env; + m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, ePropertyEnvVars, + property_env); + for (const auto &KV : Environment(property_env)) + env[KV.first()] = KV.second; + + return env; +} + Environment TargetProperties::GetEnvironment() const { - // TODO: Get rid of the Args intermediate step - Args env; - const uint32_t idx = ePropertyEnvVars; - m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, idx, env); - return Environment(env); + return ComputeEnvironment(); } void TargetProperties::SetEnvironment(Environment env) { // TODO: Get rid of the Args intermediate step const uint32_t idx = ePropertyEnvVars; m_collection_sp->SetPropertyAtIndexFromArgs(nullptr, idx, Args(env)); - m_launch_info.GetEnvironment() = std::move(env); } bool TargetProperties::GetSkipPrologue() const { @@ -3992,7 +3981,7 @@ void TargetProperties::EnvVarsValueChangedCallback(void *target_property_ptr, OptionValue *) { TargetProperties *this_ = static_cast(target_property_ptr); - this_->m_launch_info.GetEnvironment() = this_->GetEnvironment(); + this_->m_launch_info.GetEnvironment() = this_->ComputeEnvironment(); } void TargetProperties::InputPathValueChangedCallback(void *target_property_ptr, diff --git a/lldb/source/Target/TargetProperties.td b/lldb/source/Target/TargetProperties.td index ff8062aaa2cb3..009d96ccbf919 100644 --- a/lldb/source/Target/TargetProperties.td +++ b/lldb/source/Target/TargetProperties.td @@ -80,7 +80,10 @@ let Definition = "target" in { Desc<"A list containing all the arguments to be passed to the executable when it is run. Note that this does NOT include the argv[0] which is in target.arg0.">; def EnvVars: Property<"env-vars", "Dictionary">, DefaultUnsignedValue<16>, - Desc<"A list of all the environment variables to be passed to the executable's environment, and their values.">; + Desc<"A list of user provided environment variables to be passed to the executable's environment, and their values.">; + def UnsetEnvVars: Property<"unset-env-vars", "Array">, + DefaultUnsignedValue<16>, + Desc<"A list of environment variable names to be unset in the inferior's environment. This is most useful to unset some host environment variables when target.inherit-env is true. target.env-vars takes precedence over target.unset-env-vars.">; def InheritEnv: Property<"inherit-env", "Boolean">, DefaultTrue, Desc<"Inherit the environment from the process that is running LLDB.">; diff --git a/lldb/test/API/commands/settings/TestSettings.py b/lldb/test/API/commands/settings/TestSettings.py index e9d6ff0076509..23f4de05ea0cb 100644 --- a/lldb/test/API/commands/settings/TestSettings.py +++ b/lldb/test/API/commands/settings/TestSettings.py @@ -237,6 +237,10 @@ def do_test_run_args_and_env_vars(self, use_launchsimple): self.assertTrue(found_env_var, "MY_ENV_VAR was not set in LunchInfo object") + self.expect( + 'target show-launch-environment', + substrs=["MY_ENV_VAR=YES"]) + wd = self.get_process_working_directory() if use_launchsimple: process = target.LaunchSimple(None, None, wd) @@ -257,6 +261,31 @@ def do_test_run_args_and_env_vars(self, use_launchsimple): "argv[3] matches", "Environment variable 'MY_ENV_VAR' successfully passed."]) + # Check that env-vars overrides unset-env-vars. + self.runCmd('settings set target.unset-env-vars MY_ENV_VAR') + + self.expect( + 'target show-launch-environment', + 'env-vars overrides unset-env-vars', + substrs=["MY_ENV_VAR=YES"]) + + wd = self.get_process_working_directory() + if use_launchsimple: + process = target.LaunchSimple(None, None, wd) + self.assertTrue(process) + else: + self.runCmd("process launch --working-dir '{0}'".format(wd), + RUN_SUCCEEDED) + + # Read the output file produced by running the program. + output = lldbutil.read_file_from_process_wd(self, "output2.txt") + + self.expect( + output, + exe=False, + substrs=[ + "Environment variable 'MY_ENV_VAR' successfully passed."]) + @skipIfRemote # it doesn't make sense to send host env to remote target def test_pass_host_env_vars(self): """Test that the host env vars are passed to the launched process.""" @@ -270,6 +299,7 @@ def test_pass_host_env_vars(self): def unset_env_variables(): os.environ.pop("MY_HOST_ENV_VAR1") os.environ.pop("MY_HOST_ENV_VAR2") + self.addTearDownHook(unset_env_variables) exe = self.getBuildArtifact("a.out") self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) @@ -280,7 +310,33 @@ def unset_env_variables(): "Default inherit-env is 'true'", startstr="target.inherit-env (boolean) = true") - self.addTearDownHook(unset_env_variables) + self.expect( + 'target show-launch-environment', + 'Host environment is passed correctly', + substrs=['MY_HOST_ENV_VAR1=VAR1', 'MY_HOST_ENV_VAR2=VAR2']) + self.runCmd("process launch --working-dir '{0}'".format(self.get_process_working_directory()), + RUN_SUCCEEDED) + + # Read the output file produced by running the program. + output = lldbutil.read_file_from_process_wd(self, "output1.txt") + + self.expect( + output, + exe=False, + substrs=[ + "The host environment variable 'MY_HOST_ENV_VAR1' successfully passed.", + "The host environment variable 'MY_HOST_ENV_VAR2' successfully passed."]) + + # Now test that we can prevent the inferior from inheriting the + # environment. + self.runCmd('settings set target.inherit-env false') + + self.expect( + 'target show-launch-environment', + 'target.inherit-env affects `target show-launch-environment`', + matching=False, + substrs = ['MY_HOST_ENV_VAR1=VAR1', 'MY_HOST_ENV_VAR2=VAR2']) + self.runCmd("process launch --working-dir '{0}'".format(self.get_process_working_directory()), RUN_SUCCEEDED) @@ -290,10 +346,42 @@ def unset_env_variables(): self.expect( output, exe=False, + matching=False, substrs=[ "The host environment variable 'MY_HOST_ENV_VAR1' successfully passed.", "The host environment variable 'MY_HOST_ENV_VAR2' successfully passed."]) + # Now test that we can unset variables from the inherited environment. + self.runCmd('settings set target.inherit-env true') + self.runCmd('settings set target.unset-env-vars MY_HOST_ENV_VAR1') + self.runCmd("process launch --working-dir '{0}'".format(self.get_process_working_directory()), + RUN_SUCCEEDED) + + # Read the output file produced by running the program. + output = lldbutil.read_file_from_process_wd(self, "output1.txt") + + self.expect( + 'target show-launch-environment', + 'MY_HOST_ENV_VAR1 is unset, it shouldn\'t be in `target show-launch-environment`', + matching=False, + substrs = ['MY_HOST_ENV_VAR1=VAR1']) + self.expect( + 'target show-launch-environment', + 'MY_HOST_ENV_VAR2 shouldn be in `target show-launch-environment`', + substrs = ['MY_HOST_ENV_VAR2=VAR2']) + + self.expect( + output, + exe=False, + matching=False, + substrs=[ + "The host environment variable 'MY_HOST_ENV_VAR1' successfully passed."]) + self.expect( + output, + exe=False, + substrs=[ + "The host environment variable 'MY_HOST_ENV_VAR2' successfully passed."]) + @skipIfDarwinEmbedded # debugserver on ios etc can't write files def test_set_error_output_path(self): """Test that setting target.error/output-path for the launched process works.""" From 3b0da7e1ba1c38706c77413dce6dc187e30a9b35 Mon Sep 17 00:00:00 2001 From: Davide Italiano Date: Mon, 9 Mar 2020 15:35:24 -0700 Subject: [PATCH 070/286] [ObjC] Dynamic type resolution logging should go to the types log. --- .../ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp index 5d77082420e60..8032d66e8e109 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp @@ -1208,7 +1208,8 @@ AppleObjCRuntimeV2::GetClassDescriptor(ValueObject &valobj) { if (isa != LLDB_INVALID_ADDRESS) { objc_class_sp = GetClassDescriptorFromISA(isa); if (isa && !objc_class_sp) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | + LIBLLDB_LOG_TYPES)); LLDB_LOGF(log, "0x%" PRIx64 ": AppleObjCRuntimeV2::GetClassDescriptor() ISA was " From abc6cf3f0c81787e2de314e62ec43990727719b0 Mon Sep 17 00:00:00 2001 From: Davide Italiano Date: Wed, 18 Mar 2020 19:22:52 -0700 Subject: [PATCH 071/286] [AppleObjCRuntimeV2] Rewrite GetClassDescriptor, reducing indentation. I'm going to modify this function to account for lazily allocated class names in the Obj-C runtime, but first I need to understand what it does. --- .../AppleObjCRuntime/AppleObjCRuntimeV2.cpp | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp index 8032d66e8e109..c906dfb0d22c8 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp @@ -1192,33 +1192,33 @@ AppleObjCRuntimeV2::GetClassDescriptor(ValueObject &valobj) { // if we get an invalid VO (which might still happen when playing around with // pointers returned by the expression parser, don't consider this a valid // ObjC object) - if (valobj.GetCompilerType().IsValid()) { - addr_t isa_pointer = valobj.GetPointerValue(); + if (!valobj.GetCompilerType().IsValid()) + return objc_class_sp; + addr_t isa_pointer = valobj.GetPointerValue(); - // tagged pointer - if (IsTaggedPointer(isa_pointer)) { - return m_tagged_pointer_vendor_up->GetClassDescriptor(isa_pointer); - } else { - ExecutionContext exe_ctx(valobj.GetExecutionContextRef()); + // tagged pointer + if (IsTaggedPointer(isa_pointer)) + return m_tagged_pointer_vendor_up->GetClassDescriptor(isa_pointer); + ExecutionContext exe_ctx(valobj.GetExecutionContextRef()); - Process *process = exe_ctx.GetProcessPtr(); - if (process) { - Status error; - ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error); - if (isa != LLDB_INVALID_ADDRESS) { - objc_class_sp = GetClassDescriptorFromISA(isa); - if (isa && !objc_class_sp) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | - LIBLLDB_LOG_TYPES)); - LLDB_LOGF(log, - "0x%" PRIx64 - ": AppleObjCRuntimeV2::GetClassDescriptor() ISA was " - "not in class descriptor cache 0x%" PRIx64, - isa_pointer, isa); - } - } - } - } + Process *process = exe_ctx.GetProcessPtr(); + if (!process) + return objc_class_sp; + + Status error; + ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error); + if (isa == LLDB_INVALID_ADDRESS) + return objc_class_sp; + + objc_class_sp = GetClassDescriptorFromISA(isa); + if (isa && !objc_class_sp) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | + LIBLLDB_LOG_TYPES)); + LLDB_LOGF(log, + "0x%" PRIx64 + ": AppleObjCRuntimeV2::GetClassDescriptor() ISA was " + "not in class descriptor cache 0x%" PRIx64, + isa_pointer, isa); } return objc_class_sp; } From 9207e4a854280b7620844947ab468b39e3ffc570 Mon Sep 17 00:00:00 2001 From: Davide Italiano Date: Fri, 20 Mar 2020 13:42:21 -0700 Subject: [PATCH 072/286] [AppleObjCRuntimeV2] Force lazily allocated class names to be resolved. Fixes a couple of tests on new versions of the Obj-C runtime. --- .../AppleObjCRuntime/AppleObjCRuntimeV2.cpp | 34 ++++++++++++++++++- .../Shell/ExecControl/StopHook/stop-hook.test | 2 +- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp index c906dfb0d22c8..85b551539b506 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp @@ -1176,6 +1176,28 @@ AppleObjCRuntimeV2::GetClassDescriptorFromISA(ObjCISA isa) { return class_descriptor_sp; } +static std::pair ObjCGetClassNameRaw( + AppleObjCRuntime::ObjCISA isa, + Process *process) { + StreamString expr_string; + std::string input = std::to_string(isa); + expr_string.Printf("(const char *)objc_debug_class_getNameRaw(%s)", + input.c_str()); + + ValueObjectSP result_sp; + EvaluateExpressionOptions eval_options; + eval_options.SetLanguage(lldb::eLanguageTypeObjC); + eval_options.SetResultIsInternal(true); + eval_options.SetGenerateDebugInfo(true); + eval_options.SetTimeout(process->GetUtilityExpressionTimeout()); + auto eval_result = process->GetTarget().EvaluateExpression( + expr_string.GetData(), + process->GetThreadList().GetSelectedThread()->GetSelectedFrame().get(), + result_sp, eval_options); + ConstString type_name(result_sp->GetSummaryAsCString()); + return std::make_pair(eval_result == eExpressionCompleted, type_name); +} + ObjCLanguageRuntime::ClassDescriptorSP AppleObjCRuntimeV2::GetClassDescriptor(ValueObject &valobj) { ClassDescriptorSP objc_class_sp; @@ -1211,7 +1233,10 @@ AppleObjCRuntimeV2::GetClassDescriptor(ValueObject &valobj) { return objc_class_sp; objc_class_sp = GetClassDescriptorFromISA(isa); - if (isa && !objc_class_sp) { + + if (objc_class_sp) + return objc_class_sp; + else { Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES)); LLDB_LOGF(log, @@ -1220,6 +1245,13 @@ AppleObjCRuntimeV2::GetClassDescriptor(ValueObject &valobj) { "not in class descriptor cache 0x%" PRIx64, isa_pointer, isa); } + + ClassDescriptorSP descriptor_sp(new ClassDescriptorV2(*this, isa, nullptr)); + auto resolved = ObjCGetClassNameRaw(isa, process); + if (resolved.first == true) { + AddClass(isa, descriptor_sp, resolved.second.AsCString()); + objc_class_sp = descriptor_sp; + } return objc_class_sp; } diff --git a/lldb/test/Shell/ExecControl/StopHook/stop-hook.test b/lldb/test/Shell/ExecControl/StopHook/stop-hook.test index a06de6634ea19..7e5b37b638547 100644 --- a/lldb/test/Shell/ExecControl/StopHook/stop-hook.test +++ b/lldb/test/Shell/ExecControl/StopHook/stop-hook.test @@ -51,7 +51,7 @@ run thread step-over # Stepping inside of the stop hook range # CHECK: (lldb) thread step-over -# CHECK-NEXT: (void *) $1 = 0x +# CHECK-NEXT: (void *) $2 = 0x # CHECK: ->{{.*}} // We should stop here after stepping. process continue From 70cfcc8c0d8ec88cbccbd3c2c015c6f5c3f35a29 Mon Sep 17 00:00:00 2001 From: Davide Italiano Date: Fri, 20 Mar 2020 13:57:40 -0700 Subject: [PATCH 073/286] [StopHook] Use wildcard matching. Pointed out by Jim Ingham. --- lldb/test/Shell/ExecControl/StopHook/stop-hook.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lldb/test/Shell/ExecControl/StopHook/stop-hook.test b/lldb/test/Shell/ExecControl/StopHook/stop-hook.test index 7e5b37b638547..98a77cac99bac 100644 --- a/lldb/test/Shell/ExecControl/StopHook/stop-hook.test +++ b/lldb/test/Shell/ExecControl/StopHook/stop-hook.test @@ -46,12 +46,12 @@ target stop-hook list run # Stopping inside of the stop hook range # CHECK: (lldb) run -# CHECK-NEXT: (void *) $0 = 0x +# CHECK-NEXT: (void *) ${{.*}} = 0x thread step-over # Stepping inside of the stop hook range # CHECK: (lldb) thread step-over -# CHECK-NEXT: (void *) $2 = 0x +# CHECK-NEXT: (void *) ${{.*}} = 0x # CHECK: ->{{.*}} // We should stop here after stepping. process continue From 363723ec997e30e69b359deef7cebcbc45f6645b Mon Sep 17 00:00:00 2001 From: Fred Riss Date: Thu, 19 Mar 2020 08:43:41 -0700 Subject: [PATCH 074/286] [lldb/PlatformDarwin] Always delete destination file first in PutFile Summary: The default behavior of Platform::PutFile is to open the file and truncate it if it already exists. This works fine and is a sensible default, but it interacts badly with code-signing on iOS, as doing so invalidates the signature of the file (even if the new content has a valid code signature). We have a couple tests which on purpose reload a different binary with the same name. Those tests are currently broken because of the above interaction. This patch simply makes the Darwin platform unconditionally delete the destination file before sending the new one to work around this issue. Reviewers: jasonmolenda Subscribers: lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D76450 (cherry picked from commit b6ae8937e031cde2e70e6a83d46c21e940fdf4ac) --- .../source/Plugins/Platform/MacOSX/PlatformDarwin.cpp | 11 +++++++++++ lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp index 906b2bdf4b1d0..0347bde7d23d2 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp @@ -58,6 +58,17 @@ PlatformDarwin::PlatformDarwin(bool is_host) /// inherited from by the plug-in instance. PlatformDarwin::~PlatformDarwin() {} +lldb_private::Status +PlatformDarwin::PutFile(const lldb_private::FileSpec &source, + const lldb_private::FileSpec &destination, uint32_t uid, + uint32_t gid) { + // Unconditionally unlink the destination. If it is an executable, + // simply opening it and truncating its contents would invalidate + // its cached code signature. + Unlink(destination); + return PlatformPOSIX::PutFile(source, destination, uid, gid); +} + FileSpecList PlatformDarwin::LocateExecutableScriptingResources( Target *target, Module &module, Stream *feedback_stream) { FileSpecList file_list; diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h index b90a32c201587..66feeb95602c3 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h @@ -26,6 +26,11 @@ class PlatformDarwin : public PlatformPOSIX { ~PlatformDarwin() override; + lldb_private::Status PutFile(const lldb_private::FileSpec &source, + const lldb_private::FileSpec &destination, + uint32_t uid = UINT32_MAX, + uint32_t gid = UINT32_MAX) override; + // lldb_private::Platform functions lldb_private::Status ResolveSymbolFile(lldb_private::Target &target, From 1f4c8d4ec521d1b08ad646a3844845daca3df633 Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Mon, 23 Mar 2020 15:10:03 -0700 Subject: [PATCH 075/286] [objc_direct] also go through implementations when looking for clashes Some methods are sometimes declared in the @implementation blocks which can cause undiagnosed clashes. Just write a checkObjCDirectMethodClashes() for this purpose. Also make sure that "unavailable" selectors do not inherit objc_direct_members. Differential Revision: https://reviews.llvm.org/D76643 Signed-off-by: Pierre Habouzit Radar-ID: rdar://problem/59332804, rdar://problem/59782963 (cherry picked from commit 20d704a75ed51c7a9a155aa3978d0c02671c3f69) --- clang/lib/Sema/SemaDeclObjC.cpp | 95 +++++++++++++------ .../SemaObjC/method-direct-one-definition.m | 11 +++ clang/test/SemaObjC/method-direct.m | 4 + 3 files changed, 79 insertions(+), 31 deletions(-) diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index ef49e5718e9ad..d1e5189015ec4 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -4636,6 +4636,62 @@ static void checkObjCMethodX86VectorTypes(Sema &SemaRef, << (Triple.isMacOSX() ? "macOS 10.11" : "iOS 9"); } +static void mergeObjCDirectMembers(Sema &S, Decl *CD, ObjCMethodDecl *Method) { + if (!Method->isDirectMethod() && !Method->hasAttr() && + CD->hasAttr()) { + Method->addAttr( + ObjCDirectAttr::CreateImplicit(S.Context, Method->getLocation())); + } +} + +static void checkObjCDirectMethodClashes(Sema &S, ObjCInterfaceDecl *IDecl, + ObjCMethodDecl *Method, + ObjCImplDecl *ImpDecl = nullptr) { + auto Sel = Method->getSelector(); + bool isInstance = Method->isInstanceMethod(); + bool diagnosed = false; + + auto diagClash = [&](const ObjCMethodDecl *IMD) { + if (diagnosed || IMD->isImplicit()) + return; + if (Method->isDirectMethod() || IMD->isDirectMethod()) { + S.Diag(Method->getLocation(), diag::err_objc_direct_duplicate_decl) + << Method->isDirectMethod() << /* method */ 0 << IMD->isDirectMethod() + << Method->getDeclName(); + S.Diag(IMD->getLocation(), diag::note_previous_declaration); + diagnosed = true; + } + }; + + // Look for any other declaration of this method anywhere we can see in this + // compilation unit. + // + // We do not use IDecl->lookupMethod() because we have specific needs: + // + // - we absolutely do not need to walk protocols, because + // diag::err_objc_direct_on_protocol has already been emitted + // during parsing if there's a conflict, + // + // - when we do not find a match in a given @interface container, + // we need to attempt looking it up in the @implementation block if the + // translation unit sees it to find more clashes. + + if (auto *IMD = IDecl->getMethod(Sel, isInstance)) + diagClash(IMD); + else if (auto *Impl = IDecl->getImplementation()) + if (Impl != ImpDecl) + if (auto *IMD = IDecl->getImplementation()->getMethod(Sel, isInstance)) + diagClash(IMD); + + for (const auto *Cat : IDecl->visible_categories()) + if (auto *IMD = Cat->getMethod(Sel, isInstance)) + diagClash(IMD); + else if (auto CatImpl = Cat->getImplementation()) + if (CatImpl != ImpDecl) + if (auto *IMD = Cat->getMethod(Sel, isInstance)) + diagClash(IMD); +} + Decl *Sema::ActOnMethodDeclaration( Scope *S, SourceLocation MethodLoc, SourceLocation EndLoc, tok::TokenKind MethodType, ObjCDeclSpec &ReturnQT, ParsedType ReturnType, @@ -4866,9 +4922,9 @@ Decl *Sema::ActOnMethodDeclaration( Diag(ObjCMethod->getLocation(), diag::warn_dealloc_in_category) << ObjCMethod->getDeclName(); } - } else if (ImpDecl->hasAttr()) { - ObjCMethod->addAttr( - ObjCDirectAttr::CreateImplicit(Context, ObjCMethod->getLocation())); + } else { + mergeObjCDirectMembers(*this, ClassDecl, ObjCMethod); + checkObjCDirectMethodClashes(*this, IDecl, ObjCMethod, ImpDecl); } // Warn if a method declared in a protocol to which a category or @@ -4889,39 +4945,16 @@ Decl *Sema::ActOnMethodDeclaration( } } else { if (!isa(ClassDecl)) { - if (!ObjCMethod->isDirectMethod() && - ClassDecl->hasAttr()) { - ObjCMethod->addAttr( - ObjCDirectAttr::CreateImplicit(Context, ObjCMethod->getLocation())); - } + mergeObjCDirectMembers(*this, ClassDecl, ObjCMethod); - // There can be a single declaration in any @interface container - // for a given direct method, look for clashes as we add them. - // - // For valid code, we should always know the primary interface - // declaration by now, however for invalid code we'll keep parsing - // but we won't find the primary interface and IDecl will be nil. ObjCInterfaceDecl *IDecl = dyn_cast(ClassDecl); if (!IDecl) IDecl = cast(ClassDecl)->getClassInterface(); - + // For valid code, we should always know the primary interface + // declaration by now, however for invalid code we'll keep parsing + // but we won't find the primary interface and IDecl will be nil. if (IDecl) - if (auto *IMD = IDecl->lookupMethod(ObjCMethod->getSelector(), - ObjCMethod->isInstanceMethod(), - /*shallowCategoryLookup=*/false, - /*followSuper=*/false)) { - if (isa(IMD->getDeclContext())) { - // Do not emit a diagnostic for the Protocol case: - // diag::err_objc_direct_on_protocol has already been emitted - // during parsing for these with a nicer diagnostic. - } else if (ObjCMethod->isDirectMethod() || IMD->isDirectMethod()) { - Diag(ObjCMethod->getLocation(), - diag::err_objc_direct_duplicate_decl) - << ObjCMethod->isDirectMethod() << /* method */ 0 - << IMD->isDirectMethod() << ObjCMethod->getDeclName(); - Diag(IMD->getLocation(), diag::note_previous_declaration); - } - } + checkObjCDirectMethodClashes(*this, IDecl, ObjCMethod); } cast(ClassDecl)->addDecl(ObjCMethod); diff --git a/clang/test/SemaObjC/method-direct-one-definition.m b/clang/test/SemaObjC/method-direct-one-definition.m index e6355d2cb7bac..3dcf89d784cf1 100644 --- a/clang/test/SemaObjC/method-direct-one-definition.m +++ b/clang/test/SemaObjC/method-direct-one-definition.m @@ -30,6 +30,15 @@ @interface B (OtherCat) - (void)B_OtherCat __attribute__((objc_direct)); // expected-note {{previous declaration is here}} @end +@implementation B +- (void)B_primary { +} +- (void)B_extension { +} +- (void)B_implOnly __attribute__((objc_direct)) { // expected-note {{previous declaration is here}} +} +@end + @implementation B (Cat) - (void)B_primary { // expected-error {{direct method was declared in the primary interface but is implemented in a category}} } @@ -39,6 +48,8 @@ - (void)B_Cat { } - (void)B_OtherCat { // expected-error {{direct method was declared in a category but is implemented in a different category}} } +- (void)B_implOnly __attribute__((objc_direct)) { // expected-error {{direct method declaration conflicts with previous direct declaration of method 'B_implOnly'}} +} @end __attribute__((objc_root_class)) diff --git a/clang/test/SemaObjC/method-direct.m b/clang/test/SemaObjC/method-direct.m index 9aef9808abbda..80ca5b2e6ebe1 100644 --- a/clang/test/SemaObjC/method-direct.m +++ b/clang/test/SemaObjC/method-direct.m @@ -12,6 +12,7 @@ + (void)classProtoMethod __attribute__((objc_direct)); // expected-error {{'objc __attribute__((objc_root_class)) @interface Root +- (void)unavailableInChild; - (void)rootRegular; // expected-note {{previous declaration is here}} + (void)classRootRegular; // expected-note {{previous declaration is here}} - (void)rootDirect __attribute__((objc_direct)); // expected-note {{previous declaration is here}}; @@ -52,6 +53,7 @@ + (void)classRootCategoryDirect2 __attribute__((objc_direct)); // expected-note __attribute__((objc_direct_members)) @interface SubDirectMembers : Root @property int foo; // expected-note {{previous declaration is here}} +- (void)unavailableInChild __attribute__((unavailable)); // should not warn - (instancetype)init; @end @@ -81,6 +83,8 @@ + (void)classRootCategoryDirect2; // expected-error {{cannot override a method __attribute__((objc_direct_members)) @implementation Root +- (void)unavailableInChild { +} - (void)rootRegular { } + (void)classRootRegular { From 3d2655307218ed074af2b6d6ebc6aabbaa7735bc Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Thu, 12 Mar 2020 09:51:59 -0700 Subject: [PATCH 076/286] [lldb/Utility] Add YAML traits for ConstString and FileSpec. Add YAML traits for the ConstString and FileSpec classes so they can be serialized as part of ProcessInfo. The latter needs to be serializable for the reproducers. Differential revision: https://reviews.llvm.org/D76002 (cherry picked from commit bc9b6b33a0d5760370e72ae06c520c25aa8d61c6) --- lldb/include/lldb/Utility/ConstString.h | 15 +++++++++++++-- lldb/include/lldb/Utility/FileSpec.h | 15 +++++++++++++++ lldb/source/Utility/ConstString.cpp | 12 ++++++++++++ lldb/source/Utility/FileSpec.cpp | 16 ++++++++++++++++ lldb/unittests/Utility/ConstStringTest.cpp | 20 ++++++++++++++++++++ lldb/unittests/Utility/FileSpecTest.cpp | 21 +++++++++++++++++++++ 6 files changed, 97 insertions(+), 2 deletions(-) diff --git a/lldb/include/lldb/Utility/ConstString.h b/lldb/include/lldb/Utility/ConstString.h index 74750459d16fb..cff191135934b 100644 --- a/lldb/include/lldb/Utility/ConstString.h +++ b/lldb/include/lldb/Utility/ConstString.h @@ -9,9 +9,10 @@ #ifndef liblldb_ConstString_h_ #define liblldb_ConstString_h_ -#include "llvm/ADT/StringRef.h" #include "llvm/ADT/DenseMapInfo.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/YAMLTraits.h" #include @@ -481,6 +482,16 @@ template <> struct DenseMapInfo { } }; /// \} -} + +namespace yaml { +template <> struct ScalarTraits { + static void output(const lldb_private::ConstString &, void *, raw_ostream &); + static StringRef input(StringRef, void *, lldb_private::ConstString &); + static QuotingType mustQuote(StringRef S) { return QuotingType::Double; } +}; +} // namespace yaml +} // namespace llvm + +LLVM_YAML_IS_SEQUENCE_VECTOR(lldb_private::ConstString) #endif // liblldb_ConstString_h_ diff --git a/lldb/include/lldb/Utility/FileSpec.h b/lldb/include/lldb/Utility/FileSpec.h index 533426671cc6a..5e2002e525219 100644 --- a/lldb/include/lldb/Utility/FileSpec.h +++ b/lldb/include/lldb/Utility/FileSpec.h @@ -18,6 +18,7 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/Path.h" +#include "llvm/Support/YAMLTraits.h" #include #include @@ -397,6 +398,8 @@ class FileSpec { ConstString GetLastPathComponent() const; protected: + friend struct llvm::yaml::MappingTraits; + // Convenience method for setting the file without changing the style. void SetFile(llvm::StringRef path); @@ -410,6 +413,8 @@ class FileSpec { /// Dump a FileSpec object to a stream Stream &operator<<(Stream &s, const FileSpec &f); +/// Prevent ODR violations with traits for llvm::sys::path::Style. +LLVM_YAML_STRONG_TYPEDEF(FileSpec::Style, FileSpecStyle) } // namespace lldb_private namespace llvm { @@ -436,6 +441,16 @@ template <> struct format_provider { static void format(const lldb_private::FileSpec &F, llvm::raw_ostream &Stream, StringRef Style); }; + +namespace yaml { +template <> struct ScalarEnumerationTraits { + static void enumeration(IO &io, lldb_private::FileSpecStyle &style); +}; + +template <> struct MappingTraits { + static void mapping(IO &io, lldb_private::FileSpec &f); +}; +} // namespace yaml } // namespace llvm #endif // liblldb_FileSpec_h_ diff --git a/lldb/source/Utility/ConstString.cpp b/lldb/source/Utility/ConstString.cpp index e90bb929bb81f..6bcb10d971be2 100644 --- a/lldb/source/Utility/ConstString.cpp +++ b/lldb/source/Utility/ConstString.cpp @@ -309,3 +309,15 @@ void llvm::format_provider::format(const ConstString &CS, llvm::StringRef Options) { format_provider::format(CS.AsCString(), OS, Options); } + +void llvm::yaml::ScalarTraits::output(const ConstString &Val, + void *, raw_ostream &Out) { + Out << Val.GetStringRef(); +} + +llvm::StringRef +llvm::yaml::ScalarTraits::input(llvm::StringRef Scalar, void *, + ConstString &Val) { + Val = ConstString(Scalar); + return {}; +} diff --git a/lldb/source/Utility/FileSpec.cpp b/lldb/source/Utility/FileSpec.cpp index 5c216d947f75a..79ed6d3d2f602 100644 --- a/lldb/source/Utility/FileSpec.cpp +++ b/lldb/source/Utility/FileSpec.cpp @@ -537,3 +537,19 @@ void llvm::format_provider::format(const FileSpec &F, if (!file.empty()) Stream << file; } + +void llvm::yaml::ScalarEnumerationTraits::enumeration( + IO &io, FileSpecStyle &value) { + io.enumCase(value, "windows", FileSpecStyle(FileSpec::Style::windows)); + io.enumCase(value, "posix", FileSpecStyle(FileSpec::Style::posix)); + io.enumCase(value, "native", FileSpecStyle(FileSpec::Style::native)); +} + +void llvm::yaml::MappingTraits::mapping(IO &io, FileSpec &f) { + io.mapRequired("directory", f.m_directory); + io.mapRequired("file", f.m_filename); + io.mapRequired("resolved", f.m_is_resolved); + FileSpecStyle style = f.m_style; + io.mapRequired("style", style); + f.m_style = style; +} diff --git a/lldb/unittests/Utility/ConstStringTest.cpp b/lldb/unittests/Utility/ConstStringTest.cpp index 74753b903171d..1aefa25380455 100644 --- a/lldb/unittests/Utility/ConstStringTest.cpp +++ b/lldb/unittests/Utility/ConstStringTest.cpp @@ -8,6 +8,7 @@ #include "lldb/Utility/ConstString.h" #include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/YAMLParser.h" #include "gtest/gtest.h" using namespace lldb_private; @@ -137,3 +138,22 @@ TEST(ConstStringTest, CompareStringRef) { EXPECT_TRUE(null == static_cast(nullptr)); EXPECT_TRUE(null != "bar"); } + +TEST(ConstStringTest, YAML) { + std::string buffer; + llvm::raw_string_ostream os(buffer); + + // Serialize. + std::vector strings = {ConstString("foo"), ConstString("bar"), + ConstString("")}; + llvm::yaml::Output yout(os); + yout << strings; + os.flush(); + + // Deserialize. + std::vector deserialized; + llvm::yaml::Input yin(buffer); + yin >> deserialized; + + EXPECT_EQ(strings, deserialized); +} diff --git a/lldb/unittests/Utility/FileSpecTest.cpp b/lldb/unittests/Utility/FileSpecTest.cpp index d5f1091d5d469..b5ccb5373df98 100644 --- a/lldb/unittests/Utility/FileSpecTest.cpp +++ b/lldb/unittests/Utility/FileSpecTest.cpp @@ -420,3 +420,24 @@ TEST(FileSpecTest, Match) { EXPECT_TRUE(Match("", "")); } + +TEST(FileSpecTest, Yaml) { + std::string buffer; + llvm::raw_string_ostream os(buffer); + + // Serialize. + FileSpec fs_windows("F:\\bar", FileSpec::Style::windows); + llvm::yaml::Output yout(os); + yout << fs_windows; + os.flush(); + + // Deserialize. + FileSpec deserialized; + llvm::yaml::Input yin(buffer); + yin >> deserialized; + + EXPECT_EQ(deserialized.GetPathStyle(), fs_windows.GetPathStyle()); + EXPECT_EQ(deserialized.GetFilename(), fs_windows.GetFilename()); + EXPECT_EQ(deserialized.GetDirectory(), fs_windows.GetDirectory()); + EXPECT_EQ(deserialized, fs_windows); +} From 686200acc8315147cab829886229b196f21a625e Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Thu, 12 Mar 2020 14:10:25 -0700 Subject: [PATCH 077/286] [lldb/Utility] Replace ProcessInstanceInfoList with std::vector. (NFCI) Replace ProcessInstanceInfoList with std::vector and update the call sites. (cherry picked from commit 638b06cf298bc622c3ffd93dc4715c6f806de5b5) --- lldb/include/lldb/Host/Host.h | 2 +- lldb/include/lldb/Target/Platform.h | 2 +- lldb/include/lldb/Utility/ProcessInfo.h | 36 +------------------ lldb/include/lldb/lldb-forward.h | 1 - .../source/Commands/CommandObjectPlatform.cpp | 6 ++-- lldb/source/Commands/CommandObjectProcess.cpp | 4 +-- lldb/source/Host/freebsd/Host.cpp | 8 ++--- lldb/source/Host/linux/Host.cpp | 4 +-- lldb/source/Host/macosx/objcxx/Host.mm | 4 +-- lldb/source/Host/netbsd/Host.cpp | 8 ++--- lldb/source/Host/openbsd/Host.cpp | 4 +-- lldb/source/Host/windows/Host.cpp | 4 +-- .../MacOSX/PlatformAppleTVSimulator.cpp | 7 ++-- .../MacOSX/PlatformAppleWatchSimulator.cpp | 7 ++-- .../Platform/MacOSX/PlatformiOSSimulator.cpp | 7 ++-- .../GDBRemoteCommunicationClient.cpp | 6 ++-- .../gdb-remote/GDBRemoteCommunicationClient.h | 1 + .../GDBRemoteCommunicationServerCommon.cpp | 7 ++-- lldb/source/Target/Process.cpp | 6 ++-- 19 files changed, 43 insertions(+), 81 deletions(-) diff --git a/lldb/include/lldb/Host/Host.h b/lldb/include/lldb/Host/Host.h index 884c5cf632134..269bb18571b0f 100644 --- a/lldb/include/lldb/Host/Host.h +++ b/lldb/include/lldb/Host/Host.h @@ -27,8 +27,8 @@ namespace lldb_private { class FileAction; class ProcessLaunchInfo; class ProcessInstanceInfo; -class ProcessInstanceInfoList; class ProcessInstanceInfoMatch; +typedef std::vector ProcessInstanceInfoList; // Exit Type for inferior processes struct WaitStatus { diff --git a/lldb/include/lldb/Target/Platform.h b/lldb/include/lldb/Target/Platform.h index 780b7156eb009..46d5974e3c30b 100644 --- a/lldb/include/lldb/Target/Platform.h +++ b/lldb/include/lldb/Target/Platform.h @@ -33,8 +33,8 @@ namespace lldb_private { class ProcessInstanceInfo; -class ProcessInstanceInfoList; class ProcessInstanceInfoMatch; +typedef std::vector ProcessInstanceInfoList; class ModuleCache; enum MmapFlags { eMmapFlagsPrivate = 1, eMmapFlagsAnon = 2 }; diff --git a/lldb/include/lldb/Utility/ProcessInfo.h b/lldb/include/lldb/Utility/ProcessInfo.h index 9188bf3b70900..14decee80e0c7 100644 --- a/lldb/include/lldb/Utility/ProcessInfo.h +++ b/lldb/include/lldb/Utility/ProcessInfo.h @@ -155,41 +155,7 @@ class ProcessInstanceInfo : public ProcessInfo { lldb::pid_t m_parent_pid; }; -class ProcessInstanceInfoList { -public: - ProcessInstanceInfoList() = default; - - void Clear() { m_infos.clear(); } - - size_t GetSize() { return m_infos.size(); } - - void Append(const ProcessInstanceInfo &info) { m_infos.push_back(info); } - - llvm::StringRef GetProcessNameAtIndex(size_t idx) { - return ((idx < m_infos.size()) ? m_infos[idx].GetNameAsStringRef() : ""); - } - - lldb::pid_t GetProcessIDAtIndex(size_t idx) { - return ((idx < m_infos.size()) ? m_infos[idx].GetProcessID() : 0); - } - - bool GetInfoAtIndex(size_t idx, ProcessInstanceInfo &info) { - if (idx < m_infos.size()) { - info = m_infos[idx]; - return true; - } - return false; - } - - // You must ensure "idx" is valid before calling this function - const ProcessInstanceInfo &GetProcessInfoAtIndex(size_t idx) const { - assert(idx < m_infos.size()); - return m_infos[idx]; - } - -protected: - std::vector m_infos; -}; +typedef std::vector ProcessInstanceInfoList; // ProcessInstanceInfoMatch // diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h index f5e345d22419b..be8b03ea85285 100644 --- a/lldb/include/lldb/lldb-forward.h +++ b/lldb/include/lldb/lldb-forward.h @@ -169,7 +169,6 @@ class ProcessAttachInfo; class ProcessModID; class ProcessInfo; class ProcessInstanceInfo; -class ProcessInstanceInfoList; class ProcessInstanceInfoMatch; class ProcessLaunchInfo; class Property; diff --git a/lldb/source/Commands/CommandObjectPlatform.cpp b/lldb/source/Commands/CommandObjectPlatform.cpp index 10e6a4aa17930..4accf4a9aaa34 100644 --- a/lldb/source/Commands/CommandObjectPlatform.cpp +++ b/lldb/source/Commands/CommandObjectPlatform.cpp @@ -1128,7 +1128,7 @@ class CommandObjectPlatformProcessList : public CommandObjectParsed { ProcessInstanceInfo::DumpTableHeader(ostrm, m_options.show_args, m_options.verbose); for (uint32_t i = 0; i < matches; ++i) { - proc_infos.GetProcessInfoAtIndex(i).DumpAsTableRow( + proc_infos[i].DumpAsTableRow( ostrm, platform_sp->GetUserIDResolver(), m_options.show_args, m_options.verbose); } @@ -1462,12 +1462,12 @@ class CommandObjectPlatformProcessAttach : public CommandObjectParsed { match_info.SetNameMatchType(NameMatch::StartsWith); } platform_sp->FindProcesses(match_info, process_infos); - const uint32_t num_matches = process_infos.GetSize(); + const uint32_t num_matches = process_infos.size(); if (num_matches == 0) return; for (uint32_t i = 0; i < num_matches; ++i) { - request.AddCompletion(process_infos.GetProcessNameAtIndex(i)); + request.AddCompletion(process_infos[i].GetNameAsStringRef()); } return; } diff --git a/lldb/source/Commands/CommandObjectProcess.cpp b/lldb/source/Commands/CommandObjectProcess.cpp index fb7b061ce5599..4ec889833f980 100644 --- a/lldb/source/Commands/CommandObjectProcess.cpp +++ b/lldb/source/Commands/CommandObjectProcess.cpp @@ -348,11 +348,11 @@ class CommandObjectProcessAttach : public CommandObjectProcessLaunchOrAttach { match_info.SetNameMatchType(NameMatch::StartsWith); } platform_sp->FindProcesses(match_info, process_infos); - const size_t num_matches = process_infos.GetSize(); + const size_t num_matches = process_infos.size(); if (num_matches == 0) return; for (size_t i = 0; i < num_matches; ++i) { - request.AddCompletion(process_infos.GetProcessNameAtIndex(i)); + request.AddCompletion(process_infos[i].GetNameAsStringRef()); } } diff --git a/lldb/source/Host/freebsd/Host.cpp b/lldb/source/Host/freebsd/Host.cpp index 99d728d63bc04..52283d818bb1c 100644 --- a/lldb/source/Host/freebsd/Host.cpp +++ b/lldb/source/Host/freebsd/Host.cpp @@ -196,10 +196,10 @@ uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, bool already_registered = false; for (uint32_t pi = 0; !already_registered && (const int)kinfo.ki_numthreads > 1 && - pi < (const uint32_t)process_infos.GetSize(); + pi < (const uint32_t)process_infos.size(); pi++) already_registered = - (process_infos.GetProcessIDAtIndex(pi) == (uint32_t)kinfo.ki_pid); + (process_infos[pi].GetProcessID() == (uint32_t)kinfo.ki_pid); if (already_registered) continue; @@ -217,11 +217,11 @@ uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, GetFreeBSDProcessArgs(&match_info, process_info)) { GetFreeBSDProcessCPUType(process_info); if (match_info.Matches(process_info)) - process_infos.Append(process_info); + process_infos.push_back(process_info); } } - return process_infos.GetSize(); + return process_infos.size(); } bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) { diff --git a/lldb/source/Host/linux/Host.cpp b/lldb/source/Host/linux/Host.cpp index fe60d1fd8a730..6c9c67d69e18c 100644 --- a/lldb/source/Host/linux/Host.cpp +++ b/lldb/source/Host/linux/Host.cpp @@ -262,14 +262,14 @@ uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, continue; if (match_info.Matches(process_info)) { - process_infos.Append(process_info); + process_infos.push_back(process_info); } } closedir(dirproc); } - return process_infos.GetSize(); + return process_infos.size(); } bool Host::FindProcessThreads(const lldb::pid_t pid, TidMap &tids_to_attach) { diff --git a/lldb/source/Host/macosx/objcxx/Host.mm b/lldb/source/Host/macosx/objcxx/Host.mm index 233734109c41c..0e668713d4bd5 100644 --- a/lldb/source/Host/macosx/objcxx/Host.mm +++ b/lldb/source/Host/macosx/objcxx/Host.mm @@ -660,11 +660,11 @@ static bool GetMacOSXProcessUserAndGroup(ProcessInstanceInfo &process_info) { if (GetMacOSXProcessCPUType(process_info)) { if (GetMacOSXProcessArgs(&match_info, process_info)) { if (match_info.Matches(process_info)) - process_infos.Append(process_info); + process_infos.push_back(process_info); } } } - return process_infos.GetSize(); + return process_infos.size(); } bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) { diff --git a/lldb/source/Host/netbsd/Host.cpp b/lldb/source/Host/netbsd/Host.cpp index 20f3db3c22c1d..ee61d51e81ff0 100644 --- a/lldb/source/Host/netbsd/Host.cpp +++ b/lldb/source/Host/netbsd/Host.cpp @@ -197,8 +197,8 @@ uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, // list if a process with given identifier is already registered there. if (proc_kinfo[i].p_nlwps > 1) { bool already_registered = false; - for (size_t pi = 0; pi < process_infos.GetSize(); pi++) { - if (process_infos.GetProcessIDAtIndex(pi) == proc_kinfo[i].p_pid) { + for (size_t pi = 0; pi < process_infos.size(); pi++) { + if (process_infos[pi].GetProcessID() == proc_kinfo[i].p_pid) { already_registered = true; break; } @@ -219,13 +219,13 @@ uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, GetNetBSDProcessArgs(&match_info, process_info)) { GetNetBSDProcessCPUType(process_info); if (match_info.Matches(process_info)) - process_infos.Append(process_info); + process_infos.push_back(process_info); } } kvm_close(kdp); /* XXX: we don't check for error here */ - return process_infos.GetSize(); + return process_infos.size(); } bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) { diff --git a/lldb/source/Host/openbsd/Host.cpp b/lldb/source/Host/openbsd/Host.cpp index ba6cf057ca171..3fdf414a3a47a 100644 --- a/lldb/source/Host/openbsd/Host.cpp +++ b/lldb/source/Host/openbsd/Host.cpp @@ -193,11 +193,11 @@ uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, GetOpenBSDProcessArgs(&match_info, process_info)) { GetOpenBSDProcessCPUType(process_info); if (match_info.Matches(process_info)) - process_infos.Append(process_info); + process_infos.push_back(process_info); } } - return process_infos.GetSize(); + return process_infos.size(); } bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) { diff --git a/lldb/source/Host/windows/Host.cpp b/lldb/source/Host/windows/Host.cpp index 1282bbe8e5c55..8e8605a549a9f 100644 --- a/lldb/source/Host/windows/Host.cpp +++ b/lldb/source/Host/windows/Host.cpp @@ -156,10 +156,10 @@ uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, GetProcessExecutableAndTriple(handle, process); if (match_info.MatchAllProcesses() || match_info.Matches(process)) - process_infos.Append(process); + process_infos.push_back(process); } while (Process32NextW(snapshot.get(), &pe)); } - return process_infos.GetSize(); + return process_infos.size(); } bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) { diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.cpp index 40148e23a1b11..08a5b084cb1ad 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.cpp @@ -361,13 +361,12 @@ uint32_t PlatformAppleTVSimulator::FindProcesses( // Now we filter them down to only the TvOS triples for (uint32_t i = 0; i < n; ++i) { - const ProcessInstanceInfo &proc_info = - all_osx_process_infos.GetProcessInfoAtIndex(i); + const ProcessInstanceInfo &proc_info = all_osx_process_infos[i]; if (proc_info.GetArchitecture().GetTriple().getOS() == llvm::Triple::TvOS) { - process_infos.Append(proc_info); + process_infos.push_back(proc_info); } } - return process_infos.GetSize(); + return process_infos.size(); } bool PlatformAppleTVSimulator::GetSupportedArchitectureAtIndex(uint32_t idx, diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.cpp index 0e21f3b96d999..65ee668b47849 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.cpp @@ -361,14 +361,13 @@ uint32_t PlatformAppleWatchSimulator::FindProcesses( // Now we filter them down to only the WatchOS triples for (uint32_t i = 0; i < n; ++i) { - const ProcessInstanceInfo &proc_info = - all_osx_process_infos.GetProcessInfoAtIndex(i); + const ProcessInstanceInfo &proc_info = all_osx_process_infos[i]; if (proc_info.GetArchitecture().GetTriple().getOS() == llvm::Triple::WatchOS) { - process_infos.Append(proc_info); + process_infos.push_back(proc_info); } } - return process_infos.GetSize(); + return process_infos.size(); } bool PlatformAppleWatchSimulator::GetSupportedArchitectureAtIndex( diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp index 6230962c2e29d..f9a7e2061003d 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp @@ -367,13 +367,12 @@ PlatformiOSSimulator::FindProcesses(const ProcessInstanceInfoMatch &match_info, // Now we filter them down to only the iOS triples for (uint32_t i = 0; i < n; ++i) { - const ProcessInstanceInfo &proc_info = - all_osx_process_infos.GetProcessInfoAtIndex(i); + const ProcessInstanceInfo &proc_info = all_osx_process_infos[i]; if (proc_info.GetArchitecture().GetTriple().getOS() == llvm::Triple::IOS) { - process_infos.Append(proc_info); + process_infos.push_back(proc_info); } } - return process_infos.GetSize(); + return process_infos.size(); } bool PlatformiOSSimulator::GetSupportedArchitectureAtIndex(uint32_t idx, diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index 1d5f2b60b2dcc..101dd12296a57 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -2146,7 +2146,7 @@ bool GDBRemoteCommunicationClient::GetCurrentProcessInfo(bool allow_lazy) { uint32_t GDBRemoteCommunicationClient::FindProcesses( const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos) { - process_infos.Clear(); + process_infos.clear(); if (m_supports_qfProcessInfo) { StreamString packet; @@ -2226,7 +2226,7 @@ uint32_t GDBRemoteCommunicationClient::FindProcesses( ProcessInstanceInfo process_info; if (!DecodeProcessInfoResponse(response, process_info)) break; - process_infos.Append(process_info); + process_infos.push_back(process_info); response = StringExtractorGDBRemote(); } while (SendPacketAndWaitForResponse("qsProcessInfo", response, false) == PacketResult::Success); @@ -2235,7 +2235,7 @@ uint32_t GDBRemoteCommunicationClient::FindProcesses( return 0; } } - return process_infos.GetSize(); + return process_infos.size(); } bool GDBRemoteCommunicationClient::GetUserName(uint32_t uid, diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index 11fd40bce44f7..2edcb4d0421a7 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -20,6 +20,7 @@ #include "lldb/Host/File.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/GDBRemote.h" +#include "lldb/Utility/ProcessInfo.h" #include "lldb/Utility/StructuredData.h" #if defined(_WIN32) #include "lldb/Host/windows/PosixApi.h" diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp index 4b5fc0774a6d2..7326316623bc3 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp @@ -334,7 +334,7 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo( StringExtractorGDBRemote &packet) { m_proc_infos_index = 0; - m_proc_infos.Clear(); + m_proc_infos.clear(); ProcessInstanceInfoMatch match_info; packet.SetFilePos(::strlen("qfProcessInfo")); @@ -416,10 +416,9 @@ GDBRemoteCommunicationServerCommon::Handle_qfProcessInfo( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerCommon::Handle_qsProcessInfo( StringExtractorGDBRemote &packet) { - if (m_proc_infos_index < m_proc_infos.GetSize()) { + if (m_proc_infos_index < m_proc_infos.size()) { StreamString response; - CreateProcessInfoResponse( - m_proc_infos.GetProcessInfoAtIndex(m_proc_infos_index), response); + CreateProcessInfoResponse(m_proc_infos[m_proc_infos_index], response); ++m_proc_infos_index; return SendPacketNoLock(response.GetString()); } diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index db21bc2485b47..a874322234645 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -2809,9 +2809,9 @@ Status Process::Attach(ProcessAttachInfo &attach_info) { match_info.GetProcessInfo() = attach_info; match_info.SetNameMatchType(NameMatch::Equals); platform_sp->FindProcesses(match_info, process_infos); - const uint32_t num_matches = process_infos.GetSize(); + const uint32_t num_matches = process_infos.size(); if (num_matches == 1) { - attach_pid = process_infos.GetProcessIDAtIndex(0); + attach_pid = process_infos[0].GetProcessID(); // Fall through and attach using the above process ID } else { match_info.GetProcessInfo().GetExecutableFile().GetPath( @@ -2820,7 +2820,7 @@ Status Process::Attach(ProcessAttachInfo &attach_info) { StreamString s; ProcessInstanceInfo::DumpTableHeader(s, true, false); for (size_t i = 0; i < num_matches; i++) { - process_infos.GetProcessInfoAtIndex(i).DumpAsTableRow( + process_infos[i].DumpAsTableRow( s, platform_sp->GetUserIDResolver(), true, false); } error.SetErrorStringWithFormat( From 103464a5008c65fba5ff1acd34aedddb5cde30e9 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Thu, 12 Mar 2020 14:34:44 -0700 Subject: [PATCH 078/286] [lldb] Add YAML traits for ArchSpec and ProcessInstanceInfo Add YAML traits for ArchSpec and ProcessInstanceInfo so they can be serialized for the reproducers. Differential revision: https://reviews.llvm.org/D76004 (cherry picked from commit 0ce3b710b49c7b9ab837d220547aec92564dd78d) --- lldb/include/lldb/Utility/ArchSpec.h | 15 ++++- lldb/include/lldb/Utility/ProcessInfo.h | 17 +++++- lldb/source/Utility/ArchSpec.cpp | 12 ++++ lldb/source/Utility/ProcessInfo.cpp | 13 +++++ lldb/unittests/Utility/ArchSpecTest.cpp | 27 ++++++++- .../Utility/ProcessInstanceInfoTest.cpp | 57 +++++++++++++++++++ 6 files changed, 134 insertions(+), 7 deletions(-) diff --git a/lldb/include/lldb/Utility/ArchSpec.h b/lldb/include/lldb/Utility/ArchSpec.h index 15e2fdb10c324..cc8d6222e9239 100644 --- a/lldb/include/lldb/Utility/ArchSpec.h +++ b/lldb/include/lldb/Utility/ArchSpec.h @@ -16,6 +16,7 @@ #include "lldb/lldb-private-enumerations.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" +#include "llvm/Support/YAMLTraits.h" #include #include #include @@ -537,4 +538,16 @@ bool ParseMachCPUDashSubtypeTriple(llvm::StringRef triple_str, ArchSpec &arch); } // namespace lldb_private -#endif // #ifndef LLDB_UTILITY_ARCHSPEC_H +namespace llvm { +namespace yaml { +template <> struct ScalarTraits { + static void output(const lldb_private::ArchSpec &, void *, raw_ostream &); + static StringRef input(StringRef, void *, lldb_private::ArchSpec &); + static QuotingType mustQuote(StringRef S) { return QuotingType::Double; } +}; +} // namespace yaml +} // namespace llvm + +LLVM_YAML_IS_SEQUENCE_VECTOR(lldb_private::ArchSpec) + +#endif // LLDB_UTILITY_ARCHSPEC_H diff --git a/lldb/include/lldb/Utility/ProcessInfo.h b/lldb/include/lldb/Utility/ProcessInfo.h index 14decee80e0c7..0d631d06d2dfb 100644 --- a/lldb/include/lldb/Utility/ProcessInfo.h +++ b/lldb/include/lldb/Utility/ProcessInfo.h @@ -9,13 +9,12 @@ #ifndef LLDB_UTILITY_PROCESSINFO_H #define LLDB_UTILITY_PROCESSINFO_H -// LLDB headers #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/Args.h" #include "lldb/Utility/Environment.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/NameMatches.h" - +#include "llvm/Support/YAMLTraits.h" #include namespace lldb_private { @@ -89,6 +88,7 @@ class ProcessInfo { const Environment &GetEnvironment() const { return m_environment; } protected: + template friend struct llvm::yaml::MappingTraits; FileSpec m_executable; std::string m_arg0; // argv[0] if supported. If empty, then use m_executable. // Not all process plug-ins support specifying an argv[0] that differs from @@ -150,6 +150,7 @@ class ProcessInstanceInfo : public ProcessInfo { bool verbose) const; protected: + friend struct llvm::yaml::MappingTraits; uint32_t m_euid; uint32_t m_egid; lldb::pid_t m_parent_pid; @@ -216,4 +217,14 @@ class ProcessInstanceInfoMatch { } // namespace lldb_private -#endif // #ifndef LLDB_UTILITY_PROCESSINFO_H +LLVM_YAML_IS_SEQUENCE_VECTOR(lldb_private::ProcessInstanceInfo) + +namespace llvm { +namespace yaml { +template <> struct MappingTraits { + static void mapping(IO &io, lldb_private::ProcessInstanceInfo &PII); +}; +} // namespace yaml +} // namespace llvm + +#endif // LLDB_UTILITY_PROCESSINFO_H diff --git a/lldb/source/Utility/ArchSpec.cpp b/lldb/source/Utility/ArchSpec.cpp index 3dae25ceacd6c..0507710204a7a 100644 --- a/lldb/source/Utility/ArchSpec.cpp +++ b/lldb/source/Utility/ArchSpec.cpp @@ -1460,3 +1460,15 @@ void ArchSpec::DumpTriple(llvm::raw_ostream &s) const { if (!environ_str.empty()) s << "-" << environ_str; } + +void llvm::yaml::ScalarTraits::output(const ArchSpec &Val, void *, + raw_ostream &Out) { + Val.DumpTriple(Out); +} + +llvm::StringRef +llvm::yaml::ScalarTraits::input(llvm::StringRef Scalar, void *, + ArchSpec &Val) { + Val = ArchSpec(Scalar); + return {}; +} diff --git a/lldb/source/Utility/ProcessInfo.cpp b/lldb/source/Utility/ProcessInfo.cpp index b159e26419737..c016e57d03415 100644 --- a/lldb/source/Utility/ProcessInfo.cpp +++ b/lldb/source/Utility/ProcessInfo.cpp @@ -331,3 +331,16 @@ void ProcessInstanceInfoMatch::Clear() { m_name_match_type = NameMatch::Ignore; m_match_all_users = false; } + +void llvm::yaml::MappingTraits::mapping( + IO &io, ProcessInstanceInfo &Info) { + io.mapRequired("executable", Info.m_executable); + io.mapRequired("arg0", Info.m_arg0); + io.mapRequired("arch", Info.m_arch); + io.mapRequired("uid", Info.m_uid); + io.mapRequired("gid", Info.m_gid); + io.mapRequired("pid", Info.m_pid); + io.mapRequired("effective-uid", Info.m_euid); + io.mapRequired("effective-gid", Info.m_egid); + io.mapRequired("parent-pid", Info.m_parent_pid); +} diff --git a/lldb/unittests/Utility/ArchSpecTest.cpp b/lldb/unittests/Utility/ArchSpecTest.cpp index 9115808c12587..19186667da9e9 100644 --- a/lldb/unittests/Utility/ArchSpecTest.cpp +++ b/lldb/unittests/Utility/ArchSpecTest.cpp @@ -9,8 +9,9 @@ #include "gtest/gtest.h" #include "lldb/Utility/ArchSpec.h" -#include "llvm/BinaryFormat/MachO.h" #include "llvm/BinaryFormat/ELF.h" +#include "llvm/BinaryFormat/MachO.h" +#include "llvm/Support/YAMLParser.h" using namespace lldb; using namespace lldb_private; @@ -200,14 +201,14 @@ TEST(ArchSpecTest, MergeFrom) { EXPECT_TRUE(A.IsValid()); EXPECT_TRUE(B.IsValid()); - + EXPECT_EQ(llvm::Triple::ArchType::arm, B.GetTriple().getArch()); EXPECT_EQ(llvm::Triple::VendorType::UnknownVendor, B.GetTriple().getVendor()); EXPECT_EQ(llvm::Triple::OSType::Linux, B.GetTriple().getOS()); EXPECT_EQ(llvm::Triple::EnvironmentType::UnknownEnvironment, B.GetTriple().getEnvironment()); - + A.MergeFrom(B); EXPECT_EQ(llvm::Triple::ArchType::arm, A.GetTriple().getArch()); EXPECT_EQ(llvm::Triple::VendorType::UnknownVendor, @@ -406,3 +407,23 @@ TEST(ArchSpecTest, TripleComponentsWereSpecified) { ASSERT_TRUE(D.TripleEnvironmentWasSpecified()); } } + +TEST(ArchSpecTest, YAML) { + std::string buffer; + llvm::raw_string_ostream os(buffer); + + // Serialize. + llvm::yaml::Output yout(os); + std::vector archs = {ArchSpec("x86_64-pc-linux"), + ArchSpec("x86_64-apple-macosx10.12"), + ArchSpec("i686-pc-windows")}; + yout << archs; + os.flush(); + + // Deserialize. + std::vector deserialized; + llvm::yaml::Input yin(buffer); + yin >> deserialized; + + EXPECT_EQ(archs, deserialized); +} diff --git a/lldb/unittests/Utility/ProcessInstanceInfoTest.cpp b/lldb/unittests/Utility/ProcessInstanceInfoTest.cpp index 1d363ac80a365..d433b04e4f258 100644 --- a/lldb/unittests/Utility/ProcessInstanceInfoTest.cpp +++ b/lldb/unittests/Utility/ProcessInstanceInfoTest.cpp @@ -108,3 +108,60 @@ TEST(ProcessInstanceInfoMatch, Name) { EXPECT_TRUE(match.Matches(info_bar)); EXPECT_TRUE(match.Matches(info_empty)); } + +TEST(ProcessInstanceInfo, Yaml) { + std::string buffer; + llvm::raw_string_ostream os(buffer); + + // Serialize. + ProcessInstanceInfo info("a.out", ArchSpec("x86_64-pc-linux"), 47); + info.SetUserID(1); + info.SetEffectiveUserID(2); + info.SetGroupID(3); + info.SetEffectiveGroupID(4); + llvm::yaml::Output yout(os); + yout << info; + os.flush(); + + // Deserialize. + ProcessInstanceInfo deserialized; + llvm::yaml::Input yin(buffer); + yin >> deserialized; + + EXPECT_EQ(deserialized.GetNameAsStringRef(), info.GetNameAsStringRef()); + EXPECT_EQ(deserialized.GetArchitecture(), info.GetArchitecture()); + EXPECT_EQ(deserialized.GetUserID(), info.GetUserID()); + EXPECT_EQ(deserialized.GetGroupID(), info.GetGroupID()); + EXPECT_EQ(deserialized.GetEffectiveUserID(), info.GetEffectiveUserID()); + EXPECT_EQ(deserialized.GetEffectiveGroupID(), info.GetEffectiveGroupID()); +} + +TEST(ProcessInstanceInfoList, Yaml) { + std::string buffer; + llvm::raw_string_ostream os(buffer); + + // Serialize. + ProcessInstanceInfo info("a.out", ArchSpec("x86_64-pc-linux"), 47); + info.SetUserID(1); + info.SetEffectiveUserID(2); + info.SetGroupID(3); + info.SetEffectiveGroupID(4); + ProcessInstanceInfoList list; + list.push_back(info); + llvm::yaml::Output yout(os); + yout << list; + os.flush(); + + // Deserialize. + ProcessInstanceInfoList deserialized; + llvm::yaml::Input yin(buffer); + yin >> deserialized; + + ASSERT_EQ(deserialized.size(), static_cast(1)); + EXPECT_EQ(deserialized[0].GetNameAsStringRef(), info.GetNameAsStringRef()); + EXPECT_EQ(deserialized[0].GetArchitecture(), info.GetArchitecture()); + EXPECT_EQ(deserialized[0].GetUserID(), info.GetUserID()); + EXPECT_EQ(deserialized[0].GetGroupID(), info.GetGroupID()); + EXPECT_EQ(deserialized[0].GetEffectiveUserID(), info.GetEffectiveUserID()); + EXPECT_EQ(deserialized[0].GetEffectiveGroupID(), info.GetEffectiveGroupID()); +} From c9cf5331964228ce52e4a43ae21811f4242982cf Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Thu, 12 Mar 2020 15:30:34 -0700 Subject: [PATCH 079/286] [lldb/Host] Fix the Windows build Update use of ProcessInstanceInfoList which is now a std::vector. (cherry picked from commit 2411f56bfd1c36f30239c832b75e094d927ee219) --- lldb/source/Host/windows/Host.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/source/Host/windows/Host.cpp b/lldb/source/Host/windows/Host.cpp index 8e8605a549a9f..336a4bd54318a 100644 --- a/lldb/source/Host/windows/Host.cpp +++ b/lldb/source/Host/windows/Host.cpp @@ -133,7 +133,7 @@ FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos) { - process_infos.Clear(); + process_infos.clear(); AutoHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)); if (!snapshot.IsValid()) From abd7ab55914878472b849857231c182f53fa2273 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Fri, 13 Mar 2020 08:49:15 -0700 Subject: [PATCH 080/286] [lldb/Reproducers] Intercept the FindProcesses API This patch extends the reproducers to intercept calls to FindProcesses. During capture it serializes the ProcessInstanceInfoList returned by the API. During replay, it returns the serialized data instead of querying the host. The motivation for this patch is supporting the process attach workflow during replay. Without this change it would incorrectly look for the inferior on the host during replay and failing if no matching process was found. Differential revision: https://reviews.llvm.org/D75877 (cherry picked from commit 2451cbf07bbc500718c30a9e9447385f7235707b) --- lldb/include/lldb/Host/Host.h | 4 + lldb/include/lldb/Utility/ProcessInfo.h | 37 ++++++++ .../Commands/CommandObjectReproducer.cpp | 73 ++++++++++++---- lldb/source/Host/common/Host.cpp | 20 +++++ lldb/source/Host/linux/Host.cpp | 4 +- lldb/source/Host/macosx/objcxx/Host.mm | 4 +- lldb/source/Host/netbsd/Host.cpp | 4 +- lldb/source/Host/openbsd/Host.cpp | 4 +- lldb/source/Utility/ProcessInfo.cpp | 84 +++++++++++++++++++ .../reproducers/attach/Makefile | 2 + .../attach/TestReproducerAttach.py | 71 ++++++++++++++++ .../reproducers/attach/main.cpp | 24 ++++++ 12 files changed, 308 insertions(+), 23 deletions(-) create mode 100644 lldb/test/API/functionalities/reproducers/attach/Makefile create mode 100644 lldb/test/API/functionalities/reproducers/attach/TestReproducerAttach.py create mode 100644 lldb/test/API/functionalities/reproducers/attach/main.cpp diff --git a/lldb/include/lldb/Host/Host.h b/lldb/include/lldb/Host/Host.h index 269bb18571b0f..f19cb85d2329c 100644 --- a/lldb/include/lldb/Host/Host.h +++ b/lldb/include/lldb/Host/Host.h @@ -232,6 +232,10 @@ class Host { static std::unique_ptr CreateDefaultConnection(llvm::StringRef url); + +protected: + static uint32_t FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &proc_infos); }; } // namespace lldb_private diff --git a/lldb/include/lldb/Utility/ProcessInfo.h b/lldb/include/lldb/Utility/ProcessInfo.h index 0d631d06d2dfb..ec91060cda54e 100644 --- a/lldb/include/lldb/Utility/ProcessInfo.h +++ b/lldb/include/lldb/Utility/ProcessInfo.h @@ -14,6 +14,7 @@ #include "lldb/Utility/Environment.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/NameMatches.h" +#include "lldb/Utility/Reproducer.h" #include "llvm/Support/YAMLTraits.h" #include @@ -215,6 +216,42 @@ class ProcessInstanceInfoMatch { bool m_match_all_users; }; +namespace repro { +class ProcessInfoRecorder : public AbstractRecorder { +public: + ProcessInfoRecorder(const FileSpec &filename, std::error_code &ec) + : AbstractRecorder(filename, ec) {} + + static llvm::Expected> + Create(const FileSpec &filename); + + void Record(const ProcessInstanceInfoList &process_infos); +}; + +class ProcessInfoProvider : public repro::Provider { +public: + struct Info { + static const char *name; + static const char *file; + }; + + ProcessInfoProvider(const FileSpec &directory) : Provider(directory) {} + + ProcessInfoRecorder *GetNewProcessInfoRecorder(); + + void Keep() override; + void Discard() override; + + static char ID; + +private: + std::unique_ptr m_stream_up; + std::vector> m_process_info_recorders; +}; + +llvm::Optional GetReplayProcessInstanceInfoList(); + +} // namespace repro } // namespace lldb_private LLVM_YAML_IS_SEQUENCE_VECTOR(lldb_private::ProcessInstanceInfo) diff --git a/lldb/source/Commands/CommandObjectReproducer.cpp b/lldb/source/Commands/CommandObjectReproducer.cpp index 52c42a7336a48..3c410aec6635e 100644 --- a/lldb/source/Commands/CommandObjectReproducer.cpp +++ b/lldb/source/Commands/CommandObjectReproducer.cpp @@ -8,13 +8,14 @@ #include "CommandObjectReproducer.h" +#include "lldb/Host/HostInfo.h" #include "lldb/Host/OptionParser.h" -#include "lldb/Utility/GDBRemote.h" -#include "lldb/Utility/Reproducer.h" - #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/OptionArgParser.h" +#include "lldb/Utility/GDBRemote.h" +#include "lldb/Utility/ProcessInfo.h" +#include "lldb/Utility/Reproducer.h" #include @@ -27,6 +28,7 @@ enum ReproducerProvider { eReproducerProviderCommands, eReproducerProviderFiles, eReproducerProviderGDB, + eReproducerProviderProcessInfo, eReproducerProviderVersion, eReproducerProviderWorkingDirectory, eReproducerProviderNone @@ -48,6 +50,11 @@ static constexpr OptionEnumValueElement g_reproducer_provider_type[] = { "gdb", "GDB Remote Packets", }, + { + eReproducerProviderProcessInfo, + "processes", + "Process Info", + }, { eReproducerProviderVersion, "version", @@ -97,6 +104,24 @@ static constexpr OptionEnumValues ReproducerSignalType() { #define LLDB_OPTIONS_reproducer_xcrash #include "CommandOptions.inc" +template +llvm::Expected static ReadFromYAML(StringRef filename) { + auto error_or_file = MemoryBuffer::getFile(filename); + if (auto err = error_or_file.getError()) { + return errorCodeToError(err); + } + + T t; + yaml::Input yin((*error_or_file)->getBuffer()); + yin >> t; + + if (auto err = yin.error()) { + return errorCodeToError(err); + } + + return t; +} + class CommandObjectReproducerGenerate : public CommandObjectParsed { public: CommandObjectReproducerGenerate(CommandInterpreter &interpreter) @@ -450,23 +475,41 @@ class CommandObjectReproducerDump : public CommandObjectParsed { repro::MultiLoader::Create(loader); llvm::Optional gdb_file; while ((gdb_file = multi_loader->GetNextFile())) { - auto error_or_file = MemoryBuffer::getFile(*gdb_file); - if (auto err = error_or_file.getError()) { - SetError(result, errorCodeToError(err)); + if (llvm::Expected> packets = + ReadFromYAML>(*gdb_file)) { + for (GDBRemotePacket &packet : *packets) { + packet.Dump(result.GetOutputStream()); + } + } else { + SetError(result, packets.takeError()); return false; } + } - std::vector packets; - yaml::Input yin((*error_or_file)->getBuffer()); - yin >> packets; + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } + case eReproducerProviderProcessInfo: { + std::unique_ptr> + multi_loader = + repro::MultiLoader::Create(loader); - if (auto err = yin.error()) { - SetError(result, errorCodeToError(err)); - return false; - } + if (!multi_loader) { + SetError(result, make_error( + llvm::inconvertibleErrorCode(), + "Unable to create process info loader.")); + return false; + } - for (GDBRemotePacket &packet : packets) { - packet.Dump(result.GetOutputStream()); + llvm::Optional process_file; + while ((process_file = multi_loader->GetNextFile())) { + if (llvm::Expected infos = + ReadFromYAML(*process_file)) { + for (ProcessInstanceInfo info : *infos) + info.Dump(result.GetOutputStream(), HostInfo::GetUserIDResolver()); + } else { + SetError(result, infos.takeError()); + return false; } } diff --git a/lldb/source/Host/common/Host.cpp b/lldb/source/Host/common/Host.cpp index 5fbb655fc7937..aa7f87aab58e3 100644 --- a/lldb/source/Host/common/Host.cpp +++ b/lldb/source/Host/common/Host.cpp @@ -678,3 +678,23 @@ void llvm::format_provider::format(const WaitStatus &WS, } OS << desc << " " << int(WS.status); } + +uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &process_infos) { + + if (llvm::Optional infos = + repro::GetReplayProcessInstanceInfoList()) { + process_infos = *infos; + return process_infos.size(); + } + + uint32_t result = FindProcessesImpl(match_info, process_infos); + + if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator()) { + g->GetOrCreate() + .GetNewProcessInfoRecorder() + ->Record(process_infos); + } + + return result; +} diff --git a/lldb/source/Host/linux/Host.cpp b/lldb/source/Host/linux/Host.cpp index 6c9c67d69e18c..1589e21a3cc4c 100644 --- a/lldb/source/Host/linux/Host.cpp +++ b/lldb/source/Host/linux/Host.cpp @@ -221,8 +221,8 @@ static bool GetProcessAndStatInfo(::pid_t pid, return true; } -uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, - ProcessInstanceInfoList &process_infos) { +uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &process_infos) { static const char procdir[] = "/proc/"; DIR *dirproc = opendir(procdir); diff --git a/lldb/source/Host/macosx/objcxx/Host.mm b/lldb/source/Host/macosx/objcxx/Host.mm index 0e668713d4bd5..2475338a37fd5 100644 --- a/lldb/source/Host/macosx/objcxx/Host.mm +++ b/lldb/source/Host/macosx/objcxx/Host.mm @@ -591,8 +591,8 @@ static bool GetMacOSXProcessUserAndGroup(ProcessInstanceInfo &process_info) { return false; } -uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, - ProcessInstanceInfoList &process_infos) { +uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &process_infos) { std::vector kinfos; int mib[3] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL}; diff --git a/lldb/source/Host/netbsd/Host.cpp b/lldb/source/Host/netbsd/Host.cpp index ee61d51e81ff0..83d8c49499658 100644 --- a/lldb/source/Host/netbsd/Host.cpp +++ b/lldb/source/Host/netbsd/Host.cpp @@ -154,8 +154,8 @@ static bool GetNetBSDProcessUserAndGroup(ProcessInstanceInfo &process_info) { return false; } -uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, - ProcessInstanceInfoList &process_infos) { +uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &process_infos) { const ::pid_t our_pid = ::getpid(); const ::uid_t our_uid = ::getuid(); diff --git a/lldb/source/Host/openbsd/Host.cpp b/lldb/source/Host/openbsd/Host.cpp index 3fdf414a3a47a..2202bc809f711 100644 --- a/lldb/source/Host/openbsd/Host.cpp +++ b/lldb/source/Host/openbsd/Host.cpp @@ -140,8 +140,8 @@ static bool GetOpenBSDProcessUserAndGroup(ProcessInstanceInfo &process_info) { return false; } -uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, - ProcessInstanceInfoList &process_infos) { +uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &process_infos) { std::vector kinfos; int mib[3] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL}; diff --git a/lldb/source/Utility/ProcessInfo.cpp b/lldb/source/Utility/ProcessInfo.cpp index c016e57d03415..f03e698e99689 100644 --- a/lldb/source/Utility/ProcessInfo.cpp +++ b/lldb/source/Utility/ProcessInfo.cpp @@ -18,6 +18,7 @@ using namespace lldb; using namespace lldb_private; +using namespace lldb_private::repro; ProcessInfo::ProcessInfo() : m_executable(), m_arguments(), m_environment(), m_uid(UINT32_MAX), @@ -344,3 +345,86 @@ void llvm::yaml::MappingTraits::mapping( io.mapRequired("effective-gid", Info.m_egid); io.mapRequired("parent-pid", Info.m_parent_pid); } + +llvm::Expected> +ProcessInfoRecorder::Create(const FileSpec &filename) { + std::error_code ec; + auto recorder = + std::make_unique(std::move(filename), ec); + if (ec) + return llvm::errorCodeToError(ec); + return std::move(recorder); +} + +void ProcessInfoProvider::Keep() { + std::vector files; + for (auto &recorder : m_process_info_recorders) { + recorder->Stop(); + files.push_back(recorder->GetFilename().GetPath()); + } + + FileSpec file = GetRoot().CopyByAppendingPathComponent(Info::file); + std::error_code ec; + llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_Text); + if (ec) + return; + llvm::yaml::Output yout(os); + yout << files; +} + +void ProcessInfoProvider::Discard() { m_process_info_recorders.clear(); } + +ProcessInfoRecorder *ProcessInfoProvider::GetNewProcessInfoRecorder() { + std::size_t i = m_process_info_recorders.size() + 1; + std::string filename = (llvm::Twine(Info::name) + llvm::Twine("-") + + llvm::Twine(i) + llvm::Twine(".yaml")) + .str(); + auto recorder_or_error = ProcessInfoRecorder::Create( + GetRoot().CopyByAppendingPathComponent(filename)); + if (!recorder_or_error) { + llvm::consumeError(recorder_or_error.takeError()); + return nullptr; + } + + m_process_info_recorders.push_back(std::move(*recorder_or_error)); + return m_process_info_recorders.back().get(); +} + +void ProcessInfoRecorder::Record(const ProcessInstanceInfoList &process_infos) { + if (!m_record) + return; + llvm::yaml::Output yout(m_os); + yout << const_cast(process_infos); + m_os.flush(); +} + +llvm::Optional +repro::GetReplayProcessInstanceInfoList() { + static std::unique_ptr> + loader = repro::MultiLoader::Create( + repro::Reproducer::Instance().GetLoader()); + + if (!loader) + return {}; + + llvm::Optional nextfile = loader->GetNextFile(); + if (!nextfile) + return {}; + + auto error_or_file = llvm::MemoryBuffer::getFile(*nextfile); + if (std::error_code err = error_or_file.getError()) + return {}; + + ProcessInstanceInfoList infos; + llvm::yaml::Input yin((*error_or_file)->getBuffer()); + yin >> infos; + + if (auto err = yin.error()) + return {}; + + return infos; +} + +char ProcessInfoProvider::ID = 0; +const char *ProcessInfoProvider::Info::file = "process-info.yaml"; +const char *ProcessInfoProvider::Info::name = "process-info"; diff --git a/lldb/test/API/functionalities/reproducers/attach/Makefile b/lldb/test/API/functionalities/reproducers/attach/Makefile new file mode 100644 index 0000000000000..3d0b98f13f3d7 --- /dev/null +++ b/lldb/test/API/functionalities/reproducers/attach/Makefile @@ -0,0 +1,2 @@ +CXX_SOURCES := main.cpp +include Makefile.rules diff --git a/lldb/test/API/functionalities/reproducers/attach/TestReproducerAttach.py b/lldb/test/API/functionalities/reproducers/attach/TestReproducerAttach.py new file mode 100644 index 0000000000000..48659e46ebd7a --- /dev/null +++ b/lldb/test/API/functionalities/reproducers/attach/TestReproducerAttach.py @@ -0,0 +1,71 @@ +""" +Test reproducer attach. +""" + +import lldb +import tempfile +from lldbsuite.test import lldbtest_config +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class CreateAfterAttachTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + NO_DEBUG_INFO_TESTCASE = True + + @skipIfFreeBSD + @skipIfNetBSD + @skipIfWindows + @skipIfRemote + @skipIfiOSSimulator + def test_create_after_attach_with_fork(self): + """Test thread creation after process attach.""" + exe = '%s_%d' % (self.testMethodName, os.getpid()) + + token = self.getBuildArtifact(exe + '.token') + if os.path.exists(token): + os.remove(token) + + reproducer = self.getBuildArtifact(exe + '.reproducer') + if os.path.exists(reproducer): + try: + shutil.rmtree(reproducer) + except OSError: + pass + + self.build(dictionary={'EXE': exe}) + self.addTearDownHook(self.cleanupSubprocesses) + + inferior = self.spawnSubprocess(self.getBuildArtifact(exe), [token]) + pid = inferior.pid + + lldbutil.wait_for_file_on_target(self, token) + + # Use Popen because pexpect is overkill and spawnSubprocess is + # asynchronous. + capture = subprocess.Popen([ + lldbtest_config.lldbExec, '-b', '--capture', '--capture-path', + reproducer, '-o', 'proc att -n {}'.format(exe), '-o', + 'reproducer generate' + ], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + outs, errs = capture.communicate() + self.assertIn('Process {} stopped'.format(pid), outs) + self.assertIn('Reproducer written', outs) + + # Check that replay works. + replay = subprocess.Popen( + [lldbtest_config.lldbExec, '-replay', reproducer], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + outs, errs = replay.communicate() + self.assertIn('Process {} stopped'.format(pid), outs) + + # We can dump the reproducer in the current context. + self.expect('reproducer dump -f {} -p process'.format(reproducer), + substrs=['pid = {}'.format(pid), 'name = {}'.format(exe)]) diff --git a/lldb/test/API/functionalities/reproducers/attach/main.cpp b/lldb/test/API/functionalities/reproducers/attach/main.cpp new file mode 100644 index 0000000000000..781da12400af9 --- /dev/null +++ b/lldb/test/API/functionalities/reproducers/attach/main.cpp @@ -0,0 +1,24 @@ +#include +#include +#include + +using std::chrono::seconds; + +int main(int argc, char const *argv[]) { + lldb_enable_attach(); + + // Create the synchronization token. + FILE *f; + if (f = fopen(argv[1], "wx")) { + fputs("\n", f); + fflush(f); + fclose(f); + } else + return 1; + + while (true) { + std::this_thread::sleep_for(seconds(1)); + } + + return 0; +} From 623ed2bd28c73651983721c4b196b0287e846344 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Fri, 13 Mar 2020 10:03:52 -0700 Subject: [PATCH 081/286] [lldb/Test] Temporarily skip TestReproducerAttach on Linux The test is failing with an unexpected packet during replay. Temporarily disabling the test while I setup and environment to investigate. (cherry picked from commit 01387c44d05287bd330e67af68fc265f01b8d2ed) --- .../reproducers/attach/TestReproducerAttach.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lldb/test/API/functionalities/reproducers/attach/TestReproducerAttach.py b/lldb/test/API/functionalities/reproducers/attach/TestReproducerAttach.py index 48659e46ebd7a..20de90b581dff 100644 --- a/lldb/test/API/functionalities/reproducers/attach/TestReproducerAttach.py +++ b/lldb/test/API/functionalities/reproducers/attach/TestReproducerAttach.py @@ -10,17 +10,18 @@ from lldbsuite.test import lldbutil -class CreateAfterAttachTestCase(TestBase): +class ReproducerAttachTestCase(TestBase): mydir = TestBase.compute_mydir(__file__) NO_DEBUG_INFO_TESTCASE = True + @skipIfLinux # Reproducer received unexpected packet. @skipIfFreeBSD @skipIfNetBSD @skipIfWindows @skipIfRemote @skipIfiOSSimulator - def test_create_after_attach_with_fork(self): + def test_reproducer_attach(self): """Test thread creation after process attach.""" exe = '%s_%d' % (self.testMethodName, os.getpid()) From 94b445950f5bbb327906f519457940b1ad43eb3d Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Fri, 13 Mar 2020 10:06:45 -0700 Subject: [PATCH 082/286] [lldb/Host] s/FindProcesses/FindProcessesImpl/ in windows/Host.cpp Fix the Windows build. (cherry picked from commit 20e36f31dfc1bb079dc6e6db5f692a4e90aa0c9d) --- lldb/source/Host/windows/Host.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lldb/source/Host/windows/Host.cpp b/lldb/source/Host/windows/Host.cpp index 336a4bd54318a..9b625310f854c 100644 --- a/lldb/source/Host/windows/Host.cpp +++ b/lldb/source/Host/windows/Host.cpp @@ -131,8 +131,8 @@ FileSpec Host::GetModuleFileSpecForHostAddress(const void *host_addr) { return module_filespec; } -uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, - ProcessInstanceInfoList &process_infos) { +uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &process_infos) { process_infos.clear(); AutoHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)); From 55a86f3c808f60b7b917487f1d0267111dacdd12 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Sun, 15 Mar 2020 20:36:40 -0700 Subject: [PATCH 083/286] [lldb/Host] s/FindProcesses/FindProcessesImpl/ in freebsd/Host.cpp Fix the FreeBSD build. Thank you to Paulf for pointing this out. (cherry picked from commit bfedb663ccf70b511b8f9fcef91ecdb063fd4ab5) --- lldb/source/Host/freebsd/Host.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lldb/source/Host/freebsd/Host.cpp b/lldb/source/Host/freebsd/Host.cpp index 52283d818bb1c..7c4c42e75ba74 100644 --- a/lldb/source/Host/freebsd/Host.cpp +++ b/lldb/source/Host/freebsd/Host.cpp @@ -150,8 +150,8 @@ static bool GetFreeBSDProcessUserAndGroup(ProcessInstanceInfo &process_info) { return false; } -uint32_t Host::FindProcesses(const ProcessInstanceInfoMatch &match_info, - ProcessInstanceInfoList &process_infos) { +uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &process_infos) { const ::pid_t our_pid = ::getpid(); const ::uid_t our_uid = ::getuid(); std::vector kinfos; From c2554b64490c6f619aec55f5b564d30e40380dca Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Mon, 16 Mar 2020 08:34:51 -0700 Subject: [PATCH 084/286] [lldb/Reproducers] Decode run-length encoding in GDB replay server. The GDB replay server sanity-checks that every packet it receives matches what it expects from the serialized packet log. This mechanism tripped for TestReproducerAttach.py on Linux, because one of the packets (jModulesInfo) uses run-length encoding. The replay server was comparing the expanded incoming packet with the unexpanded packet in the log. As a result, it claimed to have received an unexpected packet, which caused the test to fail. This patch addresses that issue by expanding the run-length encoding before comparing the packets. Differential revision: https://reviews.llvm.org/D76163 (cherry picked from commit 88fbd8f9e79096da4d013f826fc8b4f0eea1ef66) --- .../gdb-remote/GDBRemoteCommunication.cpp | 55 ++++++++++--------- .../gdb-remote/GDBRemoteCommunication.h | 3 + .../GDBRemoteCommunicationReplayServer.cpp | 12 ++-- .../attach/TestReproducerAttach.py | 1 - 4 files changed, 41 insertions(+), 30 deletions(-) diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index 7cea013eea7fa..05a83ed83f7b7 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -810,31 +810,9 @@ GDBRemoteCommunication::CheckForPacket(const uint8_t *src, size_t src_len, GDBRemotePacket::ePacketTypeRecv, total_length); // Copy the packet from m_bytes to packet_str expanding the run-length - // encoding in the process. Reserve enough byte for the most common case - // (no RLE used) - std ::string packet_str; - packet_str.reserve(m_bytes.length()); - for (std::string::const_iterator c = m_bytes.begin() + content_start; - c != m_bytes.begin() + content_end; ++c) { - if (*c == '*') { - // '*' indicates RLE. Next character will give us the repeat count - // and previous character is what is to be repeated. - char char_to_repeat = packet_str.back(); - // Number of time the previous character is repeated - int repeat_count = *++c + 3 - ' '; - // We have the char_to_repeat and repeat_count. Now push it in the - // packet. - for (int i = 0; i < repeat_count; ++i) - packet_str.push_back(char_to_repeat); - } else if (*c == 0x7d) { - // 0x7d is the escape character. The next character is to be XOR'd - // with 0x20. - char escapee = *++c ^ 0x20; - packet_str.push_back(escapee); - } else { - packet_str.push_back(*c); - } - } + // encoding in the process. + std ::string packet_str = + ExpandRLE(m_bytes.substr(content_start, content_end - content_start)); packet = StringExtractorGDBRemote(packet_str); if (m_bytes[0] == '$' || m_bytes[0] == '%') { @@ -1382,3 +1360,30 @@ void llvm::format_provider::format( break; } } + +std::string GDBRemoteCommunication::ExpandRLE(std::string packet) { + // Reserve enough byte for the most common case (no RLE used). + std::string decoded; + decoded.reserve(packet.size()); + for (std::string::const_iterator c = packet.begin(); c != packet.end(); ++c) { + if (*c == '*') { + // '*' indicates RLE. Next character will give us the repeat count and + // previous character is what is to be repeated. + char char_to_repeat = decoded.back(); + // Number of time the previous character is repeated. + int repeat_count = *++c + 3 - ' '; + // We have the char_to_repeat and repeat_count. Now push it in the + // packet. + for (int i = 0; i < repeat_count; ++i) + decoded.push_back(char_to_repeat); + } else if (*c == 0x7d) { + // 0x7d is the escape character. The next character is to be XOR'd with + // 0x20. + char escapee = *++c ^ 0x20; + decoded.push_back(escapee); + } else { + decoded.push_back(*c); + } + } + return decoded; +} diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h index 0b670018bd693..89a1a4aa342b4 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h @@ -142,6 +142,9 @@ class GDBRemoteCommunication : public Communication { static llvm::Error ConnectLocally(GDBRemoteCommunication &client, GDBRemoteCommunication &server); + /// Expand GDB run-length encoding. + static std::string ExpandRLE(std::string); + protected: std::chrono::seconds m_packet_timeout; uint32_t m_echo_number; diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp index 15c73e78bd444..1a2c55fc1eb1d 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp @@ -131,22 +131,26 @@ GDBRemoteCommunicationReplayServer::GetPacketAndSendResponse( GDBRemotePacket entry = m_packet_history.back(); m_packet_history.pop_back(); + // Decode run-length encoding. + const std::string expanded_data = + GDBRemoteCommunication::ExpandRLE(entry.packet.data); + // We've handled the handshake implicitly before. Skip the packet and move // on. if (entry.packet.data == "+") continue; if (entry.type == GDBRemotePacket::ePacketTypeSend) { - if (unexpected(entry.packet.data, packet.GetStringRef())) { + if (unexpected(expanded_data, packet.GetStringRef())) { LLDB_LOG(log, "GDBRemoteCommunicationReplayServer expected packet: '{0}'", - entry.packet.data); + expanded_data); LLDB_LOG(log, "GDBRemoteCommunicationReplayServer actual packet: '{0}'", packet.GetStringRef()); #ifndef NDEBUG // This behaves like a regular assert, but prints the expected and // received packet before aborting. - printf("Reproducer expected packet: '%s'\n", entry.packet.data.c_str()); + printf("Reproducer expected packet: '%s'\n", expanded_data.c_str()); printf("Reproducer received packet: '%s'\n", packet.GetStringRef().data()); llvm::report_fatal_error("Encountered unexpected packet during replay"); @@ -155,7 +159,7 @@ GDBRemoteCommunicationReplayServer::GetPacketAndSendResponse( } // Ignore QEnvironment packets as they're handled earlier. - if (entry.packet.data.find("QEnvironment") == 1) { + if (expanded_data.find("QEnvironment") == 1) { assert(m_packet_history.back().type == GDBRemotePacket::ePacketTypeRecv); m_packet_history.pop_back(); diff --git a/lldb/test/API/functionalities/reproducers/attach/TestReproducerAttach.py b/lldb/test/API/functionalities/reproducers/attach/TestReproducerAttach.py index 20de90b581dff..96c031f62286a 100644 --- a/lldb/test/API/functionalities/reproducers/attach/TestReproducerAttach.py +++ b/lldb/test/API/functionalities/reproducers/attach/TestReproducerAttach.py @@ -15,7 +15,6 @@ class ReproducerAttachTestCase(TestBase): mydir = TestBase.compute_mydir(__file__) NO_DEBUG_INFO_TESTCASE = True - @skipIfLinux # Reproducer received unexpected packet. @skipIfFreeBSD @skipIfNetBSD @skipIfWindows From c247801d1e7d2fab0bc7df54c4e26a01a8bcd54f Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Thu, 19 Mar 2020 11:55:24 -0700 Subject: [PATCH 085/286] [debugserver] Implement hardware breakpoints for ARM64 Add support for hardware breakpoints on ARM64. Differential revision: https://reviews.llvm.org/D76411 (cherry picked from commit 90308a4da167c531a16fcecc3927596fffd5d5d5) --- .../source/MacOSX/arm64/DNBArchImplARM64.cpp | 132 ++++++++++++++++++ .../source/MacOSX/arm64/DNBArchImplARM64.h | 15 +- 2 files changed, 144 insertions(+), 3 deletions(-) diff --git a/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp b/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp index f99dbc48b128e..e5d4b05d987c1 100644 --- a/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp +++ b/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp @@ -666,6 +666,112 @@ uint32_t DNBArchMachARM64::NumSupportedHardwareWatchpoints() { return g_num_supported_hw_watchpoints; } +uint32_t DNBArchMachARM64::NumSupportedHardwareBreakpoints() { + // Set the init value to something that will let us know that we need to + // autodetect how many breakpoints are supported dynamically... + static uint32_t g_num_supported_hw_breakpoints = UINT_MAX; + if (g_num_supported_hw_breakpoints == UINT_MAX) { + // Set this to zero in case we can't tell if there are any HW breakpoints + g_num_supported_hw_breakpoints = 0; + + size_t len; + uint32_t n = 0; + len = sizeof(n); + if (::sysctlbyname("hw.optional.breakpoint", &n, &len, NULL, 0) == 0) { + g_num_supported_hw_breakpoints = n; + DNBLogThreadedIf(LOG_THREAD, "hw.optional.breakpoint=%u", n); + } else { +// For AArch64 we would need to look at ID_AA64DFR0_EL1 but debugserver runs in +// EL0 so it can't access that reg. The kernel should have filled in the +// sysctls based on it though. +#if defined(__arm__) + uint32_t register_DBGDIDR; + + asm("mrc p14, 0, %0, c0, c0, 0" : "=r"(register_DBGDIDR)); + uint32_t numWRPs = bits(register_DBGDIDR, 31, 28); + // Zero is reserved for the WRP count, so don't increment it if it is zero + if (numWRPs > 0) + numWRPs++; + g_num_supported_hw_breakpoints = numWRPs; + DNBLogThreadedIf(LOG_THREAD, + "Number of supported hw breakpoint via asm(): %d", + g_num_supported_hw_breakpoints); +#endif + } + } + return g_num_supported_hw_breakpoints; +} + +uint32_t DNBArchMachARM64::EnableHardwareBreakpoint(nub_addr_t addr, + nub_size_t size, + bool also_set_on_task) { + DNBLogThreadedIf(LOG_WATCHPOINTS, + "DNBArchMachARM64::EnableHardwareBreakpoint(addr = " + "0x%8.8llx, size = %zu)", + (uint64_t)addr, size); + + const uint32_t num_hw_breakpoints = NumSupportedHardwareBreakpoints(); + + nub_addr_t aligned_bp_address = addr; + uint32_t control_value = 0; + + switch (size) { + case 2: + control_value = (0x3 << 5) | 7; + aligned_bp_address &= ~1; + break; + case 4: + control_value = (0xfu << 5) | 7; + aligned_bp_address &= ~3; + break; + }; + + // Read the debug state + kern_return_t kret = GetDBGState(false); + if (kret == KERN_SUCCESS) { + // Check to make sure we have the needed hardware support + uint32_t i = 0; + + for (i = 0; i < num_hw_breakpoints; ++i) { + if ((m_state.dbg.__bcr[i] & BCR_ENABLE) == 0) + break; // We found an available hw breakpoint slot (in i) + } + + // See if we found an available hw breakpoint slot above + if (i < num_hw_breakpoints) { + m_state.dbg.__bvr[i] = aligned_bp_address; + m_state.dbg.__bcr[i] = control_value; + + DNBLogThreadedIf(LOG_WATCHPOINTS, + "DNBArchMachARM64::EnableHardwareBreakpoint() " + "adding breakpoint on address 0x%llx with control " + "register value 0x%x", + (uint64_t)m_state.dbg.__bvr[i], + (uint32_t)m_state.dbg.__bcr[i]); + + // The kernel will set the MDE_ENABLE bit in the MDSCR_EL1 for us + // automatically, don't need to do it here. + kret = SetDBGState(also_set_on_task); + + DNBLogThreadedIf(LOG_WATCHPOINTS, + "DNBArchMachARM64::" + "EnableHardwareBreakpoint() " + "SetDBGState() => 0x%8.8x.", + kret); + + if (kret == KERN_SUCCESS) + return i; + } else { + DNBLogThreadedIf(LOG_WATCHPOINTS, + "DNBArchMachARM64::" + "EnableHardwareBreakpoint(): All " + "hardware resources (%u) are in use.", + num_hw_breakpoints); + } + } + return INVALID_NUB_HW_INDEX; +} + uint32_t DNBArchMachARM64::EnableHardwareWatchpoint(nub_addr_t addr, nub_size_t size, bool read, bool write, @@ -905,6 +1011,32 @@ bool DNBArchMachARM64::DisableHardwareWatchpoint_helper(uint32_t hw_index, return (kret == KERN_SUCCESS); } +bool DNBArchMachARM64::DisableHardwareBreakpoint(uint32_t hw_index, + bool also_set_on_task) { + kern_return_t kret = GetDBGState(false); + if (kret != KERN_SUCCESS) + return false; + + const uint32_t num_hw_points = NumSupportedHardwareBreakpoints(); + if (hw_index >= num_hw_points) + return false; + + m_disabled_breakpoints[hw_index].addr = m_state.dbg.__bvr[hw_index]; + m_disabled_breakpoints[hw_index].control = m_state.dbg.__bcr[hw_index]; + + m_state.dbg.__bcr[hw_index] = 0; + DNBLogThreadedIf(LOG_WATCHPOINTS, + "DNBArchMachARM64::" + "DisableHardwareBreakpoint( %u ) - WVR%u = " + "0x%8.8llx BCR%u = 0x%8.8llx", + hw_index, hw_index, (uint64_t)m_state.dbg.__bvr[hw_index], + hw_index, (uint64_t)m_state.dbg.__bcr[hw_index]); + + kret = SetDBGState(also_set_on_task); + + return (kret == KERN_SUCCESS); +} + // This is for checking the Byte Address Select bits in the DBRWCRn_EL1 control // register. // Returns -1 if the trailing bit patterns are not one of: diff --git a/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.h b/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.h index 2c59a0ceb5d98..87228a15ae614 100644 --- a/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.h +++ b/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.h @@ -26,10 +26,12 @@ class DNBArchMachARM64 : public DNBArchProtocol { DNBArchMachARM64(MachThread *thread) : m_thread(thread), m_state(), m_disabled_watchpoints(), - m_watchpoint_hw_index(-1), m_watchpoint_did_occur(false), + m_disabled_breakpoints(), m_watchpoint_hw_index(-1), + m_watchpoint_did_occur(false), m_watchpoint_resume_single_step_enabled(false), m_saved_register_states() { m_disabled_watchpoints.resize(16); + m_disabled_breakpoints.resize(16); memset(&m_dbg_save, 0, sizeof(m_dbg_save)); } @@ -62,7 +64,13 @@ class DNBArchMachARM64 : public DNBArchProtocol { static const uint8_t *SoftwareBreakpointOpcode(nub_size_t byte_size); static uint32_t GetCPUType(); + virtual uint32_t NumSupportedHardwareBreakpoints(); virtual uint32_t NumSupportedHardwareWatchpoints(); + + virtual uint32_t EnableHardwareBreakpoint(nub_addr_t addr, nub_size_t size, + bool also_set_on_task); + virtual bool DisableHardwareBreakpoint(uint32_t hw_break_index, + bool also_set_on_task); virtual uint32_t EnableHardwareWatchpoint(nub_addr_t addr, nub_size_t size, bool read, bool write, bool also_set_on_task); @@ -229,10 +237,11 @@ class DNBArchMachARM64 : public DNBArchProtocol { State m_state; arm_debug_state64_t m_dbg_save; - // arm64 doesn't keep the disabled watchpoint values in the debug register - // context like armv7; + // arm64 doesn't keep the disabled watchpoint and breakpoint values in the + // debug register context like armv7; // we need to save them aside when we disable them temporarily. std::vector m_disabled_watchpoints; + std::vector m_disabled_breakpoints; // The following member variables should be updated atomically. int32_t m_watchpoint_hw_index; From 3440b30b5adfc49f43dbb8a51784522dd1828e46 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Thu, 19 Mar 2020 08:34:26 -0700 Subject: [PATCH 086/286] [lldb/Test] Remove debug print in supports_hw_breakpoints. (cherry picked from commit 99a0cbb42321ef5b967ba4aac51cea5f5804bb81) --- .../require_hw_breakpoints/TestRequireHWBreakpoints.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lldb/test/API/functionalities/breakpoint/require_hw_breakpoints/TestRequireHWBreakpoints.py b/lldb/test/API/functionalities/breakpoint/require_hw_breakpoints/TestRequireHWBreakpoints.py index 74f2fbb0c1a01..61e4171131013 100644 --- a/lldb/test/API/functionalities/breakpoint/require_hw_breakpoints/TestRequireHWBreakpoints.py +++ b/lldb/test/API/functionalities/breakpoint/require_hw_breakpoints/TestRequireHWBreakpoints.py @@ -19,7 +19,6 @@ def supports_hw_breakpoints(self): CURRENT_EXECUTABLE_SET) self.runCmd("breakpoint set -b main --hardware") self.runCmd("run") - print(self.res.GetOutput()) if 'stopped' in self.res.GetOutput(): return 'Hardware breakpoints are supported' return None From cab1c032788fe8a17158b814231b34cfffd7c78a Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Fri, 13 Mar 2020 16:40:02 -0700 Subject: [PATCH 087/286] [lldb/Utils] Use PYTHON_EXECUTABLE to configure lldb-dotest's shebang Ideally we'd want all shebangs to be configurable, but that's not a viable solution. Given that lldb-dotest is already configured, we might as well make sure it uses the correct interpreter. Differential revision: https://reviews.llvm.org/D76167 (cherry picked from commit 2059d28bfd3cfedfcf7420f1c4627219811e81c4) --- lldb/utils/lldb-dotest/lldb-dotest.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/utils/lldb-dotest/lldb-dotest.in b/lldb/utils/lldb-dotest/lldb-dotest.in index 2032e2159d942..e25738b45b4db 100755 --- a/lldb/utils/lldb-dotest/lldb-dotest.in +++ b/lldb/utils/lldb-dotest/lldb-dotest.in @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!@PYTHON_EXECUTABLE@ import subprocess import sys From 607fbb56b296cb1622c3d855f3d4784e370d7e4b Mon Sep 17 00:00:00 2001 From: shafik Date: Mon, 23 Mar 2020 11:42:41 -0700 Subject: [PATCH 088/286] [DataFormatters] Add formatter for libc++ std::unique_ptr This adds a formatter for libc++ std::unique_ptr. I also refactored GetValueOfCompressedPair(...) out of LibCxxList.cpp since I need the same functionality and it made sense to share it. Differential Revision: https://reviews.llvm.org/D76476 (cherry picked from commit a567d6809e1514f34975d746bb1c93301792a74c) --- .../lldb/DataFormatters/FormattersHelpers.h | 2 + .../DataFormatters/FormattersHelpers.cpp | 11 +++ .../Language/CPlusPlus/CPlusPlusLanguage.cpp | 13 +++ .../Plugins/Language/CPlusPlus/LibCxx.cpp | 98 +++++++++++++++++++ .../Plugins/Language/CPlusPlus/LibCxx.h | 28 ++++++ .../Plugins/Language/CPlusPlus/LibCxxList.cpp | 13 +-- .../libcxx/unique_ptr/Makefile | 6 ++ .../TestDataFormatterLibcxxUniquePtr.py | 47 +++++++++ .../libcxx/unique_ptr/main.cpp | 13 +++ 9 files changed, 220 insertions(+), 11 deletions(-) create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/Makefile create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/main.cpp diff --git a/lldb/include/lldb/DataFormatters/FormattersHelpers.h b/lldb/include/lldb/DataFormatters/FormattersHelpers.h index 79bd376c76eb6..c9d13726be97c 100644 --- a/lldb/include/lldb/DataFormatters/FormattersHelpers.h +++ b/lldb/include/lldb/DataFormatters/FormattersHelpers.h @@ -56,6 +56,8 @@ size_t ExtractIndexFromString(const char *item_name); lldb::addr_t GetArrayAddressOrPointerValue(ValueObject &valobj); +lldb::ValueObjectSP GetValueOfLibCXXCompressedPair(ValueObject &pair); + time_t GetOSXEpoch(); struct InferiorSizedWord { diff --git a/lldb/source/DataFormatters/FormattersHelpers.cpp b/lldb/source/DataFormatters/FormattersHelpers.cpp index b2a5a17595c8f..6fafcdabdd3dc 100644 --- a/lldb/source/DataFormatters/FormattersHelpers.cpp +++ b/lldb/source/DataFormatters/FormattersHelpers.cpp @@ -143,3 +143,14 @@ lldb_private::formatters::GetArrayAddressOrPointerValue(ValueObject &valobj) { return data_addr; } + +lldb::ValueObjectSP +lldb_private::formatters::GetValueOfLibCXXCompressedPair(ValueObject &pair) { + ValueObjectSP value = + pair.GetChildMemberWithName(ConstString("__value_"), true); + if (!value) { + // pre-r300140 member name + value = pair.GetChildMemberWithName(ConstString("__first_"), true); + } + return value; +} diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index 4385a60f58623..6f9cb1460e8eb 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -609,6 +609,15 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { "shared_ptr synthetic children", ConstString("^(std::__[[:alnum:]]+::)shared_ptr<.+>(( )?&)?$"), stl_synth_flags, true); + + ConstString libcxx_std_unique_ptr_regex( + "^std::__[[:alnum:]]+::unique_ptr<.+>(( )?&)?$"); + AddCXXSynthetic( + cpp_category_sp, + lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEndCreator, + "unique_ptr synthetic children", libcxx_std_unique_ptr_regex, + stl_synth_flags, true); + AddCXXSynthetic( cpp_category_sp, lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator, @@ -713,6 +722,10 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { "libc++ std::weak_ptr summary provider", ConstString("^std::__[[:alnum:]]+::weak_ptr<.+>(( )?&)?$"), stl_summary_flags, true); + AddCXXSummary(cpp_category_sp, + lldb_private::formatters::LibcxxUniquePointerSummaryProvider, + "libc++ std::unique_ptr summary provider", + libcxx_std_unique_ptr_regex, stl_summary_flags, true); AddCXXSynthetic( cpp_category_sp, diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp index cdfdc16dc8e02..07e9a0e83fab4 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp @@ -144,6 +144,43 @@ bool lldb_private::formatters::LibcxxSmartPointerSummaryProvider( return true; } +bool lldb_private::formatters::LibcxxUniquePointerSummaryProvider( + ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { + ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); + if (!valobj_sp) + return false; + + ValueObjectSP ptr_sp( + valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true)); + if (!ptr_sp) + return false; + + ptr_sp = GetValueOfLibCXXCompressedPair(*ptr_sp); + if (!ptr_sp) + return false; + + if (ptr_sp->GetValueAsUnsigned(0) == 0) { + stream.Printf("nullptr"); + return true; + } else { + bool print_pointee = false; + Status error; + ValueObjectSP pointee_sp = ptr_sp->Dereference(error); + if (pointee_sp && error.Success()) { + if (pointee_sp->DumpPrintableRepresentation( + stream, ValueObject::eValueObjectRepresentationStyleSummary, + lldb::eFormatInvalid, + ValueObject::PrintableRepresentationSpecialCases::eDisable, + false)) + print_pointee = true; + } + if (!print_pointee) + stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0)); + } + + return true; +} + /* (lldb) fr var ibeg --raw --ptr-depth 1 (std::__1::__map_iteratorGetChildMemberWithName(ConstString("__ptr_"), true)); + if (!ptr_sp) + return false; + + m_compressed_pair_sp = GetValueOfLibCXXCompressedPair(*ptr_sp); + + return false; +} + +bool lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: + MightHaveChildren() { + return true; +} + +size_t lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: + GetIndexOfChildWithName(ConstString name) { + if (name == "__value_") + return 0; + return UINT32_MAX; +} + bool lldb_private::formatters::LibcxxContainerSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { if (valobj.IsPointerType()) { diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h index 214f5512e4a50..a3e41a44432a3 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h @@ -43,6 +43,10 @@ bool LibcxxSmartPointerSummaryProvider( const TypeSummaryOptions &options); // libc++ std::shared_ptr<> and std::weak_ptr<> +// libc++ std::unique_ptr<> +bool LibcxxUniquePointerSummaryProvider(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options); + bool LibcxxFunctionSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options); // libc++ std::function<> @@ -107,6 +111,26 @@ class LibcxxSharedPtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd { lldb::ByteOrder m_byte_order; }; +class LibcxxUniquePtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd { +public: + LibcxxUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); + + size_t CalculateNumChildren() override; + + lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + + bool Update() override; + + bool MightHaveChildren() override; + + size_t GetIndexOfChildWithName(ConstString name) override; + + ~LibcxxUniquePtrSyntheticFrontEnd() override; + +private: + lldb::ValueObjectSP m_compressed_pair_sp; +}; + SyntheticChildrenFrontEnd * LibcxxBitsetSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); @@ -115,6 +139,10 @@ SyntheticChildrenFrontEnd * LibcxxSharedPtrSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); +SyntheticChildrenFrontEnd * +LibcxxUniquePtrSyntheticFrontEndCreator(CXXSyntheticChildren *, + lldb::ValueObjectSP); + SyntheticChildrenFrontEnd * LibcxxStdVectorSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp index 97eb2a24a2f1d..ea4cc41440c66 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp @@ -290,15 +290,6 @@ ValueObjectSP ForwardListFrontEnd::GetChildAtIndex(size_t idx) { m_element_type); } -static ValueObjectSP GetValueOfCompressedPair(ValueObject &pair) { - ValueObjectSP value = pair.GetChildMemberWithName(ConstString("__value_"), true); - if (! value) { - // pre-r300140 member name - value = pair.GetChildMemberWithName(ConstString("__first_"), true); - } - return value; -} - bool ForwardListFrontEnd::Update() { AbstractListFrontEnd::Update(); @@ -311,7 +302,7 @@ bool ForwardListFrontEnd::Update() { m_backend.GetChildMemberWithName(ConstString("__before_begin_"), true)); if (!impl_sp) return false; - impl_sp = GetValueOfCompressedPair(*impl_sp); + impl_sp = GetValueOfLibCXXCompressedPair(*impl_sp); if (!impl_sp) return false; m_head = impl_sp->GetChildMemberWithName(ConstString("__next_"), true).get(); @@ -332,7 +323,7 @@ size_t ListFrontEnd::CalculateNumChildren() { ValueObjectSP size_alloc( m_backend.GetChildMemberWithName(ConstString("__size_alloc_"), true)); if (size_alloc) { - ValueObjectSP value = GetValueOfCompressedPair(*size_alloc); + ValueObjectSP value = GetValueOfLibCXXCompressedPair(*size_alloc); if (value) { m_count = value->GetValueAsUnsigned(UINT32_MAX); } diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/Makefile b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/Makefile new file mode 100644 index 0000000000000..7e57f13aea55a --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/Makefile @@ -0,0 +1,6 @@ +CXX_SOURCES := main.cpp + +USE_LIBCPP := 1 + +CXXFLAGS_EXTRAS := -std=c++14 +include Makefile.rules diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py new file mode 100644 index 0000000000000..b91e494258bf9 --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py @@ -0,0 +1,47 @@ +""" +Test lldb data formatter for libc++ std::unique_ptr. +""" + + + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class LibcxUniquePtrDataFormatterTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @add_test_categories(["libc++"]) + def test_with_run_command(self): + """Test that that file and class static variables display correctly.""" + self.build() + + (self.target, self.process, _, bkpt) = lldbutil.run_to_source_breakpoint(self, '// break here', + lldb.SBFileSpec("main.cpp", False)) + + self.expect("frame variable up_empty", + substrs=['(std::unique_ptr >) up_empty = nullptr {', + '__value_ = ', + '}']) + + self.expect("frame variable up_int", + substrs=['(std::unique_ptr >) up_int = 10 {', + '__value_ = ', + '}']) + + self.expect("frame variable up_int_ref", + substrs=['(std::unique_ptr > &) up_int_ref = 10: {', + '__value_ = ', + '}']) + + self.expect("frame variable up_int_ref_ref", + substrs=['(std::unique_ptr > &&) up_int_ref_ref = 10: {', + '__value_ = ', + '}']) + + self.expect("frame variable up_str", + substrs=['up_str = "hello" {', + '__value_ = ', + '}']) diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/main.cpp new file mode 100644 index 0000000000000..4ccffe2a006d3 --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/main.cpp @@ -0,0 +1,13 @@ +#include +#include +#include + +int main() { + std::unique_ptr up_empty; + std::unique_ptr up_int = std::make_unique(10); + std::unique_ptr up_str = std::make_unique("hello"); + std::unique_ptr &up_int_ref = up_int; + std::unique_ptr &&up_int_ref_ref = std::make_unique(10); + + return 0; // break here +} From 61c86e39172d32fe2ac135a280c6076d94420199 Mon Sep 17 00:00:00 2001 From: Augusto Noronha Date: Mon, 23 Mar 2020 19:39:47 -0300 Subject: [PATCH 089/286] Disables the DWARF importer when initializing the Swift REPL --- lldb/include/lldb/Core/ModuleList.h | 1 + lldb/source/Core/ModuleList.cpp | 5 +++++ lldb/source/Target/Target.cpp | 10 ++++++++++ lldb/test/Shell/SwiftREPL/ImportError.test | 6 ++++++ 4 files changed, 22 insertions(+) create mode 100644 lldb/test/Shell/SwiftREPL/ImportError.test diff --git a/lldb/include/lldb/Core/ModuleList.h b/lldb/include/lldb/Core/ModuleList.h index 1b81a9a0aa8a9..5e17b07bd6fdb 100644 --- a/lldb/include/lldb/Core/ModuleList.h +++ b/lldb/include/lldb/Core/ModuleList.h @@ -51,6 +51,7 @@ class ModuleListProperties : public Properties { bool GetUseSwiftClangImporter() const; bool GetUseSwiftDWARFImporter() const; + bool SetUseSwiftDWARFImporter(bool new_value); FileSpec GetClangModulesCachePath() const; bool SetClangModulesCachePath(llvm::StringRef path); SwiftModuleLoadingMode GetSwiftModuleLoadingMode() const; diff --git a/lldb/source/Core/ModuleList.cpp b/lldb/source/Core/ModuleList.cpp index 8ee1846b466d6..1d986210df2fa 100644 --- a/lldb/source/Core/ModuleList.cpp +++ b/lldb/source/Core/ModuleList.cpp @@ -136,6 +136,11 @@ bool ModuleListProperties::GetUseSwiftDWARFImporter() const { return m_collection_sp->GetPropertyAtIndexAsBoolean( NULL, idx, g_modulelist_properties[idx].default_uint_value != 0); } + +bool ModuleListProperties::SetUseSwiftDWARFImporter(bool new_value) { + return m_collection_sp->SetPropertyAtIndexAsBoolean( + nullptr, ePropertyUseSwiftDWARFImporter, new_value); +} // END SWIFT bool ModuleListProperties::SetClangModulesCachePath(llvm::StringRef path) { diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index 25345238b982f..2ee8fbdef882d 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -266,6 +266,16 @@ void Target::SetREPL(lldb::LanguageType language, lldb::REPLSP repl_sp) { lldbassert(!m_repl_map.count(language)); m_repl_map[language] = repl_sp; + + if (language == eLanguageTypeSwift) { + // The DWARFImporter always claims to be able to load a module, even if it + // doesn't exist, because it doesn't "import" anything until the first type is + // requested. To make the REPL behave more like the compiler and diagnose when + // Clang modules can't be located up front, the DWARFImporter is disabled in + // the REPL. There are use-cases for loading Clang types from debug info, but + // this needs a better diagnostic mechanism before it can be enabled. + ModuleList::GetGlobalModuleListProperties().SetUseSwiftDWARFImporter(repl_sp == NULL); + } } void Target::Destroy() { diff --git a/lldb/test/Shell/SwiftREPL/ImportError.test b/lldb/test/Shell/SwiftREPL/ImportError.test new file mode 100644 index 0000000000000..44fe179103c57 --- /dev/null +++ b/lldb/test/Shell/SwiftREPL/ImportError.test @@ -0,0 +1,6 @@ +// Test that importing non-existing module fails. + +// RUN: %lldb --repl < %s 2>&1 | FileCheck %s + +import ModuleThatDoesNotExist +// CHECK: error: no such module 'ModuleThatDoesNotExist' From 4d178b1d30ebfc5152d06e9804d2b5d6c15598f7 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Tue, 17 Mar 2020 17:56:28 -0700 Subject: [PATCH 090/286] [DWARF] Emit DW_AT_call_pc for tail calls Record the address of a tail-calling branch instruction within its call site entry using DW_AT_call_pc. This allows a debugger to determine the address to use when creating aritificial frames. This creates an extra attribute + relocation at tail call sites, which constitute 3-5% of all call sites in xnu/clang respectively. rdar://60307600 Differential Revision: https://reviews.llvm.org/D76336 (cherry picked from commit f7052da6db8f85814adb2e1a6742d607e774bb88) --- .../CodeGen/AsmPrinter/DwarfCompileUnit.cpp | 33 ++++++++--- .../lib/CodeGen/AsmPrinter/DwarfCompileUnit.h | 8 ++- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 55 ++++++++++++------ .../MIR/X86/call-site-gnu-vs-dwarf5-attrs.mir | 25 +++++--- .../X86/dwarf-callsite-related-attrs.ll | 3 +- .../tools/dsymutil/X86/Inputs/tail-call.cpp | 28 +++++++++ .../X86/Inputs/tail-call.macho.x86_64 | Bin 0 -> 4720 bytes .../X86/Inputs/tail-call.macho.x86_64.o | Bin 0 -> 2744 bytes .../tools/dsymutil/X86/tail-call-linking.test | 4 ++ llvm/tools/dsymutil/DwarfLinker.cpp | 4 ++ llvm/tools/dsymutil/DwarfLinker.h | 3 + 11 files changed, 128 insertions(+), 35 deletions(-) create mode 100644 llvm/test/tools/dsymutil/X86/Inputs/tail-call.cpp create mode 100755 llvm/test/tools/dsymutil/X86/Inputs/tail-call.macho.x86_64 create mode 100644 llvm/test/tools/dsymutil/X86/Inputs/tail-call.macho.x86_64.o create mode 100644 llvm/test/tools/dsymutil/X86/tail-call-linking.test diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp index 075b75effa709..f97bf71e06607 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -904,13 +904,12 @@ void DwarfCompileUnit::constructAbstractSubprogramScopeDIE( ContextCU->addDIEEntry(*AbsDef, dwarf::DW_AT_object_pointer, *ObjectPointer); } -/// Whether to use the GNU analog for a DWARF5 tag, attribute, or location atom. -static bool useGNUAnalogForDwarf5Feature(DwarfDebug *DD) { +bool DwarfCompileUnit::useGNUAnalogForDwarf5Feature() const { return DD->getDwarfVersion() == 4 && DD->tuneForGDB(); } dwarf::Tag DwarfCompileUnit::getDwarf5OrGNUTag(dwarf::Tag Tag) const { - if (!useGNUAnalogForDwarf5Feature(DD)) + if (!useGNUAnalogForDwarf5Feature()) return Tag; switch (Tag) { case dwarf::DW_TAG_call_site: @@ -924,7 +923,7 @@ dwarf::Tag DwarfCompileUnit::getDwarf5OrGNUTag(dwarf::Tag Tag) const { dwarf::Attribute DwarfCompileUnit::getDwarf5OrGNUAttr(dwarf::Attribute Attr) const { - if (!useGNUAnalogForDwarf5Feature(DD)) + if (!useGNUAnalogForDwarf5Feature()) return Attr; switch (Attr) { case dwarf::DW_AT_call_all_calls: @@ -946,7 +945,7 @@ DwarfCompileUnit::getDwarf5OrGNUAttr(dwarf::Attribute Attr) const { dwarf::LocationAtom DwarfCompileUnit::getDwarf5OrGNULocationAtom(dwarf::LocationAtom Loc) const { - if (!useGNUAnalogForDwarf5Feature(DD)) + if (!useGNUAnalogForDwarf5Feature()) return Loc; switch (Loc) { case dwarf::DW_OP_entry_value: @@ -960,6 +959,7 @@ DIE &DwarfCompileUnit::constructCallSiteEntryDIE(DIE &ScopeDIE, DIE *CalleeDIE, bool IsTail, const MCSymbol *PCAddr, + const MCSymbol *CallAddr, unsigned CallReg) { // Insert a call site entry DIE within ScopeDIE. DIE &CallSiteDIE = createAndAddDIE(getDwarf5OrGNUTag(dwarf::DW_TAG_call_site), @@ -975,16 +975,33 @@ DIE &DwarfCompileUnit::constructCallSiteEntryDIE(DIE &ScopeDIE, *CalleeDIE); } - if (IsTail) + if (IsTail) { // Attach DW_AT_call_tail_call to tail calls for standards compliance. addFlag(CallSiteDIE, getDwarf5OrGNUAttr(dwarf::DW_AT_call_tail_call)); + // Attach the address of the branch instruction to allow the debugger to + // show where the tail call occurred. This attribute has no GNU analog. + // + // GDB works backwards from non-standard usage of DW_AT_low_pc (in DWARF4 + // mode -- equivalently, in DWARF5 mode, DW_AT_call_return_pc) at tail-call + // site entries to figure out the PC of tail-calling branch instructions. + // This means it doesn't need the compiler to emit DW_AT_call_pc, so we + // don't emit it here. + // + // There's no need to tie non-GDB debuggers to this non-standardness, as it + // adds unnecessary complexity to the debugger. For non-GDB debuggers, emit + // the standard DW_AT_call_pc info. + if (!useGNUAnalogForDwarf5Feature()) + addLabelAddress(CallSiteDIE, dwarf::DW_AT_call_pc, CallAddr); + } + // Attach the return PC to allow the debugger to disambiguate call paths // from one function to another. // // The return PC is only really needed when the call /isn't/ a tail call, but - // for some reason GDB always expects it. - if (!IsTail || DD->tuneForGDB()) { + // GDB expects it in DWARF4 mode, even for tail calls (see the comment above + // the DW_AT_call_pc emission logic for an explanation). + if (!IsTail || useGNUAnalogForDwarf5Feature()) { assert(PCAddr && "Missing return PC information for a call"); addLabelAddress(CallSiteDIE, getDwarf5OrGNUAttr(dwarf::DW_AT_call_return_pc), PCAddr); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h index 52e1c71a8e653..5d0afee4c3df0 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h @@ -230,6 +230,10 @@ class DwarfCompileUnit final : public DwarfUnit { void constructAbstractSubprogramScopeDIE(LexicalScope *Scope); + /// Whether to use the GNU analog for a DWARF5 tag, attribute, or location + /// atom. Only applicable when emitting otherwise DWARF4-compliant debug info. + bool useGNUAnalogForDwarf5Feature() const; + /// This takes a DWARF 5 tag and returns it or a GNU analog. dwarf::Tag getDwarf5OrGNUTag(dwarf::Tag Tag) const; @@ -245,10 +249,12 @@ class DwarfCompileUnit final : public DwarfUnit { /// For indirect calls \p CalleeDIE is set to nullptr. /// \p IsTail specifies whether the call is a tail call. /// \p PCAddr points to the PC value after the call instruction. + /// \p CallAddr points to the PC value at the call instruction (or is null). /// \p CallReg is a register location for an indirect call. For direct calls /// the \p CallReg is set to 0. DIE &constructCallSiteEntryDIE(DIE &ScopeDIE, DIE *CalleeDIE, bool IsTail, - const MCSymbol *PCAddr, unsigned CallReg); + const MCSymbol *PCAddr, + const MCSymbol *CallAddr, unsigned CallReg); /// Construct call site parameter DIEs for the \p CallSiteDIE. The \p Params /// were collected by the \ref collectCallSiteParameters. /// Note: The order of parameters does not matter, since debuggers recognize diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 63583471977e3..680b11ed8b77e 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -878,16 +878,21 @@ void DwarfDebug::constructCallSiteEntryDIEs(const DISubprogram &SP, const MachineInstr *TopLevelCallMI = MI.isInsideBundle() ? &*getBundleStart(MI.getIterator()) : &MI; - // For tail calls, no return PC information is needed. - // For regular calls (and tail calls in GDB tuning), the return PC - // is needed to disambiguate paths in the call graph which could lead to - // some target function. + // For non-tail calls, the return PC is needed to disambiguate paths in + // the call graph which could lead to some target function. For tail + // calls, no return PC information is needed, unless tuning for GDB in + // DWARF4 mode in which case we fake a return PC for compatibility. const MCSymbol *PCAddr = - (IsTail && !tuneForGDB()) - ? nullptr - : const_cast(getLabelAfterInsn(TopLevelCallMI)); + (!IsTail || CU.useGNUAnalogForDwarf5Feature()) + ? const_cast(getLabelAfterInsn(TopLevelCallMI)) + : nullptr; - assert((IsTail || PCAddr) && "Call without return PC information"); + // For tail calls, it's necessary to record the address of the branch + // instruction so that the debugger can show where the tail call occurred. + const MCSymbol *CallAddr = + IsTail ? getLabelBeforeInsn(TopLevelCallMI) : nullptr; + + assert((IsTail || PCAddr) && "Non-tail call without return PC"); LLVM_DEBUG(dbgs() << "CallSiteEntry: " << MF.getName() << " -> " << (CalleeDecl ? CalleeDecl->getName() @@ -896,8 +901,8 @@ void DwarfDebug::constructCallSiteEntryDIEs(const DISubprogram &SP, ->getName(CallReg))) << (IsTail ? " [IsTail]" : "") << "\n"); - DIE &CallSiteDIE = CU.constructCallSiteEntryDIE(ScopeDIE, CalleeDIE, - IsTail, PCAddr, CallReg); + DIE &CallSiteDIE = CU.constructCallSiteEntryDIE( + ScopeDIE, CalleeDIE, IsTail, PCAddr, CallAddr, CallReg); // Optionally emit call-site-param debug info. if (emitDebugEntryValues()) { @@ -1786,11 +1791,32 @@ void DwarfDebug::collectEntityInfo(DwarfCompileUnit &TheCU, // Process beginning of an instruction. void DwarfDebug::beginInstruction(const MachineInstr *MI) { + const MachineFunction &MF = *MI->getMF(); + const auto *SP = MF.getFunction().getSubprogram(); + bool NoDebug = + !SP || SP->getUnit()->getEmissionKind() == DICompileUnit::NoDebug; + + // When describing calls, we need a label for the call instruction. + // TODO: Add support for targets with delay slots. + if (!NoDebug && SP->areAllCallsDescribed() && + MI->isCandidateForCallSiteEntry(MachineInstr::AnyInBundle) && + !MI->hasDelaySlot()) { + const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); + bool IsTail = TII->isTailCall(*MI); + // For tail calls, we need the address of the branch instruction for + // DW_AT_call_pc. + if (IsTail) + requestLabelBeforeInsn(MI); + // For non-tail calls, we need the return address for the call for + // DW_AT_call_return_pc. Under GDB tuning, this information is needed for + // tail calls as well. + requestLabelAfterInsn(MI); + } + DebugHandlerBase::beginInstruction(MI); assert(CurMI); - const auto *SP = MI->getMF()->getFunction().getSubprogram(); - if (!SP || SP->getUnit()->getEmissionKind() == DICompileUnit::NoDebug) + if (NoDebug) return; // Check if source location changes, but ignore DBG_VALUE and CFI locations. @@ -1804,11 +1830,6 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) { unsigned LastAsmLine = Asm->OutStreamer->getContext().getCurrentDwarfLoc().getLine(); - // Request a label after the call in order to emit AT_return_pc information - // in call site entries. TODO: Add support for targets with delay slots. - if (SP->areAllCallsDescribed() && MI->isCall() && !MI->hasDelaySlot()) - requestLabelAfterInsn(MI); - if (DL == PrevInstLoc) { // If we have an ongoing unspecified location, nothing to do here. if (!DL) diff --git a/llvm/test/DebugInfo/MIR/X86/call-site-gnu-vs-dwarf5-attrs.mir b/llvm/test/DebugInfo/MIR/X86/call-site-gnu-vs-dwarf5-attrs.mir index 0718878e0faa4..53bb954b4ef2b 100644 --- a/llvm/test/DebugInfo/MIR/X86/call-site-gnu-vs-dwarf5-attrs.mir +++ b/llvm/test/DebugInfo/MIR/X86/call-site-gnu-vs-dwarf5-attrs.mir @@ -1,20 +1,24 @@ # Test the call site encoding in DWARF5 vs GNU extensions. # +# === DWARF4, tune for gdb === # RUN: llc -dwarf-version 4 -debugger-tune=gdb -filetype=obj \ # RUN: -mtriple=x86_64-unknown-unknown -start-after=machineverifier -o - %s \ -# RUN: | llvm-dwarfdump - | FileCheck %s -check-prefixes=CHECK-GNU +# RUN: | llvm-dwarfdump - | FileCheck %s -check-prefixes=CHECK-GNU -implicit-check-not=DW_AT_call # -# RUN: llc -dwarf-version 5 -debugger-tune=lldb -filetype=obj \ -# RUN: -mtriple=x86_64-unknown-unknown -start-after=machineverifier -o - %s \ -# RUN: | llvm-dwarfdump - | FileCheck %s -check-prefixes=CHECK-DWARF5 +# === DWARF5, tune for gdb === +# RUN: llc -dwarf-version 5 -debugger-tune=gdb -filetype=obj \ +# RUN: -mtriple=x86_64-unknown-unknown -start-after=machineverifier -o - %s \ +# RUN: | llvm-dwarfdump - | FileCheck %s -check-prefixes=CHECK-DWARF5 -implicit-check-not=DW_AT_call # -# RUN: llc -dwarf-version 5 -filetype=obj \ +# === DWARF4, tune for lldb === +# RUN: llc -dwarf-version 4 -debugger-tune=lldb -filetype=obj \ # RUN: -mtriple=x86_64-unknown-unknown -start-after=machineverifier -o - %s \ -# RUN: | llvm-dwarfdump - | FileCheck %s -check-prefixes=CHECK-DWARF5 +# RUN: | llvm-dwarfdump - | FileCheck %s -check-prefixes=CHECK-DWARF5 -implicit-check-not=DW_AT_call # -# RUN: llc -dwarf-version 5 -filetype=obj -debugger-tune=sce -emit-debug-entry-values \ +# === DWARF5, tune for lldb === +# RUN: llc -dwarf-version 5 -debugger-tune=lldb -filetype=obj \ # RUN: -mtriple=x86_64-unknown-unknown -start-after=machineverifier -o - %s \ -# RUN: | llvm-dwarfdump - | FileCheck %s -check-prefixes=CHECK-DWARF5 +# RUN: | llvm-dwarfdump - | FileCheck %s -check-prefixes=CHECK-DWARF5 -implicit-check-not=DW_AT_call # # This is based on the following reproducer: # @@ -49,6 +53,7 @@ # CHECK-GNU: DW_TAG_GNU_call_site # CHECK-GNU-NEXT: DW_AT_abstract_origin # CHECK-GNU-NEXT: DW_AT_GNU_tail_call +# CHECK-GNU-NEXT: DW_AT_low_pc # # # Check DWARF 5: @@ -58,6 +63,9 @@ # CHECK-DWARF5: DW_TAG_call_site # CHECK-DWARF5-NEXT: DW_AT_call_origin # CHECK-DWARF5-NEXT: DW_AT_call_return_pc +# CHECK-DWARF5: DW_TAG_call_site +# CHECK-DWARF5-NEXT: DW_AT_call_origin +# CHECK-DWARF5-NEXT: DW_AT_call_return_pc # CHECK-DWARF5: DW_TAG_call_site_parameter # CHECK-DWARF5-NEXT: DW_AT_location # CHECK-DWARF5-NEXT: DW_AT_call_value @@ -67,6 +75,7 @@ # CHECK-DWARF5: DW_TAG_call_site # CHECK-DWARF5-NEXT: DW_AT_call_origin # CHECK-DWARF5-NEXT: DW_AT_call_tail_call +# CHECK-DWARF5-NEXT: DW_AT_call_pc # --- | ; ModuleID = 'call-site-attrs.c' diff --git a/llvm/test/DebugInfo/X86/dwarf-callsite-related-attrs.ll b/llvm/test/DebugInfo/X86/dwarf-callsite-related-attrs.ll index 33e06faba57bc..51738f2122425 100644 --- a/llvm/test/DebugInfo/X86/dwarf-callsite-related-attrs.ll +++ b/llvm/test/DebugInfo/X86/dwarf-callsite-related-attrs.ll @@ -15,7 +15,7 @@ ; REQUIRES: object-emission ; RUN: %llc_dwarf -mtriple=x86_64-- < %s -o - | FileCheck %s -check-prefix=ASM ; RUN: %llc_dwarf -debugger-tune=lldb -mtriple=x86_64-- < %s -filetype=obj -o %t.o -; RUN: llvm-dwarfdump %t.o -o - | FileCheck %s -check-prefix=OBJ -implicit-check-not=DW_TAG_call_site +; RUN: llvm-dwarfdump %t.o -o - | FileCheck %s -check-prefix=OBJ -implicit-check-not=DW_TAG_call -implicit-check-not=DW_AT_call ; RUN: llvm-dwarfdump -verify %t.o 2>&1 | FileCheck %s -check-prefix=VERIFY ; RUN: llvm-dwarfdump -statistics %t.o | FileCheck %s -check-prefix=STATS ; RUN: llvm-as < %s | llvm-dis | llvm-as | llvm-dis -o /dev/null @@ -76,6 +76,7 @@ entry: ; OBJ: DW_TAG_call_site ; OBJ: DW_AT_call_origin ([[bat_sp]]) ; OBJ: DW_AT_call_tail_call +; OBJ: DW_AT_call_pc define void @_Z3foov() !dbg !25 { entry: tail call void @__has_no_subprogram() diff --git a/llvm/test/tools/dsymutil/X86/Inputs/tail-call.cpp b/llvm/test/tools/dsymutil/X86/Inputs/tail-call.cpp new file mode 100644 index 0000000000000..57e512e7009d9 --- /dev/null +++ b/llvm/test/tools/dsymutil/X86/Inputs/tail-call.cpp @@ -0,0 +1,28 @@ +/* + * This file is used to test dsymutil support for call site entries with tail + * calls (DW_AT_call_pc). + * + * Instructions for regenerating binaries (on Darwin/x86_64): + * + * 1. Copy the source to a top-level directory to work around having absolute + * paths in the symtab's OSO entries. + * + * mkdir -p /Inputs/ && cp tail-call.c /Inputs && cd /Inputs + * + * 2. Compile with call site info enabled. -O2 is used to get tail call + * promotion. + * + * clang -g -O2 tail-call.c -c -o tail-call.macho.x86_64.o + * clang tail-call.macho.x86_64.o -o tail-call.macho.x86_64 + * + * 3. Copy the binaries back into the repo's Inputs directory. You'll need + * -oso-prepend-path=%p to link. + */ + +volatile int x; + +__attribute__((disable_tail_calls, noinline)) void func2() { x++; } + +__attribute__((noinline)) void func1() { func2(); /* tail */ } + +__attribute__((disable_tail_calls)) int main() { func1(); /* regular */ } diff --git a/llvm/test/tools/dsymutil/X86/Inputs/tail-call.macho.x86_64 b/llvm/test/tools/dsymutil/X86/Inputs/tail-call.macho.x86_64 new file mode 100755 index 0000000000000000000000000000000000000000..d6098d0de5e4bb8c4646983f52ea95cb1ab73b22 GIT binary patch literal 4720 zcmeHLO=}ZD7@kcmiq@tgeqkYt7E!TDThh{lh}A}0)V64aP>5r)*^o%GiOr^_ppuJ+ z-g2-gp85;KpCI<=L4SZpKkC6h;KBGjo1JF2R_R&xg=c1-d1u~vKlbwOho3)w?G-`` z3n4;41ZaXh6FOExoB*Z)Dd#7zCl`~q=eX+^%};k^w6h6FxsXgP_>VaE`~7>u{!+icjKb%*=yH4y;q4Y^0i_jHewG`&>Hy7j1N;FDSRHo%ILpl*hxW8Gsl7Z;Kwk3JS4kYhO<*QoyZs5*>}7h^ z&Y`JO4{1jGoet(2)~W~N{@ga62G55z@u~9g9`%ebhC%i5Pr(O0occjPwMXQ$7`&YK zTZo^!Ri5{7?(OD2`#YX}?%r2i-9LzZ3OV0b{1vzkD4{;b!4>8&0+{o1BZ$eNF2Bz4oJX(10oXQz{kG;5+4N#Dd!dues6ZxakfU}NpF7h=Dqpt zn|U*1|9JPWfBJ}&AfbVVpj+G|p^yZ$pY8vUV%T-OFJtDU4NhV`BIl{9W3(M<091AH z;_~9Y?e$W!!+cD6XMl)vgR#ZniK^w-X z%{5gkl^RBi^DDfVzw~q`#LMdgIr4osu{+jH-{CW@a*f@7z8@sd=MpWMFAci;hT)!k zw$l(Z{Csb5@gQ-DV-eTxYJGfKy3+T~A78TnU~;f}=I6X#@44O&CEqiWrtrUfIDg2?QJdClrnRc7 z&lS2e*p+-&oa=ixnf#^ z(Z7E`Nj_ap+QL0!SwMdB2p!0e>o&{*F$6%^c^tY7lc{b4lR)G_3(#(1zx-VH@S*yb zi*NtBC+^0|PW^kr2r%-n%`o$)nA}-DwP?qa1h?d`*z%OX#po%gO z^d7We5d)#$(1b%`U(ge;tg^I=-k(q<7!jpHmy4w=aYgTPFWmP$;6bR6{-o>-0hOge zgeh1P(Ey*N)6z+#S2Sxa*)kfoS+kPaYbY`LJ%~Be7VY*UjRWsbA>W$il zp*v|flevkrdM<06EwAcRXC_PM#?KhpNnM-DWwj~&d`>@C&g$n&6XnyCnYZdq$IdvK zSxMs)c}fBju6z61UJ;wPt0d={W@fE%0dUE|GeLvKNELqCFk z0Tm?!vY$oN7RWVZ;d=9TJe!XT+i9o}7;JmCeg343Ph7nF|;-wezRah+K>t^jSzIKE&)dc;-WxFX|ZKIG?9 z5fdW5?TVt@iw!Yw(ojX-2%>{mLab?^^Ew|3&kQ~ro{N;j6j={Hi9UT9o&d~8mIER1 zfsJTPw3K=Xh>;Yp2WRud$F3dOmUvU5DRDvK1t2~dd0g7F5|a`E%o~}O7zgry5wBh$ jX#<2jf|mVB*W|er#|OM;j?^}O!#elS>*5Nk;tu``px9tt literal 0 HcmV?d00001 diff --git a/llvm/test/tools/dsymutil/X86/tail-call-linking.test b/llvm/test/tools/dsymutil/X86/tail-call-linking.test new file mode 100644 index 0000000000000..29ae2cc544cf6 --- /dev/null +++ b/llvm/test/tools/dsymutil/X86/tail-call-linking.test @@ -0,0 +1,4 @@ +RUN: dsymutil -oso-prepend-path=%p %p/Inputs/tail-call.macho.x86_64 -o %t.dSYM +RUN: llvm-dwarfdump %t.dSYM | FileCheck %s -implicit-check-not=DW_AT_call_pc + +CHECK: DW_AT_call_pc (0x0000000100000f95) diff --git a/llvm/tools/dsymutil/DwarfLinker.cpp b/llvm/tools/dsymutil/DwarfLinker.cpp index 16863fa5f197b..949cef6627ec6 100644 --- a/llvm/tools/dsymutil/DwarfLinker.cpp +++ b/llvm/tools/dsymutil/DwarfLinker.cpp @@ -1428,6 +1428,10 @@ unsigned DwarfLinker::DIECloner::cloneAddressAttribute( if (Die.getTag() == dwarf::DW_TAG_call_site) Addr = (Info.OrigCallReturnPc ? Info.OrigCallReturnPc : Addr) + Info.PCOffset; + } else if (AttrSpec.Attr == dwarf::DW_AT_call_pc) { + // Relocate the address of a branch instruction within a call site entry. + if (Die.getTag() == dwarf::DW_TAG_call_site) + Addr = (Info.OrigCallPc ? Info.OrigCallPc : Addr) + Info.PCOffset; } Die.addValue(DIEAlloc, static_cast(AttrSpec.Attr), diff --git a/llvm/tools/dsymutil/DwarfLinker.h b/llvm/tools/dsymutil/DwarfLinker.h index f0057f88f5992..eeb533fd55b76 100644 --- a/llvm/tools/dsymutil/DwarfLinker.h +++ b/llvm/tools/dsymutil/DwarfLinker.h @@ -321,6 +321,9 @@ class DwarfLinker { /// Value of DW_AT_call_return_pc in the input DIE uint64_t OrigCallReturnPc = 0; + /// Value of DW_AT_call_pc in the input DIE + uint64_t OrigCallPc = 0; + /// Offset to apply to PC addresses inside a function. int64_t PCOffset = 0; From b6ad73e0434197837d8c25945d930bbed757c1d7 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Tue, 17 Mar 2020 17:59:08 -0700 Subject: [PATCH 091/286] [lldb/DWARF] Reland: Use DW_AT_call_pc to determine artificial frame address Reland with changes: the test modified in this change originally failed on a Debian/x86_64 builder, and I suspect the cause was that lldb looked up the line location for an artificial frame by subtracting 1 from the frame's address. For artificial frames, the subtraction must not happen because the address is already exact. --- lldb currently guesses the address to use when creating an artificial frame (i.e., a frame constructed by determining the sequence of (tail) calls which must have happened). Guessing the address creates problems -- use the actual address provided by the DW_AT_call_pc attribute instead. Depends on D76336. rdar://60307600 Differential Revision: https://reviews.llvm.org/D76337 (cherry picked from commit 03e29e2c19a8e1f6a225b1878df3eed4e54891e5) --- lldb/include/lldb/Symbol/Function.h | 25 ++++++++-- .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 23 ++++++--- lldb/source/Symbol/Function.cpp | 23 ++++++--- lldb/source/Target/StackFrameList.cpp | 49 ++++++++++++------- .../unambiguous_sequence/main.cpp | 29 +++++------ 5 files changed, 99 insertions(+), 50 deletions(-) diff --git a/lldb/include/lldb/Symbol/Function.h b/lldb/include/lldb/Symbol/Function.h index c8f888c3bdd18..fc99904610386 100644 --- a/lldb/include/lldb/Symbol/Function.h +++ b/lldb/include/lldb/Symbol/Function.h @@ -284,19 +284,33 @@ class CallEdge { /// Like \ref GetReturnPCAddress, but returns an unresolved file address. lldb::addr_t GetUnresolvedReturnPCAddress() const { return return_pc; } + /// Get the load PC address of the call instruction (or LLDB_INVALID_ADDRESS). + lldb::addr_t GetCallInstPC(Function &caller, Target &target) const; + /// Get the call site parameters available at this call edge. llvm::ArrayRef GetCallSiteParameters() const { return parameters; } protected: - CallEdge(lldb::addr_t return_pc, CallSiteParameterArray &¶meters) - : return_pc(return_pc), parameters(std::move(parameters)) {} + CallEdge(lldb::addr_t return_pc, lldb::addr_t call_inst_pc, + CallSiteParameterArray &¶meters) + : return_pc(return_pc), call_inst_pc(call_inst_pc), + parameters(std::move(parameters)) {} + + /// Helper that finds the load address of \p unresolved_pc, a file address + /// which refers to an instruction within \p caller. + static lldb::addr_t GetLoadAddress(lldb::addr_t unresolved_pc, + Function &caller, Target &target); /// An invalid address if this is a tail call. Otherwise, the return PC for /// the call. Note that this is a file address which must be resolved. lldb::addr_t return_pc; + /// The address of the call instruction. Usually an invalid address, unless + /// this is a tail call. + lldb::addr_t call_inst_pc; + CallSiteParameterArray parameters; }; @@ -308,8 +322,8 @@ class DirectCallEdge : public CallEdge { /// Construct a call edge using a symbol name to identify the callee, and a /// return PC within the calling function to identify a specific call site. DirectCallEdge(const char *symbol_name, lldb::addr_t return_pc, - CallSiteParameterArray &¶meters) - : CallEdge(return_pc, std::move(parameters)) { + lldb::addr_t call_inst_pc, CallSiteParameterArray &¶meters) + : CallEdge(return_pc, call_inst_pc, std::move(parameters)) { lazy_callee.symbol_name = symbol_name; } @@ -339,8 +353,9 @@ class IndirectCallEdge : public CallEdge { /// Construct a call edge using a DWARFExpression to identify the callee, and /// a return PC within the calling function to identify a specific call site. IndirectCallEdge(DWARFExpression call_target, lldb::addr_t return_pc, + lldb::addr_t call_inst_pc, CallSiteParameterArray &¶meters) - : CallEdge(return_pc, std::move(parameters)), + : CallEdge(return_pc, call_inst_pc, std::move(parameters)), call_target(std::move(call_target)) {} Function *GetCallee(ModuleList &images, ExecutionContext &exe_ctx) override; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index b1f5ad03a48f3..a4646fd9336ee 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -3854,6 +3854,7 @@ SymbolFileDWARF::CollectCallEdges(ModuleSP module, DWARFDIE function_die) { llvm::Optional call_origin; llvm::Optional call_target; addr_t return_pc = LLDB_INVALID_ADDRESS; + addr_t call_inst_pc = LLDB_INVALID_ADDRESS; DWARFAttributes attributes; const size_t num_attributes = child.GetAttributes(attributes); @@ -3882,6 +3883,12 @@ SymbolFileDWARF::CollectCallEdges(ModuleSP module, DWARFDIE function_die) { if (attr == DW_AT_call_return_pc) return_pc = form_value.Address(); + // Extract DW_AT_call_pc (the PC at the call/branch instruction). It + // should only ever be unavailable for non-tail calls, in which case use + // LLDB_INVALID_ADDRESS. + if (attr == DW_AT_call_pc) + call_inst_pc = form_value.Address(); + // Extract DW_AT_call_target (the location of the address of the indirect // call). if (attr == DW_AT_call_target) { @@ -3904,10 +3911,11 @@ SymbolFileDWARF::CollectCallEdges(ModuleSP module, DWARFDIE function_die) { continue; } - // Adjust the return PC. It needs to be fixed up if the main executable + // Adjust any PC forms. It needs to be fixed up if the main executable // contains a debug map (i.e. pointers to object files), because we need a // file address relative to the executable's text section. return_pc = FixupAddress(return_pc); + call_inst_pc = FixupAddress(call_inst_pc); // Extract call site parameters. CallSiteParameterArray parameters = @@ -3915,10 +3923,13 @@ SymbolFileDWARF::CollectCallEdges(ModuleSP module, DWARFDIE function_die) { std::unique_ptr edge; if (call_origin) { - LLDB_LOG(log, "CollectCallEdges: Found call origin: {0} (retn-PC: {1:x})", - call_origin->GetPubname(), return_pc); + LLDB_LOG(log, + "CollectCallEdges: Found call origin: {0} (retn-PC: {1:x}) " + "(call-PC: {2:x})", + call_origin->GetPubname(), return_pc, call_inst_pc); edge = std::make_unique(call_origin->GetMangledName(), - return_pc, std::move(parameters)); + return_pc, call_inst_pc, + std::move(parameters)); } else { if (log) { StreamString call_target_desc; @@ -3927,8 +3938,8 @@ SymbolFileDWARF::CollectCallEdges(ModuleSP module, DWARFDIE function_die) { LLDB_LOG(log, "CollectCallEdges: Found indirect call target: {0}", call_target_desc.GetString()); } - edge = std::make_unique(*call_target, return_pc, - std::move(parameters)); + edge = std::make_unique( + *call_target, return_pc, call_inst_pc, std::move(parameters)); } if (log && parameters.size()) { diff --git a/lldb/source/Symbol/Function.cpp b/lldb/source/Symbol/Function.cpp index caec00ea218fd..558bdb79add29 100644 --- a/lldb/source/Symbol/Function.cpp +++ b/lldb/source/Symbol/Function.cpp @@ -131,27 +131,36 @@ size_t InlineFunctionInfo::MemorySize() const { /// @name Call site related structures /// @{ -lldb::addr_t CallEdge::GetReturnPCAddress(Function &caller, - Target &target) const { +lldb::addr_t CallEdge::GetLoadAddress(lldb::addr_t unresolved_pc, + Function &caller, Target &target) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); const Address &caller_start_addr = caller.GetAddressRange().GetBaseAddress(); ModuleSP caller_module_sp = caller_start_addr.GetModule(); if (!caller_module_sp) { - LLDB_LOG(log, "GetReturnPCAddress: cannot get Module for caller"); + LLDB_LOG(log, "GetLoadAddress: cannot get Module for caller"); return LLDB_INVALID_ADDRESS; } SectionList *section_list = caller_module_sp->GetSectionList(); if (!section_list) { - LLDB_LOG(log, "GetReturnPCAddress: cannot get SectionList for Module"); + LLDB_LOG(log, "GetLoadAddress: cannot get SectionList for Module"); return LLDB_INVALID_ADDRESS; } - Address return_pc_addr = Address(return_pc, section_list); - lldb::addr_t ret_addr = return_pc_addr.GetLoadAddress(&target); - return ret_addr; + Address the_addr = Address(unresolved_pc, section_list); + lldb::addr_t load_addr = the_addr.GetLoadAddress(&target); + return load_addr; +} + +lldb::addr_t CallEdge::GetReturnPCAddress(Function &caller, + Target &target) const { + return GetLoadAddress(return_pc, caller, target); +} + +lldb::addr_t CallEdge::GetCallInstPC(Function &caller, Target &target) const { + return GetLoadAddress(call_inst_pc, caller, target); } void DirectCallEdge::ParseSymbolFileAndResolve(ModuleList &images) { diff --git a/lldb/source/Target/StackFrameList.cpp b/lldb/source/Target/StackFrameList.cpp index 527f2630374c2..e52b7c8b27f15 100644 --- a/lldb/source/Target/StackFrameList.cpp +++ b/lldb/source/Target/StackFrameList.cpp @@ -239,13 +239,17 @@ void StackFrameList::GetOnlyConcreteFramesUpTo(uint32_t end_idx, m_frames.resize(num_frames); } +/// A sequence of calls that comprise some portion of a backtrace. Each frame +/// is represented as a pair of a callee (Function *) and an address within the +/// callee. +using CallSequence = std::vector>; + /// Find the unique path through the call graph from \p begin (with return PC /// \p return_pc) to \p end. On success this path is stored into \p path, and /// on failure \p path is unchanged. static void FindInterveningFrames(Function &begin, Function &end, ExecutionContext &exe_ctx, Target &target, - addr_t return_pc, - std::vector &path, + addr_t return_pc, CallSequence &path, ModuleList &images, Log *log) { LLDB_LOG(log, "Finding frames between {0} and {1}, retn-pc={2:x}", begin.GetDisplayName(), end.GetDisplayName(), return_pc); @@ -278,24 +282,27 @@ static void FindInterveningFrames(Function &begin, Function &end, // Fully explore the set of functions reachable from the first edge via tail // calls in order to detect ambiguous executions. struct DFS { - std::vector active_path = {}; - std::vector solution_path = {}; + CallSequence active_path = {}; + CallSequence solution_path = {}; llvm::SmallPtrSet visited_nodes = {}; bool ambiguous = false; Function *end; ModuleList &images; + Target ⌖ ExecutionContext &context; - DFS(Function *end, ModuleList &images, ExecutionContext &context) - : end(end), images(images), context(context) {} + DFS(Function *end, ModuleList &images, Target &target, + ExecutionContext &context) + : end(end), images(images), target(target), context(context) {} - void search(Function &first_callee, std::vector &path) { - dfs(first_callee); + void search(CallEdge &first_edge, Function &first_callee, + CallSequence &path) { + dfs(first_edge, first_callee); if (!ambiguous) path = std::move(solution_path); } - void dfs(Function &callee) { + void dfs(CallEdge ¤t_edge, Function &callee) { // Found a path to the target function. if (&callee == end) { if (solution_path.empty()) @@ -315,13 +322,16 @@ static void FindInterveningFrames(Function &begin, Function &end, } // Search the calls made from this callee. - active_path.push_back(&callee); + active_path.emplace_back(&callee, LLDB_INVALID_ADDRESS); for (const auto &edge : callee.GetTailCallingEdges()) { Function *next_callee = edge->GetCallee(images, context); if (!next_callee) continue; - dfs(*next_callee); + addr_t tail_call_pc = edge->GetCallInstPC(callee, target); + active_path.back().second = tail_call_pc; + + dfs(*edge, *next_callee); if (ambiguous) return; } @@ -329,7 +339,7 @@ static void FindInterveningFrames(Function &begin, Function &end, } }; - DFS(&end, images, exe_ctx).search(*first_callee, path); + DFS(&end, images, target, exe_ctx).search(*first_edge, *first_callee, path); } /// Given that \p next_frame will be appended to the frame list, synthesize @@ -382,7 +392,7 @@ void StackFrameList::SynthesizeTailCallFrames(StackFrame &next_frame) { // Try to find the unique sequence of (tail) calls which led from next_frame // to prev_frame. - std::vector path; + CallSequence path; addr_t return_pc = next_reg_ctx_sp->GetPC(); Target &target = *target_sp.get(); ModuleList &images = next_frame.CalculateTarget()->GetImages(); @@ -392,14 +402,17 @@ void StackFrameList::SynthesizeTailCallFrames(StackFrame &next_frame) { path, images, log); // Push synthetic tail call frames. - for (Function *callee : llvm::reverse(path)) { + for (auto calleeInfo : llvm::reverse(path)) { + Function *callee = calleeInfo.first; uint32_t frame_idx = m_frames.size(); uint32_t concrete_frame_idx = next_frame.GetConcreteFrameIndex(); addr_t cfa = LLDB_INVALID_ADDRESS; bool cfa_is_valid = false; - addr_t pc = - callee->GetAddressRange().GetBaseAddress().GetLoadAddress(&target); - constexpr bool behaves_like_zeroth_frame = false; + addr_t pc = calleeInfo.second; + // We do not want to subtract 1 from this PC, as it's the actual address + // of the tail-calling branch instruction. This address is provided by the + // compiler via DW_AT_call_pc. + constexpr bool behaves_like_zeroth_frame = true; SymbolContext sc; callee->CalculateSymbolContext(&sc); auto synth_frame = std::make_shared( @@ -407,7 +420,7 @@ void StackFrameList::SynthesizeTailCallFrames(StackFrame &next_frame) { cfa_is_valid, pc, StackFrame::Kind::Artificial, behaves_like_zeroth_frame, &sc); m_frames.push_back(synth_frame); - LLDB_LOG(log, "Pushed frame {0}", callee->GetDisplayName()); + LLDB_LOG(log, "Pushed frame {0} at {1:x}", callee->GetDisplayName(), pc); } // If any frames were created, adjust next_frame's index. diff --git a/lldb/test/API/functionalities/tail_call_frames/unambiguous_sequence/main.cpp b/lldb/test/API/functionalities/tail_call_frames/unambiguous_sequence/main.cpp index edfe59777c6cd..559f8a6d66aa9 100644 --- a/lldb/test/API/functionalities/tail_call_frames/unambiguous_sequence/main.cpp +++ b/lldb/test/API/functionalities/tail_call_frames/unambiguous_sequence/main.cpp @@ -1,29 +1,30 @@ -//===-- main.cpp ------------------------------------------------*- 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 -// -//===----------------------------------------------------------------------===// - volatile int x; void __attribute__((noinline)) sink() { x++; //% self.filecheck("bt", "main.cpp", "-implicit-check-not=artificial") // CHECK: frame #0: 0x{{[0-9a-f]+}} a.out`sink() at main.cpp:[[@LINE-1]]:4 [opt] - // CHECK-NEXT: frame #1: 0x{{[0-9a-f]+}} a.out`func3{{.*}} [opt] [artificial] - // CHECK-NEXT: frame #2: 0x{{[0-9a-f]+}} a.out`func2{{.*}} [opt] - // CHECK-NEXT: frame #3: 0x{{[0-9a-f]+}} a.out`func1{{.*}} [opt] [artificial] + // CHECK-NEXT: frame #1: 0x{{[0-9a-f]+}} a.out`func3() at main.cpp:14:3 [opt] [artificial] + // CHECK-NEXT: frame #2: 0x{{[0-9a-f]+}} a.out`func2() {{.*}} [opt] + // CHECK-NEXT: frame #3: 0x{{[0-9a-f]+}} a.out`func1() at main.cpp:23:3 [opt] [artificial] // CHECK-NEXT: frame #4: 0x{{[0-9a-f]+}} a.out`main{{.*}} [opt] } -void __attribute__((noinline)) func3() { sink(); /* tail */ } +void __attribute__((noinline)) func3() { + x++; + sink(); /* tail */ +} -void __attribute__((disable_tail_calls, noinline)) func2() { func3(); /* regular */ } +void __attribute__((disable_tail_calls, noinline)) func2() { + func3(); /* regular */ +} -void __attribute__((noinline)) func1() { func2(); /* tail */ } +void __attribute__((noinline)) func1() { + x++; + func2(); /* tail */ +} int __attribute__((disable_tail_calls)) main() { + // DEBUG: self.runCmd("log enable lldb step -f /tmp/lldbstep.log") func1(); /* regular */ return 0; } From 7dad1a7f286d80294a5f544e39487f3c4e4b0c9b Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Mon, 23 Mar 2020 15:09:38 -0700 Subject: [PATCH 092/286] [GlobalOpt] Treat null-check of loaded value as use of global (PR35760) PR35760 shows an example program which, when compiled with `clang -O0` or gcc at any optimization level, prints '0'. However, llvm transforms the program in a way that causes it to print '1'. Fix the issue by having `AllUsesOfValueWillTrapIfNull` return false when analyzing a load from a global which is used by an `icmp`. This special case was untested [0] so this is just deleting dead code. An alternative fix might be to change the GlobalStatus analysis for the global to report "Stored" instead of "StoredOnce". However, "StoredOnce" is appropriate when only one value other than the initializer is stored to the global. [0] http://lab.llvm.org:8080/coverage/coverage-reports/coverage/Users/buildslave/jenkins/workspace/coverage/llvm-project/llvm/lib/Transforms/IPO/GlobalOpt.cpp.html#L662 Differential Revision: https://reviews.llvm.org/D76645 (cherry picked from commit b7cd291c1542aee12c9e9fde6c411314a163a8ea) --- llvm/lib/Transforms/IPO/GlobalOpt.cpp | 3 -- .../GlobalOpt/null-check-is-use-pr35760.ll | 41 +++++++++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 llvm/test/Transforms/GlobalOpt/null-check-is-use-pr35760.ll diff --git a/llvm/lib/Transforms/IPO/GlobalOpt.cpp b/llvm/lib/Transforms/IPO/GlobalOpt.cpp index beb3785eda31f..06659760e7cdc 100644 --- a/llvm/lib/Transforms/IPO/GlobalOpt.cpp +++ b/llvm/lib/Transforms/IPO/GlobalOpt.cpp @@ -659,9 +659,6 @@ static bool AllUsesOfValueWillTrapIfNull(const Value *V, // checked. if (PHIs.insert(PN).second && !AllUsesOfValueWillTrapIfNull(PN, PHIs)) return false; - } else if (isa(U) && - isa(U->getOperand(1))) { - // Ignore icmp X, null } else { //cerr << "NONTRAPPING USE: " << *U; return false; diff --git a/llvm/test/Transforms/GlobalOpt/null-check-is-use-pr35760.ll b/llvm/test/Transforms/GlobalOpt/null-check-is-use-pr35760.ll new file mode 100644 index 0000000000000..32516b6db7ca2 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/null-check-is-use-pr35760.ll @@ -0,0 +1,41 @@ +; RUN: opt -S -globalopt -o - < %s | FileCheck %s + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@_ZL3g_i = internal global i32* null, align 8 +@.str = private unnamed_addr constant [2 x i8] c"0\00", align 1 +@.str.1 = private unnamed_addr constant [2 x i8] c"1\00", align 1 + +define dso_local i32 @main() { + store i32* null, i32** @_ZL3g_i, align 8 + call void @_ZL13PutsSomethingv() + ret i32 0 +} + +; CHECK-LABEL: define {{.*}} @_ZL13PutsSomethingv() +; CHECK: [[gvLoad:%.*]] = load i32*, i32** @_ZL3g_i +; CHECK-NEXT: icmp eq i32* [[gvLoad]], null +define internal void @_ZL13PutsSomethingv() { + %1 = load i32*, i32** @_ZL3g_i, align 8 + %2 = icmp eq i32* %1, null + br i1 %2, label %3, label %7 + +3: ; preds = %0 + %4 = call noalias i8* @malloc(i64 4) #3 + %5 = bitcast i8* %4 to i32* + store i32* %5, i32** @_ZL3g_i, align 8 + %6 = call i32 @puts(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str, i64 0, i64 0)) + br label %9 + +7: ; preds = %0 + %8 = call i32 @puts(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.1, i64 0, i64 0)) + br label %9 + +9: ; preds = %7, %3 + ret void +} + +declare dso_local noalias i8* @malloc(i64) + +declare dso_local i32 @puts(i8* nocapture readonly) From ae3f05b331cfd15ff96d8bf2fdacd3b860c0c039 Mon Sep 17 00:00:00 2001 From: Augusto Noronha Date: Tue, 24 Mar 2020 19:00:10 -0300 Subject: [PATCH 093/286] Remove skip from 'TestSwiftConditionalBreakpoint' and 'TestSwiftStepping' on Linux --- .../conditional_breakpoints/TestSwiftConditionalBreakpoint.py | 1 - lldb/test/API/lang/swift/stepping/TestSwiftStepping.py | 1 - 2 files changed, 2 deletions(-) diff --git a/lldb/test/API/lang/swift/conditional_breakpoints/TestSwiftConditionalBreakpoint.py b/lldb/test/API/lang/swift/conditional_breakpoints/TestSwiftConditionalBreakpoint.py index e6e1c74785362..f4ab631c8ec46 100644 --- a/lldb/test/API/lang/swift/conditional_breakpoints/TestSwiftConditionalBreakpoint.py +++ b/lldb/test/API/lang/swift/conditional_breakpoints/TestSwiftConditionalBreakpoint.py @@ -24,7 +24,6 @@ class TestSwiftConditionalBreakpoint(TestBase): mydir = TestBase.compute_mydir(__file__) @swiftTest - @skipIfLinux def test_swift_conditional_breakpoint(self): """Tests that we can set a conditional breakpoint in Swift code""" self.build() diff --git a/lldb/test/API/lang/swift/stepping/TestSwiftStepping.py b/lldb/test/API/lang/swift/stepping/TestSwiftStepping.py index 7b7eb58cf3874..766f01aaf4c4b 100644 --- a/lldb/test/API/lang/swift/stepping/TestSwiftStepping.py +++ b/lldb/test/API/lang/swift/stepping/TestSwiftStepping.py @@ -25,7 +25,6 @@ class TestSwiftStepping(lldbtest.TestBase): mydir = lldbtest.TestBase.compute_mydir(__file__) @swiftTest - @skipIfLinux def test_swift_stepping(self): """Tests that we can step reliably in swift code.""" self.build() From 4f4a1c60ed6bf2438cd4d83d9fd90ef20328c3bc Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Mon, 23 Mar 2020 19:57:33 -0700 Subject: [PATCH 094/286] Add a `Symbolizer::GetEnvP()` method that allows symbolizer implementations to customise the environment of the symbolizer binary. Summary: This change introduces the `Symbolizer::GetEnvP()` method that returns a pointer to environment array used for spawning the symbolizer process. The motivation is to allow implementations to customise the environment if required. The default implementation just returns `__sanitizer::GetEnviron()` which (provided it's implemented) should preserve the existing behaviours of the various implementations. This change has been plumbed through the `internal_spawn(...)` and `StartSubprocess(...)` process spawning implementations. For the `StartSubprocess()` implementation we need to call `execve()` rather than `execv()` to pass the environment. However, it appears that `internal_execve(...)` exists in sanitizer_common so this patch use that which seems like a nice clean up. Support in the Windows implementation of `SymbolizerProcess:StartSymbolizerSubprocess()` has not been added because the Windows sanitizer runtime doesn't implement `GetEnviron()`. rdar://problem/58789439 Reviewers: kubamracek, yln, dvyukov, vitalybuka, eugenis, phosek, aizatsky, rnk Subscribers: #sanitizers, llvm-commits Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D76666 (cherry picked from commit b684c1a50f70a39ceb51973950c5cca520ce8b2c) --- compiler-rt/lib/sanitizer_common/sanitizer_file.h | 4 ++-- compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp | 11 ++++++----- compiler-rt/lib/sanitizer_common/sanitizer_posix.h | 2 +- .../lib/sanitizer_common/sanitizer_posix_libcdep.cpp | 6 ++++-- .../sanitizer_common/sanitizer_symbolizer_internal.h | 2 ++ .../sanitizer_symbolizer_posix_libcdep.cpp | 4 ++-- compiler-rt/lib/sanitizer_common/sanitizer_win.cpp | 3 ++- .../sanitizer_common/tests/sanitizer_linux_test.cpp | 2 +- 8 files changed, 20 insertions(+), 14 deletions(-) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_file.h b/compiler-rt/lib/sanitizer_common/sanitizer_file.h index 4a78a0e0ac881..26681f0493d73 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_file.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_file.h @@ -87,8 +87,8 @@ bool IsAbsolutePath(const char *path); // The child process will close all fds after STDERR_FILENO // before passing control to a program. pid_t StartSubprocess(const char *filename, const char *const argv[], - fd_t stdin_fd = kInvalidFd, fd_t stdout_fd = kInvalidFd, - fd_t stderr_fd = kInvalidFd); + const char *const envp[], fd_t stdin_fd = kInvalidFd, + fd_t stdout_fd = kInvalidFd, fd_t stderr_fd = kInvalidFd); // Checks if specified process is still running bool IsProcessRunning(pid_t pid); // Waits for the process to finish and returns its exit code. diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp index ea4bd02aa92e4..c7a111c38ae57 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_mac.cpp @@ -242,7 +242,8 @@ int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, (size_t)newlen); } -static fd_t internal_spawn_impl(const char *argv[], pid_t *pid) { +static fd_t internal_spawn_impl(const char *argv[], const char *envp[], + pid_t *pid) { fd_t master_fd = kInvalidFd; fd_t slave_fd = kInvalidFd; @@ -298,8 +299,8 @@ static fd_t internal_spawn_impl(const char *argv[], pid_t *pid) { // posix_spawn char **argv_casted = const_cast(argv); - char **env = GetEnviron(); - res = posix_spawn(pid, argv[0], &acts, &attrs, argv_casted, env); + char **envp_casted = const_cast(envp); + res = posix_spawn(pid, argv[0], &acts, &attrs, argv_casted, envp_casted); if (res != 0) return kInvalidFd; // Disable echo in the new terminal, disable CR. @@ -316,7 +317,7 @@ static fd_t internal_spawn_impl(const char *argv[], pid_t *pid) { return fd; } -fd_t internal_spawn(const char *argv[], pid_t *pid) { +fd_t internal_spawn(const char *argv[], const char *envp[], pid_t *pid) { // The client program may close its stdin and/or stdout and/or stderr thus // allowing open/posix_openpt to reuse file descriptors 0, 1 or 2. In this // case the communication is broken if either the parent or the child tries to @@ -331,7 +332,7 @@ fd_t internal_spawn(const char *argv[], pid_t *pid) { break; } - fd_t fd = internal_spawn_impl(argv, pid); + fd_t fd = internal_spawn_impl(argv, envp, pid); for (; count > 0; count--) { internal_close(low_fds[count]); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix.h b/compiler-rt/lib/sanitizer_common/sanitizer_posix.h index 05fb0f630207c..4ea6263d56bfb 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix.h @@ -63,7 +63,7 @@ uptr internal_ptrace(int request, int pid, void *addr, void *data); uptr internal_waitpid(int pid, int *status, int options); int internal_fork(); -fd_t internal_spawn(const char *argv[], pid_t *pid); +fd_t internal_spawn(const char *argv[], const char *envp[], pid_t *pid); int internal_sysctl(const int *name, unsigned int namelen, void *oldp, uptr *oldlenp, const void *newp, uptr newlen); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp index 304b3a01a08b6..f920172c06d63 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp @@ -426,7 +426,8 @@ void AdjustStackSize(void *attr_) { #endif // !SANITIZER_GO pid_t StartSubprocess(const char *program, const char *const argv[], - fd_t stdin_fd, fd_t stdout_fd, fd_t stderr_fd) { + const char *const envp[], fd_t stdin_fd, fd_t stdout_fd, + fd_t stderr_fd) { auto file_closer = at_scope_exit([&] { if (stdin_fd != kInvalidFd) { internal_close(stdin_fd); @@ -469,7 +470,8 @@ pid_t StartSubprocess(const char *program, const char *const argv[], for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--) internal_close(fd); - execv(program, const_cast(&argv[0])); + internal_execve(program, const_cast(&argv[0]), + const_cast(envp)); internal__exit(1); } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h index c04797dd61b8b..0639543308422 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h @@ -86,6 +86,8 @@ class SymbolizerProcess { // Customizable by subclasses. virtual bool StartSymbolizerSubprocess(); virtual bool ReadFromSymbolizer(char *buffer, uptr max_length); + // Return the environment to run the symbolizer in. + virtual char **GetEnvP() { return GetEnviron(); } private: virtual bool ReachedEndOfOutput(const char *buffer, uptr length) const { diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp index c123ecb11206c..4c3cd966dd5a0 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp @@ -153,7 +153,7 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() { if (use_posix_spawn_) { #if SANITIZER_MAC - fd_t fd = internal_spawn(argv, &pid); + fd_t fd = internal_spawn(argv, const_cast(GetEnvP()), &pid); if (fd == kInvalidFd) { Report("WARNING: failed to spawn external symbolizer (errno: %d)\n", errno); @@ -173,7 +173,7 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() { return false; } - pid = StartSubprocess(path_, argv, /* stdin */ outfd[0], + pid = StartSubprocess(path_, argv, GetEnvP(), /* stdin */ outfd[0], /* stdout */ infd[1]); if (pid < 0) { internal_close(infd[0]); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp index 36dde49d87083..1d6b914618a5c 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_win.cpp @@ -1060,7 +1060,8 @@ char **GetEnviron() { } pid_t StartSubprocess(const char *program, const char *const argv[], - fd_t stdin_fd, fd_t stdout_fd, fd_t stderr_fd) { + const char *const envp[], fd_t stdin_fd, fd_t stdout_fd, + fd_t stderr_fd) { // FIXME: implement on this platform // Should be implemented based on // SymbolizerProcess::StarAtSymbolizerSubprocess diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_linux_test.cpp b/compiler-rt/lib/sanitizer_common/tests/sanitizer_linux_test.cpp index 1d8e7e8af26ca..cb6c0724ac884 100644 --- a/compiler-rt/lib/sanitizer_common/tests/sanitizer_linux_test.cpp +++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_linux_test.cpp @@ -264,7 +264,7 @@ TEST(SanitizerCommon, StartSubprocessTest) { const char *shell = "/bin/sh"; #endif const char *argv[] = {shell, "-c", "echo -n 'hello'", (char *)NULL}; - int pid = StartSubprocess(shell, argv, + int pid = StartSubprocess(shell, argv, GetEnviron(), /* stdin */ kInvalidFd, /* stdout */ pipe_fds[1]); ASSERT_GT(pid, 0); From 797299c6fcaf1227639fcbed3913095050cad59d Mon Sep 17 00:00:00 2001 From: Davide Italiano Date: Tue, 24 Mar 2020 16:55:47 -0700 Subject: [PATCH 095/286] [Bridging] Reorder a test. NFC. --- lldb/test/Shell/SwiftREPL/DictBridging.test | 54 ++++++++++----------- lldb/test/Shell/SwiftREPL/SetBridging.test | 48 +++++++++--------- 2 files changed, 51 insertions(+), 51 deletions(-) diff --git a/lldb/test/Shell/SwiftREPL/DictBridging.test b/lldb/test/Shell/SwiftREPL/DictBridging.test index d2be9e7548f6a..e7bae8548e94c 100644 --- a/lldb/test/Shell/SwiftREPL/DictBridging.test +++ b/lldb/test/Shell/SwiftREPL/DictBridging.test @@ -42,6 +42,33 @@ let d2: Dictionary = [ // DICT-NEXT: } // DICT-NEXT: } +// Test formatters in Objective-C context. + +// Empty singleton +let d_objc1 = NSArray(object: [:] as [NSNumber: NSNumber] as NSDictionary) +// DICT-LABEL: d_objc1: NSArray = 1 element { +// DICT-NEXT: [0] = 0 key/value pairs +// DICT-NEXT: } + +// Verbatim bridging +let d_objc2 = NSArray(object: [1: 2] as [NSNumber: NSNumber] as NSDictionary) +// DICT-LABEL: d_objc2: NSArray = 1 element { +// DICT-NEXT: [0] = 1 key/value pair { +// DICT-NEXT: [0] = { +// DICT-NEXT: key = Int64(1) +// DICT-NEXT: value = Int64(2) +// DICT-NEXT: } +// DICT-NEXT: } +// DICT-NEXT: } + +// Non-verbatim bridging +let d_objc3 = NSArray(object: [1: 2] as [Int: Int] as NSDictionary) +// DICT-LABEL: d_objc3: NSArray = 1 element { +// DICT-NEXT: [0] = 1 key/value pair { +// DICT-NEXT: [0] = (key = 1, value = 2) +// DICT-NEXT: } +// DICT-NEXT: } + // Verbatim bridging from Swift to Objective-C let d2b = d2 as NSDictionary // DICT-LABEL: d2b: {{(_HashableTypedNativeDictionaryStorage|_DictionaryStorage)}} = 1 key/value pair { @@ -80,30 +107,3 @@ let d3b2 = d3 as! [Int: Int] // DICT-NEXT: value = 2 // DICT-NEXT: } // DICT-NEXT: } - -// Test formatters in Objective-C context. - -// Empty singleton -let d4 = NSArray(object: [:] as [NSNumber: NSNumber] as NSDictionary) -// DICT-LABEL: d4: NSArray = 1 element { -// DICT-NEXT: [0] = 0 key/value pairs -// DICT-NEXT: } - -// Verbatim bridging -let d5 = NSArray(object: [1: 2] as [NSNumber: NSNumber] as NSDictionary) -// DICT-LABEL: d5: NSArray = 1 element { -// DICT-NEXT: [0] = 1 key/value pair { -// DICT-NEXT: [0] = { -// DICT-NEXT: key = Int64(1) -// DICT-NEXT: value = Int64(2) -// DICT-NEXT: } -// DICT-NEXT: } -// DICT-NEXT: } - -// Non-verbatim bridging -let d6 = NSArray(object: [1: 2] as [Int: Int] as NSDictionary) -// DICT-LABEL: d6: NSArray = 1 element { -// DICT-NEXT: [0] = 1 key/value pair { -// DICT-NEXT: [0] = (key = 1, value = 2) -// DICT-NEXT: } -// DICT-NEXT: } diff --git a/lldb/test/Shell/SwiftREPL/SetBridging.test b/lldb/test/Shell/SwiftREPL/SetBridging.test index b11985b059c53..4c7aca292f144 100644 --- a/lldb/test/Shell/SwiftREPL/SetBridging.test +++ b/lldb/test/Shell/SwiftREPL/SetBridging.test @@ -31,6 +31,30 @@ let s2: Set = [NSNumber(value: 1)] // SET-NEXT: [0] = Int64(1) // SET-NEXT: } +// Test formatters in Objective-C context. + +// Empty singleton +let s_objc1 = NSArray(object: [] as Set as NSSet) +// SET-LABEL: s_objc1: NSArray = 1 element { +// SET-NEXT: [0] = 0 values +// SET-NEXT: } + +// Verbatim bridging +let s_objc2 = NSArray(object: [1] as Set as NSSet) +// SET-LABEL: s_objc2: NSArray = 1 element { +// SET-NEXT: [0] = 1 value { +// SET-NEXT: [0] = Int64(1) +// SET-NEXT: } +// SET-NEXT: } + +// Non-verbatim bridging +let s_objc3 = NSArray(object: [1] as Set as NSSet) +// SET-LABEL: s_objc3: NSArray = 1 element { +// SET-NEXT: [0] = 1 value { +// SET-NEXT: [0] = 1 +// SET-NEXT: } +// SET-NEXT: } + // Verbatim bridging from Swift to Objective-C let s2b = s2 as NSSet // SET-LABEL: s2b: {{(_HashableTypedNativeSetStorage|_SetStorage)}} = 1 value { @@ -58,27 +82,3 @@ let s3b2 = s3 as! Set // SET-NEXT: [0] = {{[12]}} // SET-NEXT: [1] = {{[12]}} // SET-NEXT: } - -// Test formatters in Objective-C context. - -// Empty singleton -let s4 = NSArray(object: [] as Set as NSSet) -// SET-LABEL: s4: NSArray = 1 element { -// SET-NEXT: [0] = 0 values -// SET-NEXT: } - -// Verbatim bridging -let s5 = NSArray(object: [1] as Set as NSSet) -// SET-LABEL: s5: NSArray = 1 element { -// SET-NEXT: [0] = 1 value { -// SET-NEXT: [0] = Int64(1) -// SET-NEXT: } -// SET-NEXT: } - -// Non-verbatim bridging -let s6 = NSArray(object: [1] as Set as NSSet) -// SET-LABEL: s6: NSArray = 1 element { -// SET-NEXT: [0] = 1 value { -// SET-NEXT: [0] = 1 -// SET-NEXT: } -// SET-NEXT: } From 0b4d1868d76f418b9f3c491415d77372a826a0e6 Mon Sep 17 00:00:00 2001 From: Davide Italiano Date: Tue, 24 Mar 2020 13:04:08 -0700 Subject: [PATCH 096/286] [Darwin] Add another hint to find the kernel. NFC. --- .../DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp index 6019a1cc76021..bda9dd06c9114 100644 --- a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp +++ b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp @@ -244,6 +244,7 @@ DynamicLoaderDarwinKernel::SearchForKernelWithDebugHints(Process *process) { Status read_err; addr_t kernel_addresses_64[] = { + 0xfffffff000002010ULL, 0xfffffff000004010ULL, // newest arm64 devices 0xffffff8000004010ULL, // 2014-2015-ish arm64 devices 0xffffff8000002010ULL, // oldest arm64 devices From 57144979798d29660126f55e5f1734849941c642 Mon Sep 17 00:00:00 2001 From: Anthony Latsis Date: Wed, 25 Mar 2020 07:04:09 +0300 Subject: [PATCH 097/286] [Swift] Replace calls to FuncDecl::getName & EnumElementDecl::getName with ValueDecl::getBaseIdentifier for apple/swift#30606 --- .../ExpressionParser/Swift/SwiftASTManipulator.cpp | 4 ++-- .../ExpressionParser/Swift/SwiftExpressionParser.cpp | 2 +- .../Swift/SwiftPersistentExpressionState.cpp | 2 +- lldb/source/Symbol/SwiftASTContext.cpp | 8 ++++---- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lldb/source/Plugins/ExpressionParser/Swift/SwiftASTManipulator.cpp b/lldb/source/Plugins/ExpressionParser/Swift/SwiftASTManipulator.cpp index 67e397529c44e..02af3191930a3 100644 --- a/lldb/source/Plugins/ExpressionParser/Swift/SwiftASTManipulator.cpp +++ b/lldb/source/Plugins/ExpressionParser/Swift/SwiftASTManipulator.cpp @@ -283,8 +283,8 @@ void SwiftASTManipulatorBase::DoInitialization() { break; } } - } else if (FD->hasName() && - FD->getName().str().startswith(m_wrapper_func_prefix)) { + } else if (FD->hasName() && FD->getBaseIdentifier().str() + .startswith(m_wrapper_func_prefix)) { m_wrapper_decl = FD; } diff --git a/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp index ce0d19594859b..1ec871ba6f9f3 100644 --- a/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp +++ b/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp @@ -250,7 +250,7 @@ class LLDBExprNameLookup : public LLDBNameLookup { // must be moved to the source-file level to be legal. But we // don't want to register them with lldb unless they are of the // kind lldb explicitly wants to globalize. - if (shouldGlobalize(value_decl->getBaseName().getIdentifier(), + if (shouldGlobalize(value_decl->getBaseIdentifier(), value_decl->getKind())) m_staged_decls.AddDecl(value_decl, false, ConstString()); } diff --git a/lldb/source/Plugins/ExpressionParser/Swift/SwiftPersistentExpressionState.cpp b/lldb/source/Plugins/ExpressionParser/Swift/SwiftPersistentExpressionState.cpp index 0bbf1feabfb3b..c5635e582199f 100644 --- a/lldb/source/Plugins/ExpressionParser/Swift/SwiftPersistentExpressionState.cpp +++ b/lldb/source/Plugins/ExpressionParser/Swift/SwiftPersistentExpressionState.cpp @@ -136,7 +136,7 @@ void SwiftPersistentExpressionState::SwiftDeclMap::AddDecl( std::string name_str; if (alias.IsEmpty()) { - name_str = (value_decl->getBaseName().getIdentifier().str()); + name_str = (value_decl->getBaseIdentifier().str()); } else { name_str.assign(alias.GetCString()); } diff --git a/lldb/source/Symbol/SwiftASTContext.cpp b/lldb/source/Symbol/SwiftASTContext.cpp index 96f127b301104..a06aeae96e6e4 100644 --- a/lldb/source/Symbol/SwiftASTContext.cpp +++ b/lldb/source/Symbol/SwiftASTContext.cpp @@ -948,7 +948,7 @@ class SwiftCStyleEnumDescriptor : public SwiftEnumDescriptor { Dump(m_nopayload_elems_bitmask).c_str()); for (auto enum_case : elements_with_no_payload) { - ConstString case_name(enum_case.decl->getName().str()); + ConstString case_name(enum_case.decl->getBaseIdentifier().str()); swift::ClusteredBitVector case_value = enum_impl_strategy.getBitPatternForNoPayloadElement(enum_case.decl); @@ -1081,7 +1081,7 @@ class SwiftAllPayloadEnumDescriptor : public SwiftEnumDescriptor { auto module_ctx = enum_decl->getModuleContext(); const bool has_payload = true; for (auto enum_case : elements_with_payload) { - ConstString case_name(enum_case.decl->getName().str()); + ConstString case_name(enum_case.decl->getBaseIdentifier().str()); swift::EnumElementDecl *case_decl = enum_case.decl; assert(case_decl); @@ -6542,10 +6542,10 @@ TypeMemberFunctionImpl SwiftASTContext::GetMemberFunctionAtIndex(void *type, swift::FuncDecl *func_decl = llvm::dyn_cast(*iter); if (func_decl) { - if (func_decl->getName().empty()) + if (func_decl->getBaseIdentifier().empty()) name.clear(); else - name.assign(func_decl->getName().get()); + name.assign(func_decl->getBaseIdentifier().get()); if (func_decl->isStatic()) kind = lldb::eMemberFunctionKindStaticMethod; else From 3ca0eec4570759b7e14e68da7c1f089d45084150 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Wed, 25 Mar 2020 09:08:07 -0700 Subject: [PATCH 098/286] [lldb/Test] Re-enable TestDataFormatterObjCNSError --- .../data-formatter-objc/TestDataFormatterObjCNSError.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSError.py b/lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSError.py index ced7444c0ca5a..df380aefd88f4 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSError.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSError.py @@ -15,7 +15,6 @@ class ObjCDataFormatterNSError(ObjCDataFormatterTestCase): @skipUnlessDarwin - @expectedFailureAll(bugnumber="rdar://25587546") def test_nserror_with_run_command(self): """Test formatters for NSError.""" self.appkit_tester_impl(self.nserror_data_formatter_commands) From fbde3a2d271b6c1572e1243acc71e2050959c6e9 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Tue, 24 Mar 2020 08:54:26 -0700 Subject: [PATCH 099/286] [lldb/Reproducers] Collect files imported by command script import Files imported by the script interpreter aren't opened by LLDB so they don't end up in the reproducer. The solution is to explicitly add them to the FileCollector. Differential revision: https://reviews.llvm.org/D76626 (cherry picked from commit 1f80e51546bf2bf77982fd013519631f4c86898b) --- lldb/include/lldb/Host/FileSystem.h | 3 +++ lldb/source/Host/common/FileSystem.cpp | 16 ++++++++++++---- .../Python/ScriptInterpreterPython.cpp | 1 + lldb/test/Shell/Reproducer/Inputs/foo.lua | 1 + lldb/test/Shell/Reproducer/Inputs/foo.py | 1 + lldb/test/Shell/Reproducer/TestPythonImport.test | 11 +++++++++++ 6 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 lldb/test/Shell/Reproducer/Inputs/foo.lua create mode 100644 lldb/test/Shell/Reproducer/Inputs/foo.py create mode 100644 lldb/test/Shell/Reproducer/TestPythonImport.test diff --git a/lldb/include/lldb/Host/FileSystem.h b/lldb/include/lldb/Host/FileSystem.h index 528c43519a326..32aa548e8420f 100644 --- a/lldb/include/lldb/Host/FileSystem.h +++ b/lldb/include/lldb/Host/FileSystem.h @@ -186,6 +186,9 @@ class FileSystem { return m_fs; } + void Collect(const FileSpec &file_spec); + void Collect(const llvm::Twine &file); + private: static llvm::Optional &InstanceImpl(); llvm::IntrusiveRefCntPtr m_fs; diff --git a/lldb/source/Host/common/FileSystem.cpp b/lldb/source/Host/common/FileSystem.cpp index 2db5bff3207fd..debfba5efd32a 100644 --- a/lldb/source/Host/common/FileSystem.cpp +++ b/lldb/source/Host/common/FileSystem.cpp @@ -279,8 +279,7 @@ void FileSystem::Resolve(FileSpec &file_spec) { std::shared_ptr FileSystem::CreateDataBuffer(const llvm::Twine &path, uint64_t size, uint64_t offset) { - if (m_collector) - m_collector->addFile(path); + Collect(path); const bool is_volatile = !IsLocal(path); const ErrorOr external_path = GetExternalPath(path); @@ -418,8 +417,7 @@ static mode_t GetOpenMode(uint32_t permissions) { Expected FileSystem::Open(const FileSpec &file_spec, File::OpenOptions options, uint32_t permissions, bool should_close_fd) { - if (m_collector) - m_collector->addFile(file_spec.GetPath()); + Collect(file_spec.GetPath()); const int open_flags = GetOpenFlags(options); const mode_t open_mode = @@ -466,3 +464,13 @@ ErrorOr FileSystem::GetExternalPath(const llvm::Twine &path) { ErrorOr FileSystem::GetExternalPath(const FileSpec &file_spec) { return GetExternalPath(file_spec.GetPath()); } + +void FileSystem::Collect(const FileSpec &file_spec) { + Collect(file_spec.GetPath()); +} + +void FileSystem::Collect(const llvm::Twine &file) { + if (m_collector && !llvm::sys::fs::is_directory(file)) { + m_collector->addFile(file); + } +} diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp index 1bb3cde7ab241..56cf9ee5caa46 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -2748,6 +2748,7 @@ bool ScriptInterpreterPythonImpl::LoadScriptingModule( { FileSpec target_file(pathname); FileSystem::Instance().Resolve(target_file); + FileSystem::Instance().Collect(target_file); std::string basename(target_file.GetFilename().GetCString()); StreamString command_stream; diff --git a/lldb/test/Shell/Reproducer/Inputs/foo.lua b/lldb/test/Shell/Reproducer/Inputs/foo.lua new file mode 100644 index 0000000000000..8ed0c94cbba96 --- /dev/null +++ b/lldb/test/Shell/Reproducer/Inputs/foo.lua @@ -0,0 +1 @@ +print('95126') diff --git a/lldb/test/Shell/Reproducer/Inputs/foo.py b/lldb/test/Shell/Reproducer/Inputs/foo.py new file mode 100644 index 0000000000000..8ed0c94cbba96 --- /dev/null +++ b/lldb/test/Shell/Reproducer/Inputs/foo.py @@ -0,0 +1 @@ +print('95126') diff --git a/lldb/test/Shell/Reproducer/TestPythonImport.test b/lldb/test/Shell/Reproducer/TestPythonImport.test new file mode 100644 index 0000000000000..7bea97c91d986 --- /dev/null +++ b/lldb/test/Shell/Reproducer/TestPythonImport.test @@ -0,0 +1,11 @@ +# REQUIRES: python +# UNSUPPORTED: system-windows +# Ensure that the reproducers know about imported Python modules. + +# RUN: rm -rf %t.repro +# RUN: %lldb -x -b --capture --capture-path %t.repro -o 'command script import %S/Inputs/foo.py' -o 'reproducer generate' | FileCheck %s --check-prefix CAPTURE + +# CAPTURE: 95126 + +# RUN: %lldb -b -o 'reproducer dump -p files -f %t.repro' | FileCheck %s --check-prefix FILES +# FILES: foo.py From ab18ed9d0b3c762f8f416e1f7abcc0b3a21bb295 Mon Sep 17 00:00:00 2001 From: John McCall Date: Fri, 20 Mar 2020 16:45:39 -0400 Subject: [PATCH 100/286] Add an algorithm for performing "optimal" layout of a struct. The algorithm supports both assigning a fixed offset to a field prior to layout and allowing fields to have sizes that aren't multiples of their required alignments. This means that the well-known algorithm of sorting by decreasing alignment isn't always good enough. Still, we start with that, and only if that leaves padding around do we fall back on a greedy padding-minimizing algorithm. There is no known efficient algorithm for producing a guaranteed-minimal layout in all cases. In fact, allowing arbitrary fixed-offset fields means there's a straightforward reduction from bin-packing, making this NP-hard. But as usual with such problems, we can still efficiently produce adequate solutions to the cases that matter most to us. I intend to use this in coroutine frame layout, where the retcon lowerings very badly want to minimize total space usage, and where the switch lowering can indeed produce a header with interior padding if the promise field is highly-aligned. But it may be useful in a much wider variety of situations. --- llvm/include/llvm/Support/OptimalLayout.h | 130 ++++++ llvm/lib/Support/CMakeLists.txt | 1 + llvm/lib/Support/OptimalLayout.cpp | 452 +++++++++++++++++++ llvm/unittests/Support/CMakeLists.txt | 1 + llvm/unittests/Support/OptimalLayoutTest.cpp | 132 ++++++ 5 files changed, 716 insertions(+) create mode 100644 llvm/include/llvm/Support/OptimalLayout.h create mode 100644 llvm/lib/Support/OptimalLayout.cpp create mode 100644 llvm/unittests/Support/OptimalLayoutTest.cpp diff --git a/llvm/include/llvm/Support/OptimalLayout.h b/llvm/include/llvm/Support/OptimalLayout.h new file mode 100644 index 0000000000000..870dc78791bb3 --- /dev/null +++ b/llvm/include/llvm/Support/OptimalLayout.h @@ -0,0 +1,130 @@ +//===-- OptimalLayout.h - Optimal data layout algorithm -----------*- 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 +// +//===----------------------------------------------------------------------===// +/// +/// This file provides an interface for laying out a sequence of fields +/// as a struct in a way that attempts to minimizes the total space +/// requirements of the struct. +/// +/// The word "optimal" is a misnomer in several ways. First, minimizing +/// space usage doesn't necessarily yield optimal performance because it +/// may decrease locality. Second, there is no known efficient algorithm +/// that guarantees a minimal layout for arbitrary inputs. Nonetheless, +/// this algorithm is likely to produce much more compact layouts than +/// would be produced by just allocating space in a buffer. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_OPTIMALLAYOUT_H +#define LLVM_SUPPORT_OPTIMALLAYOUT_H + +#include "llvm/Support/Alignment.h" +#include "llvm/ADT/ArrayRef.h" +#include + +namespace llvm { + +/// A field in a structure. +struct OptimalLayoutField { + /// A special value for Offset indicating that the field can be moved + /// anywhere. + static constexpr uint64_t FlexibleOffset = ~(uint64_t)0; + + OptimalLayoutField(const void *Id, uint64_t Size, Align Alignment, + uint64_t FixedOffset = FlexibleOffset) + : Offset(FixedOffset), Size(Size), Id(Id), Alignment(Alignment) { + assert(Size > 0 && "adding an empty field to the layout"); + } + + /// The offset of this field in the final layout. If this is + /// initialized to FlexibleOffset, layout will overwrite it with + /// the assigned offset of the field. + uint64_t Offset; + + /// The required size of this field in bytes. Does not have to be + /// a multiple of Alignment. Must be non-zero. + uint64_t Size; + + /// A opaque value which uniquely identifies this field. + const void *Id; + + /// Private scratch space for the algorithm. The implementation + /// must treat this as uninitialized memory on entry. + void *Scratch; + + /// The required alignment of this field. + Align Alignment; + + /// Return true if this field has been assigned a fixed offset. + /// After layout, this will be true of all the fields. + bool hasFixedOffset() const { + return (Offset != FlexibleOffset); + } + + /// Given that this field has a fixed offset, return the offset + /// of the first byte following it. + uint64_t getEndOffset() const { + assert(hasFixedOffset()); + return Offset + Size; + } +}; + +/// Compute a layout for a struct containing the given fields, making a +/// best-effort attempt to minimize the amount of space required. +/// +/// Two features are supported which require a more careful solution +/// than the well-known "sort by decreasing alignment" solution: +/// +/// - Fields may be assigned a fixed offset in the layout. If there are +/// gaps among the fixed-offset fields, the algorithm may attempt +/// to allocate flexible-offset fields into those gaps. If that's +/// undesirable, the caller should "block out" those gaps by e.g. +/// just creating a single fixed-offset field that represents the +/// entire "header". +/// +/// - The size of a field is not required to be a multiple of, or even +/// greater than, the field's required alignment. The only constraint +/// on fields is that they must not be zero-sized. +/// +/// To simplify the implementation, any fixed-offset fields in the +/// layout must appear at the start of the field array, and they must +/// be ordered by increasing offset. +/// +/// The algorithm will produce a guaranteed-minimal layout with no +/// interior padding in the following "C-style" case: +/// +/// - every field's size is a multiple of its required alignment and +/// - either no fields have initially fixed offsets, or the fixed-offset +/// fields have no interior padding and end at an offset that is at +/// least as aligned as all the flexible-offset fields. +/// +/// Otherwise, while the algorithm will make a best-effort attempt to +/// avoid padding, it cannot guarantee a minimal layout, as there is +/// no known efficient algorithm for doing so. +/// +/// The layout produced by this algorithm may not be stable across LLVM +/// releases. Do not use this anywhere where ABI stability is required. +/// +/// Flexible-offset fields with the same size and alignment will be ordered +/// the same way they were in the initial array. Otherwise the current +/// algorithm makes no effort to preserve the initial order of +/// flexible-offset fields. +/// +/// On return, all fields will have been assigned a fixed offset, and the +/// array will be sorted in order of ascending offsets. Note that this +/// means that the fixed-offset fields may no longer form a strict prefix +/// if there's any padding before they end. +/// +/// The return value is the total size of the struct and its required +/// alignment. Note that the total size is not rounded up to a multiple +/// of the required alignment; clients which require this can do so easily. +std::pair +performOptimalLayout(MutableArrayRef Fields); + +} // namespace llvm + +#endif diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt index 26332d4f539c5..11606ce82adc8 100644 --- a/llvm/lib/Support/CMakeLists.txt +++ b/llvm/lib/Support/CMakeLists.txt @@ -115,6 +115,7 @@ add_llvm_component_library(LLVMSupport MemoryBuffer.cpp MD5.cpp NativeFormatting.cpp + OptimalLayout.cpp Optional.cpp Parallel.cpp PluginLoader.cpp diff --git a/llvm/lib/Support/OptimalLayout.cpp b/llvm/lib/Support/OptimalLayout.cpp new file mode 100644 index 0000000000000..b0c7720e71c60 --- /dev/null +++ b/llvm/lib/Support/OptimalLayout.cpp @@ -0,0 +1,452 @@ +//===--- OptimalLayout.cpp - Optimal data layout algorithm ----------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// This file implements the performOptimalLayout interface. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/OptimalLayout.h" + +using namespace llvm; + +#ifndef NDEBUG +void checkValidLayout(ArrayRef Fields, + uint64_t Size, Align MaxAlign) { + uint64_t LastEnd = 0; + Align ComputedMaxAlign; + for (auto &Field : Fields) { + assert(Field.hasFixedOffset() && + "didn't assign a fixed offset to field"); + assert(isAligned(Field.Alignment, Field.Offset) && + "didn't assign a correctly-aligned offset to field"); + assert(Field.Offset >= LastEnd && + "didn't assign offsets in ascending order"); + LastEnd = Field.getEndOffset(); + assert(Field.Alignment <= MaxAlign && + "didn't compute MaxAlign correctly"); + ComputedMaxAlign = std::max(Field.Alignment, MaxAlign); + } + assert(LastEnd == Size && "didn't compute LastEnd correctly"); + assert(ComputedMaxAlign == MaxAlign && "didn't compute MaxAlign correctly"); +} +#endif + +std::pair +llvm::performOptimalLayout(MutableArrayRef Fields) { +#ifndef NDEBUG + // Do some simple precondition checks. + { + bool InFixedPrefix = true; + size_t LastEnd = 0; + for (auto &Field : Fields) { + assert(Field.Size > 0 && "field of zero size"); + if (Field.hasFixedOffset()) { + assert(InFixedPrefix && + "fixed-offset fields are not a strict prefix of array"); + assert(LastEnd <= Field.Offset && + "fixed-offset fields overlap or are not in order"); + LastEnd = Field.getEndOffset(); + assert(LastEnd > Field.Offset && + "overflow in fixed-offset end offset"); + } else { + InFixedPrefix = false; + } + } + } +#endif + + // Do an initial pass over the fields. + Align MaxAlign; + + // Find the first flexible-offset field, tracking MaxAlign. + auto FirstFlexible = Fields.begin(), E = Fields.end(); + while (FirstFlexible != E && FirstFlexible->hasFixedOffset()) { + MaxAlign = std::max(MaxAlign, FirstFlexible->Alignment); + ++FirstFlexible; + } + + // If there are no flexible fields, we're done. + if (FirstFlexible == E) { + uint64_t Size = 0; + if (!Fields.empty()) + Size = Fields.back().getEndOffset(); + +#ifndef NDEBUG + checkValidLayout(Fields, Size, MaxAlign); +#endif + return std::make_pair(Size, MaxAlign); + } + + // Walk over the flexible-offset fields, tracking MaxAlign and + // assigning them a unique number in order of their appearance. + // We'll use this unique number in the comparison below so that + // we can use array_pod_sort, which isn't stable. We won't use it + // past that point. + { + uintptr_t UniqueNumber = 0; + for (auto I = FirstFlexible; I != E; ++I) { + I->Scratch = reinterpret_cast(UniqueNumber++); + MaxAlign = std::max(MaxAlign, I->Alignment); + } + } + + // Sort the flexible elements in order of decreasing alignment, + // then decreasing size, and then the original order as recorded + // in Scratch. The decreasing-size aspect of this is only really + // important if we get into the gap-filling stage below, but it + // doesn't hurt here. + array_pod_sort(FirstFlexible, E, + [](const OptimalLayoutField *lhs, + const OptimalLayoutField *rhs) -> int { + // Decreasing alignment. + if (lhs->Alignment != rhs->Alignment) + return (lhs->Alignment < rhs->Alignment ? 1 : -1); + + // Decreasing size. + if (lhs->Size != rhs->Size) + return (lhs->Size < rhs->Size ? 1 : -1); + + // Original order. + auto lhsNumber = reinterpret_cast(lhs->Scratch); + auto rhsNumber = reinterpret_cast(rhs->Scratch); + if (lhsNumber != rhsNumber) + return (lhsNumber < rhsNumber ? -1 : 1); + + return 0; + }); + + // Do a quick check for whether that sort alone has given us a perfect + // layout with no interior padding. This is very common: if the + // fixed-layout fields have no interior padding, and they end at a + // sufficiently-aligned offset for all the flexible-layout fields, + // and the flexible-layout fields all have sizes that are multiples + // of their alignment, then this will reliably trigger. + { + bool HasPadding = false; + uint64_t LastEnd = 0; + + // Walk the fixed-offset fields. + for (auto I = Fields.begin(); I != FirstFlexible; ++I) { + assert(I->hasFixedOffset()); + if (LastEnd != I->Offset) { + HasPadding = true; + break; + } + LastEnd = I->getEndOffset(); + } + + // Walk the flexible-offset fields, optimistically assigning fixed + // offsets. Note that we maintain a strict division between the + // fixed-offset and flexible-offset fields, so if we end up + // discovering padding later in this loop, we can just abandon this + // work and we'll ignore the offsets we already assigned. + if (!HasPadding) { + for (auto I = FirstFlexible; I != E; ++I) { + auto Offset = alignTo(LastEnd, I->Alignment); + if (LastEnd != Offset) { + HasPadding = true; + break; + } + I->Offset = Offset; + LastEnd = I->getEndOffset(); + } + } + + // If we already have a perfect layout, we're done. + if (!HasPadding) { +#ifndef NDEBUG + checkValidLayout(Fields, LastEnd, MaxAlign); +#endif + return std::make_pair(LastEnd, MaxAlign); + } + } + + // The algorithm sketch at this point is as follows. + // + // Consider the padding gaps between fixed-offset fields in ascending + // order. Let LastEnd be the offset of the first byte following the + // field before the gap, or 0 if the gap is at the beginning of the + // structure. Find the "best" flexible-offset field according to the + // criteria below. If no such field exists, proceed to the next gap. + // Otherwise, add the field at the first properly-aligned offset for + // that field that is >= LastEnd, then update LastEnd and repeat in + // order to fill any remaining gap following that field. + // + // Next, let LastEnd to be the offset of the first byte following the + // last fixed-offset field, or 0 if there are no fixed-offset fields. + // While there are flexible-offset fields remaining, find the "best" + // flexible-offset field according to the criteria below, add it at + // the first properly-aligned offset for that field that is >= LastEnd, + // and update LastEnd to the first byte following the field. + // + // The "best" field is chosen by the following criteria, considered + // strictly in order: + // + // - When filling a gap betweeen fields, the field must fit. + // - A field is preferred if it requires less padding following LastEnd. + // - A field is preferred if it is more aligned. + // - A field is preferred if it is larger. + // - A field is preferred if it appeared earlier in the initial order. + // + // Minimizing leading padding is a greedy attempt to avoid padding + // entirely. Preferring more-aligned fields is an attempt to eliminate + // stricter constraints earlier, with the idea that weaker alignment + // constraints may be resolvable with less padding elsewhere. These + // These two rules are sufficient to ensure that we get the optimal + // layout in the "C-style" case. Preferring larger fields tends to take + // better advantage of large gaps and may be more likely to have a size + // that's a multiple of a useful alignment. Preferring the initial + // order may help somewhat with locality but is mostly just a way of + // ensuring deterministic output. + // + // Note that this algorithm does not guarantee a minimal layout. Picking + // a larger object greedily may leave a gap that cannot be filled as + // efficiently. Unfortunately, solving this perfectly is an NP-complete + // problem (by reduction from bin-packing: let B_i be the bin sizes and + // O_j be the object sizes; add fixed-offset fields such that the gaps + // between them have size B_i, and add flexible-offset fields with + // alignment 1 and size O_j; if the layout size is equal to the end of + // the last fixed-layout field, the objects fit in the bins; note that + // this doesn't even require the complexity of alignment). + + // The implementation below is essentially just an optimized version of + // scanning the list of remaining fields looking for the best, which + // would be O(n^2). In the worst case, it doesn't improve on that. + // However, in practice it'll just scan the array of alignment bins + // and consider the first few elements from one or two bins. The + // number of bins is bounded by a small constant: alignments are powers + // of two that are vanishingly unlikely to be over 64 and fairly unlikely + // to be over 8. And multiple elements only need to be considered when + // filling a gap between fixed-offset fields, which doesn't happen very + // often. We could use a data structure within bins that optimizes for + // finding the best-sized match, but it would require allocating memory + // and copying data, so it's unlikely to be worthwhile. + + + // Start by organizing the flexible-offset fields into bins according to + // their alignment. We expect a small enough number of bins that we + // don't care about the asymptotic costs of walking this. + struct AlignmentQueue { + /// The minimum size of anything currently in this queue. + uint64_t MinSize; + + /// The head of the queue. A singly-linked list. The order here should + /// be consistent with the earlier sort, i.e. the elements should be + /// monotonically descending in size and otherwise in the original order. + /// + /// We remove the queue from the array as soon as this is empty. + OptimalLayoutField *Head; + + /// The alignment requirement of the queue. + Align Alignment; + + static OptimalLayoutField *getNext(OptimalLayoutField *Cur) { + return static_cast(Cur->Scratch); + } + }; + SmallVector FlexibleFieldsByAlignment; + for (auto I = FirstFlexible; I != E; ) { + auto Head = I; + auto Alignment = I->Alignment; + + uint64_t MinSize = I->Size; + auto LastInQueue = I; + for (++I; I != E && I->Alignment == Alignment; ++I) { + LastInQueue->Scratch = I; + LastInQueue = I; + MinSize = std::min(MinSize, I->Size); + } + LastInQueue->Scratch = nullptr; + + FlexibleFieldsByAlignment.push_back({MinSize, Head, Alignment}); + } + +#ifndef NDEBUG + // Verify that we set the queues up correctly. + auto checkQueues = [&]{ + bool FirstQueue = true; + Align LastQueueAlignment; + for (auto &Queue : FlexibleFieldsByAlignment) { + assert((FirstQueue || Queue.Alignment < LastQueueAlignment) && + "bins not in order of descending alignment"); + LastQueueAlignment = Queue.Alignment; + FirstQueue = false; + + assert(Queue.Head && "queue was empty"); + uint64_t LastSize = ~(uint64_t)0; + for (auto I = Queue.Head; I; I = Queue.getNext(I)) { + assert(I->Alignment == Queue.Alignment && "bad field in queue"); + assert(I->Size <= LastSize && "queue not in descending size order"); + LastSize = I->Size; + } + } + }; + checkQueues(); +#endif + + /// Helper function to remove a field from a queue. + auto spliceFromQueue = [&](AlignmentQueue *Queue, + OptimalLayoutField *Last, + OptimalLayoutField *Cur) { + assert(Last ? Queue->getNext(Last) == Cur : Queue->Head == Cur); + + // If we're removing Cur from a non-initial position, splice it out + // of the linked list. + if (Last) { + Last->Scratch = Cur->Scratch; + + // If Cur was the last field in the list, we need to update MinSize. + // We can just use the last field's size because the list is in + // descending order of size. + if (!Cur->Scratch) + Queue->MinSize = Last->Size; + + // Otherwise, replace the head. + } else { + if (auto NewHead = Queue->getNext(Cur)) + Queue->Head = NewHead; + + // If we just emptied the queue, destroy its bin. + else + FlexibleFieldsByAlignment.erase(Queue); + } + }; + + // Do layout into a local array. Doing this in-place on Fields is + // not really feasible. + SmallVector Layout; + Layout.reserve(Fields.size()); + + // The offset that we're currently looking to insert at (or after). + uint64_t LastEnd = 0; + + // Helper function to splice Cur out of the given queue and add it + // to the layout at the given offset. + auto addToLayout = [&](AlignmentQueue *Queue, + OptimalLayoutField *Last, + OptimalLayoutField *Cur, + uint64_t Offset) -> bool { + assert(Offset == alignTo(LastEnd, Cur->Alignment)); + + // Splice out. This potentially invalidates Queue. + spliceFromQueue(Queue, Last, Cur); + + // Add Cur to the layout. + Layout.push_back(*Cur); + Layout.back().Offset = Offset; + LastEnd = Layout.back().getEndOffset(); + + // Always return true so that we can be tail-called. + return true; + }; + + // Helper function to try to find a field in the given queue that'll + // fit starting at StartOffset but before EndOffset (if present). + // Note that this never fails if EndOffset is not provided. + auto tryAddFillerFromQueue = [&](AlignmentQueue *Queue, + uint64_t StartOffset, + Optional EndOffset) -> bool { + assert(Queue->Head); + assert(StartOffset == alignTo(LastEnd, Queue->Alignment)); + + // Figure out the maximum size that a field can be, and ignore this + // queue if there's nothing in it that small. + auto MaxViableSize = + (EndOffset ? *EndOffset - StartOffset : ~(uint64_t)0); + if (Queue->MinSize > MaxViableSize) return false; + + // Find the matching field. Note that this should always find + // something because of the MinSize check above. + for (OptimalLayoutField *Cur = Queue->Head, *Last = nullptr; + true; Last = Cur, Cur = Queue->getNext(Cur)) { + assert(Cur && "didn't find a match in queue despite its MinSize"); + if (Cur->Size <= MaxViableSize) + return addToLayout(Queue, Last, Cur, StartOffset); + } + + llvm_unreachable("didn't find a match in queue despite its MinSize"); + }; + + // Helper function to find the "best" flexible-offset field according + // to the criteria described above. + auto tryAddBestField = [&](Optional BeforeOffset) -> bool { + auto QueueB = FlexibleFieldsByAlignment.begin(); + auto QueueE = FlexibleFieldsByAlignment.end(); + + // Start by looking for the most-aligned queue that doesn't need any + // leading padding after LastEnd. + auto FirstQueueToSearch = QueueB; + for (; FirstQueueToSearch != QueueE; ++FirstQueueToSearch) { + if (isAligned(FirstQueueToSearch->Alignment, LastEnd)) + break; + } + + uint64_t Offset = LastEnd; + while (true) { + // Invariant: all of the queues in [FirstQueueToSearch, QueueE) + // require the same initial padding offset. + + // Search those queues in descending order of alignment for a + // satisfactory field. + for (auto Queue = FirstQueueToSearch; Queue != QueueE; ++Queue) { + if (tryAddFillerFromQueue(Queue, Offset, BeforeOffset)) + return true; + } + + // Okay, we don't need to scan those again. + QueueE = FirstQueueToSearch; + + // If we started from the first queue, we're done. + if (FirstQueueToSearch == QueueB) + return false; + + // Otherwise, scan backwards to find the most-aligned queue that + // still has minimal leading padding after LastEnd. + --FirstQueueToSearch; + Offset = alignTo(LastEnd, FirstQueueToSearch->Alignment); + while (FirstQueueToSearch != QueueB && + Offset == alignTo(LastEnd, FirstQueueToSearch[-1].Alignment)) + --FirstQueueToSearch; + } + }; + + // Phase 1: fill the gaps between fixed-offset fields with the best + // flexible-offset field that fits. + for (auto I = Fields.begin(); I != FirstFlexible; ++I) { + while (LastEnd != I->Offset) { + if (!tryAddBestField(I->Offset)) + break; + } + Layout.push_back(*I); + LastEnd = I->getEndOffset(); + } + +#ifndef NDEBUG + checkQueues(); +#endif + + // Phase 2: repeatedly add the best flexible-offset field until + // they're all gone. + while (!FlexibleFieldsByAlignment.empty()) { + bool Success = tryAddBestField(None); + assert(Success && "didn't find a field with no fixed limit?"); + (void) Success; + } + + // Copy the layout back into place. + assert(Layout.size() == Fields.size()); + memcpy(Fields.data(), Layout.data(), + Fields.size() * sizeof(OptimalLayoutField)); + +#ifndef NDEBUG + // Make a final check that the layout is valid. + checkValidLayout(Fields, LastEnd, MaxAlign); +#endif + + return std::make_pair(LastEnd, MaxAlign); +} diff --git a/llvm/unittests/Support/CMakeLists.txt b/llvm/unittests/Support/CMakeLists.txt index 161891517cf37..0b46040e10e57 100644 --- a/llvm/unittests/Support/CMakeLists.txt +++ b/llvm/unittests/Support/CMakeLists.txt @@ -50,6 +50,7 @@ add_llvm_unittest(SupportTests MemoryBufferTest.cpp MemoryTest.cpp NativeFormatTests.cpp + OptimalLayoutTest.cpp ParallelTest.cpp Path.cpp ProcessTest.cpp diff --git a/llvm/unittests/Support/OptimalLayoutTest.cpp b/llvm/unittests/Support/OptimalLayoutTest.cpp new file mode 100644 index 0000000000000..a31fbaf3f2e68 --- /dev/null +++ b/llvm/unittests/Support/OptimalLayoutTest.cpp @@ -0,0 +1,132 @@ +//=== - llvm/unittest/Support/OptimalLayoutTest.cpp - Layout tests --------===// +// +// 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/Support/OptimalLayout.h" +#include "gtest/gtest.h" + +using namespace llvm; + +namespace { + +class LayoutTest { + struct Field { + uint64_t Size; + Align Alignment; + uint64_t ForcedOffset; + uint64_t ExpectedOffset; + }; + + SmallVector Fields; + bool Verified = false; + +public: + LayoutTest() {} + LayoutTest(const LayoutTest &) = delete; + LayoutTest &operator=(const LayoutTest &) = delete; + ~LayoutTest() { assert(Verified); } + + LayoutTest &flexible(uint64_t Size, uint64_t Alignment, + uint64_t ExpectedOffset) { + Fields.push_back({Size, Align(Alignment), + OptimalLayoutField::FlexibleOffset, ExpectedOffset}); + return *this; + } + + LayoutTest &fixed(uint64_t Size, uint64_t Alignment, uint64_t Offset) { + Fields.push_back({Size, Align(Alignment), Offset, Offset}); + return *this; + } + + void verify(uint64_t ExpectedSize, uint64_t ExpectedAlignment) { + SmallVector LayoutFields; + LayoutFields.reserve(Fields.size()); + for (auto &F : Fields) + LayoutFields.emplace_back(&F, F.Size, F.Alignment, F.ForcedOffset); + + auto SizeAndAlign = performOptimalLayout(LayoutFields); + + EXPECT_EQ(SizeAndAlign.first, ExpectedSize); + EXPECT_EQ(SizeAndAlign.second, Align(ExpectedAlignment)); + + for (auto &LF : LayoutFields) { + auto &F = *static_cast(LF.Id); + EXPECT_EQ(LF.Offset, F.ExpectedOffset); + } + + Verified = true; + } +}; + +} + +TEST(OptimalLayoutTest, Basic) { + LayoutTest() + .flexible(12, 4, 8) + .flexible(8, 8, 0) + .flexible(4, 4, 20) + .verify(24, 8); +} + +TEST(OptimalLayoutTest, OddSize) { + LayoutTest() + .flexible(8, 8, 16) + .flexible(4, 4, 12) + .flexible(1, 1, 10) + .flexible(10, 8, 0) + .verify(24, 8); +} + +TEST(OptimalLayoutTest, Gaps) { + LayoutTest() + .fixed(4, 4, 8) + .fixed(4, 4, 16) + .flexible(4, 4, 0) + .flexible(4, 4, 4) + .flexible(4, 4, 12) + .flexible(4, 4, 20) + .verify(24, 4); +} + +TEST(OptimalLayoutTest, Greed) { + // The greedy algorithm doesn't find the optimal layout here, which + // would be to put the 5-byte field at the end. + LayoutTest() + .fixed(4, 4, 8) + .flexible(5, 4, 0) + .flexible(4, 4, 12) + .flexible(4, 4, 16) + .flexible(4, 4, 20) + .verify(24, 4); +} + +TEST(OptimalLayoutTest, Jagged) { + LayoutTest() + .flexible(1, 2, 18) + .flexible(13, 8, 0) + .flexible(3, 2, 14) + .verify(19, 8); +} + +TEST(OptimalLayoutTest, GardenPath) { + // The 4-byte-aligned field is our highest priority, but the less-aligned + // fields keep leaving the end offset mis-aligned. + LayoutTest() + .fixed(7, 4, 0) + .flexible(4, 4, 44) + .flexible(6, 1, 7) + .flexible(5, 1, 13) + .flexible(7, 2, 18) + .flexible(4, 1, 25) + .flexible(4, 1, 29) + .flexible(1, 1, 33) + .flexible(4, 2, 34) + .flexible(4, 2, 38) + .flexible(2, 2, 42) + .flexible(2, 2, 48) + .verify(50, 4); +} \ No newline at end of file From e7a91f21aa58fa416a1fdd0b6731a226000a3057 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Thu, 26 Mar 2020 08:45:08 -0700 Subject: [PATCH 101/286] [lldb/Test] XFAIL TestDataFormatterObjCNSError except for gmodules. --- .../data-formatter-objc/TestDataFormatterObjCNSError.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSError.py b/lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSError.py index df380aefd88f4..b5e1f149354fd 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSError.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSError.py @@ -15,6 +15,7 @@ class ObjCDataFormatterNSError(ObjCDataFormatterTestCase): @skipUnlessDarwin + @expectedFailureAll(debug_info=["dwarf", "dsym", "dwo"], bugnumber="rdar://25587546") def test_nserror_with_run_command(self): """Test formatters for NSError.""" self.appkit_tester_impl(self.nserror_data_formatter_commands) From 5830dc52cd5e1944c7db4595f20a25fa41ff64b7 Mon Sep 17 00:00:00 2001 From: John McCall Date: Wed, 25 Mar 2020 16:58:09 -0400 Subject: [PATCH 102/286] Use optimal layout and preserve alloca alignment in coroutine frames. Previously, we would ignore alloca alignment when building the frame and just use the natural alignment of the allocated type. If an alloca is over-aligned for its IR type, this could lead to a frame entry with inadequate alignment for the downstream uses of the alloca. Since highly-aligned fields also tend to produce poor layouts under a naive layout algorithm, I've also switched coroutine frames to use the new optimal struct layout algorithm. In order to communicate the frame size and alignment to later passes, I needed to set align+dereferenceable attributes on the frame-pointer parameter of the resume function. This is clearly the right thing to do, but the align attribute currently seems to result in assumptions being added during inlining that the optimizer cannot easily remove. --- llvm/lib/IR/Verifier.cpp | 4 +- llvm/lib/Transforms/Coroutines/CoroEarly.cpp | 4 +- llvm/lib/Transforms/Coroutines/CoroElide.cpp | 36 ++- llvm/lib/Transforms/Coroutines/CoroFrame.cpp | 289 +++++++++++++----- llvm/lib/Transforms/Coroutines/CoroInstr.h | 13 +- llvm/lib/Transforms/Coroutines/CoroInternal.h | 42 +-- llvm/lib/Transforms/Coroutines/CoroSplit.cpp | 29 +- llvm/test/Transforms/Coroutines/ArgAddr.ll | 2 +- .../Coroutines/coro-alloc-with-param.ll | 8 +- .../Transforms/Coroutines/coro-catchswitch.ll | 2 +- llvm/test/Transforms/Coroutines/coro-debug.ll | 6 +- .../Coroutines/coro-eh-aware-edge-split.ll | 8 +- .../Coroutines/coro-frame-arrayalloca.ll | 14 +- llvm/test/Transforms/Coroutines/coro-frame.ll | 8 +- .../Transforms/Coroutines/coro-heap-elide.ll | 2 +- .../Transforms/Coroutines/coro-materialize.ll | 2 +- .../Transforms/Coroutines/coro-padding.ll | 12 +- .../Transforms/Coroutines/coro-param-copy.ll | 6 +- .../Coroutines/coro-retcon-alloca.ll | 31 +- .../Coroutines/coro-retcon-once-value.ll | 4 +- .../Coroutines/coro-retcon-once-value2.ll | 2 +- .../Coroutines/coro-retcon-resume-values.ll | 2 +- .../Coroutines/coro-retcon-resume-values2.ll | 6 +- .../Coroutines/coro-retcon-value.ll | 2 +- .../test/Transforms/Coroutines/coro-retcon.ll | 2 +- .../Coroutines/coro-spill-after-phi.ll | 6 +- .../Coroutines/coro-spill-corobegin.ll | 6 +- .../Transforms/Coroutines/coro-swifterror.ll | 4 +- llvm/test/Transforms/Coroutines/ex0.ll | 2 +- llvm/test/Transforms/Coroutines/ex1.ll | 2 +- llvm/test/Transforms/Coroutines/ex3.ll | 2 +- llvm/test/Transforms/Coroutines/ex5.ll | 2 +- 32 files changed, 371 insertions(+), 189 deletions(-) diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 547ad0f115b2e..c2fa55b9880c7 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -3073,7 +3073,9 @@ static AttrBuilder getParameterABIAttributes(int I, AttributeList Attrs) { if (Attrs.hasParamAttribute(I, AK)) Copy.addAttribute(AK); } - if (Attrs.hasParamAttribute(I, Attribute::Alignment)) + // `align` is ABI-affecting only in combination with `byval`. + if (Attrs.hasParamAttribute(I, Attribute::Alignment) && + Attrs.hasParamAttribute(I, Attribute::ByVal)) Copy.addAlignmentAttr(Attrs.getParamAlignment(I)); return Copy; } diff --git a/llvm/lib/Transforms/Coroutines/CoroEarly.cpp b/llvm/lib/Transforms/Coroutines/CoroEarly.cpp index e73fb9eeb1e9d..02f7a420e8cd0 100644 --- a/llvm/lib/Transforms/Coroutines/CoroEarly.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroEarly.cpp @@ -64,14 +64,14 @@ void Lowerer::lowerResumeOrDestroy(CallSite CS, // TODO: Handle the case when coroutine promise alloca has align override. void Lowerer::lowerCoroPromise(CoroPromiseInst *Intrin) { Value *Operand = Intrin->getArgOperand(0); - unsigned Alignement = Intrin->getAlignment(); + Align Alignment = Intrin->getAlignment(); Type *Int8Ty = Builder.getInt8Ty(); auto *SampleStruct = StructType::get(Context, {AnyResumeFnPtrTy, AnyResumeFnPtrTy, Int8Ty}); const DataLayout &DL = TheModule.getDataLayout(); int64_t Offset = alignTo( - DL.getStructLayout(SampleStruct)->getElementOffset(2), Alignement); + DL.getStructLayout(SampleStruct)->getElementOffset(2), Alignment); if (Intrin->isFromPromise()) Offset = -Offset; diff --git a/llvm/lib/Transforms/Coroutines/CoroElide.cpp b/llvm/lib/Transforms/Coroutines/CoroElide.cpp index 23d22e23861a5..889fcff889842 100644 --- a/llvm/lib/Transforms/Coroutines/CoroElide.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroElide.cpp @@ -35,7 +35,8 @@ struct Lowerer : coro::LowererBase { Lowerer(Module &M) : LowererBase(M) {} - void elideHeapAllocations(Function *F, Type *FrameTy, AAResults &AA); + void elideHeapAllocations(Function *F, uint64_t FrameSize, + MaybeAlign FrameAlign, AAResults &AA); bool shouldElide(Function *F, DominatorTree &DT) const; bool processCoroId(CoroIdInst *, AAResults &AA, DominatorTree &DT); }; @@ -90,10 +91,23 @@ static void removeTailCallAttribute(AllocaInst *Frame, AAResults &AA) { } } -// Given a resume function @f.resume(%f.frame* %frame), returns %f.frame type. -static Type *getFrameType(Function *Resume) { - auto *ArgType = Resume->arg_begin()->getType(); - return cast(ArgType)->getElementType(); +// Given a resume function @f.resume(%f.frame* %frame), returns the size +// and expected alignment of %f.frame type. +static std::pair getFrameLayout(Function *Resume) { + // Prefer to pull information from the function attributes. + auto Size = Resume->getParamDereferenceableBytes(0); + auto Align = Resume->getParamAlign(0); + + // If those aren't given, extract them from the type. + if (Size == 0 || !Align) { + auto *FrameTy = Resume->arg_begin()->getType()->getPointerElementType(); + + const DataLayout &DL = Resume->getParent()->getDataLayout(); + if (!Size) Size = DL.getTypeAllocSize(FrameTy); + if (!Align) Align = llvm::Align(DL.getABITypeAlignment(FrameTy)); + } + + return std::make_pair(Size, Align); } // Finds first non alloca instruction in the entry block of a function. @@ -106,8 +120,9 @@ static Instruction *getFirstNonAllocaInTheEntryBlock(Function *F) { // To elide heap allocations we need to suppress code blocks guarded by // llvm.coro.alloc and llvm.coro.free instructions. -void Lowerer::elideHeapAllocations(Function *F, Type *FrameTy, AAResults &AA) { - LLVMContext &C = FrameTy->getContext(); +void Lowerer::elideHeapAllocations(Function *F, uint64_t FrameSize, + MaybeAlign FrameAlign, AAResults &AA) { + LLVMContext &C = F->getContext(); auto *InsertPt = getFirstNonAllocaInTheEntryBlock(CoroIds.front()->getFunction()); @@ -128,7 +143,9 @@ void Lowerer::elideHeapAllocations(Function *F, Type *FrameTy, AAResults &AA) { // here. Possibly we will need to do a mini SROA here and break the coroutine // frame into individual AllocaInst recreating the original alignment. const DataLayout &DL = F->getParent()->getDataLayout(); + auto FrameTy = ArrayType::get(Type::getInt8Ty(C), FrameSize); auto *Frame = new AllocaInst(FrameTy, DL.getAllocaAddrSpace(), "", InsertPt); + Frame->setAlignment(FrameAlign); auto *FrameVoidPtr = new BitCastInst(Frame, Type::getInt8PtrTy(C), "vFrame", InsertPt); @@ -244,8 +261,9 @@ bool Lowerer::processCoroId(CoroIdInst *CoroId, AAResults &AA, replaceWithConstant(DestroyAddrConstant, DestroyAddr); if (ShouldElide) { - auto *FrameTy = getFrameType(cast(ResumeAddrConstant)); - elideHeapAllocations(CoroId->getFunction(), FrameTy, AA); + auto FrameSizeAndAlign = getFrameLayout(cast(ResumeAddrConstant)); + elideHeapAllocations(CoroId->getFunction(), FrameSizeAndAlign.first, + FrameSizeAndAlign.second, AA); coro::replaceCoroFree(CoroId, /*Elide=*/true); } diff --git a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp index 2c42cf8a6d259..e6cbfa3198e73 100644 --- a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp @@ -28,6 +28,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/circular_raw_ostream.h" +#include "llvm/Support/OptimalLayout.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/PromoteMemToReg.h" @@ -338,52 +339,182 @@ namespace { // coroutine frame and if the alignment specified on the Alloca instruction // differs from the natural alignment of the alloca type we will need to insert // padding. -struct PaddingCalculator { +class FrameTypeBuilder { + struct Field { + uint64_t Size; + uint64_t Offset; + Spill *ForSpill; + Type *Ty; + unsigned FieldIndex; + Align Alignment; + Align TyAlignment; + }; + const DataLayout &DL; LLVMContext &Context; - unsigned StructSize = 0; + uint64_t StructSize = 0; + Align StructAlign; + bool IsFinished = false; - PaddingCalculator(LLVMContext &Context, DataLayout const &DL) - : DL(DL), Context(Context) {} + SmallVector Fields; + DenseMap FieldIndexByKey; - // Replicate the logic from IR/DataLayout.cpp to match field offset - // computation for LLVM structs. - void addType(Type *Ty) { - unsigned TyAlign = DL.getABITypeAlignment(Ty); - if ((StructSize & (TyAlign - 1)) != 0) - StructSize = alignTo(StructSize, TyAlign); +public: + FrameTypeBuilder(LLVMContext &Context, DataLayout const &DL) + : DL(DL), Context(Context) {} - StructSize += DL.getTypeAllocSize(Ty); // Consume space for this data item. - } + class FieldId { + size_t Value; + explicit FieldId(size_t Value) : Value(Value) {} - void addTypes(SmallVectorImpl const &Types) { - for (auto *Ty : Types) - addType(Ty); + friend class FrameTypeBuilder; + }; + + /// Add a field to this structure for the storage of an `alloca` + /// instruction. + FieldId addFieldForAlloca(AllocaInst *AI, Spill *ForSpill = nullptr, + bool IsHeader = false) { + Type *Ty = AI->getAllocatedType(); + + // Make an array type if this is a static array allocation. + if (AI->isArrayAllocation()) { + if (auto *CI = dyn_cast(AI->getArraySize())) + Ty = ArrayType::get(Ty, CI->getValue().getZExtValue()); + else + report_fatal_error("Coroutines cannot handle non static allocas yet"); + } + + return addField(Ty, MaybeAlign(AI->getAlignment()), ForSpill, IsHeader); } - unsigned computePadding(Type *Ty, unsigned ForcedAlignment) { - unsigned TyAlign = DL.getABITypeAlignment(Ty); - auto Natural = alignTo(StructSize, TyAlign); - auto Forced = alignTo(StructSize, ForcedAlignment); + /// Add a field to this structure. + FieldId addField(Type *Ty, MaybeAlign FieldAlignment, + Spill *ForSpill = nullptr, + bool IsHeader = false) { + assert(!IsFinished && "adding fields to a finished builder"); + assert(Ty && "must provide a type for a field"); - // Return how many bytes of padding we need to insert. - if (Natural != Forced) - return std::max(Natural, Forced) - StructSize; + // The field size is always the alloc size of the type. + uint64_t FieldSize = DL.getTypeAllocSize(Ty); - // Rely on natural alignment. - return 0; + // The field alignment might not be the type alignment, but we need + // to remember the type alignment anyway to build the type. + Align TyAlignment = Align(DL.getABITypeAlignment(Ty)); + if (!FieldAlignment) FieldAlignment = TyAlignment; + + // Lay out header fields immediately. + uint64_t Offset; + if (IsHeader) { + Offset = alignTo(StructSize, FieldAlignment); + StructSize = Offset + FieldSize; + + // Everything else has a flexible offset. + } else { + Offset = OptimalLayoutField::FlexibleOffset; + } + + Fields.push_back({FieldSize, Offset, ForSpill, Ty, 0, + *FieldAlignment, TyAlignment}); + return FieldId(Fields.size() - 1); } - // If padding required, return the padding field type to insert. - ArrayType *getPaddingType(Type *Ty, unsigned ForcedAlignment) { - if (auto Padding = computePadding(Ty, ForcedAlignment)) - return ArrayType::get(Type::getInt8Ty(Context), Padding); + /// Finish the layout and set the body on the given type. + void finish(StructType *Ty); + + uint64_t getStructSize() const { + assert(IsFinished && "not yet finished!"); + return StructSize; + } - return nullptr; + Align getStructAlign() const { + assert(IsFinished && "not yet finished!"); + return StructAlign; + } + + unsigned getFieldIndex(FieldId Id) const { + assert(IsFinished && "not yet finished!"); + return Fields[Id.Value].FieldIndex; } }; } // namespace +void FrameTypeBuilder::finish(StructType *Ty) { + assert(!IsFinished && "already finished!"); + + // Prepare the optimal-layout field array. + // The Id in the layout field is a pointer to our Field for it. + SmallVector LayoutFields; + LayoutFields.reserve(Fields.size()); + for (auto &Field : Fields) { + LayoutFields.emplace_back(&Field, Field.Size, Field.Alignment, + Field.Offset); + } + + // Perform layout. + auto SizeAndAlign = performOptimalLayout(LayoutFields); + StructSize = SizeAndAlign.first; + StructAlign = SizeAndAlign.second; + + auto getField = [](const OptimalLayoutField &LayoutField) -> Field & { + return *static_cast(const_cast(LayoutField.Id)); + }; + + // We need to produce a packed struct type if there's a field whose + // assigned offset isn't a multiple of its natural type alignment. + bool Packed = [&] { + for (auto &LayoutField : LayoutFields) { + auto &F = getField(LayoutField); + if (!isAligned(F.TyAlignment, LayoutField.Offset)) + return true; + } + return false; + }(); + + // Build the struct body. + SmallVector FieldTypes; + FieldTypes.reserve(LayoutFields.size() * 3 / 2); + uint64_t LastOffset = 0; + for (auto &LayoutField : LayoutFields) { + auto &F = getField(LayoutField); + + auto Offset = LayoutField.Offset; + + // Add a padding field if there's a padding gap and we're either + // building a packed struct or the padding gap is more than we'd + // get from aligning to the field type's natural alignment. + assert(Offset >= LastOffset); + if (Offset != LastOffset) { + if (Packed || alignTo(LastOffset, F.TyAlignment) != Offset) + FieldTypes.push_back(ArrayType::get(Type::getInt8Ty(Context), + Offset - LastOffset)); + } + + // Record the layout information into both the Field and the + // original Spill, if there is one. + F.Offset = Offset; + F.FieldIndex = FieldTypes.size(); + if (F.ForSpill) { + F.ForSpill->setFieldIndex(F.FieldIndex); + } + + FieldTypes.push_back(F.Ty); + LastOffset = Offset + F.Size; + } + + Ty->setBody(FieldTypes, Packed); + +#ifndef NDEBUG + // Check that the IR layout matches the offsets we expect. + auto Layout = DL.getStructLayout(Ty); + for (auto &F : Fields) { + assert(Ty->getElementType(F.FieldIndex) == F.Ty); + assert(Layout->getElementOffset(F.FieldIndex) == F.Offset); + } +#endif + + IsFinished = true; +} + // Build a struct that will keep state for an active coroutine. // struct f.frame { // ResumeFnTy ResumeFnAddr; @@ -396,13 +527,17 @@ static StructType *buildFrameType(Function &F, coro::Shape &Shape, SpillInfo &Spills) { LLVMContext &C = F.getContext(); const DataLayout &DL = F.getParent()->getDataLayout(); - PaddingCalculator Padder(C, DL); - SmallString<32> Name(F.getName()); - Name.append(".Frame"); - StructType *FrameTy = StructType::create(C, Name); - SmallVector Types; + StructType *FrameTy = [&] { + SmallString<32> Name(F.getName()); + Name.append(".Frame"); + return StructType::create(C, Name); + }(); + + FrameTypeBuilder B(C, DL); AllocaInst *PromiseAlloca = Shape.getPromiseAlloca(); + Optional PromiseFieldId; + Optional SwitchIndexFieldId; if (Shape.ABI == coro::ABI::Switch) { auto *FramePtrTy = FrameTy->getPointerTo(); @@ -410,74 +545,74 @@ static StructType *buildFrameType(Function &F, coro::Shape &Shape, /*IsVarArg=*/false); auto *FnPtrTy = FnTy->getPointerTo(); - // Figure out how wide should be an integer type storing the suspend index. + // Add header fields for the resume and destroy functions. + // We can rely on these being perfectly packed. + B.addField(FnPtrTy, None, nullptr, /*header*/ true); + B.addField(FnPtrTy, None, nullptr, /*header*/ true); + + // Add a header field for the promise if there is one. + if (PromiseAlloca) { + PromiseFieldId = + B.addFieldForAlloca(PromiseAlloca, nullptr, /*header*/ true); + } + + // Add a field to store the suspend index. This doesn't need to + // be in the header. unsigned IndexBits = std::max(1U, Log2_64_Ceil(Shape.CoroSuspends.size())); - Type *PromiseType = PromiseAlloca - ? PromiseAlloca->getType()->getElementType() - : Type::getInt1Ty(C); Type *IndexType = Type::getIntNTy(C, IndexBits); - Types.push_back(FnPtrTy); - Types.push_back(FnPtrTy); - Types.push_back(PromiseType); - Types.push_back(IndexType); + + SwitchIndexFieldId = B.addField(IndexType, None); } else { assert(PromiseAlloca == nullptr && "lowering doesn't support promises"); } Value *CurrentDef = nullptr; - Padder.addTypes(Types); - // Create an entry for every spilled value. for (auto &S : Spills) { + // We can have multiple entries in Spills for a single value, but + // they should form a contiguous run. Ignore all but the first. if (CurrentDef == S.def()) continue; CurrentDef = S.def(); - // PromiseAlloca was already added to Types array earlier. - if (CurrentDef == PromiseAlloca) - continue; - uint64_t Count = 1; - Type *Ty = nullptr; + assert(CurrentDef != PromiseAlloca && + "recorded spill use of promise alloca?"); + if (auto *AI = dyn_cast(CurrentDef)) { - Ty = AI->getAllocatedType(); - if (unsigned AllocaAlignment = AI->getAlignment()) { - // If alignment is specified in alloca, see if we need to insert extra - // padding. - if (auto PaddingTy = Padder.getPaddingType(Ty, AllocaAlignment)) { - Types.push_back(PaddingTy); - Padder.addType(PaddingTy); - } - } - if (auto *CI = dyn_cast(AI->getArraySize())) - Count = CI->getValue().getZExtValue(); - else - report_fatal_error("Coroutines cannot handle non static allocas yet"); + B.addFieldForAlloca(AI, &S); } else { - Ty = CurrentDef->getType(); + Type *Ty = CurrentDef->getType(); + B.addField(Ty, None, &S); } - S.setFieldIndex(Types.size()); - if (Count == 1) - Types.push_back(Ty); - else - Types.push_back(ArrayType::get(Ty, Count)); - Padder.addType(Ty); } - FrameTy->setBody(Types); + + B.finish(FrameTy); + Shape.FrameAlign = B.getStructAlign(); + Shape.FrameSize = B.getStructSize(); switch (Shape.ABI) { + // In the switch ABI, remember the field indices for the promise and + // switch-index fields. case coro::ABI::Switch: + Shape.SwitchLowering.IndexField = + B.getFieldIndex(*SwitchIndexFieldId); + Shape.SwitchLowering.PromiseField = + (PromiseAlloca ? B.getFieldIndex(*PromiseFieldId) : 0); + + // Also round the frame size up to a multiple of its alignment, as is + // generally expected in C/C++. + Shape.FrameSize = alignTo(Shape.FrameSize, Shape.FrameAlign); break; - // Remember whether the frame is inline in the storage. + // In the retcon ABI, remember whether the frame is inline in the storage. case coro::ABI::Retcon: case coro::ABI::RetconOnce: { - auto &Layout = F.getParent()->getDataLayout(); auto Id = Shape.getRetconCoroId(); Shape.RetconLowering.IsFrameInlineInStorage - = (Layout.getTypeAllocSize(FrameTy) <= Id->getStorageSize() && - Layout.getABITypeAlignment(FrameTy) <= Id->getStorageAlignment()); + = (B.getStructSize() <= Id->getStorageSize() && + B.getStructAlign() <= Id->getStorageAlignment()); break; } } @@ -606,10 +741,12 @@ static Instruction *insertSpills(const SpillInfo &Spills, coro::Shape &Shape) { // we remember allocas and their indices to be handled once we processed // all the spills. SmallVector, 4> Allocas; - // Promise alloca (if present) has a fixed field number. + + // Promise alloca (if present) doesn't show in the spills and has a + // special field number. if (auto *PromiseAlloca = Shape.getPromiseAlloca()) { assert(Shape.ABI == coro::ABI::Switch); - Allocas.emplace_back(PromiseAlloca, coro::Shape::SwitchFieldIndex::Promise); + Allocas.emplace_back(PromiseAlloca, Shape.getPromiseField()); } // Create a GEP with the given index into the coroutine frame for the original diff --git a/llvm/lib/Transforms/Coroutines/CoroInstr.h b/llvm/lib/Transforms/Coroutines/CoroInstr.h index de2d2920cb15a..384e20cd0a9b2 100644 --- a/llvm/lib/Transforms/Coroutines/CoroInstr.h +++ b/llvm/lib/Transforms/Coroutines/CoroInstr.h @@ -211,8 +211,8 @@ class LLVM_LIBRARY_VISIBILITY AnyCoroIdRetconInst : public AnyCoroIdInst { return cast(getArgOperand(SizeArg))->getZExtValue(); } - uint64_t getStorageAlignment() const { - return cast(getArgOperand(AlignArg))->getZExtValue(); + Align getStorageAlignment() const { + return Align(cast(getArgOperand(AlignArg))->getZExtValue()); } Value *getStorage() const { @@ -338,11 +338,16 @@ class LLVM_LIBRARY_VISIBILITY CoroPromiseInst : public IntrinsicInst { enum { FrameArg, AlignArg, FromArg }; public: + /// Are we translating from the frame to the promise (false) or from + /// the promise to the frame (true)? bool isFromPromise() const { return cast(getArgOperand(FromArg))->isOneValue(); } - unsigned getAlignment() const { - return cast(getArgOperand(AlignArg))->getZExtValue(); + + /// The required alignment of the promise. This must match the + /// alignment of the promise alloca in the coroutine. + Align getAlignment() const { + return Align(cast(getArgOperand(AlignArg))->getZExtValue()); } // Methods to support type inquiry through isa, cast, and dyn_cast: diff --git a/llvm/lib/Transforms/Coroutines/CoroInternal.h b/llvm/lib/Transforms/Coroutines/CoroInternal.h index 7eb35400c0d51..bd76e93c91241 100644 --- a/llvm/lib/Transforms/Coroutines/CoroInternal.h +++ b/llvm/lib/Transforms/Coroutines/CoroInternal.h @@ -96,17 +96,22 @@ struct LLVM_LIBRARY_VISIBILITY Shape { struct SwitchFieldIndex { enum { Resume, - Destroy, - Promise, - Index, - /// The index of the first spill field. - FirstSpill + Destroy + + // The promise field is always at a fixed offset from the start of + // frame given its type, but the index isn't a constant for all + // possible frames. + + // The switch-index field isn't at a fixed offset or index, either; + // we just work it in where it fits best. }; }; coro::ABI ABI; StructType *FrameTy; + Align FrameAlign; + uint64_t FrameSize; Instruction *FramePtr; BasicBlock *AllocaSpillBlock; @@ -114,6 +119,8 @@ struct LLVM_LIBRARY_VISIBILITY Shape { SwitchInst *ResumeSwitch; AllocaInst *PromiseAlloca; BasicBlock *ResumeEntryBlock; + unsigned IndexField; + unsigned PromiseField; bool HasFinalSuspend; }; @@ -141,10 +148,15 @@ struct LLVM_LIBRARY_VISIBILITY Shape { return cast(CoroBegin->getId()); } + unsigned getSwitchIndexField() const { + assert(ABI == coro::ABI::Switch); + assert(FrameTy && "frame type not assigned"); + return SwitchLowering.IndexField; + } IntegerType *getIndexType() const { assert(ABI == coro::ABI::Switch); assert(FrameTy && "frame type not assigned"); - return cast(FrameTy->getElementType(SwitchFieldIndex::Index)); + return cast(FrameTy->getElementType(getSwitchIndexField())); } ConstantInt *getIndex(uint64_t Value) const { return ConstantInt::get(getIndexType(), Value); @@ -203,23 +215,17 @@ struct LLVM_LIBRARY_VISIBILITY Shape { llvm_unreachable("Unknown coro::ABI enum"); } - unsigned getFirstSpillFieldIndex() const { - switch (ABI) { - case coro::ABI::Switch: - return SwitchFieldIndex::FirstSpill; - - case coro::ABI::Retcon: - case coro::ABI::RetconOnce: - return 0; - } - llvm_unreachable("Unknown coro::ABI enum"); - } - AllocaInst *getPromiseAlloca() const { if (ABI == coro::ABI::Switch) return SwitchLowering.PromiseAlloca; return nullptr; } + unsigned getPromiseField() const { + assert(ABI == coro::ABI::Switch); + assert(FrameTy && "frame type not assigned"); + assert(SwitchLowering.PromiseAlloca && "no promise alloca"); + return SwitchLowering.PromiseField; + } /// Allocate memory according to the rules of the active lowering. /// diff --git a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp index 66cb3e74e53e6..c83a7f2e0ed52 100644 --- a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp @@ -283,7 +283,7 @@ static void createResumeEntryBlock(Function &F, coro::Shape &Shape) { auto *FramePtr = Shape.FramePtr; auto *FrameTy = Shape.FrameTy; auto *GepIndex = Builder.CreateStructGEP( - FrameTy, FramePtr, coro::Shape::SwitchFieldIndex::Index, "index.addr"); + FrameTy, FramePtr, Shape.getSwitchIndexField(), "index.addr"); auto *Index = Builder.CreateLoad(Shape.getIndexType(), GepIndex, "index"); auto *Switch = Builder.CreateSwitch(Index, UnreachBB, Shape.CoroSuspends.size()); @@ -309,7 +309,7 @@ static void createResumeEntryBlock(Function &F, coro::Shape &Shape) { Builder.CreateStore(NullPtr, GepIndex); } else { auto *GepIndex = Builder.CreateStructGEP( - FrameTy, FramePtr, coro::Shape::SwitchFieldIndex::Index, "index.addr"); + FrameTy, FramePtr, Shape.getSwitchIndexField(), "index.addr"); Builder.CreateStore(IndexVal, GepIndex); } Save->replaceAllUsesWith(ConstantTokenNone::get(C)); @@ -636,6 +636,17 @@ Value *CoroCloner::deriveNewFramePointer() { llvm_unreachable("bad ABI"); } +static void addFramePointerAttrs(AttributeList &Attrs, LLVMContext &Context, + unsigned ParamIndex, + uint64_t Size, Align Alignment) { + AttrBuilder ParamAttrs; + ParamAttrs.addAttribute(Attribute::NonNull); + ParamAttrs.addAttribute(Attribute::NoAlias); + ParamAttrs.addAlignmentAttr(Alignment); + ParamAttrs.addDereferenceableAttr(Size); + Attrs = Attrs.addParamAttributes(Context, ParamIndex, ParamAttrs); +} + /// Clone the body of the original function into a resume function of /// some sort. void CoroCloner::create() { @@ -684,6 +695,9 @@ void CoroCloner::create() { // original function. This should include optimization settings and so on. NewAttrs = NewAttrs.addAttributes(Context, AttributeList::FunctionIndex, OrigAttrs.getFnAttributes()); + + addFramePointerAttrs(NewAttrs, Context, 0, + Shape.FrameSize, Shape.FrameAlign); break; case coro::ABI::Retcon: @@ -691,13 +705,13 @@ void CoroCloner::create() { // If we have a continuation prototype, just use its attributes, // full-stop. NewAttrs = Shape.RetconLowering.ResumePrototype->getAttributes(); + + addFramePointerAttrs(NewAttrs, Context, 0, + Shape.getRetconCoroId()->getStorageSize(), + Shape.getRetconCoroId()->getStorageAlignment()); break; } - // Make the frame parameter nonnull and noalias. - NewAttrs = NewAttrs.addParamAttribute(Context, 0, Attribute::NonNull); - NewAttrs = NewAttrs.addParamAttribute(Context, 0, Attribute::NoAlias); - switch (Shape.ABI) { // In these ABIs, the cloned functions always return 'void', and the // existing return sites are meaningless. Note that for unique @@ -993,8 +1007,8 @@ static void handleNoSuspendCoroutine(coro::Shape &Shape) { coro::replaceCoroFree(SwitchId, /*Elide=*/AllocInst != nullptr); if (AllocInst) { IRBuilder<> Builder(AllocInst); - // FIXME: Need to handle overaligned members. auto *Frame = Builder.CreateAlloca(Shape.FrameTy); + Frame->setAlignment(Shape.FrameAlign); auto *VFrame = Builder.CreateBitCast(Frame, Builder.getInt8PtrTy()); AllocInst->replaceAllUsesWith(Builder.getFalse()); AllocInst->eraseFromParent(); @@ -1225,6 +1239,7 @@ static void splitRetconCoroutine(Function &F, coro::Shape &Shape, // Allocate. We don't need to update the call graph node because we're // going to recompute it from scratch after splitting. + // FIXME: pass the required alignment RawFramePtr = Shape.emitAlloc(Builder, Builder.getInt64(Size), nullptr); RawFramePtr = Builder.CreateBitCast(RawFramePtr, Shape.CoroBegin->getType()); diff --git a/llvm/test/Transforms/Coroutines/ArgAddr.ll b/llvm/test/Transforms/Coroutines/ArgAddr.ll index 5d0fbd781be96..83523763d9d94 100644 --- a/llvm/test/Transforms/Coroutines/ArgAddr.ll +++ b/llvm/test/Transforms/Coroutines/ArgAddr.ll @@ -1,6 +1,6 @@ ; Need to move users of allocas that were moved into the coroutine frame after ; coro.begin. -; RUN: opt < %s -O2 -enable-coroutines -S | FileCheck %s +; RUN: opt < %s -preserve-alignment-assumptions-during-inlining=false -O2 -enable-coroutines -S | FileCheck %s define nonnull i8* @f(i32 %n) { entry: diff --git a/llvm/test/Transforms/Coroutines/coro-alloc-with-param.ll b/llvm/test/Transforms/Coroutines/coro-alloc-with-param.ll index ce0975f108d8a..803c138d0bf59 100644 --- a/llvm/test/Transforms/Coroutines/coro-alloc-with-param.ll +++ b/llvm/test/Transforms/Coroutines/coro-alloc-with-param.ll @@ -52,18 +52,18 @@ suspend: } ; See if %this was added to the frame -; CHECK: %f_direct.Frame = type { void (%f_direct.Frame*)*, void (%f_direct.Frame*)*, i1, i1, i64 } -; CHECK: %f_copy.Frame = type { void (%f_copy.Frame*)*, void (%f_copy.Frame*)*, i1, i1, i64 } +; CHECK: %f_direct.Frame = type { void (%f_direct.Frame*)*, void (%f_direct.Frame*)*, i64, i1 } +; CHECK: %f_copy.Frame = type { void (%f_copy.Frame*)*, void (%f_copy.Frame*)*, i64, i1 } ; See that %this is spilled into the frame ; CHECK-LABEL: define i8* @f_direct(i64 %this) -; CHECK: %this.spill.addr = getelementptr inbounds %f_direct.Frame, %f_direct.Frame* %FramePtr, i32 0, i32 4 +; CHECK: %this.spill.addr = getelementptr inbounds %f_direct.Frame, %f_direct.Frame* %FramePtr, i32 0, i32 2 ; CHECK: store i64 %this, i64* %this.spill.addr ; CHECK: ret i8* %hdl ; See that %this is spilled into the frame ; CHECK-LABEL: define i8* @f_copy(i64 %this_arg) -; CHECK: %this.spill.addr = getelementptr inbounds %f_copy.Frame, %f_copy.Frame* %FramePtr, i32 0, i32 4 +; CHECK: %this.spill.addr = getelementptr inbounds %f_copy.Frame, %f_copy.Frame* %FramePtr, i32 0, i32 2 ; CHECK: store i64 %this_arg, i64* %this.spill.addr ; CHECK: ret i8* %hdl diff --git a/llvm/test/Transforms/Coroutines/coro-catchswitch.ll b/llvm/test/Transforms/Coroutines/coro-catchswitch.ll index dd06f1280caed..24ceb421cfe9a 100644 --- a/llvm/test/Transforms/Coroutines/coro-catchswitch.ll +++ b/llvm/test/Transforms/Coroutines/coro-catchswitch.ll @@ -31,7 +31,7 @@ catch.dispatch: ; preds = %if.else, %if.then ; CHECK: catch.dispatch: ; CHECK: %val = phi i32 [ 2, %if.else ], [ 1, %if.then ] ; CHECK: %[[Pad:.+]] = cleanuppad within none [] -; CHECK: %val.spill.addr = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 4 +; CHECK: %val.spill.addr = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 2 ; CHECK: store i32 %val, i32* %val.spill.addr ; CHECK: cleanupret from %[[Pad]] unwind label %[[Switch:.+]] diff --git a/llvm/test/Transforms/Coroutines/coro-debug.ll b/llvm/test/Transforms/Coroutines/coro-debug.ll index 1d40ddd671738..6f5e3ff887d11 100644 --- a/llvm/test/Transforms/Coroutines/coro-debug.ll +++ b/llvm/test/Transforms/Coroutines/coro-debug.ll @@ -127,9 +127,9 @@ attributes #7 = { noduplicate } !24 = !DILocation(line: 62, column: 3, scope: !6) ; CHECK: define i8* @f(i32 %x) #0 !dbg ![[ORIG:[0-9]+]] -; CHECK: define internal fastcc void @f.resume(%f.Frame* noalias nonnull %FramePtr) #0 !dbg ![[RESUME:[0-9]+]] -; CHECK: define internal fastcc void @f.destroy(%f.Frame* noalias nonnull %FramePtr) #0 !dbg ![[DESTROY:[0-9]+]] -; CHECK: define internal fastcc void @f.cleanup(%f.Frame* noalias nonnull %FramePtr) #0 !dbg ![[CLEANUP:[0-9]+]] +; CHECK: define internal fastcc void @f.resume(%f.Frame* noalias nonnull align 8 dereferenceable(32) %FramePtr) #0 !dbg ![[RESUME:[0-9]+]] +; CHECK: define internal fastcc void @f.destroy(%f.Frame* noalias nonnull align 8 dereferenceable(32) %FramePtr) #0 !dbg ![[DESTROY:[0-9]+]] +; CHECK: define internal fastcc void @f.cleanup(%f.Frame* noalias nonnull align 8 dereferenceable(32) %FramePtr) #0 !dbg ![[CLEANUP:[0-9]+]] ; CHECK: ![[ORIG]] = distinct !DISubprogram(name: "f", linkageName: "flink" ; CHECK: !DILocalVariable(name: "x", arg: 1, scope: ![[ORIG]] diff --git a/llvm/test/Transforms/Coroutines/coro-eh-aware-edge-split.ll b/llvm/test/Transforms/Coroutines/coro-eh-aware-edge-split.ll index 5da0e3c199db5..763025c1ac058 100644 --- a/llvm/test/Transforms/Coroutines/coro-eh-aware-edge-split.ll +++ b/llvm/test/Transforms/Coroutines/coro-eh-aware-edge-split.ll @@ -99,13 +99,13 @@ invoke2: ; CHECK: pad.with.phi.from.invoke2: ; CHECK: %0 = cleanuppad within none [] -; CHECK: %y.reload.addr = getelementptr inbounds %g.Frame, %g.Frame* %FramePtr, i32 0, i32 6 +; CHECK: %y.reload.addr = getelementptr inbounds %g.Frame, %g.Frame* %FramePtr, i32 0, i32 3 ; CHECK: %y.reload = load i32, i32* %y.reload.addr ; CHECK: cleanupret from %0 unwind label %pad.with.phi ; CHECK: pad.with.phi.from.invoke1: ; CHECK: %1 = cleanuppad within none [] -; CHECK: %x.reload.addr = getelementptr inbounds %g.Frame, %g.Frame* %FramePtr, i32 0, i32 5 +; CHECK: %x.reload.addr = getelementptr inbounds %g.Frame, %g.Frame* %FramePtr, i32 0, i32 2 ; CHECK: %x.reload = load i32, i32* %x.reload.addr ; CHECK: cleanupret from %1 unwind label %pad.with.phi @@ -161,13 +161,13 @@ invoke2: ; CHECK: pad.with.phi.from.invoke2: ; CHECK: %0 = cleanuppad within none [] -; CHECK: %y.reload.addr = getelementptr inbounds %h.Frame, %h.Frame* %FramePtr, i32 0, i32 6 +; CHECK: %y.reload.addr = getelementptr inbounds %h.Frame, %h.Frame* %FramePtr, i32 0, i32 3 ; CHECK: %y.reload = load i32, i32* %y.reload.addr ; CHECK: cleanupret from %0 unwind label %pad.with.phi ; CHECK: pad.with.phi.from.invoke1: ; CHECK: %1 = cleanuppad within none [] -; CHECK: %x.reload.addr = getelementptr inbounds %h.Frame, %h.Frame* %FramePtr, i32 0, i32 5 +; CHECK: %x.reload.addr = getelementptr inbounds %h.Frame, %h.Frame* %FramePtr, i32 0, i32 2 ; CHECK: %x.reload = load i32, i32* %x.reload.addr ; CHECK: cleanupret from %1 unwind label %pad.with.phi diff --git a/llvm/test/Transforms/Coroutines/coro-frame-arrayalloca.ll b/llvm/test/Transforms/Coroutines/coro-frame-arrayalloca.ll index d01120e379cec..e682b4e6726a3 100644 --- a/llvm/test/Transforms/Coroutines/coro-frame-arrayalloca.ll +++ b/llvm/test/Transforms/Coroutines/coro-frame-arrayalloca.ll @@ -35,13 +35,13 @@ suspend: } ; See if the array alloca was stored as an array field. -; CHECK-LABEL: %f.Frame = type { void (%f.Frame*)*, void (%f.Frame*)*, i1, i1, double, [4 x i32], double } +; CHECK-LABEL: %f.Frame = type { void (%f.Frame*)*, void (%f.Frame*)*, double, double, [4 x i32], i1 } ; See if we used correct index to access prefix, data, suffix (@f) ; CHECK-LABEL: @f( -; CHECK: %prefix = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 4 -; CHECK-NEXT: %data = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 5 -; CHECK-NEXT: %suffix = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 6 +; CHECK: %prefix = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 2 +; CHECK-NEXT: %data = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 4 +; CHECK-NEXT: %suffix = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 3 ; CHECK-NEXT: call void @consume.double.ptr(double* %prefix) ; CHECK-NEXT: call void @consume.i32.ptr(i32* %data) ; CHECK-NEXT: call void @consume.double.ptr(double* %suffix) @@ -49,9 +49,9 @@ suspend: ; See if we used correct index to access prefix, data, suffix (@f.resume) ; CHECK-LABEL: @f.resume( -; CHECK: %[[SUFFIX:.+]] = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 6 -; CHECK: %[[DATA:.+]] = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 5 -; CHECK: %[[PREFIX:.+]] = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 4 +; CHECK: %[[SUFFIX:.+]] = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 3 +; CHECK: %[[DATA:.+]] = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 4 +; CHECK: %[[PREFIX:.+]] = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 2 ; CHECK: call void @consume.double.ptr(double* %[[PREFIX]]) ; CHECK-NEXT: call void @consume.i32.ptr(i32* %[[DATA]]) ; CHECK-NEXT: call void @consume.double.ptr(double* %[[SUFFIX]]) diff --git a/llvm/test/Transforms/Coroutines/coro-frame.ll b/llvm/test/Transforms/Coroutines/coro-frame.ll index 826d3a04fa1e1..9d1ee9ab30fe0 100644 --- a/llvm/test/Transforms/Coroutines/coro-frame.ll +++ b/llvm/test/Transforms/Coroutines/coro-frame.ll @@ -34,17 +34,17 @@ pad: } ; See if the float was added to the frame -; CHECK-LABEL: %f.Frame = type { void (%f.Frame*)*, void (%f.Frame*)*, i1, i1, i64, double } +; CHECK-LABEL: %f.Frame = type { void (%f.Frame*)*, void (%f.Frame*)*, double, i64, i1 } ; See if the float was spilled into the frame ; CHECK-LABEL: @f( ; CHECK: %r = call double @print( -; CHECK: %r.spill.addr = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 5 +; CHECK: %r.spill.addr = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 2 ; CHECK: store double %r, double* %r.spill.addr ; CHECK: ret i8* %hdl -; See of the float was loaded from the frame -; CHECK-LABEL: @f.resume( +; See if the float was loaded from the frame +; CHECK-LABEL: @f.resume(%f.Frame* noalias nonnull align 8 ; CHECK: %r.reload = load double, double* %r.reload.addr ; CHECK: call double @print(double %r.reload) ; CHECK: ret void diff --git a/llvm/test/Transforms/Coroutines/coro-heap-elide.ll b/llvm/test/Transforms/Coroutines/coro-heap-elide.ll index 5ce2b693bc5e5..5696a4f387d0e 100644 --- a/llvm/test/Transforms/Coroutines/coro-heap-elide.ll +++ b/llvm/test/Transforms/Coroutines/coro-heap-elide.ll @@ -54,7 +54,7 @@ if.end: ; CHECK-LABEL: @callResume( define void @callResume() { entry: -; CHECK: alloca %f.frame +; CHECK: alloca [4 x i8], align 4 ; CHECK-NOT: coro.begin ; CHECK-NOT: CustomAlloc ; CHECK: call void @may_throw() diff --git a/llvm/test/Transforms/Coroutines/coro-materialize.ll b/llvm/test/Transforms/Coroutines/coro-materialize.ll index 95e8a049ad2f6..c17c525272721 100644 --- a/llvm/test/Transforms/Coroutines/coro-materialize.ll +++ b/llvm/test/Transforms/Coroutines/coro-materialize.ll @@ -33,7 +33,7 @@ suspend: } ; See that we only spilled one value -; CHECK: %f.Frame = type { void (%f.Frame*)*, void (%f.Frame*)*, i1, i1, i32 } +; CHECK: %f.Frame = type { void (%f.Frame*)*, void (%f.Frame*)*, i32, i1 } ; CHECK-LABEL: @f( declare i8* @llvm.coro.free(token, i8*) diff --git a/llvm/test/Transforms/Coroutines/coro-padding.ll b/llvm/test/Transforms/Coroutines/coro-padding.ll index 87b5bf732d9df..b912a28afa923 100644 --- a/llvm/test/Transforms/Coroutines/coro-padding.ll +++ b/llvm/test/Transforms/Coroutines/coro-padding.ll @@ -8,7 +8,7 @@ declare void @consume(%PackedStruct*) define i8* @f() "coroutine.presplit"="1" { entry: - %data = alloca %PackedStruct, align 8 + %data = alloca %PackedStruct, align 32 %id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null) %size = call i32 @llvm.coro.size.i32() %alloc = call i8* @malloc(i32 %size) @@ -31,17 +31,17 @@ suspend: } ; See if the padding was inserted before PackedStruct -; CHECK-LABEL: %f.Frame = type { void (%f.Frame*)*, void (%f.Frame*)*, i1, i1, [6 x i8], %PackedStruct } +; CHECK-LABEL: %f.Frame = type { void (%f.Frame*)*, void (%f.Frame*)*, i1, [15 x i8], %PackedStruct } -; See if we used correct index to access packed struct (padding is field 4) +; See if we used correct index to access packed struct (padding is field 3) ; CHECK-LABEL: @f( -; CHECK: %[[DATA:.+]] = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 5 +; CHECK: %[[DATA:.+]] = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 4 ; CHECK-NEXT: call void @consume(%PackedStruct* %[[DATA]]) ; CHECK: ret i8* -; See if we used correct index to access packed struct (padding is field 4) +; See if we used correct index to access packed struct (padding is field 3) ; CHECK-LABEL: @f.resume( -; CHECK: %[[DATA:.+]] = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 5 +; CHECK: %[[DATA:.+]] = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 4 ; CHECK-NEXT: call void @consume(%PackedStruct* %[[DATA]]) ; CHECK: ret void diff --git a/llvm/test/Transforms/Coroutines/coro-param-copy.ll b/llvm/test/Transforms/Coroutines/coro-param-copy.ll index 6f4d0f3b22484..d075e8a964ce9 100644 --- a/llvm/test/Transforms/Coroutines/coro-param-copy.ll +++ b/llvm/test/Transforms/Coroutines/coro-param-copy.ll @@ -32,7 +32,7 @@ suspend: } ; See that we added both x and y to the frame. -; CHECK: %f.Frame = type { void (%f.Frame*)*, void (%f.Frame*)*, i1, i1, i64, i64 } +; CHECK: %f.Frame = type { void (%f.Frame*)*, void (%f.Frame*)*, i64, i64, i1 } ; See that all of the uses prior to coro-begin stays put. ; CHECK-LABEL: define i8* @f() { @@ -45,10 +45,10 @@ suspend: ; See that we only copy the x as y was not modified prior to coro.begin. ; CHECK: store void (%f.Frame*)* @f.destroy, void (%f.Frame*)** %destroy.addr -; CHECK-NEXT: %0 = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 4 +; CHECK-NEXT: %0 = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 2 ; CHECK-NEXT: %1 = load i64, i64* %x.addr ; CHECK-NEXT: store i64 %1, i64* %0 -; CHECK-NEXT: %index.addr1 = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 3 +; CHECK-NEXT: %index.addr1 = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 4 ; CHECK-NEXT: store i1 false, i1* %index.addr1 ; CHECK-NEXT: ret i8* %hdl diff --git a/llvm/test/Transforms/Coroutines/coro-retcon-alloca.ll b/llvm/test/Transforms/Coroutines/coro-retcon-alloca.ll index 17aec4eed1b23..61c21324d94a2 100644 --- a/llvm/test/Transforms/Coroutines/coro-retcon-alloca.ll +++ b/llvm/test/Transforms/Coroutines/coro-retcon-alloca.ll @@ -28,21 +28,20 @@ cleanup: ; CHECK-LABEL: define { i8*, i8*, i32 } @f(i8* %buffer, i32 %n) ; CHECK-NEXT: entry: -; CHECK-NEXT: [[T0:%.*]] = bitcast i8* %buffer to i32* -; CHECK-NEXT: store i32 %n, i32* [[T0]], align 4 -; CHECK-NEXT: [[ALLOC:%.*]] = tail call i8* @allocate(i32 %n) ; CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds i8, i8* %buffer, i64 8 -; CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to i8** +; CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to i32* +; CHECK-NEXT: store i32 %n, i32* [[T1]], align 4 +; CHECK-NEXT: [[ALLOC:%.*]] = tail call i8* @allocate(i32 %n) +; CHECK-NEXT: [[T1:%.*]] = bitcast i8* %buffer to i8** ; CHECK-NEXT: store i8* [[ALLOC]], i8** [[T1]], align 8 ; CHECK-NEXT: [[T0:%.*]] = insertvalue { i8*, i8*, i32 } { i8* bitcast ({ i8*, i8*, i32 } (i8*, i1)* @f.resume.0 to i8*), i8* undef, i32 undef }, i8* [[ALLOC]], 1 ; CHECK-NEXT: [[RET:%.*]] = insertvalue { i8*, i8*, i32 } [[T0]], i32 %n, 2 ; CHECK-NEXT: ret { i8*, i8*, i32 } [[RET]] ; CHECK-NEXT: } -; CHECK-LABEL: define internal { i8*, i8*, i32 } @f.resume.0(i8* noalias nonnull %0, i1 %1) +; CHECK-LABEL: define internal { i8*, i8*, i32 } @f.resume.0(i8* noalias nonnull align 8 dereferenceable(1024) %0, i1 %1) ; CHECK-NEXT: : -; CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds i8, i8* %0, i64 8 -; CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to i8** +; CHECK-NEXT: [[T1:%.*]] = bitcast i8* %0 to i8** ; CHECK-NEXT: [[ALLOC:%.*]] = load i8*, i8** [[T1]], align 8 ; CHECK-NEXT: tail call void @deallocate(i8* [[ALLOC]]) ; CHECK-NEXT: br i1 %1, @@ -83,14 +82,14 @@ cleanup: ; CHECK-NEXT: ret { i8*, i32 } [[RET]] ; CHECK-NEXT: } -; CHECK-LABEL: define internal { i8*, i32 } @g.resume.0(i8* noalias nonnull %0, i1 %1) +; CHECK-LABEL: define internal { i8*, i32 } @g.resume.0(i8* noalias nonnull align 8 dereferenceable(1024) %0, i1 %1) ; CHECK-NEXT: : ; CHECK-NEXT: br i1 %1, ; CHECK: : ; CHECK-NEXT: [[T0:%.*]] = bitcast i8* %0 to i32* -; CHECK-NEXT: [[T1:%.*]] = load i32, i32* [[T0]], align 4 +; CHECK-NEXT: [[T1:%.*]] = load i32, i32* [[T0]], align 8 ; CHECK-NEXT: %inc = add i32 [[T1]], 1 -; CHECK-NEXT: store i32 %inc, i32* [[T0]], align 4 +; CHECK-NEXT: store i32 %inc, i32* [[T0]], align 8 ; CHECK-NEXT: [[T0:%.*]] = zext i32 %inc to i64 ; CHECK-NEXT: [[ALLOC:%.*]] = alloca i8, i64 [[T0]], align 8 ; CHECK-NEXT: call void @use(i8* nonnull [[ALLOC]]) @@ -132,17 +131,17 @@ cleanup: ; CHECK-NEXT: ret { i8*, i32 } [[RET]] ; CHECK-NEXT: } -; CHECK-LABEL: define internal { i8*, i32 } @h.resume.0(i8* noalias nonnull %0, i1 %1) +; CHECK-LABEL: define internal { i8*, i32 } @h.resume.0(i8* noalias nonnull align 8 dereferenceable(1024) %0, i1 %1) ; CHECK-NEXT: : ; CHECK-NEXT: br i1 %1, ; CHECK: : ; CHECK-NEXT: [[NSLOT:%.*]] = bitcast i8* %0 to i32* -; CHECK-NEXT: [[T1:%.*]] = load i32, i32* [[NSLOT]], align 4 +; CHECK-NEXT: [[T1:%.*]] = load i32, i32* [[NSLOT]], align 8 ; CHECK-NEXT: %inc = add i32 [[T1]], 1 ; CHECK-NEXT: [[T0:%.*]] = zext i32 %inc to i64 ; CHECK-NEXT: [[ALLOC:%.*]] = alloca i8, i64 [[T0]], align 8 ; CHECK-NEXT: call void @use(i8* nonnull [[ALLOC]]) -; CHECK-NEXT: store i32 %inc, i32* [[NSLOT]], align 4 +; CHECK-NEXT: store i32 %inc, i32* [[NSLOT]], align 8 ; CHECK-NEXT: [[RET:%.*]] = insertvalue { i8*, i32 } { i8* bitcast ({ i8*, i32 } (i8*, i1)* @h.resume.0 to i8*), i32 undef }, i32 %inc, 1 ; CHECK-NEXT: ret { i8*, i32 } [[RET]] ; CHECK: : @@ -180,14 +179,14 @@ loop2: ; CHECK-NEXT: ret { i8*, i32 } [[RET]] ; CHECK-NEXT: } -; CHECK-LABEL: define internal { i8*, i32 } @i.resume.0(i8* noalias nonnull %0) +; CHECK-LABEL: define internal { i8*, i32 } @i.resume.0(i8* noalias nonnull align 8 dereferenceable(1024) %0) ; CHECK-NEXT: : ; CHECK-NEXT: [[NSLOT:%.*]] = bitcast i8* %0 to i32* -; CHECK-NEXT: [[T1:%.*]] = load i32, i32* [[NSLOT]], align 4 +; CHECK-NEXT: [[T1:%.*]] = load i32, i32* [[NSLOT]], align 8 ; CHECK-NEXT: %inc = add i32 [[T1]], 1 ; CHECK-NEXT: br label %loop2 ; CHECK: : -; CHECK-NEXT: store i32 %k, i32* [[NSLOT]], align 4 +; CHECK-NEXT: store i32 %k, i32* [[NSLOT]], align 8 ; CHECK-NEXT: [[RET:%.*]] = insertvalue { i8*, i32 } { i8* bitcast ({ i8*, i32 } (i8*)* @i.resume.0 to i8*), i32 undef }, i32 %k, 1 ; CHECK-NEXT: ret { i8*, i32 } [[RET]] ; CHECK: loop2: diff --git a/llvm/test/Transforms/Coroutines/coro-retcon-once-value.ll b/llvm/test/Transforms/Coroutines/coro-retcon-once-value.ll index ac49b22ee6bb9..6e80da87bc09f 100644 --- a/llvm/test/Transforms/Coroutines/coro-retcon-once-value.ll +++ b/llvm/test/Transforms/Coroutines/coro-retcon-once-value.ll @@ -45,7 +45,7 @@ cleanup: ; CHECK-NEXT: ret { i8*, i32 } [[T1]] ; CHECK-NEXT: } -; CHECK-LABEL: define internal void @f.resume.0(i8* noalias nonnull %0, i1 zeroext %1) +; CHECK-LABEL: define internal void @f.resume.0(i8* noalias nonnull align 8 dereferenceable(8) %0, i1 zeroext %1) ; CHECK-NEXT: : ; CHECK-NEXT: br i1 %1, ; CHECK: : @@ -57,7 +57,7 @@ cleanup: ; CHECK-NEXT: ret void ; CHECK-NEXT: } -; CHECK-LABEL: define internal void @f.resume.1(i8* noalias nonnull %0, i1 zeroext %1) +; CHECK-LABEL: define internal void @f.resume.1(i8* noalias nonnull align 8 dereferenceable(8) %0, i1 zeroext %1) ; CHECK-NEXT: : ; CHECK-NEXT: br i1 %1, ; CHECK: : diff --git a/llvm/test/Transforms/Coroutines/coro-retcon-once-value2.ll b/llvm/test/Transforms/Coroutines/coro-retcon-once-value2.ll index ad49f24dc547a..4f43da03550c8 100644 --- a/llvm/test/Transforms/Coroutines/coro-retcon-once-value2.ll +++ b/llvm/test/Transforms/Coroutines/coro-retcon-once-value2.ll @@ -37,7 +37,7 @@ cleanup: ; CHECK-NEXT: ret { i8*, i32* } [[T0]] ; CHECK-NEXT: } -; CHECK-LABEL: define internal void @f.resume.0(i8* noalias nonnull %0, i1 zeroext %1) +; CHECK-LABEL: define internal void @f.resume.0(i8* noalias nonnull align 8 dereferenceable(8) %0, i1 zeroext %1) ; CHECK-NEXT: : ; CHECK-NEXT: [[T0:%.*]] = bitcast i8* %0 to [[FRAME_T:%.*]]** ; CHECK-NEXT: [[FRAME:%.*]] = load [[FRAME_T]]*, [[FRAME_T]]** [[T0]] diff --git a/llvm/test/Transforms/Coroutines/coro-retcon-resume-values.ll b/llvm/test/Transforms/Coroutines/coro-retcon-resume-values.ll index ac99dd15b9882..80e8170d7ba1e 100644 --- a/llvm/test/Transforms/Coroutines/coro-retcon-resume-values.ll +++ b/llvm/test/Transforms/Coroutines/coro-retcon-resume-values.ll @@ -30,7 +30,7 @@ cleanup: ; CHECK-NEXT: ret i8* bitcast (i8* (i8*, i32, i1)* @f.resume.0 to i8*) ; CHECK-NEXT: } -; CHECK-LABEL: define internal i8* @f.resume.0(i8* noalias nonnull %0, i32 %1, i1 zeroext %2) +; CHECK-LABEL: define internal i8* @f.resume.0(i8* noalias nonnull align 4 dereferenceable(8) %0, i32 %1, i1 zeroext %2) ; CHECK-NEXT: : ; CHECK-NEXT: [[T0:%.*]] = bitcast i8* %0 to i32* ; CHECK-NEXT: [[T1:%.*]] = load i32, i32* [[T0]], align 4 diff --git a/llvm/test/Transforms/Coroutines/coro-retcon-resume-values2.ll b/llvm/test/Transforms/Coroutines/coro-retcon-resume-values2.ll index 43f98e958aab3..e2412b6b8a5a3 100644 --- a/llvm/test/Transforms/Coroutines/coro-retcon-resume-values2.ll +++ b/llvm/test/Transforms/Coroutines/coro-retcon-resume-values2.ll @@ -29,7 +29,7 @@ entry: ; CHECK-NEXT: ret i8* bitcast (i8* (i8*, i32)* @f.resume.0 to i8*) ; CHECK-NEXT: } -; CHECK-LABEL: define internal i8* @f.resume.0(i8* noalias nonnull %0, i32 %1) +; CHECK-LABEL: define internal i8* @f.resume.0(i8* noalias nonnull align 4 dereferenceable(8) %0, i32 %1) ; CHECK-NEXT: : ; CHECK-NEXT: [[T0:%.*]] = bitcast i8* %0 to [[FRAME_T:%.*]]** ; CHECK-NEXT: [[FRAME:%.*]] = load [[FRAME_T]]*, [[FRAME_T]]** [[T0]] @@ -45,7 +45,7 @@ entry: ; CHECK-NEXT: ret i8* [[CONT]] ; CHECK-NEXT: } -; CHECK-LABEL: define internal i8* @f.resume.1(i8* noalias nonnull %0, i32 %1) +; CHECK-LABEL: define internal i8* @f.resume.1(i8* noalias nonnull align 4 dereferenceable(8) %0, i32 %1) ; CHECK-NEXT: : ; CHECK-NEXT: [[T0:%.*]] = bitcast i8* %0 to [[FRAME_T:%.*]]** ; CHECK-NEXT: [[FRAME:%.*]] = load [[FRAME_T]]*, [[FRAME_T]]** [[T0]] @@ -64,7 +64,7 @@ entry: ; CHECK-NEXT: ret i8* [[CONT]] ; CHECK-NEXT: } -; CHECK-LABEL: define internal i8* @f.resume.2(i8* noalias nonnull %0, i32 %1) +; CHECK-LABEL: define internal i8* @f.resume.2(i8* noalias nonnull align 4 dereferenceable(8) %0, i32 %1) ; CHECK-NEXT: : ; CHECK-NEXT: [[T0:%.*]] = bitcast i8* %0 to [[FRAME_T:%.*]]** ; CHECK-NEXT: [[FRAME:%.*]] = load [[FRAME_T]]*, [[FRAME_T]]** [[T0]] diff --git a/llvm/test/Transforms/Coroutines/coro-retcon-value.ll b/llvm/test/Transforms/Coroutines/coro-retcon-value.ll index cfda73bbe754a..29ec7cda170f2 100644 --- a/llvm/test/Transforms/Coroutines/coro-retcon-value.ll +++ b/llvm/test/Transforms/Coroutines/coro-retcon-value.ll @@ -30,7 +30,7 @@ cleanup: ; CHECK-NEXT: ret { i8*, i32 } [[RET]] ; CHECK-NEXT: } -; CHECK-LABEL: define internal { i8*, i32 } @f.resume.0(i8* noalias nonnull %0, i8 zeroext %1) +; CHECK-LABEL: define internal { i8*, i32 } @f.resume.0(i8* noalias nonnull align 4 dereferenceable(8) %0, i8 zeroext %1) ; CHECK-NEXT: : ; CHECK-NEXT: [[T0:%.*]] = icmp eq i8 %1, 0 ; CHECK-NEXT: br i1 [[T0]], diff --git a/llvm/test/Transforms/Coroutines/coro-retcon.ll b/llvm/test/Transforms/Coroutines/coro-retcon.ll index 5cd4cb61d94cc..13283f05b2661 100644 --- a/llvm/test/Transforms/Coroutines/coro-retcon.ll +++ b/llvm/test/Transforms/Coroutines/coro-retcon.ll @@ -30,7 +30,7 @@ cleanup: ; CHECK-NEXT: ret i8* bitcast (i8* (i8*, i1)* @f.resume.0 to i8*) ; CHECK-NEXT: } -; CHECK-LABEL: define internal i8* @f.resume.0(i8* noalias nonnull %0, i1 zeroext %1) +; CHECK-LABEL: define internal i8* @f.resume.0(i8* noalias nonnull align 4 dereferenceable(8) %0, i1 zeroext %1) ; CHECK-NEXT: : ; CHECK-NEXT: br i1 %1, ; CHECK: : diff --git a/llvm/test/Transforms/Coroutines/coro-spill-after-phi.ll b/llvm/test/Transforms/Coroutines/coro-spill-after-phi.ll index 3c7e050c09e95..463705f3b3f3b 100644 --- a/llvm/test/Transforms/Coroutines/coro-spill-after-phi.ll +++ b/llvm/test/Transforms/Coroutines/coro-spill-after-phi.ll @@ -33,14 +33,14 @@ suspend: } ; Verifies that the both phis are stored correctly in the coroutine frame -; CHECK: %f.Frame = type { void (%f.Frame*)*, void (%f.Frame*)*, i1, i1, i32, i32 } +; CHECK: %f.Frame = type { void (%f.Frame*)*, void (%f.Frame*)*, i32, i32, i1 } ; CHECK-LABEL: @f( ; CHECK: store void (%f.Frame*)* @f.destroy, void (%f.Frame*)** %destroy.addr ; CHECK: %phi1 = select i1 %n, i32 0, i32 2 ; CHECK: %phi2 = select i1 %n, i32 1, i32 3 -; CHECK: %phi2.spill.addr = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 5 +; CHECK: %phi2.spill.addr = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 3 ; CHECK: store i32 %phi2, i32* %phi2.spill.addr -; CHECK: %phi1.spill.addr = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 4 +; CHECK: %phi1.spill.addr = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 2 ; CHECK: store i32 %phi1, i32* %phi1.spill.addr ; CHECK: ret i8* %hdl diff --git a/llvm/test/Transforms/Coroutines/coro-spill-corobegin.ll b/llvm/test/Transforms/Coroutines/coro-spill-corobegin.ll index e57e2f28ed3c2..299de76c5c427 100644 --- a/llvm/test/Transforms/Coroutines/coro-spill-corobegin.ll +++ b/llvm/test/Transforms/Coroutines/coro-spill-corobegin.ll @@ -37,18 +37,18 @@ suspend: } ; See if the i8* for coro.begin was added to f.Frame -; CHECK-LABEL: %f.Frame = type { void (%f.Frame*)*, void (%f.Frame*)*, i1, i1, i8* } +; CHECK-LABEL: %f.Frame = type { void (%f.Frame*)*, void (%f.Frame*)*, i8*, i1 } ; See if the g's coro.begin was spilled into the frame ; CHECK-LABEL: @f( ; CHECK: %innerid = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* bitcast ([3 x void (%g.Frame*)*]* @g.resumers to i8*)) ; CHECK: %innerhdl = call noalias nonnull i8* @llvm.coro.begin(token %innerid, i8* null) -; CHECK: %[[spilladdr:.+]] = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 4 +; CHECK: %[[spilladdr:.+]] = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 2 ; CHECK: store i8* %innerhdl, i8** %[[spilladdr]] ; See if the coro.begin was loaded from the frame ; CHECK-LABEL: @f.resume( -; CHECK: %[[innerhdlAddr:.+]] = getelementptr inbounds %f.Frame, %f.Frame* %{{.+}}, i32 0, i32 4 +; CHECK: %[[innerhdlAddr:.+]] = getelementptr inbounds %f.Frame, %f.Frame* %{{.+}}, i32 0, i32 2 ; CHECK: %[[innerhdl:.+]] = load i8*, i8** %[[innerhdlAddr]] ; CHECK: %[[gframe:.+]] = bitcast i8* %[[innerhdl]] to %g.Frame* ; CHECK: %[[gvarAddr:.+]] = getelementptr inbounds %g.Frame, %g.Frame* %[[gframe]], i32 0, i32 4 diff --git a/llvm/test/Transforms/Coroutines/coro-swifterror.ll b/llvm/test/Transforms/Coroutines/coro-swifterror.ll index 932e448a57193..7390bb77ca9b6 100644 --- a/llvm/test/Transforms/Coroutines/coro-swifterror.ll +++ b/llvm/test/Transforms/Coroutines/coro-swifterror.ll @@ -40,7 +40,7 @@ cleanup: ; CHECK-NEXT: ret i8* bitcast (i8* (i8*, i1, i8**)* @f.resume.0 to i8*) ; CHECK-NEXT: } -; CHECK-LABEL: define internal i8* @f.resume.0(i8* noalias nonnull %0, i1 zeroext %1, i8** swifterror %2) +; CHECK-LABEL: define internal i8* @f.resume.0(i8* noalias nonnull align 4 dereferenceable(8) %0, i1 zeroext %1, i8** swifterror %2) ; CHECK-NEXT: : ; CHECK-NEXT: br i1 %1, ; CHECK: : @@ -102,7 +102,7 @@ cleanup: ; CHECK-NEXT: ret i8* bitcast (i8* (i8*, i1)* @g.resume.0 to i8*) ; CHECK-NEXT: } -; CHECK-LABEL: define internal i8* @g.resume.0(i8* noalias nonnull %0, i1 zeroext %1) +; CHECK-LABEL: define internal i8* @g.resume.0(i8* noalias nonnull align 4 dereferenceable(8) %0, i1 zeroext %1) ; CHECK-NEXT: : ; CHECK-NEXT: [[ERRORSLOT:%.*]] = alloca swifterror i8*, align 4 ; CHECK-NEXT: br i1 %1, diff --git a/llvm/test/Transforms/Coroutines/ex0.ll b/llvm/test/Transforms/Coroutines/ex0.ll index 59bebc5466490..64f87065cc816 100644 --- a/llvm/test/Transforms/Coroutines/ex0.ll +++ b/llvm/test/Transforms/Coroutines/ex0.ll @@ -1,5 +1,5 @@ ; First example from Doc/Coroutines.rst (two block loop) -; RUN: opt < %s -enable-coroutines -O2 -S | FileCheck %s +; RUN: opt < %s -enable-coroutines -O2 -preserve-alignment-assumptions-during-inlining=false -S | FileCheck %s define i8* @f(i32 %n) { entry: diff --git a/llvm/test/Transforms/Coroutines/ex1.ll b/llvm/test/Transforms/Coroutines/ex1.ll index c2a5586fde584..f51da69ee3fcd 100644 --- a/llvm/test/Transforms/Coroutines/ex1.ll +++ b/llvm/test/Transforms/Coroutines/ex1.ll @@ -1,5 +1,5 @@ ; First example from Doc/Coroutines.rst (one block loop) -; RUN: opt < %s -O2 -enable-coroutines -S | FileCheck %s +; RUN: opt < %s -O2 -enable-coroutines -preserve-alignment-assumptions-during-inlining=false -S | FileCheck %s define i8* @f(i32 %n) { entry: diff --git a/llvm/test/Transforms/Coroutines/ex3.ll b/llvm/test/Transforms/Coroutines/ex3.ll index 8ff4d718230f5..d30afbf2e3e00 100644 --- a/llvm/test/Transforms/Coroutines/ex3.ll +++ b/llvm/test/Transforms/Coroutines/ex3.ll @@ -1,5 +1,5 @@ ; Third example from Doc/Coroutines.rst (two suspend points) -; RUN: opt < %s -O2 -enable-coroutines -S | FileCheck %s +; RUN: opt < %s -O2 -enable-coroutines -preserve-alignment-assumptions-during-inlining=false -S | FileCheck %s define i8* @f(i32 %n) { entry: diff --git a/llvm/test/Transforms/Coroutines/ex5.ll b/llvm/test/Transforms/Coroutines/ex5.ll index 34767584c8116..2c3ace2d5cf40 100644 --- a/llvm/test/Transforms/Coroutines/ex5.ll +++ b/llvm/test/Transforms/Coroutines/ex5.ll @@ -1,5 +1,5 @@ ; Fifth example from Doc/Coroutines.rst (final suspend) -; RUN: opt < %s -O2 -enable-coroutines -S | FileCheck %s +; RUN: opt < %s -O2 -enable-coroutines -preserve-alignment-assumptions-during-inlining=false -S | FileCheck %s define i8* @f(i32 %n) { entry: From a08a41ea9c91cc9cb1ab4c71240b82895daeedd7 Mon Sep 17 00:00:00 2001 From: Cyndy Ishida Date: Mon, 2 Mar 2020 16:58:14 -0800 Subject: [PATCH 103/286] [llvm][MachO] fix adding weak def syms the weak defined symbol flag was missing from the call site for adding symbols which didn't cause issues because it invoked the default parameter. --- llvm/lib/TextAPI/MachO/TextStub.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/llvm/lib/TextAPI/MachO/TextStub.cpp b/llvm/lib/TextAPI/MachO/TextStub.cpp index 0584e43d5893f..f4e370aa822b4 100644 --- a/llvm/lib/TextAPI/MachO/TextStub.cpp +++ b/llvm/lib/TextAPI/MachO/TextStub.cpp @@ -959,7 +959,8 @@ template <> struct MappingTraits { for (auto &sym : CurrentSection.WeakSymbols) File->addSymbol(SymbolKind::GlobalSymbol, sym, - CurrentSection.Targets); + CurrentSection.Targets, SymbolFlags::WeakDefined); + for (auto &sym : CurrentSection.TlvSymbols) File->addSymbol(SymbolKind::GlobalSymbol, sym, CurrentSection.Targets, From e0481bd3f668cbe349f1d6c14a40dca7bafeca1a Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Tue, 24 Mar 2020 19:39:44 -0700 Subject: [PATCH 104/286] [ASan] Fix issue where system log buffer was not cleared after reporting an issue. Summary: When ASan reports an issue the contents of the system log buffer (`error_message_buffer`) get flushed to the system log (via `LogFullErrorReport()`). After this happens the buffer is not cleared but this is usually fine because the process usually exits soon after reporting the issue. However, when ASan runs in `halt_on_error=0` mode execution continues without clearing the buffer. This leads to problems if more ASan issues are found and reported. 1. Duplicate ASan reports in the system log. The Nth (start counting from 1) ASan report will be duplicated (M - N) times in the system log if M is the number of ASan issues reported. 2. Lost ASan reports. Given a sufficient number of reports the buffer will fill up and consequently cannot be appended to. This means reports can be lost. The fix here is to reset `error_message_buffer_pos` to 0 which effectively clears the system log buffer. A test case is included but unfortunately it is Darwin specific because querying the system log is an OS specific activity. rdar://problem/55986279 Reviewers: kubamracek, yln, vitalybuka, kcc, filcab Subscribers: #sanitizers, llvm-commits Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D76749 (cherry picked from commit 445b810fbd4f1dad71fbdf96ba1c3b947417b884) --- compiler-rt/lib/asan/asan_report.cpp | 3 + .../Darwin/duplicate_os_log_reports.cpp | 68 +++++++++++++++++++ compiler-rt/test/lit.common.cfg.py | 4 ++ 3 files changed, 75 insertions(+) create mode 100644 compiler-rt/test/asan/TestCases/Darwin/duplicate_os_log_reports.cpp diff --git a/compiler-rt/lib/asan/asan_report.cpp b/compiler-rt/lib/asan/asan_report.cpp index 2e6ce436d0306..99e8678aa7857 100644 --- a/compiler-rt/lib/asan/asan_report.cpp +++ b/compiler-rt/lib/asan/asan_report.cpp @@ -160,6 +160,9 @@ class ScopedInErrorReport { BlockingMutexLock l(&error_message_buf_mutex); internal_memcpy(buffer_copy.data(), error_message_buffer, kErrorMessageBufferSize); + // Clear error_message_buffer so that if we find other errors + // we don't re-log this error. + error_message_buffer_pos = 0; } LogFullErrorReport(buffer_copy.data()); diff --git a/compiler-rt/test/asan/TestCases/Darwin/duplicate_os_log_reports.cpp b/compiler-rt/test/asan/TestCases/Darwin/duplicate_os_log_reports.cpp new file mode 100644 index 0000000000000..5f923d22a9a41 --- /dev/null +++ b/compiler-rt/test/asan/TestCases/Darwin/duplicate_os_log_reports.cpp @@ -0,0 +1,68 @@ +// UNSUPPORTED: ios +// REQUIRES: shell +// REQUIRES: darwin_log_cmd +// RUN: %clangxx_asan -fsanitize-recover=address %s -o %t +// RUN: { %env_asan_opts=halt_on_error=0,log_to_syslog=1 %run %t > %t.process_output.txt 2>&1 & } \ +// RUN: ; export TEST_PID=$! ; wait ${TEST_PID} + +// Check process output. +// RUN: FileCheck %s --check-prefixes CHECK,CHECK-PROC -input-file=%t.process_output.txt + +// Check syslog output. We filter recent system logs based on PID to avoid +// getting the logs of previous test runs. +// RUN: log show --debug --last 2m --predicate "processID == ${TEST_PID}" --style syslog > %t.process_syslog_output.txt +// RUN: FileCheck %s -input-file=%t.process_syslog_output.txt +#include +#include +#include + +const int kBufferSize = 512; +char *buffer; + +// `readZero` and `readOne` exist so that we can distinguish the two +// error reports based on the symbolized stacktrace. +void readZero() { + assert(__asan_address_is_poisoned(buffer)); + char c = buffer[0]; + printf("Read %c\n", c); +} + +void readOne() { + assert(__asan_address_is_poisoned(buffer + 1)); + char c = buffer[1]; + printf("Read %c\n", c); +} + +int main() { + buffer = static_cast(malloc(kBufferSize)); + assert(buffer); + // Deliberately poison `buffer` so that we have a deterministic way + // triggering two ASan reports in a row in the no halt_on_error mode (e.g. Two + // heap-use-after free in a row might not be deterministic). + __asan_poison_memory_region(buffer, kBufferSize); + + // This sequence of ASan reports are designed to catch an old bug in the way + // ASan's internal syslog buffer was handled after reporting an issue. + // Previously in the no halt_on_error mode the internal buffer wasn't cleared + // after reporting an issue. When another issue was encountered everything + // that was already in the buffer would be written to the syslog again + // leading to duplicate reports in the syslog. + + // First bad access. + // CHECK: use-after-poison + // CHECK-NEXT: READ of size 1 + // CHECK-NEXT: #0 0x{{[0-9a-f]+}} in readZero + // CHECK: SUMMARY: {{.*}} use-after-poison {{.*}} in readZero + readZero(); + + // Second bad access. + // CHECK: use-after-poison + // CHECK-NEXT: READ of size 1 + // CHECK-NEXT: #0 0x{{[0-9a-f]+}} in readOne + // CHECK: SUMMARY: {{.*}} use-after-poison {{.*}} in readOne + readOne(); + + // CHECK-PROC: DONE + printf("DONE\n"); + return 0; +} diff --git a/compiler-rt/test/lit.common.cfg.py b/compiler-rt/test/lit.common.cfg.py index 622261535fa2e..6026c604ce496 100644 --- a/compiler-rt/test/lit.common.cfg.py +++ b/compiler-rt/test/lit.common.cfg.py @@ -537,6 +537,10 @@ def is_windows_lto_supported(): # much slower. Let's override this and run lit tests with 'abort_on_error=0'. config.default_sanitizer_opts += ['abort_on_error=0'] config.default_sanitizer_opts += ['log_to_syslog=0'] + if lit.util.which('log'): + config.available_features.add('darwin_log_cmd') + else: + lit_config.warning('log command not found. Some tests will be skipped.') elif config.android: config.default_sanitizer_opts += ['abort_on_error=0'] From f872e471919ceb7fc7d62c1b5a34ec6f1fc98d05 Mon Sep 17 00:00:00 2001 From: Davide Italiano Date: Thu, 26 Mar 2020 15:41:48 -0700 Subject: [PATCH 105/286] [debugserver] Fix the xcode project. --- .../debugserver.xcodeproj/project.pbxproj | 561 ++++++------------ 1 file changed, 174 insertions(+), 387 deletions(-) diff --git a/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj b/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj index 3056635eff34d..1c7a55f7108a0 100644 --- a/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj +++ b/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj @@ -7,131 +7,165 @@ objects = { /* Begin PBXBuildFile section */ - 23562ED61D342A5A00AB2BD4 /* ActivityStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23562ED51D342A5A00AB2BD4 /* ActivityStore.cpp */; }; - 23562ED71D342A5A00AB2BD4 /* ActivityStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23562ED51D342A5A00AB2BD4 /* ActivityStore.cpp */; }; - 26CE05C5115C36590022F371 /* CFBundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2695DD910D3EBFF6007E4CA2 /* CFBundle.cpp */; }; - 456F67641AD46CE9002850C2 /* CFBundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2695DD910D3EBFF6007E4CA2 /* CFBundle.cpp */; }; - 26CE05C3115C36580022F371 /* CFString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2695DD9B0D3EC160007E4CA2 /* CFString.cpp */; }; - 456F67621AD46CE9002850C2 /* CFString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2695DD9B0D3EC160007E4CA2 /* CFString.cpp */; }; - 26CE05CF115C36F70022F371 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26ACA3340D3E956300A2120B /* CoreFoundation.framework */; settings = {ATTRIBUTES = (Required, ); }; }; - 456F676B1AD46CE9002850C2 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26ACA3340D3E956300A2120B /* CoreFoundation.framework */; settings = {ATTRIBUTES = (Required, ); }; }; - 26CE05B7115C363B0022F371 /* DNB.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637D60C71334A0024798E /* DNB.cpp */; }; - 456F67551AD46CE9002850C2 /* DNB.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637D60C71334A0024798E /* DNB.cpp */; }; - 264D5D581293835600ED4C01 /* DNBArch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 264D5D571293835600ED4C01 /* DNBArch.cpp */; }; - 456F67671AD46CE9002850C2 /* DNBArch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 264D5D571293835600ED4C01 /* DNBArch.cpp */; }; - 26CE05C1115C36510022F371 /* DNBArchImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2675D4220CCEB705000F49AF /* DNBArchImpl.cpp */; }; - 26CE05C2115C36550022F371 /* DNBArchImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637FB0C71334A0024798E /* DNBArchImpl.cpp */; }; - 456F67601AD46CE9002850C2 /* DNBArchImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2675D4220CCEB705000F49AF /* DNBArchImpl.cpp */; }; - 456F67611AD46CE9002850C2 /* DNBArchImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637FB0C71334A0024798E /* DNBArchImpl.cpp */; }; - 266B5ED11460A68200E43F0A /* DNBArchImplARM64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 266B5ECF1460A68200E43F0A /* DNBArchImplARM64.cpp */; }; - 456F67691AD46CE9002850C2 /* DNBArchImplARM64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 266B5ECF1460A68200E43F0A /* DNBArchImplARM64.cpp */; }; - 26CE05C0115C364F0022F371 /* DNBArchImplI386.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637EA0C71334A0024798E /* DNBArchImplI386.cpp */; }; - 456F675F1AD46CE9002850C2 /* DNBArchImplI386.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637EA0C71334A0024798E /* DNBArchImplI386.cpp */; }; - 26CE05BF115C364D0022F371 /* DNBArchImplX86_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26CF99A21142EB7400011AAB /* DNBArchImplX86_64.cpp */; }; - 456F675E1AD46CE9002850C2 /* DNBArchImplX86_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26CF99A21142EB7400011AAB /* DNBArchImplX86_64.cpp */; }; - 26CE05B8115C363C0022F371 /* DNBBreakpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637D90C71334A0024798E /* DNBBreakpoint.cpp */; }; - 456F67571AD46CE9002850C2 /* DNBBreakpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637D90C71334A0024798E /* DNBBreakpoint.cpp */; }; - 26CE05B9115C363D0022F371 /* DNBDataRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637DB0C71334A0024798E /* DNBDataRef.cpp */; }; - 456F67581AD46CE9002850C2 /* DNBDataRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637DB0C71334A0024798E /* DNBDataRef.cpp */; }; - 26CE05A7115C360D0022F371 /* DNBError.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637DE0C71334A0024798E /* DNBError.cpp */; }; - 456F67461AD46CE9002850C2 /* DNBError.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637DE0C71334A0024798E /* DNBError.cpp */; }; - 26CE05BA115C363E0022F371 /* DNBLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637E00C71334A0024798E /* DNBLog.cpp */; }; - 456F67591AD46CE9002850C2 /* DNBLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637E00C71334A0024798E /* DNBLog.cpp */; }; - 26CE05BB115C363F0022F371 /* DNBRegisterInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637E20C71334A0024798E /* DNBRegisterInfo.cpp */; }; - 456F675A1AD46CE9002850C2 /* DNBRegisterInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637E20C71334A0024798E /* DNBRegisterInfo.cpp */; }; - 26CE05A8115C36170022F371 /* DNBThreadResumeActions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260E7331114BFFE600D1DFB3 /* DNBThreadResumeActions.cpp */; }; - 456F67471AD46CE9002850C2 /* DNBThreadResumeActions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260E7331114BFFE600D1DFB3 /* DNBThreadResumeActions.cpp */; }; - 23AE72E41D25DECF00945BCE /* DarwinLogCollector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23AE72E21D25DECF00945BCE /* DarwinLogCollector.cpp */; }; - 23AE72E51D25DEE100945BCE /* DarwinLogCollector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23AE72E21D25DECF00945BCE /* DarwinLogCollector.cpp */; }; - 49D404621E39260F00570CDC /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 49D404611E39260F00570CDC /* Foundation.framework */; }; - AFA3FCA11E39984900218D5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 49D404611E39260F00570CDC /* Foundation.framework */; }; - 456F67561AD46CE9002850C2 /* Genealogy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AFEC3363194A8B0B00FF05C6 /* Genealogy.cpp */; }; - AFEC3364194A8B0B00FF05C6 /* Genealogy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AFEC3363194A8B0B00FF05C6 /* Genealogy.cpp */; }; 23043C9D1D35DBEC00FC25CA /* JSON.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 233B4EA51D2DB54300E98261 /* JSON.cpp */; }; + 23043C9E1D35DBFA00FC25CA /* StringConvert.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 233B4EA81D2DB96A00E98261 /* StringConvert.cpp */; }; + 2307CCCB1D4A5D630016ABC0 /* LogFilterExactMatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 237821AE1D4917D20028B7A1 /* LogFilterExactMatch.cpp */; }; 233B4EA71D2DB54300E98261 /* JSON.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 233B4EA51D2DB54300E98261 /* JSON.cpp */; }; + 233B4EA91D2DB96A00E98261 /* StringConvert.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 233B4EA81D2DB96A00E98261 /* StringConvert.cpp */; }; + 23562ED21D3424DF00AB2BD4 /* LogMessageOsLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23562ED01D3424DF00AB2BD4 /* LogMessageOsLog.cpp */; }; + 23562ED31D3424DF00AB2BD4 /* LogMessageOsLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23562ED01D3424DF00AB2BD4 /* LogMessageOsLog.cpp */; }; + 23562ED61D342A5A00AB2BD4 /* ActivityStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23562ED51D342A5A00AB2BD4 /* ActivityStore.cpp */; }; + 23562ED71D342A5A00AB2BD4 /* ActivityStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23562ED51D342A5A00AB2BD4 /* ActivityStore.cpp */; }; + 23562ED91D342B0000AB2BD4 /* LogMessage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23562ED81D342B0000AB2BD4 /* LogMessage.cpp */; }; + 23562EDA1D342B0000AB2BD4 /* LogMessage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23562ED81D342B0000AB2BD4 /* LogMessage.cpp */; }; + 237821B01D4917D20028B7A1 /* LogFilterExactMatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 237821AE1D4917D20028B7A1 /* LogFilterExactMatch.cpp */; }; 23AC04C61D2F41A00072351D /* LogFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23AC04C41D2F41A00072351D /* LogFilter.cpp */; }; 23AC04C71D2F41A00072351D /* LogFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23AC04C41D2F41A00072351D /* LogFilter.cpp */; }; 23AC04CA1D2F42250072351D /* LogFilterChain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23AC04C81D2F42250072351D /* LogFilterChain.cpp */; }; 23AC04CB1D2F42250072351D /* LogFilterChain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23AC04C81D2F42250072351D /* LogFilterChain.cpp */; }; - 2307CCCB1D4A5D630016ABC0 /* LogFilterExactMatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 237821AE1D4917D20028B7A1 /* LogFilterExactMatch.cpp */; }; - 237821B01D4917D20028B7A1 /* LogFilterExactMatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 237821AE1D4917D20028B7A1 /* LogFilterExactMatch.cpp */; }; 23AC04CF1D2F58AF0072351D /* LogFilterRegex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23AC04CD1D2F58AF0072351D /* LogFilterRegex.cpp */; }; 23AC04D01D2F58AF0072351D /* LogFilterRegex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23AC04CD1D2F58AF0072351D /* LogFilterRegex.cpp */; }; - 23562ED91D342B0000AB2BD4 /* LogMessage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23562ED81D342B0000AB2BD4 /* LogMessage.cpp */; }; - 23562EDA1D342B0000AB2BD4 /* LogMessage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23562ED81D342B0000AB2BD4 /* LogMessage.cpp */; }; - 23562ED21D3424DF00AB2BD4 /* LogMessageOsLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23562ED01D3424DF00AB2BD4 /* LogMessageOsLog.cpp */; }; - 23562ED31D3424DF00AB2BD4 /* LogMessageOsLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23562ED01D3424DF00AB2BD4 /* LogMessageOsLog.cpp */; }; + 23AE72E41D25DECF00945BCE /* DarwinLogCollector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23AE72E21D25DECF00945BCE /* DarwinLogCollector.cpp */; }; + 23AE72E51D25DEE100945BCE /* DarwinLogCollector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23AE72E21D25DECF00945BCE /* DarwinLogCollector.cpp */; }; + 23D1B0291D497E8B00FF831B /* OsLogger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23D1B0271D497E8B00FF831B /* OsLogger.cpp */; }; + 23D1B02A1D497E8B00FF831B /* OsLogger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23D1B0271D497E8B00FF831B /* OsLogger.cpp */; }; + 264D5D581293835600ED4C01 /* DNBArch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 264D5D571293835600ED4C01 /* DNBArch.cpp */; }; + 266B5ED11460A68200E43F0A /* DNBArchImplARM64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 266B5ECF1460A68200E43F0A /* DNBArchImplARM64.cpp */; }; + 26CE05A7115C360D0022F371 /* DNBError.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637DE0C71334A0024798E /* DNBError.cpp */; }; + 26CE05A8115C36170022F371 /* DNBThreadResumeActions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260E7331114BFFE600D1DFB3 /* DNBThreadResumeActions.cpp */; }; + 26CE05A9115C36250022F371 /* debugserver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A02918114AB9240029C479 /* debugserver.cpp */; }; + 26CE05AA115C36260022F371 /* RNBContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A68F7E0D104EC800665A9E /* RNBContext.cpp */; }; + 26CE05AB115C36270022F371 /* RNBServices.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF8878A00D9C797C001831DA /* RNBServices.cpp */; }; + 26CE05AC115C36280022F371 /* RNBSocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A68FB00D1054DA00665A9E /* RNBSocket.cpp */; }; + 26CE05AD115C36280022F371 /* RNBRemote.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A68FD60D10574500665A9E /* RNBRemote.cpp */; }; + 26CE05AE115C36320022F371 /* dbgnub-mig.defs in Sources */ = {isa = PBXBuildFile; fileRef = 26C637E80C71334A0024798E /* dbgnub-mig.defs */; settings = {ATTRIBUTES = (Client, Server, ); }; }; 26CE05B0115C36340022F371 /* MachException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637EE0C71334A0024798E /* MachException.cpp */; }; - 456F674E1AD46CE9002850C2 /* MachException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637EE0C71334A0024798E /* MachException.cpp */; }; 26CE05B1115C36350022F371 /* MachProcess.mm in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F00C71334A0024798E /* MachProcess.mm */; }; - 456F674F1AD46CE9002850C2 /* MachProcess.mm in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F00C71334A0024798E /* MachProcess.mm */; }; - 26CE05B6115C36390022F371 /* MachTask.mm in Sources */ = {isa = PBXBuildFile; fileRef = 26B67DE10EE9BC30006C8BC0 /* MachTask.mm */; }; - 456F67541AD46CE9002850C2 /* MachTask.mm in Sources */ = {isa = PBXBuildFile; fileRef = 26B67DE10EE9BC30006C8BC0 /* MachTask.mm */; }; 26CE05B2115C36360022F371 /* MachThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F20C71334A0024798E /* MachThread.cpp */; }; - 456F67501AD46CE9002850C2 /* MachThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F20C71334A0024798E /* MachThread.cpp */; }; 26CE05B3115C36370022F371 /* MachThreadList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F40C71334A0024798E /* MachThreadList.cpp */; }; - 456F67511AD46CE9002850C2 /* MachThreadList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F40C71334A0024798E /* MachThreadList.cpp */; }; 26CE05B4115C36380022F371 /* MachVMMemory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F60C71334A0024798E /* MachVMMemory.cpp */; }; - 456F67521AD46CE9002850C2 /* MachVMMemory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F60C71334A0024798E /* MachVMMemory.cpp */; }; 26CE05B5115C36380022F371 /* MachVMRegion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F80C71334A0024798E /* MachVMRegion.cpp */; }; - 456F67531AD46CE9002850C2 /* MachVMRegion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F80C71334A0024798E /* MachVMRegion.cpp */; }; - 23D1B0291D497E8B00FF831B /* OsLogger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23D1B0271D497E8B00FF831B /* OsLogger.cpp */; }; - 23D1B02A1D497E8B00FF831B /* OsLogger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23D1B0271D497E8B00FF831B /* OsLogger.cpp */; }; + 26CE05B6115C36390022F371 /* MachTask.mm in Sources */ = {isa = PBXBuildFile; fileRef = 26B67DE10EE9BC30006C8BC0 /* MachTask.mm */; }; + 26CE05B7115C363B0022F371 /* DNB.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637D60C71334A0024798E /* DNB.cpp */; }; + 26CE05B8115C363C0022F371 /* DNBBreakpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637D90C71334A0024798E /* DNBBreakpoint.cpp */; }; + 26CE05B9115C363D0022F371 /* DNBDataRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637DB0C71334A0024798E /* DNBDataRef.cpp */; }; + 26CE05BA115C363E0022F371 /* DNBLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637E00C71334A0024798E /* DNBLog.cpp */; }; + 26CE05BB115C363F0022F371 /* DNBRegisterInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637E20C71334A0024798E /* DNBRegisterInfo.cpp */; }; 26CE05BC115C36420022F371 /* PThreadEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637FE0C71334A0024798E /* PThreadEvent.cpp */; }; - 456F675B1AD46CE9002850C2 /* PThreadEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637FE0C71334A0024798E /* PThreadEvent.cpp */; }; 26CE05BD115C36430022F371 /* PThreadMutex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2672DBEE0EEF446700E92059 /* PThreadMutex.cpp */; }; - 456F675C1AD46CE9002850C2 /* PThreadMutex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2672DBEE0EEF446700E92059 /* PThreadMutex.cpp */; }; + 26CE05BE115C36440022F371 /* SysSignal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C638010C71334A0024798E /* SysSignal.cpp */; }; + 26CE05BF115C364D0022F371 /* DNBArchImplX86_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26CF99A21142EB7400011AAB /* DNBArchImplX86_64.cpp */; }; + 26CE05C0115C364F0022F371 /* DNBArchImplI386.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637EA0C71334A0024798E /* DNBArchImplI386.cpp */; }; + 26CE05C1115C36510022F371 /* DNBArchImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2675D4220CCEB705000F49AF /* DNBArchImpl.cpp */; }; + 26CE05C3115C36580022F371 /* CFString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2695DD9B0D3EC160007E4CA2 /* CFString.cpp */; }; + 26CE05C5115C36590022F371 /* CFBundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2695DD910D3EBFF6007E4CA2 /* CFBundle.cpp */; }; + 26CE05CF115C36F70022F371 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26ACA3340D3E956300A2120B /* CoreFoundation.framework */; settings = {ATTRIBUTES = (Required, ); }; }; 26CE05F1115C387C0022F371 /* PseudoTerminal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF67ABFF0D34604D0022D128 /* PseudoTerminal.cpp */; }; - 456F67651AD46CE9002850C2 /* PseudoTerminal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF67ABFF0D34604D0022D128 /* PseudoTerminal.cpp */; }; - 26CE05AA115C36260022F371 /* RNBContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A68F7E0D104EC800665A9E /* RNBContext.cpp */; }; + 456F67461AD46CE9002850C2 /* DNBError.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637DE0C71334A0024798E /* DNBError.cpp */; }; + 456F67471AD46CE9002850C2 /* DNBThreadResumeActions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260E7331114BFFE600D1DFB3 /* DNBThreadResumeActions.cpp */; }; + 456F67481AD46CE9002850C2 /* debugserver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A02918114AB9240029C479 /* debugserver.cpp */; }; 456F67491AD46CE9002850C2 /* RNBContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A68F7E0D104EC800665A9E /* RNBContext.cpp */; }; - 26CE05AD115C36280022F371 /* RNBRemote.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A68FD60D10574500665A9E /* RNBRemote.cpp */; }; - 456F674C1AD46CE9002850C2 /* RNBRemote.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A68FD60D10574500665A9E /* RNBRemote.cpp */; }; - 26CE05AB115C36270022F371 /* RNBServices.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF8878A00D9C797C001831DA /* RNBServices.cpp */; }; 456F674A1AD46CE9002850C2 /* RNBServices.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EF8878A00D9C797C001831DA /* RNBServices.cpp */; }; - 26CE05AC115C36280022F371 /* RNBSocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A68FB00D1054DA00665A9E /* RNBSocket.cpp */; }; 456F674B1AD46CE9002850C2 /* RNBSocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A68FB00D1054DA00665A9E /* RNBSocket.cpp */; }; - AF588449206077BD00A0CB5A /* SocketAddress.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D6631CA81E848FE9006A7B11 /* SocketAddress.cpp */; }; - D6631CA91E848FE9006A7B11 /* SocketAddress.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D6631CA81E848FE9006A7B11 /* SocketAddress.cpp */; }; + 456F674C1AD46CE9002850C2 /* RNBRemote.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A68FD60D10574500665A9E /* RNBRemote.cpp */; }; + 456F674D1AD46CE9002850C2 /* dbgnub-mig.defs in Sources */ = {isa = PBXBuildFile; fileRef = 26C637E80C71334A0024798E /* dbgnub-mig.defs */; settings = {ATTRIBUTES = (Client, Server, ); }; }; + 456F674E1AD46CE9002850C2 /* MachException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637EE0C71334A0024798E /* MachException.cpp */; }; + 456F674F1AD46CE9002850C2 /* MachProcess.mm in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F00C71334A0024798E /* MachProcess.mm */; }; + 456F67501AD46CE9002850C2 /* MachThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F20C71334A0024798E /* MachThread.cpp */; }; + 456F67511AD46CE9002850C2 /* MachThreadList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F40C71334A0024798E /* MachThreadList.cpp */; }; + 456F67521AD46CE9002850C2 /* MachVMMemory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F60C71334A0024798E /* MachVMMemory.cpp */; }; + 456F67531AD46CE9002850C2 /* MachVMRegion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637F80C71334A0024798E /* MachVMRegion.cpp */; }; + 456F67541AD46CE9002850C2 /* MachTask.mm in Sources */ = {isa = PBXBuildFile; fileRef = 26B67DE10EE9BC30006C8BC0 /* MachTask.mm */; }; + 456F67551AD46CE9002850C2 /* DNB.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637D60C71334A0024798E /* DNB.cpp */; }; + 456F67561AD46CE9002850C2 /* Genealogy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AFEC3363194A8B0B00FF05C6 /* Genealogy.cpp */; }; + 456F67571AD46CE9002850C2 /* DNBBreakpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637D90C71334A0024798E /* DNBBreakpoint.cpp */; }; + 456F67581AD46CE9002850C2 /* DNBDataRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637DB0C71334A0024798E /* DNBDataRef.cpp */; }; + 456F67591AD46CE9002850C2 /* DNBLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637E00C71334A0024798E /* DNBLog.cpp */; }; + 456F675A1AD46CE9002850C2 /* DNBRegisterInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637E20C71334A0024798E /* DNBRegisterInfo.cpp */; }; + 456F675B1AD46CE9002850C2 /* PThreadEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637FE0C71334A0024798E /* PThreadEvent.cpp */; }; + 456F675C1AD46CE9002850C2 /* PThreadMutex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2672DBEE0EEF446700E92059 /* PThreadMutex.cpp */; }; + 456F675D1AD46CE9002850C2 /* SysSignal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C638010C71334A0024798E /* SysSignal.cpp */; }; + 456F675E1AD46CE9002850C2 /* DNBArchImplX86_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26CF99A21142EB7400011AAB /* DNBArchImplX86_64.cpp */; }; + 456F675F1AD46CE9002850C2 /* DNBArchImplI386.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C637EA0C71334A0024798E /* DNBArchImplI386.cpp */; }; + 456F67601AD46CE9002850C2 /* DNBArchImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2675D4220CCEB705000F49AF /* DNBArchImpl.cpp */; }; + 456F67621AD46CE9002850C2 /* CFString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2695DD9B0D3EC160007E4CA2 /* CFString.cpp */; }; + 456F67641AD46CE9002850C2 /* CFBundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2695DD910D3EBFF6007E4CA2 /* CFBundle.cpp */; }; + 456F67651AD46CE9002850C2 /* PseudoTerminal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF67ABFF0D34604D0022D128 /* PseudoTerminal.cpp */; }; + 456F67671AD46CE9002850C2 /* DNBArch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 264D5D571293835600ED4C01 /* DNBArch.cpp */; }; + 456F67691AD46CE9002850C2 /* DNBArchImplARM64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 266B5ECF1460A68200E43F0A /* DNBArchImplARM64.cpp */; }; + 456F676B1AD46CE9002850C2 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26ACA3340D3E956300A2120B /* CoreFoundation.framework */; settings = {ATTRIBUTES = (Required, ); }; }; + 49D404621E39260F00570CDC /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 49D404611E39260F00570CDC /* Foundation.framework */; }; AF48558C1D75126800D19C07 /* StdStringExtractor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF48558B1D75126800D19C07 /* StdStringExtractor.cpp */; }; AF48558D1D75127500D19C07 /* StdStringExtractor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF48558B1D75126800D19C07 /* StdStringExtractor.cpp */; }; - 23043C9E1D35DBFA00FC25CA /* StringConvert.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 233B4EA81D2DB96A00E98261 /* StringConvert.cpp */; }; - 233B4EA91D2DB96A00E98261 /* StringConvert.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 233B4EA81D2DB96A00E98261 /* StringConvert.cpp */; }; - 26CE05BE115C36440022F371 /* SysSignal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C638010C71334A0024798E /* SysSignal.cpp */; }; - 456F675D1AD46CE9002850C2 /* SysSignal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26C638010C71334A0024798E /* SysSignal.cpp */; }; - 26CE05AE115C36320022F371 /* dbgnub-mig.defs in Sources */ = {isa = PBXBuildFile; fileRef = 26C637E80C71334A0024798E /* dbgnub-mig.defs */; settings = {ATTRIBUTES = (Client, Server, ); }; }; - 456F674D1AD46CE9002850C2 /* dbgnub-mig.defs in Sources */ = {isa = PBXBuildFile; fileRef = 26C637E80C71334A0024798E /* dbgnub-mig.defs */; settings = {ATTRIBUTES = (Client, Server, ); }; }; - 26CE05A9115C36250022F371 /* debugserver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A02918114AB9240029C479 /* debugserver.cpp */; }; - 456F67481AD46CE9002850C2 /* debugserver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26A02918114AB9240029C479 /* debugserver.cpp */; }; + AF588449206077BD00A0CB5A /* SocketAddress.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D6631CA81E848FE9006A7B11 /* SocketAddress.cpp */; }; + AFA3FCA11E39984900218D5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 49D404611E39260F00570CDC /* Foundation.framework */; }; + AFEC3364194A8B0B00FF05C6 /* Genealogy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AFEC3363194A8B0B00FF05C6 /* Genealogy.cpp */; }; + D6631CA91E848FE9006A7B11 /* SocketAddress.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D6631CA81E848FE9006A7B11 /* SocketAddress.cpp */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 23562ED51D342A5A00AB2BD4 /* ActivityStore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ActivityStore.cpp; sourceTree = ""; }; + 2307CCCC1D4A5DAE0016ABC0 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + 233B4EA51D2DB54300E98261 /* JSON.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSON.cpp; sourceTree = ""; }; + 233B4EA61D2DB54300E98261 /* JSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSON.h; sourceTree = ""; }; + 233B4EA81D2DB96A00E98261 /* StringConvert.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StringConvert.cpp; path = ../../../source/Host/common/StringConvert.cpp; sourceTree = ""; }; + 23562ECF1D34110D00AB2BD4 /* DarwinLogTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DarwinLogTypes.h; sourceTree = ""; }; + 23562ED01D3424DF00AB2BD4 /* LogMessageOsLog.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogMessageOsLog.cpp; sourceTree = ""; }; + 23562ED11D3424DF00AB2BD4 /* LogMessageOsLog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogMessageOsLog.h; sourceTree = ""; }; 23562ED41D3426DD00AB2BD4 /* ActivityStore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ActivityStore.h; sourceTree = ""; }; + 23562ED51D342A5A00AB2BD4 /* ActivityStore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ActivityStore.cpp; sourceTree = ""; }; + 23562ED81D342B0000AB2BD4 /* LogMessage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogMessage.cpp; sourceTree = ""; }; + 237821AD1D4917D20028B7A1 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; + 237821AE1D4917D20028B7A1 /* LogFilterExactMatch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogFilterExactMatch.cpp; sourceTree = ""; }; + 237821AF1D4917D20028B7A1 /* LogFilterExactMatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogFilterExactMatch.h; sourceTree = ""; }; + 23AC04C41D2F41A00072351D /* LogFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogFilter.cpp; sourceTree = ""; }; + 23AC04C51D2F41A00072351D /* LogFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogFilter.h; sourceTree = ""; }; + 23AC04C81D2F42250072351D /* LogFilterChain.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogFilterChain.cpp; sourceTree = ""; }; + 23AC04C91D2F42250072351D /* LogFilterChain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogFilterChain.h; sourceTree = ""; }; + 23AC04CC1D2F42F10072351D /* DarwinLogInterfaces.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DarwinLogInterfaces.h; sourceTree = ""; }; + 23AC04CD1D2F58AF0072351D /* LogFilterRegex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogFilterRegex.cpp; sourceTree = ""; }; + 23AC04CE1D2F58AF0072351D /* LogFilterRegex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogFilterRegex.h; sourceTree = ""; }; + 23AC04D11D2F60130072351D /* LogMessage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LogMessage.h; sourceTree = ""; }; + 23AE72E21D25DECF00945BCE /* DarwinLogCollector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DarwinLogCollector.cpp; sourceTree = ""; }; + 23AE72E31D25DECF00945BCE /* DarwinLogCollector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DarwinLogCollector.h; sourceTree = ""; }; 23AE72E61D25DEFB00945BCE /* ActivityStreamSPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ActivityStreamSPI.h; sourceTree = ""; }; + 23CF6F5E1D28A3760088ADC9 /* DarwinLogEvent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DarwinLogEvent.h; sourceTree = ""; }; + 23D1B0271D497E8B00FF831B /* OsLogger.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OsLogger.cpp; sourceTree = ""; }; + 23D1B0281D497E8B00FF831B /* OsLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OsLogger.h; sourceTree = ""; }; + 260828DE0CBAF7F400F95054 /* DNBRuntimeAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNBRuntimeAction.h; sourceTree = ""; }; + 260E7331114BFFE600D1DFB3 /* DNBThreadResumeActions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DNBThreadResumeActions.cpp; sourceTree = ""; }; + 260E7332114BFFE600D1DFB3 /* DNBThreadResumeActions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNBThreadResumeActions.h; sourceTree = ""; }; + 260FC7320E5B290400043FC9 /* debugnub-exports */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "debugnub-exports"; sourceTree = SOURCE_ROOT; }; + 26203D1C1641EFB200A662F7 /* com.apple.debugserver.applist.internal.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.debugserver.applist.internal.plist; sourceTree = ""; }; + 26203D1D1641EFB200A662F7 /* com.apple.debugserver.internal.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.debugserver.internal.plist; sourceTree = ""; }; + 26242C390DDBD33C0054A4CC /* debugserver-entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "debugserver-entitlements.plist"; sourceTree = ""; }; + 264D5D571293835600ED4C01 /* DNBArch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DNBArch.cpp; sourceTree = ""; }; + 264F679A1B2F9EB200140093 /* JSONGenerator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JSONGenerator.h; sourceTree = ""; }; + 26593A060D4931CC001C9FE3 /* ChangeLog */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ChangeLog; sourceTree = ""; }; + 266B5ECF1460A68200E43F0A /* DNBArchImplARM64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DNBArchImplARM64.cpp; sourceTree = ""; }; + 266B5ED01460A68200E43F0A /* DNBArchImplARM64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNBArchImplARM64.h; sourceTree = ""; }; + 2672DBEE0EEF446700E92059 /* PThreadMutex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PThreadMutex.cpp; sourceTree = ""; }; + 2675D4220CCEB705000F49AF /* DNBArchImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = DNBArchImpl.cpp; path = arm/DNBArchImpl.cpp; sourceTree = ""; }; + 2675D4230CCEB705000F49AF /* DNBArchImpl.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = DNBArchImpl.h; path = arm/DNBArchImpl.h; sourceTree = ""; }; 2695DD910D3EBFF6007E4CA2 /* CFBundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CFBundle.cpp; sourceTree = ""; }; 2695DD920D3EBFF6007E4CA2 /* CFBundle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CFBundle.h; sourceTree = ""; }; - 2695DD9B0D3EC160007E4CA2 /* CFString.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CFString.cpp; sourceTree = ""; }; 2695DD9A0D3EC160007E4CA2 /* CFString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CFString.h; sourceTree = ""; }; - 26C637E70C71334A0024798E /* CFUtils.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CFUtils.h; sourceTree = ""; }; - 2307CCCC1D4A5DAE0016ABC0 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; - 237821AD1D4917D20028B7A1 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; - 26593A060D4931CC001C9FE3 /* ChangeLog */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ChangeLog; sourceTree = ""; }; + 2695DD9B0D3EC160007E4CA2 /* CFString.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CFString.cpp; sourceTree = ""; }; + 269E8DF8164B2ED200AD65F6 /* com.apple.debugserver.posix.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.debugserver.posix.plist; sourceTree = ""; }; + 26A02918114AB9240029C479 /* debugserver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = debugserver.cpp; sourceTree = ""; }; + 26A4BAED0D498B7D00A9BEAB /* com.apple.debugserver.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.debugserver.plist; sourceTree = ""; }; + 26A68F7D0D104EC800665A9E /* RNBContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNBContext.h; sourceTree = ""; }; + 26A68F7E0D104EC800665A9E /* RNBContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RNBContext.cpp; sourceTree = ""; }; + 26A68FAF0D1054DA00665A9E /* RNBSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNBSocket.h; sourceTree = ""; }; + 26A68FB00D1054DA00665A9E /* RNBSocket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RNBSocket.cpp; sourceTree = ""; }; + 26A68FD50D10574500665A9E /* RNBRemote.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNBRemote.h; sourceTree = ""; }; + 26A68FD60D10574500665A9E /* RNBRemote.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RNBRemote.cpp; sourceTree = ""; }; + 26A8FE1E0D11A77B00203048 /* DNBTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNBTimer.h; sourceTree = ""; }; 26ACA3340D3E956300A2120B /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; + 26B67DE00EE9BC30006C8BC0 /* MachTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachTask.h; sourceTree = ""; }; + 26B67DE10EE9BC30006C8BC0 /* MachTask.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MachTask.mm; sourceTree = ""; }; 26C637D60C71334A0024798E /* DNB.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DNB.cpp; sourceTree = ""; }; 26C637D70C71334A0024798E /* DNB.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DNB.h; sourceTree = ""; }; - 264D5D571293835600ED4C01 /* DNBArch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DNBArch.cpp; sourceTree = ""; }; 26C637D80C71334A0024798E /* DNBArch.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DNBArch.h; sourceTree = ""; }; - 2675D4220CCEB705000F49AF /* DNBArchImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = DNBArchImpl.cpp; path = arm/DNBArchImpl.cpp; sourceTree = ""; }; - 26C637FB0C71334A0024798E /* DNBArchImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DNBArchImpl.cpp; sourceTree = ""; }; - 2675D4230CCEB705000F49AF /* DNBArchImpl.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = DNBArchImpl.h; path = arm/DNBArchImpl.h; sourceTree = ""; }; - 26C637FC0C71334A0024798E /* DNBArchImpl.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DNBArchImpl.h; sourceTree = ""; }; - 266B5ECF1460A68200E43F0A /* DNBArchImplARM64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DNBArchImplARM64.cpp; sourceTree = ""; }; - 266B5ED01460A68200E43F0A /* DNBArchImplARM64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNBArchImplARM64.h; sourceTree = ""; }; - 26C637EA0C71334A0024798E /* DNBArchImplI386.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DNBArchImplI386.cpp; sourceTree = ""; }; - 26C637EB0C71334A0024798E /* DNBArchImplI386.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DNBArchImplI386.h; sourceTree = ""; }; - 26CF99A21142EB7400011AAB /* DNBArchImplX86_64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DNBArchImplX86_64.cpp; sourceTree = ""; }; - 26CF99A31142EB7400011AAB /* DNBArchImplX86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNBArchImplX86_64.h; sourceTree = ""; }; 26C637D90C71334A0024798E /* DNBBreakpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DNBBreakpoint.cpp; sourceTree = ""; }; 26C637DA0C71334A0024798E /* DNBBreakpoint.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DNBBreakpoint.h; sourceTree = ""; }; 26C637DB0C71334A0024798E /* DNBDataRef.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DNBDataRef.cpp; sourceTree = ""; }; @@ -143,42 +177,14 @@ 26C637E10C71334A0024798E /* DNBLog.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DNBLog.h; sourceTree = ""; }; 26C637E20C71334A0024798E /* DNBRegisterInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DNBRegisterInfo.cpp; sourceTree = ""; }; 26C637E30C71334A0024798E /* DNBRegisterInfo.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DNBRegisterInfo.h; sourceTree = ""; }; - 260828DE0CBAF7F400F95054 /* DNBRuntimeAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNBRuntimeAction.h; sourceTree = ""; }; - 260E7331114BFFE600D1DFB3 /* DNBThreadResumeActions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DNBThreadResumeActions.cpp; sourceTree = ""; }; - 260E7332114BFFE600D1DFB3 /* DNBThreadResumeActions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNBThreadResumeActions.h; sourceTree = ""; }; - 26A8FE1E0D11A77B00203048 /* DNBTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNBTimer.h; sourceTree = ""; }; - 23AE72E21D25DECF00945BCE /* DarwinLogCollector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DarwinLogCollector.cpp; sourceTree = ""; }; - 23AE72E31D25DECF00945BCE /* DarwinLogCollector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DarwinLogCollector.h; sourceTree = ""; }; - 23CF6F5E1D28A3760088ADC9 /* DarwinLogEvent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DarwinLogEvent.h; sourceTree = ""; }; - 23AC04CC1D2F42F10072351D /* DarwinLogInterfaces.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DarwinLogInterfaces.h; sourceTree = ""; }; - 23562ECF1D34110D00AB2BD4 /* DarwinLogTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DarwinLogTypes.h; sourceTree = ""; }; - 49D404611E39260F00570CDC /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - AFEC3363194A8B0B00FF05C6 /* Genealogy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Genealogy.cpp; sourceTree = ""; }; - AF0934BA18E12B92005A11FD /* Genealogy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Genealogy.h; sourceTree = ""; }; - AF0934BB18E12B92005A11FD /* GenealogySPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GenealogySPI.h; sourceTree = ""; }; - 233B4EA51D2DB54300E98261 /* JSON.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSON.cpp; sourceTree = ""; }; - 233B4EA61D2DB54300E98261 /* JSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSON.h; sourceTree = ""; }; - 264F679A1B2F9EB200140093 /* JSONGenerator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JSONGenerator.h; sourceTree = ""; }; - 23AC04C41D2F41A00072351D /* LogFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogFilter.cpp; sourceTree = ""; }; - 23AC04C51D2F41A00072351D /* LogFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogFilter.h; sourceTree = ""; }; - 23AC04C81D2F42250072351D /* LogFilterChain.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogFilterChain.cpp; sourceTree = ""; }; - 23AC04C91D2F42250072351D /* LogFilterChain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogFilterChain.h; sourceTree = ""; }; - 237821AE1D4917D20028B7A1 /* LogFilterExactMatch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogFilterExactMatch.cpp; sourceTree = ""; }; - 237821AF1D4917D20028B7A1 /* LogFilterExactMatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogFilterExactMatch.h; sourceTree = ""; }; - 23AC04CD1D2F58AF0072351D /* LogFilterRegex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogFilterRegex.cpp; sourceTree = ""; }; - 23AC04CE1D2F58AF0072351D /* LogFilterRegex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogFilterRegex.h; sourceTree = ""; }; - 23562ED81D342B0000AB2BD4 /* LogMessage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogMessage.cpp; sourceTree = ""; }; - 23AC04D11D2F60130072351D /* LogMessage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LogMessage.h; sourceTree = ""; }; - 23562ED01D3424DF00AB2BD4 /* LogMessageOsLog.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogMessageOsLog.cpp; sourceTree = ""; }; - 23562ED11D3424DF00AB2BD4 /* LogMessageOsLog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogMessageOsLog.h; sourceTree = ""; }; + 26C637E70C71334A0024798E /* CFUtils.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CFUtils.h; sourceTree = ""; }; + 26C637E80C71334A0024798E /* dbgnub-mig.defs */ = {isa = PBXFileReference; explicitFileType = sourcecode.mig; fileEncoding = 30; path = "dbgnub-mig.defs"; sourceTree = ""; }; + 26C637EA0C71334A0024798E /* DNBArchImplI386.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DNBArchImplI386.cpp; sourceTree = ""; }; + 26C637EB0C71334A0024798E /* DNBArchImplI386.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DNBArchImplI386.h; sourceTree = ""; }; 26C637EE0C71334A0024798E /* MachException.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = MachException.cpp; sourceTree = ""; }; 26C637EF0C71334A0024798E /* MachException.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MachException.h; sourceTree = ""; }; - 26C637F10C71334A0024798E /* MachProcess.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MachProcess.h; sourceTree = ""; }; 26C637F00C71334A0024798E /* MachProcess.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = MachProcess.mm; sourceTree = ""; }; - 49F530111331519C008956F6 /* MachRegisterStatesI386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachRegisterStatesI386.h; sourceTree = ""; }; - 49F5301213316D7F008956F6 /* MachRegisterStatesX86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachRegisterStatesX86_64.h; sourceTree = ""; }; - 26B67DE00EE9BC30006C8BC0 /* MachTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachTask.h; sourceTree = ""; }; - 26B67DE10EE9BC30006C8BC0 /* MachTask.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MachTask.mm; sourceTree = ""; }; + 26C637F10C71334A0024798E /* MachProcess.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MachProcess.h; sourceTree = ""; }; 26C637F20C71334A0024798E /* MachThread.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = MachThread.cpp; sourceTree = ""; }; 26C637F30C71334A0024798E /* MachThread.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MachThread.h; sourceTree = ""; }; 26C637F40C71334A0024798E /* MachThreadList.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = MachThreadList.cpp; sourceTree = ""; }; @@ -187,45 +193,35 @@ 26C637F70C71334A0024798E /* MachVMMemory.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MachVMMemory.h; sourceTree = ""; }; 26C637F80C71334A0024798E /* MachVMRegion.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = MachVMRegion.cpp; sourceTree = ""; }; 26C637F90C71334A0024798E /* MachVMRegion.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MachVMRegion.h; sourceTree = ""; }; - 23D1B0271D497E8B00FF831B /* OsLogger.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OsLogger.cpp; sourceTree = ""; }; - 23D1B0281D497E8B00FF831B /* OsLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OsLogger.h; sourceTree = ""; }; 26C637FD0C71334A0024798E /* PThreadCondition.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PThreadCondition.h; sourceTree = ""; }; 26C637FE0C71334A0024798E /* PThreadEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = PThreadEvent.cpp; sourceTree = ""; }; 26C637FF0C71334A0024798E /* PThreadEvent.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PThreadEvent.h; sourceTree = ""; }; - 2672DBEE0EEF446700E92059 /* PThreadMutex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PThreadMutex.cpp; sourceTree = ""; }; 26C638000C71334A0024798E /* PThreadMutex.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PThreadMutex.h; sourceTree = ""; }; - AF67ABFF0D34604D0022D128 /* PseudoTerminal.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PseudoTerminal.cpp; sourceTree = ""; }; - AF67AC000D34604D0022D128 /* PseudoTerminal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PseudoTerminal.h; sourceTree = ""; }; - 26A68F7E0D104EC800665A9E /* RNBContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RNBContext.cpp; sourceTree = ""; }; - 26A68F7D0D104EC800665A9E /* RNBContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNBContext.h; sourceTree = ""; }; - 26E6B9DA0D1329010037ECDD /* RNBDefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNBDefs.h; sourceTree = ""; }; - 26A68FD60D10574500665A9E /* RNBRemote.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RNBRemote.cpp; sourceTree = ""; }; - 26A68FD50D10574500665A9E /* RNBRemote.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNBRemote.h; sourceTree = ""; }; - EF8878A00D9C797C001831DA /* RNBServices.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RNBServices.cpp; sourceTree = ""; }; - EF88789F0D9C797C001831DA /* RNBServices.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNBServices.h; sourceTree = ""; }; - 26A68FB00D1054DA00665A9E /* RNBSocket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RNBSocket.cpp; sourceTree = ""; }; - 26A68FAF0D1054DA00665A9E /* RNBSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNBSocket.h; sourceTree = ""; }; - D6631CA81E848FE9006A7B11 /* SocketAddress.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SocketAddress.cpp; path = ../../source/Host/common/SocketAddress.cpp; sourceTree = ""; }; - AF48558B1D75126800D19C07 /* StdStringExtractor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StdStringExtractor.cpp; sourceTree = ""; }; - 233B4EA81D2DB96A00E98261 /* StringConvert.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StringConvert.cpp; path = ../../../source/Host/common/StringConvert.cpp; sourceTree = ""; }; 26C638010C71334A0024798E /* SysSignal.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = SysSignal.cpp; sourceTree = ""; }; 26C638020C71334A0024798E /* SysSignal.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SysSignal.h; sourceTree = ""; }; 26C638050C71334A0024798E /* TTYState.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = TTYState.cpp; sourceTree = ""; }; 26C638060C71334A0024798E /* TTYState.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = TTYState.h; sourceTree = ""; }; - 26203D1C1641EFB200A662F7 /* com.apple.debugserver.applist.internal.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.debugserver.applist.internal.plist; sourceTree = ""; }; - EF88788B0D9C7558001831DA /* com.apple.debugserver.applist.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.debugserver.applist.plist; sourceTree = ""; }; - 26203D1D1641EFB200A662F7 /* com.apple.debugserver.internal.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.debugserver.internal.plist; sourceTree = ""; }; - 26A4BAED0D498B7D00A9BEAB /* com.apple.debugserver.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.debugserver.plist; sourceTree = ""; }; - 269E8DF8164B2ED200AD65F6 /* com.apple.debugserver.posix.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.debugserver.posix.plist; sourceTree = ""; }; - AF949ED620605DC2002A91F9 /* com.apple.internal.xpc.remote.debugserver.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.internal.xpc.remote.debugserver.plist; sourceTree = ""; }; - 26C637E80C71334A0024798E /* dbgnub-mig.defs */ = {isa = PBXFileReference; explicitFileType = sourcecode.mig; fileEncoding = 30; path = "dbgnub-mig.defs"; sourceTree = ""; }; - 260FC7320E5B290400043FC9 /* debugnub-exports */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "debugnub-exports"; sourceTree = SOURCE_ROOT; }; 26CE0594115C31C20022F371 /* debugserver */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = debugserver; sourceTree = BUILT_PRODUCTS_DIR; }; - 26242C390DDBD33C0054A4CC /* debugserver-entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "debugserver-entitlements.plist"; sourceTree = ""; }; - AF61C60418F75ABC00B48D9D /* debugserver-macosx-entitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "debugserver-macosx-entitlements.plist"; sourceTree = ""; }; + 26CF99A21142EB7400011AAB /* DNBArchImplX86_64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DNBArchImplX86_64.cpp; sourceTree = ""; }; + 26CF99A31142EB7400011AAB /* DNBArchImplX86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNBArchImplX86_64.h; sourceTree = ""; }; + 26E6B9DA0D1329010037ECDD /* RNBDefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNBDefs.h; sourceTree = ""; }; 456F67721AD46CE9002850C2 /* debugserver-nonui */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "debugserver-nonui"; sourceTree = BUILT_PRODUCTS_DIR; }; - 26A02918114AB9240029C479 /* debugserver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = debugserver.cpp; sourceTree = ""; }; + 49D404611E39260F00570CDC /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 49F530111331519C008956F6 /* MachRegisterStatesI386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachRegisterStatesI386.h; sourceTree = ""; }; + 49F5301213316D7F008956F6 /* MachRegisterStatesX86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachRegisterStatesX86_64.h; sourceTree = ""; }; 9457ECF61419864100DFE7D8 /* stack_logging.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = stack_logging.h; sourceTree = ""; }; + AF0934BA18E12B92005A11FD /* Genealogy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Genealogy.h; sourceTree = ""; }; + AF0934BB18E12B92005A11FD /* GenealogySPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GenealogySPI.h; sourceTree = ""; }; + AF48558B1D75126800D19C07 /* StdStringExtractor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StdStringExtractor.cpp; sourceTree = ""; }; + AF61C60418F75ABC00B48D9D /* debugserver-macosx-entitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "debugserver-macosx-entitlements.plist"; sourceTree = ""; }; + AF67ABFF0D34604D0022D128 /* PseudoTerminal.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PseudoTerminal.cpp; sourceTree = ""; }; + AF67AC000D34604D0022D128 /* PseudoTerminal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PseudoTerminal.h; sourceTree = ""; }; + AF949ED620605DC2002A91F9 /* com.apple.internal.xpc.remote.debugserver.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.internal.xpc.remote.debugserver.plist; sourceTree = ""; }; + AFEC3363194A8B0B00FF05C6 /* Genealogy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Genealogy.cpp; sourceTree = ""; }; + D6631CA81E848FE9006A7B11 /* SocketAddress.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SocketAddress.cpp; path = ../../source/Host/common/SocketAddress.cpp; sourceTree = ""; }; + EF88788B0D9C7558001831DA /* com.apple.debugserver.applist.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.debugserver.applist.plist; sourceTree = ""; }; + EF88789F0D9C797C001831DA /* RNBServices.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNBServices.h; sourceTree = ""; }; + EF8878A00D9C797C001831DA /* RNBServices.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RNBServices.cpp; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -409,7 +405,6 @@ 2675D41C0CCEB6CF000F49AF /* arm */, 266B5ECE1460A68200E43F0A /* arm64 */, 26C637E90C71334A0024798E /* i386 */, - 26C637FA0C71334A0024798E /* ppc */, 26CF99A11142EB7400011AAB /* x86_64 */, 26C637E80C71334A0024798E /* dbgnub-mig.defs */, AFEC3363194A8B0B00FF05C6 /* Genealogy.cpp */, @@ -446,15 +441,6 @@ path = i386; sourceTree = ""; }; - 26C637FA0C71334A0024798E /* ppc */ = { - isa = PBXGroup; - children = ( - 26C637FB0C71334A0024798E /* DNBArchImpl.cpp */, - 26C637FC0C71334A0024798E /* DNBArchImpl.h */, - ); - path = ppc; - sourceTree = ""; - }; 26CF99A11142EB7400011AAB /* x86_64 */ = { isa = PBXGroup; children = ( @@ -535,7 +521,6 @@ 08FB7793FE84155DC02AAC07 /* Project object */ = { isa = PBXProject; attributes = { - DefaultBuildSystemTypeForWorkspace = Latest; LastSwiftUpdateCheck = 0700; LastUpgradeCheck = 0720; }; @@ -618,7 +603,6 @@ 26CE05BF115C364D0022F371 /* DNBArchImplX86_64.cpp in Sources */, 26CE05C0115C364F0022F371 /* DNBArchImplI386.cpp in Sources */, 26CE05C1115C36510022F371 /* DNBArchImpl.cpp in Sources */, - 26CE05C2115C36550022F371 /* DNBArchImpl.cpp in Sources */, 26CE05C5115C36590022F371 /* CFBundle.cpp in Sources */, 26CE05C3115C36580022F371 /* CFString.cpp in Sources */, 23562ED91D342B0000AB2BD4 /* LogMessage.cpp in Sources */, @@ -669,7 +653,6 @@ 456F67601AD46CE9002850C2 /* DNBArchImpl.cpp in Sources */, 23AC04C71D2F41A00072351D /* LogFilter.cpp in Sources */, 23043C9E1D35DBFA00FC25CA /* StringConvert.cpp in Sources */, - 456F67611AD46CE9002850C2 /* DNBArchImpl.cpp in Sources */, AF588449206077BD00A0CB5A /* SocketAddress.cpp in Sources */, 456F67621AD46CE9002850C2 /* CFString.cpp in Sources */, 23AC04CB1D2F42250072351D /* LogFilterChain.cpp in Sources */, @@ -701,7 +684,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = ""; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; @@ -736,7 +719,7 @@ CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; DEAD_CODE_STRIPPING = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; @@ -760,202 +743,6 @@ }; name = Release; }; - 237965FC1C124395008D490F /* CustomSwift-RelWithDebInfo */ = { - isa = XCBuildConfiguration; - buildSettings = { - "ARCHS[sdk=iphoneos*]" = ( - armv7, - armv7s, - ); - "ARCHS[sdk=macosx*]" = "$(ARCHS_STANDARD_64_BIT)"; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 360.0.0; - DEAD_CODE_STRIPPING = YES; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_NO_COMMON_BLOCKS = YES; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - LLDB_COMPRESSION_CFLAGS = "-DHAVE_LIBCOMPRESSION=1"; - LLDB_COMPRESSION_LDFLAGS = "-lcompression"; - LLDB_ZLIB_CFLAGS = "-DHAVE_LIBZ=1"; - LLDB_ZLIB_LDFLAGS = "-lz"; - MACOSX_DEPLOYMENT_TARGET = 10.11; - ONLY_ACTIVE_ARCH = YES; - OTHER_CFLAGS = ""; - STRIPFLAGS = ""; - STRIP_INSTALLED_PRODUCT = NO; - STRIP_STYLE = debugging; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_BUILDER = "$(USER)"; - }; - name = "CustomSwift-RelWithDebInfo"; - }; - 237965FD1C124395008D490F /* CustomSwift-RelWithDebInfo */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; - CLANG_CXX_LIBRARY = "libc++"; - "CODE_SIGN_ENTITLEMENTS[sdk=*]" = "source/debugserver-entitlements.plist"; - "CODE_SIGN_ENTITLEMENTS[sdk=macosx*]" = "source/debugserver-macosx-entitlements.plist"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; - COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.0.0; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; - "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( - "$(SDKROOT)/System/Library/PrivateFrameworks", - "$(SDKROOT)/Developer/Library/PrivateFrameworks", - ); - "FRAMEWORK_SEARCH_PATHS[sdk=macosx*][arch=*]" = "$(SDKROOT)/System/Library/PrivateFrameworks"; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_PREPROCESSOR_DEFINITIONS = LLDB_DEBUGSERVER_RELEASE; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders; - INSTALL_PATH = /usr/bin; - LLDB_COMPRESSION_CFLAGS = "-DHAVE_LIBCOMPRESSION=1"; - LLDB_COMPRESSION_LDFLAGS = "-lcompression"; - LLDB_DEBUGSERVER = 1; - LLDB_ENERGY_CFLAGS = ""; - "LLDB_ENERGY_CFLAGS[sdk=macosx.internal]" = "-DLLDB_ENERGY"; - LLDB_ENERGY_LFLAGS = "-lpmenergy -lpmsample"; - LLDB_ZLIB_CFLAGS = "-DHAVE_LIBZ=1"; - LLDB_ZLIB_LDFLAGS = "-lz"; - MACOSX_DEPLOYMENT_TARGET = 10.9; - OTHER_CFLAGS = ( - "-Wparentheses", - "$(LLDB_ENERGY_CFLAGS)", - "-DDT_VARIANT_$(DT_VARIANT)", - "$(LLDB_COMPRESSION_CFLAGS)", - "$(LLDB_ZLIB_CFLAGS)", - ); - "OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = ( - "-Wparentheses", - "-DWITH_LOCKDOWN", - "-DWITH_FBS", - "-DWITH_BKS", - "-DOS_OBJECT_USE_OBJC=0", - "$(LLDB_COMPRESSION_CFLAGS)", - "$(LLDB_ZLIB_CFLAGS)", - ); - "OTHER_CPLUSPLUSFLAGS[sdk=iphoneos*][arch=*]" = "$(OTHER_CFLAGS)"; - OTHER_LDFLAGS = ""; - "OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = ( - "-framework", - SpringBoardServices, - "-framework", - BackBoardServices, - "-llockdown", - "-framework", - FrontBoardServices, - "-framework", - MobileCoreServices, - "$(LLDB_COMPRESSION_LDFLAGS)", - "$(LLDB_ZLIB_LDFLAGS)", - ); - "OTHER_LDFLAGS[sdk=macosx*]" = ( - "-sectcreate", - __TEXT, - __info_plist, - "$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist", - "$(LLDB_ENERGY_LFLAGS)", - "$(LLDB_COMPRESSION_LDFLAGS)", - "$(LLDB_ZLIB_LDFLAGS)", - ); - OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)"; - PRODUCT_NAME = debugserver; - "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; - "PROVISIONING_PROFILE[sdk=macosx*]" = ""; - SDKROOT = macosx; - "SDKROOT[arch=i386]" = macosx; - "SDKROOT[arch=x86_64]" = macosx; - "SDKROOT[arch=x86_64h]" = macosx; - SKIP_INSTALL = YES; - USER_HEADER_SEARCH_PATHS = "./source ../../source $(DERIVED_SOURCES_DIR) ../../include"; - ZERO_LINK = NO; - }; - name = "CustomSwift-RelWithDebInfo"; - }; - 237965FE1C124395008D490F /* CustomSwift-RelWithDebInfo */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; - CLANG_CXX_LIBRARY = "libc++"; - "CODE_SIGN_ENTITLEMENTS[sdk=*]" = "source/debugserver-entitlements.plist"; - "CODE_SIGN_ENTITLEMENTS[sdk=macosx*]" = "source/debugserver-macosx-entitlements.plist"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; - COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.0.0; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; - "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( - "$(SDKROOT)/System/Library/PrivateFrameworks", - "$(SDKROOT)/Developer/Library/PrivateFrameworks", - ); - "FRAMEWORK_SEARCH_PATHS[sdk=macosx*][arch=*]" = "$(SDKROOT)/System/Library/PrivateFrameworks"; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_PREPROCESSOR_DEFINITIONS = LLDB_DEBUGSERVER_RELEASE; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders; - INSTALL_PATH = /usr/bin; - LLDB_DEBUGSERVER = 1; - LLDB_ENERGY_CFLAGS = ""; - "LLDB_ENERGY_CFLAGS[sdk=macosx.internal]" = "-DLLDB_ENERGY"; - LLDB_ENERGY_LFLAGS = "-lpmenergy -lpmsample"; - MACOSX_DEPLOYMENT_TARGET = 10.9; - OTHER_CFLAGS = ( - "$(LLDB_COMPRESSION_CFLAGS)", - "$(LLDB_ZLIB_CFLAGS)", - ); - "OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = ( - "-Wparentheses", - "-DOS_OBJECT_USE_OBJC=0", - ); - "OTHER_CPLUSPLUSFLAGS[sdk=iphoneos*][arch=*]" = "$(OTHER_CFLAGS)"; - OTHER_LDFLAGS = ""; - "OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = ( - "-framework", - Foundation, - "$(LLDB_COMPRESSION_LDFLAGS)", - "$(LLDB_ZLIB_LDFLAGS)", - ); - "OTHER_LDFLAGS[sdk=macosx*]" = ( - "-sectcreate", - __TEXT, - __info_plist, - "$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist", - "$(LLDB_ENERGY_LFLAGS)", - "$(LLDB_COMPRESSION_LDFLAGS)", - "$(LLDB_ZLIB_LDFLAGS)", - ); - OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)"; - PRODUCT_NAME = debugserver; - "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; - "PROVISIONING_PROFILE[sdk=macosx*]" = ""; - SDKROOT = macosx; - "SDKROOT[arch=i386]" = macosx; - "SDKROOT[arch=x86_64]" = macosx; - "SDKROOT[arch=x86_64h]" = macosx; - SKIP_INSTALL = YES; - USER_HEADER_SEARCH_PATHS = "./source ../../source $(DERIVED_SOURCES_DIR) ../../include"; - ZERO_LINK = NO; - }; - name = "CustomSwift-RelWithDebInfo"; - }; 262419A11198A93E00067686 /* BuildAndIntegration */ = { isa = XCBuildConfiguration; buildSettings = { @@ -970,7 +757,7 @@ CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; DEAD_CODE_STRIPPING = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; @@ -1002,7 +789,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "-"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( @@ -1060,6 +847,8 @@ "$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist", "$(LLDB_ENERGY_LDFLAGS)", "$(LLDB_COMPRESSION_LDFLAGS)", + "-framework", + Security, ); OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)"; PRODUCT_NAME = debugserver; @@ -1082,7 +871,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( "$(SDKROOT)/System/Library/PrivateFrameworks", @@ -1139,6 +928,8 @@ "$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist", "$(LLDB_ENERGY_LDFLAGS)", "$(LLDB_COMPRESSION_LDFLAGS)", + "-framework", + Security, ); OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)"; PRODUCT_NAME = debugserver; @@ -1161,7 +952,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( @@ -1217,6 +1008,8 @@ "$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist", "$(LLDB_ENERGY_LDFLAGS)", "$(LLDB_COMPRESSION_LDFLAGS)", + "-framework", + Security, ); OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)"; PRODUCT_NAME = debugserver; @@ -1248,7 +1041,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; ENABLE_STRICT_OBJC_MSGSEND = YES; FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( @@ -1327,7 +1120,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( "$(SDKROOT)/System/Library/PrivateFrameworks", @@ -1344,9 +1137,7 @@ LLDB_ENERGY_CFLAGS = ""; "LLDB_ENERGY_CFLAGS[sdk=*.internal]" = "-DLLDB_ENERGY"; LLDB_ENERGY_LDFLAGS = "-lpmenergy -lpmsample"; - OTHER_CFLAGS = ( - "$(LLDB_ENERGY_CFLAGS)", - ); + OTHER_CFLAGS = "$(LLDB_ENERGY_CFLAGS)"; "OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = ( "-Wparentheses", "-DOS_OBJECT_USE_OBJC=0", @@ -1390,7 +1181,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( @@ -1457,7 +1248,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "-"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( @@ -1527,7 +1318,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = ""; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; @@ -1558,7 +1349,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( "$(SDKROOT)/System/Library/PrivateFrameworks", @@ -1642,7 +1433,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = ""; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; @@ -1673,7 +1464,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( "$(SDKROOT)/System/Library/PrivateFrameworks", @@ -1750,7 +1541,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( "$(SDKROOT)/System/Library/PrivateFrameworks", @@ -1832,7 +1623,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = ""; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; @@ -1863,7 +1654,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( "$(SDKROOT)/System/Library/PrivateFrameworks", @@ -1946,7 +1737,7 @@ CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; DEAD_CODE_STRIPPING = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_NO_COMMON_BLOCKS = YES; @@ -1963,7 +1754,6 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; STRIPFLAGS = "-x"; - STRIP_INSTALLED_PRODUCT = YES; STRIP_STYLE = debugging; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_BUILDER = "$(USER)"; @@ -1980,7 +1770,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.0.0; + CURRENT_PROJECT_VERSION = 360.99.0; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( @@ -2059,7 +1849,6 @@ 4968B7A916657FAE00741ABB /* DebugClang */, 940AD5251B1FE3B10051E88F /* DebugPresubmission */, 1DEB915008733D8E0010E9CD /* Release */, - 237965FC1C124395008D490F /* CustomSwift-RelWithDebInfo */, 94D72C891ADF10B000A3F718 /* CustomSwift-Release */, 262419A11198A93E00067686 /* BuildAndIntegration */, ); @@ -2074,7 +1863,6 @@ 4968B7AA16657FAE00741ABB /* DebugClang */, 940AD5261B1FE3B10051E88F /* DebugPresubmission */, 26CE0597115C31C30022F371 /* Release */, - 237965FD1C124395008D490F /* CustomSwift-RelWithDebInfo */, 94D72C8A1ADF10B000A3F718 /* CustomSwift-Release */, 262419A21198A93E00067686 /* BuildAndIntegration */, ); @@ -2088,7 +1876,6 @@ 456F676F1AD46CE9002850C2 /* DebugClang */, 940AD5271B1FE3B10051E88F /* DebugPresubmission */, 456F67701AD46CE9002850C2 /* Release */, - 237965FE1C124395008D490F /* CustomSwift-RelWithDebInfo */, 456F67711AD46CE9002850C2 /* BuildAndIntegration */, 94BA9B361B1A7C5700035A23 /* CustomSwift-Debug */, 94BA9B371B1A7C5700035A23 /* CustomSwift-Release */, From 1634e7413f63945a146bc3041175473b0a1800a4 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Thu, 26 Mar 2020 15:45:18 -0700 Subject: [PATCH 106/286] [SwiftASTContext] Add missing null check in ImportType Add a missing null check in ImportType. Without this, a program that does not contain an N_AST reference pointing back to a swiftmodule it uses can cause lldb to crash. rdar://60734897 --- lldb/source/Symbol/SwiftASTContext.cpp | 2 +- .../Shell/Swift/Inputs/No.swiftmodule.swift | 10 +++++++++- .../Swift/Inputs/NoSwiftmoduleHelper.swift | 3 +++ lldb/test/Shell/Swift/No.swiftmodule.test | 17 ++++++++++++++++- 4 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 lldb/test/Shell/Swift/Inputs/NoSwiftmoduleHelper.swift diff --git a/lldb/source/Symbol/SwiftASTContext.cpp b/lldb/source/Symbol/SwiftASTContext.cpp index 96f127b301104..54925a74a5287 100644 --- a/lldb/source/Symbol/SwiftASTContext.cpp +++ b/lldb/source/Symbol/SwiftASTContext.cpp @@ -5260,7 +5260,7 @@ CompilerType SwiftASTContext::ImportType(CompilerType &type, Status &error) { auto *ts = type.GetTypeSystem(); SwiftASTContext *swift_ast_ctx = llvm::dyn_cast_or_null(ts); - if (swift_ast_ctx == nullptr && !llvm::isa(ts)) { + if (swift_ast_ctx == nullptr && (!ts || !llvm::isa(ts))) { error.SetErrorString("Can't import clang type into a Swift ASTContext."); return CompilerType(); } else if (swift_ast_ctx == this) { diff --git a/lldb/test/Shell/Swift/Inputs/No.swiftmodule.swift b/lldb/test/Shell/Swift/Inputs/No.swiftmodule.swift index 91ba2de773687..5179473605b69 100644 --- a/lldb/test/Shell/Swift/Inputs/No.swiftmodule.swift +++ b/lldb/test/Shell/Swift/Inputs/No.swiftmodule.swift @@ -1,16 +1,24 @@ +import NoSwiftmoduleHelper + // The struct could not possibly be resolved with just the mangled type name. struct s { let i = 0 } +func useTypeFromOtherModule(x: S2) { + // break here +} + func f(_ t: T) { let number = 1 // CHECK-DAG: (Int) number = 1 let array = [1, 2, 3] // CHECK-DAG: ([Int]) array = 3 values let string = "hello" // CHECK-DAG: (String) string = "hello" let tuple = (0, 1) // CHECK-DAG: (Int, Int) tuple = (0 = 0, 1 = 1) let strct = s() // CHECK-DAG: strct ={{$}} + let strct2 = S2() // CHECK-DAG: strct2 = let generic = t // CHECK-DAG: (Int) generic = 23 let generic_tuple = (t, t) // CHECK-DAG: generic_tuple = // FIXME: CHECK-DAG: Date: Thu, 26 Mar 2020 17:15:57 -0700 Subject: [PATCH 107/286] [dsymutil] Only set a translation lambda if the translator is valid The SymbolMapTranslator defines an operator bool() which checks whether we should translate at all. This returns false if the list of obfuscated strings is empty. The NonRelocatableStringPool (OffsetsStringPool) takes a lambda for translating obfuscated strings rather than a SymbolMapTranslator. However, we were unconditionally passing the SymbolMapTranslator, which got implicitly converted to a std::function because it defines an operator(). In the string pool, we call operator bool but on the lambda, and not on the SymbolMapTranslator. This would always be true, because we were passing the translator unconditionally. This caused spurious warnings about obfuscated strings not being found. This patch fixes the problem by only passing the translation lambda when SymbolMapTranslator::operator bool() is true. --- llvm/tools/dsymutil/DwarfLinker.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/llvm/tools/dsymutil/DwarfLinker.cpp b/llvm/tools/dsymutil/DwarfLinker.cpp index 949cef6627ec6..7c0eeb9dd35cc 100644 --- a/llvm/tools/dsymutil/DwarfLinker.cpp +++ b/llvm/tools/dsymutil/DwarfLinker.cpp @@ -2777,7 +2777,11 @@ bool DwarfLinker::link(const DebugMap &Map) { // This Dwarf string pool which is used for emission. It must be used // serially as the order of calling getStringOffset matters for // reproducibility. - OffsetsStringPool OffsetsStringPool(Options.Translator, true); + std::function TranslationLambda = + Options.Translator + ? [&](StringRef Input) { return Options.Translator(Input); } + : static_cast>(nullptr); + OffsetsStringPool OffsetsStringPool(TranslationLambda, true); // ODR Contexts for the link. DeclContextTree ODRContexts; From 0186eef66f270d4acfe51a577590e690521655de Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Thu, 26 Mar 2020 18:17:53 -0700 Subject: [PATCH 108/286] Only add `darwin_log_cmd` lit shell test feature when the log can be queried. Summary: Follow up fix to 445b810fbd4. The `log show` command only works for privileged users so run a quick test of the command during lit config to see if the command works and only add the `darwin_log_cmd` feature if this is the case. Unfortunately this means the `asan/TestCases/Darwin/duplicate_os_log_reports.cpp` test and any other tests in the future that use this feature won't run for unprivileged users which is likely the case in CI. rdar://problem/55986279 Reviewers: kubamracek, yln, dcoughlin Subscribers: Charusso, #sanitizers, llvm-commits Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D76899 (cherry picked from commit 853a1e6942c824775cff20142301f9b114853b0f) --- compiler-rt/test/lit.common.cfg.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/compiler-rt/test/lit.common.cfg.py b/compiler-rt/test/lit.common.cfg.py index 6026c604ce496..cc4ef031108ec 100644 --- a/compiler-rt/test/lit.common.cfg.py +++ b/compiler-rt/test/lit.common.cfg.py @@ -538,7 +538,16 @@ def is_windows_lto_supported(): config.default_sanitizer_opts += ['abort_on_error=0'] config.default_sanitizer_opts += ['log_to_syslog=0'] if lit.util.which('log'): - config.available_features.add('darwin_log_cmd') + # Querying the log can only done by a privileged user so + # so check if we can query the log. + exit_code = -1 + with open('/dev/null', 'r') as f: + # Run a `log show` command the should finish fairly quickly and produce very little output. + exit_code = subprocess.call(['log', 'show', '--last', '1m', '--predicate', '1 == 0'], stdout=f, stderr=f) + if exit_code == 0: + config.available_features.add('darwin_log_cmd') + else: + lit_config.warning('log command found but cannot queried') else: lit_config.warning('log command not found. Some tests will be skipped.') elif config.android: From 3aeec0ab3a21dca883ba04d8c96275c65213c0f0 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Fri, 27 Mar 2020 12:31:49 -0700 Subject: [PATCH 109/286] [lldb/PlatformMacOSX] Re-implement GetDeveloperDirectory GetDeveloperDirectory returns a const char* which is NULL when we cannot find the developer directory. This crashes in PlatformDarwinKernel::CollectKextAndKernelDirectories because we're unconditionally assigning it to a std::string. Coincidentally I just refactored a bunch of code in PlatformMacOSX so instead of a ad-hoc fix I've reimplemented the method based on GetXcodeContentsDirectory. The change is mostly NFC. Obviously it fixes the crash, but it also removes support for finding the Xcode directory through he legacy $XCODE_SELECT_PREFIX_DIR/usr/share/xcode-select/xcode_dir_path. Differential revision: https://reviews.llvm.org/D76938 (cherry picked from commit 457eb05db67d201f34920e762a90d0deb670becb) --- .../MacOSX/PlatformAppleSimulator.cpp | 15 +-- .../MacOSX/PlatformAppleTVSimulator.cpp | 6 +- .../MacOSX/PlatformAppleWatchSimulator.cpp | 6 +- .../Platform/MacOSX/PlatformDarwin.cpp | 95 +++---------------- .../Plugins/Platform/MacOSX/PlatformDarwin.h | 3 +- .../Platform/MacOSX/PlatformDarwinKernel.cpp | 2 +- .../MacOSX/PlatformRemoteDarwinDevice.cpp | 5 +- .../Platform/MacOSX/PlatformiOSSimulator.cpp | 6 +- 8 files changed, 33 insertions(+), 105 deletions(-) diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp index 12a63f0aacb77..082890f8571b3 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp @@ -77,9 +77,10 @@ void PlatformAppleSimulator::GetStatus(Stream &strm) { // simulator PlatformAppleSimulator::LoadCoreSimulator(); + std::string developer_dir = GetXcodeDeveloperDirectory().GetPath(); CoreSimulatorSupport::DeviceSet devices = CoreSimulatorSupport::DeviceSet::GetAvailableDevices( - GetDeveloperDirectory()); + developer_dir.c_str()); const size_t num_devices = devices.GetNumDevices(); if (num_devices) { strm.Printf("Available devices:\n"); @@ -123,9 +124,10 @@ Status PlatformAppleSimulator::ConnectRemote(Args &args) { const char *arg_cstr = args.GetArgumentAtIndex(0); if (arg_cstr) { std::string arg_str(arg_cstr); + std::string developer_dir = GetXcodeDeveloperDirectory().GetPath(); CoreSimulatorSupport::DeviceSet devices = CoreSimulatorSupport::DeviceSet::GetAvailableDevices( - GetDeveloperDirectory()); + developer_dir.c_str()); devices.ForEach( [this, &arg_str](const CoreSimulatorSupport::Device &device) -> bool { if (arg_str == device.GetUDID() || arg_str == device.GetName()) { @@ -212,12 +214,12 @@ FileSpec PlatformAppleSimulator::GetCoreSimulatorPath() { #if defined(__APPLE__) std::lock_guard guard(m_core_sim_path_mutex); if (!m_core_simulator_framework_path.hasValue()) { - const char *developer_dir = GetDeveloperDirectory(); - if (developer_dir) { + if (FileSpec fspec = GetXcodeDeveloperDirectory()) { + std::string developer_dir = fspec.GetPath(); StreamString cs_path; cs_path.Printf( "%s/Library/PrivateFrameworks/CoreSimulator.framework/CoreSimulator", - developer_dir); + developer_dir.c_str()); m_core_simulator_framework_path = FileSpec(cs_path.GetData()); FileSystem::Instance().Resolve(*m_core_simulator_framework_path); } @@ -245,8 +247,9 @@ CoreSimulatorSupport::Device PlatformAppleSimulator::GetSimulatorDevice() { if (!m_device.hasValue()) { const CoreSimulatorSupport::DeviceType::ProductFamilyID dev_id = CoreSimulatorSupport::DeviceType::ProductFamilyID::iPhone; + std::string developer_dir = GetXcodeDeveloperDirectory().GetPath(); m_device = CoreSimulatorSupport::DeviceSet::GetAvailableDevices( - GetDeveloperDirectory()) + developer_dir.c_str()) .GetFanciest(dev_id); } diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.cpp index 08a5b084cb1ad..5869d39bb1f98 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.cpp @@ -255,14 +255,14 @@ EnumerateDirectoryCallback(void *baton, llvm::sys::fs::file_type ft, const char *PlatformAppleTVSimulator::GetSDKDirectoryAsCString() { std::lock_guard guard(m_sdk_dir_mutex); if (m_sdk_directory.empty()) { - const char *developer_dir = GetDeveloperDirectory(); - if (developer_dir) { + if (FileSpec fspec = GetXcodeDeveloperDirectory()) { + std::string developer_dir = fspec.GetPath(); char sdks_directory[PATH_MAX]; char sdk_dirname[PATH_MAX]; sdk_dirname[0] = '\0'; snprintf(sdks_directory, sizeof(sdks_directory), "%s/Platforms/AppleTVSimulator.platform/Developer/SDKs", - developer_dir); + developer_dir.c_str()); FileSpec simulator_sdk_spec; bool find_directories = true; bool find_files = false; diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.cpp index 65ee668b47849..8fb279bcf1c99 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.cpp @@ -255,14 +255,14 @@ EnumerateDirectoryCallback(void *baton, llvm::sys::fs::file_type ft, const char *PlatformAppleWatchSimulator::GetSDKDirectoryAsCString() { std::lock_guard guard(m_sdk_dir_mutex); if (m_sdk_directory.empty()) { - const char *developer_dir = GetDeveloperDirectory(); - if (developer_dir) { + if (FileSpec fspec = GetXcodeDeveloperDirectory()) { + std::string developer_dir = fspec.GetPath(); char sdks_directory[PATH_MAX]; char sdk_dirname[PATH_MAX]; sdk_dirname[0] = '\0'; snprintf(sdks_directory, sizeof(sdks_directory), "%s/Platforms/AppleWatchSimulator.platform/Developer/SDKs", - developer_dir); + developer_dir.c_str()); FileSpec simulator_sdk_spec; bool find_directories = true; bool find_files = false; diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp index 0347bde7d23d2..a734bfc39d1ea 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp @@ -48,9 +48,7 @@ using namespace lldb; using namespace lldb_private; /// Default Constructor -PlatformDarwin::PlatformDarwin(bool is_host) - : PlatformPOSIX(is_host), // This is the local host platform - m_developer_directory() {} +PlatformDarwin::PlatformDarwin(bool is_host) : PlatformPOSIX(is_host) {} /// Destructor. /// @@ -1135,88 +1133,17 @@ static FileSpec GetXcodeSelectPath() { return g_xcode_select_filespec; } -// Return a directory path like /Applications/Xcode.app/Contents/Developer -const char *PlatformDarwin::GetDeveloperDirectory() { - std::lock_guard guard(m_mutex); - if (m_developer_directory.empty()) { - bool developer_dir_path_valid = false; - char developer_dir_path[PATH_MAX]; - - // Get the lldb framework's file path, and if it exists, truncate some - // components to only the developer directory path. - FileSpec temp_file_spec = HostInfo::GetShlibDir(); - if (temp_file_spec) { - if (temp_file_spec.GetPath(developer_dir_path, - sizeof(developer_dir_path))) { - // e.g. - // /Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework - char *shared_frameworks = - strstr(developer_dir_path, "/SharedFrameworks/LLDB.framework"); - if (shared_frameworks) { - shared_frameworks[0] = '\0'; // truncate developer_dir_path at this point - strncat (developer_dir_path, "/Developer", sizeof (developer_dir_path) - 1); // add /Developer on - developer_dir_path_valid = true; - } else { - // e.g. - // /Applications/Xcode.app/Contents/Developer/Toolchains/iOS11.2.xctoolchain/System/Library/PrivateFrameworks/LLDB.framework - char *developer_toolchains = - strstr(developer_dir_path, "/Contents/Developer/Toolchains/"); - if (developer_toolchains) { - developer_toolchains += sizeof ("/Contents/Developer") - 1; - developer_toolchains[0] = '\0'; // truncate developer_dir_path at this point - developer_dir_path_valid = true; - } - } - } - } - - if (!developer_dir_path_valid) { - std::string xcode_dir_path; - const char *xcode_select_prefix_dir = getenv("XCODE_SELECT_PREFIX_DIR"); - if (xcode_select_prefix_dir) - xcode_dir_path.append(xcode_select_prefix_dir); - xcode_dir_path.append("/usr/share/xcode-select/xcode_dir_path"); - temp_file_spec.SetFile(xcode_dir_path, FileSpec::Style::native); - auto dir_buffer = - FileSystem::Instance().CreateDataBuffer(temp_file_spec.GetPath()); - if (dir_buffer && dir_buffer->GetByteSize() > 0) { - llvm::StringRef path_ref(dir_buffer->GetChars()); - // Trim tailing newlines and make sure there is enough room for a null - // terminator. - path_ref = - path_ref.rtrim("\r\n").take_front(sizeof(developer_dir_path) - 1); - ::memcpy(developer_dir_path, path_ref.data(), path_ref.size()); - developer_dir_path[path_ref.size()] = '\0'; - developer_dir_path_valid = true; - } - } - - if (!developer_dir_path_valid) { - FileSpec devel_dir = GetXcodeSelectPath(); - if (FileSystem::Instance().IsDirectory(devel_dir)) { - devel_dir.GetPath(&developer_dir_path[0], sizeof(developer_dir_path)); - developer_dir_path_valid = true; - } - } - - if (developer_dir_path_valid) { - temp_file_spec.SetFile(developer_dir_path, FileSpec::Style::native); - if (FileSystem::Instance().Exists(temp_file_spec)) { - m_developer_directory.assign(developer_dir_path); - return m_developer_directory.c_str(); - } +lldb_private::FileSpec PlatformDarwin::GetXcodeDeveloperDirectory() { + static lldb_private::FileSpec g_developer_directory; + static llvm::once_flag g_once_flag; + llvm::call_once(g_once_flag, []() { + if (FileSpec fspec = GetXcodeContentsDirectory()) { + fspec.AppendPathComponent("Developer"); + if (FileSystem::Instance().Exists(fspec)) + g_developer_directory = fspec; } - // Assign a single NULL character so we know we tried to find the device - // support directory and we don't keep trying to find it over and over. - m_developer_directory.assign(1, '\0'); - } - - // We should have put a single NULL character into m_developer_directory or - // it should have a valid path if the code gets here - assert(m_developer_directory.empty() == false); - if (m_developer_directory[0]) - return m_developer_directory.c_str(); - return nullptr; + }); + return g_developer_directory; } BreakpointSP PlatformDarwin::SetThreadCreationBreakpoint(Target &target) { diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h index 66feeb95602c3..d1b960d2d5535 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h @@ -105,6 +105,7 @@ class PlatformDarwin : public PlatformPOSIX { static llvm::StringRef GetSDKNameForType(SDKType type); static lldb_private::FileSpec GetXcodeSDK(SDKType type); static lldb_private::FileSpec GetXcodeContentsDirectory(); + static lldb_private::FileSpec GetXcodeDeveloperDirectory(); /// Return the toolchain directroy the current LLDB instance is located in. static lldb_private::FileSpec GetCurrentToolchainDirectory(); @@ -177,7 +178,6 @@ class PlatformDarwin : public PlatformPOSIX { std::vector &options, SDKType sdk_type); - const char *GetDeveloperDirectory(); lldb_private::Status FindBundleBinaryInExecSearchPaths( const lldb_private::ModuleSpec &module_spec, @@ -189,7 +189,6 @@ class PlatformDarwin : public PlatformPOSIX { llvm::StringRef component); static std::string FindXcodeContentsDirectoryInPath(llvm::StringRef path); - std::string m_developer_directory; private: DISALLOW_COPY_AND_ASSIGN(PlatformDarwin); diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp index 7ca5397595c9e..e12d8a96adda5 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp @@ -328,7 +328,7 @@ void PlatformDarwinKernel::CollectKextAndKernelDirectories() { // DeveloperDirectory is something like // "/Applications/Xcode.app/Contents/Developer" - std::string developer_dir = GetDeveloperDirectory(); + std::string developer_dir = GetXcodeDeveloperDirectory().GetPath(); if (developer_dir.empty()) developer_dir = "/Applications/Xcode.app/Contents/Developer"; diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp index 0aa129c808d43..d13ed3a709fb1 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp @@ -342,9 +342,8 @@ PlatformRemoteDarwinDevice::GetSDKDirectoryForLatestOSVersion() { const char *PlatformRemoteDarwinDevice::GetDeviceSupportDirectory() { std::string platform_dir = "/Platforms/" + GetPlatformName() + "/DeviceSupport"; if (m_device_support_directory.empty()) { - const char *device_support_dir = GetDeveloperDirectory(); - if (device_support_dir) { - m_device_support_directory.assign(device_support_dir); + if (FileSpec fspec = GetXcodeDeveloperDirectory()) { + m_device_support_directory = fspec.GetPath(); m_device_support_directory.append(platform_dir.c_str()); } else { // Assign a single NULL character so we know we tried to find the device diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp index f9a7e2061003d..fc8243ea26aa2 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.cpp @@ -261,14 +261,14 @@ EnumerateDirectoryCallback(void *baton, llvm::sys::fs::file_type ft, const char *PlatformiOSSimulator::GetSDKDirectoryAsCString() { std::lock_guard guard(m_sdk_dir_mutex); if (m_sdk_directory.empty()) { - const char *developer_dir = GetDeveloperDirectory(); - if (developer_dir) { + if (FileSpec fspec = GetXcodeDeveloperDirectory()) { + std::string developer_dir = fspec.GetPath(); char sdks_directory[PATH_MAX]; char sdk_dirname[PATH_MAX]; sdk_dirname[0] = '\0'; snprintf(sdks_directory, sizeof(sdks_directory), "%s/Platforms/iPhoneSimulator.platform/Developer/SDKs", - developer_dir); + developer_dir.c_str()); FileSpec simulator_sdk_spec; bool find_directories = true; bool find_files = false; From 68be76b0515ffbda1f5d639cb42b482154f3babf Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Sat, 28 Mar 2020 15:25:24 -0700 Subject: [PATCH 110/286] [lldb] NFC: Update call to performNameBinding --- .../Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp index ce0d19594859b..01dc72e12f924 100644 --- a/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp +++ b/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp @@ -1326,7 +1326,7 @@ static llvm::Expected ParseAndImport( stack_frame_sp.reset(); } - swift::performNameBinding(*source_file); + swift::performImportResolution(*source_file); if (swift_ast_context->HasErrors()) return make_error(); From 84154566c10cadde4e0dc8d8995632fde2c28109 Mon Sep 17 00:00:00 2001 From: Fred Riss Date: Sun, 29 Mar 2020 09:15:39 -0700 Subject: [PATCH 111/286] [lldb/test] Fix Swift testsuite environemnt We have tried chaging `LLDB_SWIFT_LIBS` in `test/API/CMakelists.txt` before to point it to a directory that actually contains the just built runtime libraries. Unfortunately, `LLDB_SWIFT_LIBS` is a cache variable that gets passed by `build-script`, so this change has no effect. Instead, add `macosx` to the uses of the variable. For `LD_LIBRARY_PATH`, which is used on non-darwin systems, use `CMAKE_SYSTEM_PROCESSOR` instead which is what the Swift test code seems to be doing. This also fixed the same issue in the Shell tests. --- lldb/test/API/CMakeLists.txt | 8 ++++---- lldb/test/Shell/lit-lldb-init.in | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lldb/test/API/CMakeLists.txt b/lldb/test/API/CMakeLists.txt index e08a377e4f463..44bd39c41c071 100644 --- a/lldb/test/API/CMakeLists.txt +++ b/lldb/test/API/CMakeLists.txt @@ -31,12 +31,12 @@ option(LLDB_TEST_SWIFT "Use in-tree swift when testing lldb" On) if(LLDB_TEST_SWIFT) set(LLDB_SWIFTC ${SWIFT_BINARY_DIR}/bin/swiftc CACHE STRING "Path to swift compiler") - set(LLDB_SWIFT_LIBS ${SWIFT_LIBRARY_DIR}/swift/macosx CACHE STRING "Path to swift libraries") + set(LLDB_SWIFT_LIBS ${SWIFT_LIBRARY_DIR}/swift CACHE STRING "Path to swift libraries") set(SWIFT_TEST_ARGS --swift-compiler ${LLDB_SWIFTC} - --inferior-env "DYLD_LIBRARY_PATH=\\\"${LLDB_SWIFT_LIBS}\\\"" - --inferior-env "LD_LIBRARY_PATH=\\\"${LLDB_SWIFT_LIBS}\\\"" - --inferior-env "SIMCTL_CHILD_DYLD_LIBRARY_PATH=\\\"${LLDB_SWIFT_LIBS}\\\"" + --inferior-env "DYLD_LIBRARY_PATH=\\\"${LLDB_SWIFT_LIBS}/macosx\\\"" + --inferior-env "LD_LIBRARY_PATH=\\\"${LLDB_SWIFT_LIBS}/${CMAKE_SYSTEM_PROCESSOR}\\\"" + --inferior-env "SIMCTL_CHILD_DYLD_LIBRARY_PATH=\\\"${LLDB_SWIFT_LIBS}/macosx\\\"" ) endif() # END - Swift Mods diff --git a/lldb/test/Shell/lit-lldb-init.in b/lldb/test/Shell/lit-lldb-init.in index 77871a404b88e..c0c52b368f515 100644 --- a/lldb/test/Shell/lit-lldb-init.in +++ b/lldb/test/Shell/lit-lldb-init.in @@ -1,5 +1,5 @@ # LLDB init file for the LIT tests. -env DYLD_LIBRARY_PATH='@LLDB_SWIFT_LIBS@' LD_LIBRARY_PATH='@LLDB_SWIFT_LIBS@' SIMCTL_CHILD_DYLD_LIBRARY_PATH='@LLDB_SWIFT_LIBS@' +env DYLD_LIBRARY_PATH='@LLDB_SWIFT_LIBS@/macosx' LD_LIBRARY_PATH='@LLDB_SWIFT_LIBS@/@CMAKE_SYSTEM_PROCESSOR@' SIMCTL_CHILD_DYLD_LIBRARY_PATH='@LLDB_SWIFT_LIBS@/macosx' settings set symbols.enable-external-lookup false settings set plugin.process.gdb-remote.packet-timeout 60 settings set interpreter.echo-comment-commands false From 6c69033a25e5d52c1d678bc6d0c7a914a4f48327 Mon Sep 17 00:00:00 2001 From: Chris Jackson Date: Mon, 30 Mar 2020 14:18:01 +0100 Subject: [PATCH 112/286] [DebugInfo] Ensure dead store elimination can mark an operand value as undefined - Correct a debug info salvage and add a test Reviewers: aprantl, vsk Differential Revision: https://reviews.llvm.org/D76930 Bugzilla: https://bugs.llvm.org/show_bug.cgi?id=45080 (cherry picked from commit 135709aa9013565b9d02000bb0ca744f7585e6a5) --- .../Scalar/DeadStoreElimination.cpp | 2 +- .../X86/dead-store-elimination-marks-undef.ll | 36 +++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 llvm/test/DebugInfo/X86/dead-store-elimination-marks-undef.ll diff --git a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp index 8da1f560f7b97..d4b4c193ca009 100644 --- a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp +++ b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp @@ -144,7 +144,7 @@ deleteDeadInstruction(Instruction *I, BasicBlock::iterator *BBI, ++NumFastOther; // Try to preserve debug information attached to the dead instruction. - salvageDebugInfo(*DeadInst); + salvageDebugInfoOrMarkUndef(*DeadInst); // This instruction is dead, zap it, in stages. Start by removing it from // MemDep, which needs to know the operands and needs it to be in the diff --git a/llvm/test/DebugInfo/X86/dead-store-elimination-marks-undef.ll b/llvm/test/DebugInfo/X86/dead-store-elimination-marks-undef.ll new file mode 100644 index 0000000000000..5f9e67653d966 --- /dev/null +++ b/llvm/test/DebugInfo/X86/dead-store-elimination-marks-undef.ll @@ -0,0 +1,36 @@ +; RUN: opt -mtriple=x86_64-- -S --dse %s -o - | FileCheck %s +; Ensure that we can mark a value as undefined when performing dead +; store elimination. +; Bugzilla #45080 + +@b = common dso_local local_unnamed_addr global i32 0, align 1 + +define dso_local i32 @main() local_unnamed_addr !dbg !7 { + %1 = alloca i32, align 4 + %2 = load i32, i32* @b, align 1, !dbg !13 + ; CHECK: call void @llvm.dbg.value(metadata i32 undef + call void @llvm.dbg.value(metadata i32 %2, metadata !12, metadata !DIExpression()), !dbg !13 + store i32 %2, i32* %1, align 4, !dbg !13 + ret i32 0, !dbg !13 +} + +declare void @llvm.dbg.value(metadata, metadata, metadata) + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 10.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, globals: !2, nameTableKind: None) +!1 = !DIFile(filename: "dead-store-elimination-marks-undef.ll", directory: "/temp/bz45080") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!6 = !{!"clang version 10.0.0"} +!7 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 3, type: !8, scopeLine: 3, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11) +!8 = !DISubroutineType(types: !9) +!9 = !{!10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !{!12} +!12 = !DILocalVariable(name: "l_2864", scope: !7, file: !1, line: 4, type: !10) +!13 = !DILocation(line: 5, column: 12, scope: !7) + From d9ba731d5690af0b550d32eceac7683b5028cfac Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Mon, 30 Mar 2020 10:02:21 -0700 Subject: [PATCH 113/286] [LoopVectorize] Fix crash on "getNoopOrZeroExtend cannot truncate!" (PR45259) In InnerLoopVectorizer::getOrCreateTripCount, when the backedge taken count is a SCEV add expression, its type is defined by the type of the last operand of the add expression. In the test case from PR45259, this last operand happens to be a pointer, which (according to llvm::Type) does not have a primitive size in bits. In this case, LoopVectorize fails to truncate the SCEV and crashes as a result. Uing ScalarEvolution::getTypeSizeInBits makes the truncation work as expected. https://bugs.llvm.org/show_bug.cgi?id=45259 Differential Revision: https://reviews.llvm.org/D76669 (cherry picked from commit dcc410b5cf202e354105df431fad62d2f5f7eac7) --- .../Transforms/Vectorize/LoopVectorize.cpp | 2 +- llvm/test/Transforms/LoopVectorize/pr45259.ll | 36 +++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 llvm/test/Transforms/LoopVectorize/pr45259.ll diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp index dba4aa42b3781..e7c79e55e82a2 100644 --- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp +++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp @@ -2579,7 +2579,7 @@ Value *InnerLoopVectorizer::getOrCreateTripCount(Loop *L) { // compare. The only way that we get a backedge taken count is that the // induction variable was signed and as such will not overflow. In such a case // truncation is legal. - if (BackedgeTakenCount->getType()->getPrimitiveSizeInBits() > + if (SE->getTypeSizeInBits(BackedgeTakenCount->getType()) > IdxTy->getPrimitiveSizeInBits()) BackedgeTakenCount = SE->getTruncateOrNoop(BackedgeTakenCount, IdxTy); BackedgeTakenCount = SE->getNoopOrZeroExtend(BackedgeTakenCount, IdxTy); diff --git a/llvm/test/Transforms/LoopVectorize/pr45259.ll b/llvm/test/Transforms/LoopVectorize/pr45259.ll new file mode 100644 index 0000000000000..3d1370b14a0f4 --- /dev/null +++ b/llvm/test/Transforms/LoopVectorize/pr45259.ll @@ -0,0 +1,36 @@ +; RUN: opt < %s -S -loop-vectorize -force-vector-width=4 -force-vector-interleave=1 | FileCheck %s + +; Check that we can vectorize this loop without crashing. + +; CHECK-LABEL: define {{.*}} @widget( +; CHECK: [[vecInd:%.*]] = phi <4 x i8> [ +; CHECK-NEXT: add <4 x i8> [[vecInd]], + +define i8 @widget(i8* %arr, i8 %t9) { +bb: + br label %bb6 + +bb6: + %t1.0 = phi i8* [ %arr, %bb ], [ null, %bb6 ] + %c = call i1 @cond() + br i1 %c, label %for.preheader, label %bb6 + +for.preheader: + br label %for.body + +for.body: + %iv = phi i8 [ %iv.next, %for.body ], [ 0, %for.preheader ] + %iv.next = add i8 %iv, 1 + %ptr = getelementptr inbounds i8, i8* %arr, i8 %iv.next + %t3.i = icmp slt i8 %iv.next, %t9 + %t3.i8 = zext i1 %t3.i to i8 + store i8 %t3.i8, i8* %ptr + %ec = icmp eq i8* %t1.0, %ptr + br i1 %ec, label %for.exit, label %for.body + +for.exit: + %iv.next.lcssa = phi i8 [ %iv.next, %for.body ] + ret i8 %iv.next.lcssa +} + +declare i1 @cond() From 4554055718219822c015909a9e26501612442fb1 Mon Sep 17 00:00:00 2001 From: shafik Date: Fri, 27 Mar 2020 11:00:24 -0700 Subject: [PATCH 114/286] [LLDB] Fix handling of bit-fields when there is a base class when parsing DWARF When parsing DWARF and laying out bit-fields we currently don't take into account whether we have a base class or not. Currently if the first field is a bit-field but the bit offset is due a field we inherit from a base class we currently treat it as an unnamed bit-field and therefore add an extra field. This fix will not check if we have a base class and assume that this offset is due to members we are inheriting from the base. We are currently seeing asserts during codegen when debugging clang::DiagnosticOptions. This assumption will fail in the case where the first field in the derived class in an unnamed bit-field. Fixing the first field being an unnamed bit-field looks like it will require a larger change since we will need a way to track or discover the last field offset of the bases(s). Differential Revision: https://reviews.llvm.org/D76808 (cherry picked from commit 00c8120acbac3430c3594c5b6ca3527ef9c1afca) --- .../SymbolFile/DWARF/DWARFASTParserClang.cpp | 14 ++++++++++++-- .../API/lang/cpp/bitfields/TestCppBitfields.py | 7 +++++++ lldb/test/API/lang/cpp/bitfields/main.cpp | 12 ++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index e844f331acdc5..a8d177696427e 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -2720,9 +2720,19 @@ void DWARFASTParserClang::ParseSingleMember( } // If we have a gap between the last_field_end and the current - // field we have an unnamed bit-field + // field we have an unnamed bit-field. + // If we have a base class, we assume there is no unnamed + // bit-field if this is the first field since the gap can be + // attributed to the members from the base class. This assumption + // is not correct if the first field of the derived class is + // indeed an unnamed bit-field. We currently do not have the + // machinary to track the offset of the last field of classes we + // have seen before, so we are not handling this case. if (this_field_info.bit_offset != last_field_end && - !(this_field_info.bit_offset < last_field_end)) { + this_field_info.bit_offset > last_field_end && + !(last_field_info.bit_offset == 0 && + last_field_info.bit_size == 0 && + layout_info.base_offsets.size() != 0)) { unnamed_field_info = FieldInfo{}; unnamed_field_info->bit_size = this_field_info.bit_offset - last_field_end; diff --git a/lldb/test/API/lang/cpp/bitfields/TestCppBitfields.py b/lldb/test/API/lang/cpp/bitfields/TestCppBitfields.py index 1b362e6b04f93..7320ce2b816ec 100644 --- a/lldb/test/API/lang/cpp/bitfields/TestCppBitfields.py +++ b/lldb/test/API/lang/cpp/bitfields/TestCppBitfields.py @@ -103,3 +103,10 @@ def test_and_run_command(self): '(uint64_t:1) k = 1', ]) + self.expect( + "frame variable --show-types derived", + VARIABLES_DISPLAYED_CORRECTLY, + substrs=[ + '(uint32_t) b_a = 2', + '(uint32_t:1) d_a = 1', + ]) diff --git a/lldb/test/API/lang/cpp/bitfields/main.cpp b/lldb/test/API/lang/cpp/bitfields/main.cpp index e43bf8c138e9b..986b7cb947ed0 100644 --- a/lldb/test/API/lang/cpp/bitfields/main.cpp +++ b/lldb/test/API/lang/cpp/bitfields/main.cpp @@ -60,6 +60,16 @@ int main(int argc, char const *argv[]) { } } clang_example; + class B { + public: + uint32_t b_a; + }; + + class D : public B { + public: + uint32_t d_a : 1; + } derived; + lba.a = 2; lbb.a = 1; @@ -76,6 +86,8 @@ int main(int argc, char const *argv[]) { lbd.arr[2] = '\0'; lbd.a = 5; + derived.b_a = 2; + derived.d_a = 1; return 0; // Set break point at this line. } From 491cf94b980ab275a82165fd3a3422a167e732dc Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Mon, 30 Mar 2020 11:34:55 -0700 Subject: [PATCH 115/286] [lldb/CMake] Make check-lldb-* work for the standalone build. In order to run check-lldb-* we need the correct map_config directives in llvm-lit. For the standalone build, LLVM doesn't know about LLDB, and the lldb mappings are missing. In that case we build our own llvm-lit, and tell LLVM to use the llvm-lit in the lldb build directory. Differential revision: https://reviews.llvm.org/D76945 (cherry picked from commit 63aaecd5bebc8cf2cd4b4f2b42183978fd30ddef) --- lldb/test/CMakeLists.txt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lldb/test/CMakeLists.txt b/lldb/test/CMakeLists.txt index 21a0ca47b716b..a5c861f0536d4 100644 --- a/lldb/test/CMakeLists.txt +++ b/lldb/test/CMakeLists.txt @@ -1,6 +1,16 @@ # Test runner infrastructure for LLDB. This configures the LLDB test trees # for use by Lit, and delegates to LLVM's lit test handlers. +if(LLDB_BUILT_STANDALONE) + # In order to run check-lldb-* we need the correct map_config directives in + # llvm-lit. Because this is a standalone build, LLVM doesn't know about LLDB, + # and the lldb mappings are missing. We build our own llvm-lit, and tell LLVM + # to use the llvm-lit in the lldb build directory. + if (EXISTS ${LLVM_MAIN_SRC_DIR}/utils/llvm-lit) + set(LLVM_EXTERNAL_LIT ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/llvm-lit) + endif() +endif() + # Configure the build directory. set(LLDB_TEST_BUILD_DIRECTORY "${PROJECT_BINARY_DIR}/lldb-test-build.noindex" CACHE PATH "The build root for building tests.") @@ -179,3 +189,10 @@ add_custom_target(check-lldb) add_dependencies(check-lldb lldb-test-deps) set_target_properties(check-lldb PROPERTIES FOLDER "lldb misc") add_dependencies(check-lldb check-lldb-lit) + +if(LLDB_BUILT_STANDALONE) + # This has to happen *AFTER* add_lit_testsuite. + if (EXISTS ${LLVM_MAIN_SRC_DIR}/utils/llvm-lit) + add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/llvm-lit ${CMAKE_CURRENT_BINARY_DIR}/llvm-lit) + endif() +endif() From 564d7067f9d27ee7b06c6ae57f20109619c46cfb Mon Sep 17 00:00:00 2001 From: shafik Date: Fri, 27 Mar 2020 14:12:38 -0700 Subject: [PATCH 116/286] [LLDB] CPlusPlusNameParser does not handles templated operator< properly CPlusPlusNameParser is used in several places on of them is during IR execution and setting breakpoints to pull information C++ like the basename, the context and arguments. Currently it does not handle templated operator< properly, because of idiosyncrasy is how clang generates debug info for these cases. It uses clang::Lexer which will tokenize operator< into: tok::kw_operator tok::lessless tok::raw_identifier Later on the parser in ConsumeOperator() does not handle this case properly and we end up failing to parse. Differential Revision: https://reviews.llvm.org/D76168 (cherry picked from commit 8016d61e3cf4967dd28c8f6296cec685dadcaee6) --- .../CPlusPlus/CPlusPlusNameParser.cpp | 31 +++++++++++++++++++ .../CPlusPlus/CPlusPlusLanguageTest.cpp | 22 ++++++++++--- 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp index 932db17b964a5..6048c08d74823 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp @@ -329,6 +329,37 @@ bool CPlusPlusNameParser::ConsumeOperator() { } const auto &token = Peek(); + + // When clang generates debug info it adds template parameters to names. + // Since clang doesn't add a space between the name and the template parameter + // in some cases we are not generating valid C++ names e.g.: + // + // operator< + // + // In some of these cases we will not parse them correctly. This fixes the + // issue by detecting this case and inserting tok::less in place of + // tok::lessless and returning successfully that we consumed the operator. + if (token.getKind() == tok::lessless) { + // Make sure we have more tokens before attempting to look ahead one more. + if (m_next_token_index + 1 < m_tokens.size()) { + // Look ahead two tokens. + clang::Token n_token = m_tokens[m_next_token_index + 1]; + // If we find ( or < then this is indeed operator<< no need for fix. + if (n_token.getKind() != tok::l_paren && n_token.getKind() != tok::less) { + clang::Token tmp_tok; + + tmp_tok.setLength(1); + tmp_tok.setLocation(token.getLocation().getLocWithOffset(1)); + tmp_tok.setKind(tok::less); + + m_tokens[m_next_token_index] = tmp_tok; + + start_position.Remove(); + return true; + } + } + } + switch (token.getKind()) { case tok::kw_new: case tok::kw_delete: diff --git a/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp b/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp index deb6c7d54ea9f..acac55b7f3bfa 100644 --- a/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp +++ b/lldb/unittests/Language/CPlusPlus/CPlusPlusLanguageTest.cpp @@ -140,12 +140,20 @@ TEST(CPlusPlusLanguage, ExtractContextAndIdentifier) { "std::vector>", "_M_emplace_back_aux"}, {"`anonymous namespace'::foo", "`anonymous namespace'", "foo"}, - {"`operator<'::`2'::B<0>::operator>", - "`operator<'::`2'::B<0>", + {"`operator<'::`2'::B<0>::operator>", "`operator<'::`2'::B<0>", "operator>"}, {"`anonymous namespace'::S::<<::__l2::Foo", - "`anonymous namespace'::S::<<::__l2", - "Foo"}}; + "`anonymous namespace'::S::<<::__l2", "Foo"}, + // These cases are idiosyncratic in how clang generates debug info for + // names when we have template parameters. They are not valid C++ names + // but if we fix this we need to support them for older compilers. + {"A::operator>", "A", "operator>"}, + {"operator>", "", "operator>"}, + {"A::operator<", "A", "operator<"}, + {"operator<", "", "operator<"}, + {"A::operator<<", "A", "operator<<"}, + {"operator<<", "", "operator<<"}, + }; llvm::StringRef context, basename; for (const auto &test : test_cases) { @@ -169,6 +177,12 @@ TEST(CPlusPlusLanguage, ExtractContextAndIdentifier) { "abc::", context, basename)); EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier( "f>", context, basename)); + + // We expect these cases to fail until we turn on C++2a + EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier( + "A::operator<=>", context, basename)); + EXPECT_FALSE(CPlusPlusLanguage::ExtractContextAndIdentifier( + "operator<=>", context, basename)); } static std::set FindAlternate(llvm::StringRef Name) { From fbec4e2250713a6e82fc5e3d35ddb62187d8c065 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Mon, 30 Mar 2020 16:12:14 +0200 Subject: [PATCH 117/286] [LLDB] Initialize temporary token Found by msan. (cherry picked from commit 3806b38045c08c674dc5db65bb06cf3dc34b9cc7) --- lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp index 6048c08d74823..48f734731a651 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.cpp @@ -347,7 +347,7 @@ bool CPlusPlusNameParser::ConsumeOperator() { // If we find ( or < then this is indeed operator<< no need for fix. if (n_token.getKind() != tok::l_paren && n_token.getKind() != tok::less) { clang::Token tmp_tok; - + tmp_tok.startToken(); tmp_tok.setLength(1); tmp_tok.setLocation(token.getLocation().getLocWithOffset(1)); tmp_tok.setKind(tok::less); From 82cc7bd839ade54ad1120803a31c97b825ea656e Mon Sep 17 00:00:00 2001 From: Fred Riss Date: Mon, 20 Jan 2020 08:39:25 -0800 Subject: [PATCH 118/286] [lldb/DataFormatters] Fix the `$$deference$$` synthetic child Summary: The ValueObject code checks for a special `$$dereference$$` synthetic child to allow formatter providers to implement a natural dereferencing behavior in `frame variable` for objects like smart pointers. This support was broken when used directly throught the Python API and not trhough `frame variable`. The reason is that SBFrame.FindVariable() will return by default the synthetic variable if it exists, while `frame variable` will not do this eagerly. The code in `ValueObject::Dereference()` accounted for the latter but not for the former. The fix is trivial. The test change includes additional covergage for the already-working bahevior as it wasn't covered by the testsuite before. This commit also adds a short piece of documentatione explaining that it is possible (even advisable) to provide this synthetic child outstide of the range of the normal children. Reviewers: jingham Subscribers: lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D73053 (cherry picked from commit 0478eadf73c191199cba12c85785cfafb8bfa174) --- lldb/docs/use/variable.rst | 29 +++++++++++-- lldb/source/Core/ValueObject.cpp | 3 ++ .../TestDataFormatterPythonSynth.py | 42 +++++++++++++------ .../fooSynthProvider.py | 26 ++++++++++++ .../data-formatter-python-synth/main.cpp | 8 +++- 5 files changed, 91 insertions(+), 17 deletions(-) diff --git a/lldb/docs/use/variable.rst b/lldb/docs/use/variable.rst index f3bde2de4144d..00b384a368eb3 100644 --- a/lldb/docs/use/variable.rst +++ b/lldb/docs/use/variable.rst @@ -845,7 +845,7 @@ adheres to a given interface (the word is italicized because Python has no explicit notion of interface, by that word we mean a given set of methods must be implemented by the Python class): -:: +.. code-block:: python class SyntheticChildrenProvider: def __init__(self, valobj, internal_dict): @@ -882,9 +882,30 @@ As a shortcut for this, you can inherit from lldb.SBSyntheticValueProvider, and just define get_value as other methods are defaulted in the superclass as returning default no-children responses. -If a synthetic child provider supplies a special child named $$dereference$$ -then it will be used when evaluating opertaor* and operator-> in the frame -variable command and related SB API functions. +If a synthetic child provider supplies a special child named +``$$dereference$$`` then it will be used when evaluating ``operator *`` and +``operator ->`` in the frame variable command and related SB API +functions. It is possible to declare this synthetic child without +including it in the range of children displayed by LLDB. For example, +this subset of a synthetic children provider class would allow the +synthetic value to be dereferenced without actually showing any +synthtic children in the UI: + +.. code-block:: python + + class SyntheticChildrenProvider: + [...] + def num_children(self): + return 0 + def get_child_index(self, name): + if name == '$$dereference$$': + return 0 + return -1 + def get_child_at_index(self, index): + if index == 0: + return + return None + For examples of how synthetic children are created, you are encouraged to look at examples/synthetic in the LLDB trunk. Please, be aware that the code in diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index fcdd881dbc8d0..ee312d8d562dd 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -2859,6 +2859,9 @@ ValueObjectSP ValueObject::Dereference(Status &error) { GetSyntheticValue() ->GetChildMemberWithName(ConstString("$$dereference$$"), true) .get(); + } else if (IsSynthetic()) { + m_deref_valobj = + GetChildMemberWithName(ConstString("$$dereference$$"), true).get(); } if (m_deref_valobj) { diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-python-synth/TestDataFormatterPythonSynth.py b/lldb/test/API/functionalities/data-formatter/data-formatter-python-synth/TestDataFormatterPythonSynth.py index 5f908f76b0abc..9d4759100ce2e 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-python-synth/TestDataFormatterPythonSynth.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-python-synth/TestDataFormatterPythonSynth.py @@ -38,19 +38,9 @@ def setUp(self): def data_formatter_commands(self): """Test using Python synthetic children provider.""" - self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET) - - lldbutil.run_break_set_by_file_and_line( - self, "main.cpp", self.line, num_expected_locations=1, loc_exact=True) - - self.runCmd("run", RUN_SUCCEEDED) - - process = self.dbg.GetSelectedTarget().GetProcess() - # The stop reason of the thread should be breakpoint. - self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, - substrs=['stopped', - 'stop reason = breakpoint']) + _, process, thread, _ = lldbutil.run_to_line_breakpoint( + self, lldb.SBFileSpec("main.cpp"), self.line) # This is the function to remove the custom formats in order to have a # clean slate for the next test case. @@ -72,6 +62,7 @@ def cleanup(): # now set up the synth self.runCmd("script from fooSynthProvider import *") self.runCmd("type synth add -l fooSynthProvider foo") + self.runCmd("type synth add -l wrapfooSynthProvider wrapfoo") self.expect("type synthetic list foo", substrs=['fooSynthProvider']) # note that the value of fake_a depends on target byte order @@ -147,6 +138,10 @@ def cleanup(): substrs=['r = 45', 'fake_a = %d' % fake_a_val, 'a = 12']) + self.expect("frame variable --ptr-depth 1 wrapper", + substrs=['r = 45', + 'fake_a = %d' % fake_a_val, + 'a = 12']) # now add a filter.. it should fail self.expect("type filter add foo --child b --child j", error=True, @@ -160,9 +155,24 @@ def cleanup(): substrs=['r = 45', 'fake_a = %d' % fake_a_val, 'a = 12']) + self.expect("frame variable --ptr-depth 1 wrapper", + substrs=['r = 45', + 'fake_a = %d' % fake_a_val, + 'a = 12']) + + # Test that the custom dereference operator for `wrapfoo` works through + # the Python API. The synthetic children provider gets queried at + # slightly different times in this case. + wrapper_var = thread.GetSelectedFrame().FindVariable('wrapper') + foo_var = wrapper_var.Dereference() + self.assertEqual(foo_var.GetNumChildren(), 3) + self.assertEqual(foo_var.GetChildAtIndex(0).GetName(), 'a') + self.assertEqual(foo_var.GetChildAtIndex(1).GetName(), 'fake_a') + self.assertEqual(foo_var.GetChildAtIndex(2).GetName(), 'r') # now delete the synth and add the filter self.runCmd("type synth delete foo") + self.runCmd("type synth delete wrapfoo") self.runCmd("type filter add foo --child b --child j") self.expect('frame variable f00_1', @@ -172,6 +182,10 @@ def cleanup(): substrs=['r = 45', 'fake_a = %d' % fake_a_val, 'a = 12']) + self.expect("frame variable --ptr-depth 1 wrapper", matching=False, + substrs=['r = 45', + 'fake_a = %d' % fake_a_val, + 'a = 12']) # now add the synth and it should fail self.expect("type synth add -l fooSynthProvider foo", error=True, @@ -197,6 +211,10 @@ def cleanup(): substrs=['r = 45', 'fake_a = %d' % fake_a_val, 'a = 12']) + self.expect("frame variable --ptr-depth 1 wrapper", + substrs=['r = 45', + 'fake_a = %d' % fake_a_val, + 'a = 12']) # check the listing self.expect('type synth list', diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-python-synth/fooSynthProvider.py b/lldb/test/API/functionalities/data-formatter/data-formatter-python-synth/fooSynthProvider.py index 45fb00468e083..6ee749b720b2c 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-python-synth/fooSynthProvider.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-python-synth/fooSynthProvider.py @@ -28,3 +28,29 @@ def get_child_index(self, name): def update(self): return True + + +class wrapfooSynthProvider: + + def __init__(self, valobj, dict): + self.valobj = valobj + + def num_children(self): + return 1 + + def get_child_at_index(self, index): + if index == 0: + return self.valobj.GetChildMemberWithName('ptr') + if index == 1: + return self.valobj.GetChildMemberWithName('ptr').Dereference() + return None + + def get_child_index(self, name): + if name == 'ptr': + return 0 + if name == '$$dereference$$': + return 1 + return -1 + + def update(self): + return True diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-python-synth/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-python-synth/main.cpp index f45a2abfb9f1e..5cf4b63459271 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-python-synth/main.cpp +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-python-synth/main.cpp @@ -46,11 +46,17 @@ struct wrapint wrapint(int X) : x(X) {} }; +struct wrapfoo +{ + foo *ptr; +}; + int main() { foo f00_1(1); foo *f00_ptr = new foo(12); - + wrapfoo wrapper{f00_ptr}; + f00_1.a++; // Set break point at this line. wrapint test_cast('A' + From 62f58f5420d12cbbd2ed4675a2b77239e74d492c Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Fri, 20 Mar 2020 17:38:05 -0700 Subject: [PATCH 119/286] Move TypeSystemSwiftTypeRef into its own file. (NFC) --- lldb/include/lldb/Symbol/SwiftASTContext.h | 3 + lldb/source/Symbol/CMakeLists.txt | 1 + lldb/source/Symbol/SwiftASTContext.cpp | 490 ---------------- lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp | 530 ++++++++++++++++++ 4 files changed, 534 insertions(+), 490 deletions(-) create mode 100644 lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp diff --git a/lldb/include/lldb/Symbol/SwiftASTContext.h b/lldb/include/lldb/Symbol/SwiftASTContext.h index e2fe629459e95..9f507e4cbda30 100644 --- a/lldb/include/lldb/Symbol/SwiftASTContext.h +++ b/lldb/include/lldb/Symbol/SwiftASTContext.h @@ -20,6 +20,7 @@ #include "lldb/Core/ThreadSafeDenseSet.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Symbol/TypeSystem.h" +#include "lldb/Symbol/SymbolFile.h" #include "lldb/Utility/ConstString.h" #include "lldb/lldb-private.h" @@ -150,6 +151,7 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift { swift::CanType GetCanonicalSwiftType(CompilerType compiler_type); swift::Type GetSwiftType(CompilerType compiler_type); CompilerType ReconstructType(CompilerType type); + CompilerType GetTypeFromMangledTypename(ConstString mangled_typename); // PluginInterface functions ConstString GetPluginName() override; @@ -355,6 +357,7 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift { private: void *ReconstructType(void *type); + const char *AsMangledName(void *opaque_type); SwiftASTContext *m_swift_ast_context = nullptr; }; diff --git a/lldb/source/Symbol/CMakeLists.txt b/lldb/source/Symbol/CMakeLists.txt index 0abdefa860133..eae4fde445bf5 100644 --- a/lldb/source/Symbol/CMakeLists.txt +++ b/lldb/source/Symbol/CMakeLists.txt @@ -8,6 +8,7 @@ add_lldb_library(lldbSymbol ArmUnwindInfo.cpp Block.cpp TypeSystemClang.cpp + TypeSystemSwiftTypeRef.cpp ClangASTImporter.cpp ClangASTMetadata.cpp ClangExternalASTSourceCallbacks.cpp diff --git a/lldb/source/Symbol/SwiftASTContext.cpp b/lldb/source/Symbol/SwiftASTContext.cpp index 54925a74a5287..129a03de679a7 100644 --- a/lldb/source/Symbol/SwiftASTContext.cpp +++ b/lldb/source/Symbol/SwiftASTContext.cpp @@ -168,8 +168,6 @@ std::recursive_mutex g_log_mutex; using namespace lldb; using namespace lldb_private; -char TypeSystemSwift::ID; -char TypeSystemSwiftTypeRef::ID; char SwiftASTContext::ID; char SwiftASTContextForExpressions::ID; @@ -230,494 +228,6 @@ ConstString SwiftASTContext::GetMangledTypeName(void *type) { return GetMangledTypeName(GetSwiftType({this, type}).getPointer()); } -TypeSystemSwift::TypeSystemSwift() : TypeSystem() {} - -CompilerType TypeSystemSwift::GetInstanceType(CompilerType compiler_type) { - auto *ts = compiler_type.GetTypeSystem(); - if (auto *tr = llvm::dyn_cast_or_null(ts)) - return tr->GetInstanceType(compiler_type.GetOpaqueQualType()); - if (auto *ast = llvm::dyn_cast_or_null(ts)) - return ast->GetInstanceType(compiler_type.GetOpaqueQualType()); - return {}; -} - -TypeSystemSwiftTypeRef::TypeSystemSwiftTypeRef( - SwiftASTContext *swift_ast_context) - : m_swift_ast_context(swift_ast_context) { - m_description = "TypeSystemSwiftTypeRef"; -} - -void *TypeSystemSwiftTypeRef::ReconstructType(void *type) { - Status error; - return m_swift_ast_context->ReconstructType(GetMangledTypeName(type), error); -} - -CompilerType TypeSystemSwiftTypeRef::ReconstructType(CompilerType type) { - return {m_swift_ast_context, ReconstructType(type.GetOpaqueQualType())}; -} - -lldb::TypeSP TypeSystemSwiftTypeRef::GetCachedType(ConstString mangled) { - return m_swift_ast_context->GetCachedType(mangled); -} - -void TypeSystemSwiftTypeRef::SetCachedType(ConstString mangled, - const lldb::TypeSP &type_sp) { - return m_swift_ast_context->SetCachedType(mangled, type_sp); -} - -Module *TypeSystemSwiftTypeRef::GetModule() const { - return m_swift_ast_context->GetModule(); -} - -ConstString TypeSystemSwiftTypeRef::GetPluginName() { - return ConstString("TypeSystemSwiftTypeRef"); -} -uint32_t TypeSystemSwiftTypeRef::GetPluginVersion() { return 1; } - -bool TypeSystemSwiftTypeRef::SupportsLanguage(lldb::LanguageType language) { - return language == eLanguageTypeSwift; -} - -Status TypeSystemSwiftTypeRef::IsCompatible() { - return m_swift_ast_context->IsCompatible(); -} - -void TypeSystemSwiftTypeRef::DiagnoseWarnings(Process &process, - Module &module) const { - m_swift_ast_context->DiagnoseWarnings(process, module); -} -DWARFASTParser *TypeSystemSwiftTypeRef::GetDWARFParser() { - return m_swift_ast_context->GetDWARFParser(); -} -ConstString TypeSystemSwiftTypeRef::DeclContextGetName(void *opaque_decl_ctx) { - return m_swift_ast_context->DeclContextGetName(opaque_decl_ctx); -} -ConstString TypeSystemSwiftTypeRef::DeclContextGetScopeQualifiedName( - void *opaque_decl_ctx) { - return m_swift_ast_context->DeclContextGetScopeQualifiedName(opaque_decl_ctx); -} -bool TypeSystemSwiftTypeRef::DeclContextIsClassMethod( - void *opaque_decl_ctx, lldb::LanguageType *language_ptr, - bool *is_instance_method_ptr, ConstString *language_object_name_ptr) { - return m_swift_ast_context->DeclContextIsClassMethod( - opaque_decl_ctx, language_ptr, is_instance_method_ptr, - language_object_name_ptr); -} - -// Tests - -#ifndef NDEBUG -bool TypeSystemSwiftTypeRef::Verify(lldb::opaque_compiler_type_t type) { - if (!type) - return true; - - const char *str = reinterpret_cast(type); - return SwiftLanguageRuntime::IsSwiftMangledName(str); -} -#endif - -bool TypeSystemSwiftTypeRef::IsArrayType(void *type, CompilerType *element_type, - uint64_t *size, bool *is_incomplete) { - return m_swift_ast_context->IsArrayType(ReconstructType(type), element_type, - size, is_incomplete); -} -bool TypeSystemSwiftTypeRef::IsAggregateType(void *type) { - return m_swift_ast_context->IsAggregateType(ReconstructType(type)); -} -bool TypeSystemSwiftTypeRef::IsCharType(void *type) { - return m_swift_ast_context->IsCharType(ReconstructType(type)); -} -bool TypeSystemSwiftTypeRef::IsCompleteType(void *type) { - return m_swift_ast_context->IsCompleteType(ReconstructType(type)); -} -bool TypeSystemSwiftTypeRef::IsDefined(void *type) { - return m_swift_ast_context->IsDefined(ReconstructType(type)); -} -bool TypeSystemSwiftTypeRef::IsFloatingPointType(void *type, uint32_t &count, - bool &is_complex) { - return m_swift_ast_context->IsFloatingPointType(ReconstructType(type), count, - is_complex); -} -bool TypeSystemSwiftTypeRef::IsFunctionType(void *type, bool *is_variadic_ptr) { - return m_swift_ast_context->IsFunctionType(ReconstructType(type), - is_variadic_ptr); -} -size_t TypeSystemSwiftTypeRef::GetNumberOfFunctionArguments(void *type) { - return m_swift_ast_context->GetNumberOfFunctionArguments( - ReconstructType(type)); -} -CompilerType -TypeSystemSwiftTypeRef::GetFunctionArgumentAtIndex(void *type, - const size_t index) { - return m_swift_ast_context->GetFunctionArgumentAtIndex(ReconstructType(type), - index); -} -bool TypeSystemSwiftTypeRef::IsFunctionPointerType(void *type) { - return m_swift_ast_context->IsFunctionPointerType(ReconstructType(type)); -} -bool TypeSystemSwiftTypeRef::IsBlockPointerType( - void *type, CompilerType *function_pointer_type_ptr) { - return m_swift_ast_context->IsBlockPointerType(ReconstructType(type), - function_pointer_type_ptr); -} -bool TypeSystemSwiftTypeRef::IsIntegerType(void *type, bool &is_signed) { - return m_swift_ast_context->IsIntegerType(ReconstructType(type), is_signed); -} -bool TypeSystemSwiftTypeRef::IsPossibleDynamicType(void *type, - CompilerType *target_type, - bool check_cplusplus, - bool check_objc) { - return m_swift_ast_context->IsPossibleDynamicType( - ReconstructType(type), target_type, check_cplusplus, check_objc); -} -bool TypeSystemSwiftTypeRef::IsPointerType(void *type, - CompilerType *pointee_type) { - return m_swift_ast_context->IsPointerType(ReconstructType(type), - pointee_type); -} -bool TypeSystemSwiftTypeRef::IsScalarType(void *type) { - return m_swift_ast_context->IsScalarType(ReconstructType(type)); -} -bool TypeSystemSwiftTypeRef::IsVoidType(void *type) { - return m_swift_ast_context->IsVoidType(ReconstructType(type)); -} -bool TypeSystemSwiftTypeRef::CanPassInRegisters(const CompilerType &type) { - return m_swift_ast_context->CanPassInRegisters( - {m_swift_ast_context, ReconstructType(type.GetOpaqueQualType())}); -} -// Type Completion -bool TypeSystemSwiftTypeRef::GetCompleteType(void *type) { - return m_swift_ast_context->GetCompleteType(ReconstructType(type)); -} -// AST related queries -uint32_t TypeSystemSwiftTypeRef::GetPointerByteSize() { - return m_swift_ast_context->GetPointerByteSize(); -} -// Accessors -ConstString TypeSystemSwiftTypeRef::GetTypeName(void *type) { - return m_swift_ast_context->GetTypeName(ReconstructType(type)); -} -ConstString -TypeSystemSwiftTypeRef::GetDisplayTypeName(void *type, - const SymbolContext *sc) { - return m_swift_ast_context->GetDisplayTypeName(ReconstructType(type), sc); -} -uint32_t TypeSystemSwiftTypeRef::GetTypeInfo( - void *type, CompilerType *pointee_or_element_clang_type) { - return m_swift_ast_context->GetTypeInfo(ReconstructType(type), - pointee_or_element_clang_type); -} -lldb::LanguageType TypeSystemSwiftTypeRef::GetMinimumLanguage(void *type) { - return m_swift_ast_context->GetMinimumLanguage(ReconstructType(type)); -} -lldb::TypeClass TypeSystemSwiftTypeRef::GetTypeClass(void *type) { - return m_swift_ast_context->GetTypeClass(ReconstructType(type)); -} - -// Creating related types -CompilerType TypeSystemSwiftTypeRef::GetArrayElementType(void *type, - uint64_t *stride) { - return m_swift_ast_context->GetArrayElementType(ReconstructType(type), - stride); -} -CompilerType TypeSystemSwiftTypeRef::GetCanonicalType(void *type) { - return m_swift_ast_context->GetCanonicalType(ReconstructType(type)); -} -int TypeSystemSwiftTypeRef::GetFunctionArgumentCount(void *type) { - return m_swift_ast_context->GetFunctionArgumentCount(ReconstructType(type)); -} -CompilerType -TypeSystemSwiftTypeRef::GetFunctionArgumentTypeAtIndex(void *type, size_t idx) { - return m_swift_ast_context->GetFunctionArgumentTypeAtIndex( - ReconstructType(type), idx); -} -CompilerType TypeSystemSwiftTypeRef::GetFunctionReturnType(void *type) { - return m_swift_ast_context->GetFunctionReturnType(ReconstructType(type)); -} -size_t TypeSystemSwiftTypeRef::GetNumMemberFunctions(void *type) { - return m_swift_ast_context->GetNumMemberFunctions(ReconstructType(type)); -} -TypeMemberFunctionImpl -TypeSystemSwiftTypeRef::GetMemberFunctionAtIndex(void *type, size_t idx) { - return m_swift_ast_context->GetMemberFunctionAtIndex(ReconstructType(type), - idx); -} -CompilerType TypeSystemSwiftTypeRef::GetPointeeType(void *type) { - return m_swift_ast_context->GetPointeeType(ReconstructType(type)); -} -CompilerType TypeSystemSwiftTypeRef::GetPointerType(void *type) { - return m_swift_ast_context->GetPointerType(ReconstructType(type)); -} - -// Exploring the type -const llvm::fltSemantics & -TypeSystemSwiftTypeRef::GetFloatTypeSemantics(size_t byte_size) { - return m_swift_ast_context->GetFloatTypeSemantics(byte_size); -} -llvm::Optional -TypeSystemSwiftTypeRef::GetBitSize(lldb::opaque_compiler_type_t type, - ExecutionContextScope *exe_scope) { - return m_swift_ast_context->GetBitSize(ReconstructType(type), exe_scope); -} -llvm::Optional -TypeSystemSwiftTypeRef::GetByteStride(lldb::opaque_compiler_type_t type, - ExecutionContextScope *exe_scope) { - return m_swift_ast_context->GetByteStride(ReconstructType(type), exe_scope); -} -lldb::Encoding TypeSystemSwiftTypeRef::GetEncoding(void *type, - uint64_t &count) { - return m_swift_ast_context->GetEncoding(ReconstructType(type), count); -} -lldb::Format TypeSystemSwiftTypeRef::GetFormat(void *type) { - return m_swift_ast_context->GetFormat(ReconstructType(type)); -} -uint32_t -TypeSystemSwiftTypeRef::GetNumChildren(void *type, bool omit_empty_base_classes, - const ExecutionContext *exe_ctx) { - return m_swift_ast_context->GetNumChildren(ReconstructType(type), - omit_empty_base_classes, exe_ctx); -} -lldb::BasicType TypeSystemSwiftTypeRef::GetBasicTypeEnumeration(void *type) { - return m_swift_ast_context->GetBasicTypeEnumeration(ReconstructType(type)); -} -uint32_t TypeSystemSwiftTypeRef::GetNumFields(void *type) { - return m_swift_ast_context->GetNumFields(ReconstructType(type)); -} -CompilerType TypeSystemSwiftTypeRef::GetFieldAtIndex( - void *type, size_t idx, std::string &name, uint64_t *bit_offset_ptr, - uint32_t *bitfield_bit_size_ptr, bool *is_bitfield_ptr) { - return m_swift_ast_context->GetFieldAtIndex( - ReconstructType(type), idx, name, bit_offset_ptr, bitfield_bit_size_ptr, - is_bitfield_ptr); -} -CompilerType TypeSystemSwiftTypeRef::GetChildCompilerTypeAtIndex( - void *type, ExecutionContext *exe_ctx, size_t idx, - bool transparent_pointers, bool omit_empty_base_classes, - bool ignore_array_bounds, std::string &child_name, - uint32_t &child_byte_size, int32_t &child_byte_offset, - uint32_t &child_bitfield_bit_size, uint32_t &child_bitfield_bit_offset, - bool &child_is_base_class, bool &child_is_deref_of_parent, - ValueObject *valobj, uint64_t &language_flags) { - return m_swift_ast_context->GetChildCompilerTypeAtIndex( - ReconstructType(type), exe_ctx, idx, transparent_pointers, - omit_empty_base_classes, ignore_array_bounds, child_name, child_byte_size, - child_byte_offset, child_bitfield_bit_size, child_bitfield_bit_offset, - child_is_base_class, child_is_deref_of_parent, valobj, language_flags); -} -uint32_t -TypeSystemSwiftTypeRef::GetIndexOfChildWithName(void *type, const char *name, - bool omit_empty_base_classes) { - return m_swift_ast_context->GetIndexOfChildWithName( - ReconstructType(type), name, omit_empty_base_classes); -} -size_t TypeSystemSwiftTypeRef::GetIndexOfChildMemberWithName( - void *type, const char *name, bool omit_empty_base_classes, - std::vector &child_indexes) { - return m_swift_ast_context->GetIndexOfChildMemberWithName( - ReconstructType(type), name, omit_empty_base_classes, child_indexes); -} -size_t TypeSystemSwiftTypeRef::GetNumTemplateArguments(void *type) { - return m_swift_ast_context->GetNumTemplateArguments(ReconstructType(type)); -} -CompilerType TypeSystemSwiftTypeRef::GetTypeForFormatters(void *type) { - return m_swift_ast_context->GetTypeForFormatters(ReconstructType(type)); -} -LazyBool TypeSystemSwiftTypeRef::ShouldPrintAsOneLiner(void *type, - ValueObject *valobj) { - return m_swift_ast_context->ShouldPrintAsOneLiner(ReconstructType(type), - valobj); -} -bool TypeSystemSwiftTypeRef::IsMeaninglessWithoutDynamicResolution(void *type) { - return m_swift_ast_context->IsMeaninglessWithoutDynamicResolution( - ReconstructType(type)); -} -bool TypeSystemSwiftTypeRef::IsImportedType(CompilerType type, - CompilerType *original_type) { - return m_swift_ast_context->IsImportedType( - {m_swift_ast_context, ReconstructType(type.GetOpaqueQualType())}, - original_type); -} -bool TypeSystemSwiftTypeRef::IsErrorType(CompilerType compiler_type) { - return m_swift_ast_context->IsErrorType( - {m_swift_ast_context, - ReconstructType(compiler_type.GetOpaqueQualType())}); -} -CompilerType TypeSystemSwiftTypeRef::GetErrorType() { - return m_swift_ast_context->GetErrorType(); -} - -CompilerType -TypeSystemSwiftTypeRef::GetReferentType(CompilerType compiler_type) { - return m_swift_ast_context->GetReferentType( - {m_swift_ast_context, - ReconstructType(compiler_type.GetOpaqueQualType())}); -} - -CompilerType TypeSystemSwiftTypeRef::GetInstanceType(void *type) { - return m_swift_ast_context->GetInstanceType(ReconstructType(type)); -} -TypeSystemSwift::TypeAllocationStrategy -TypeSystemSwiftTypeRef::GetAllocationStrategy(CompilerType type) { - return m_swift_ast_context->GetAllocationStrategy( - {m_swift_ast_context, ReconstructType(type.GetOpaqueQualType())}); -} -CompilerType TypeSystemSwiftTypeRef::CreateTupleType( - const std::vector &elements) { - return m_swift_ast_context->CreateTupleType(elements); -} -void TypeSystemSwiftTypeRef::DumpTypeDescription( - void *type, bool print_help_if_available, - bool print_extensions_if_available) { - return m_swift_ast_context->DumpTypeDescription( - ReconstructType(type), print_help_if_available, print_help_if_available); -} -void TypeSystemSwiftTypeRef::DumpTypeDescription( - void *type, Stream *s, bool print_help_if_available, - bool print_extensions_if_available) { - return m_swift_ast_context->DumpTypeDescription( - ReconstructType(type), s, print_help_if_available, - print_extensions_if_available); -} - -// Dumping types -#ifndef NDEBUG -/// Convenience LLVM-style dump method for use in the debugger only. -LLVM_DUMP_METHOD void -TypeSystemSwiftTypeRef::dump(lldb::opaque_compiler_type_t type) const { - llvm::dbgs() << reinterpret_cast(type) << "\n"; -} -#endif - -void TypeSystemSwiftTypeRef::DumpValue( - void *type, ExecutionContext *exe_ctx, Stream *s, lldb::Format format, - const DataExtractor &data, lldb::offset_t data_offset, - size_t data_byte_size, uint32_t bitfield_bit_size, - uint32_t bitfield_bit_offset, bool show_types, bool show_summary, - bool verbose, uint32_t depth) { - return m_swift_ast_context->DumpValue( - ReconstructType(type), exe_ctx, s, format, data, data_offset, - data_byte_size, bitfield_bit_size, bitfield_bit_offset, show_types, - show_summary, verbose, depth); -} - -bool TypeSystemSwiftTypeRef::DumpTypeValue( - void *type, Stream *s, lldb::Format format, const DataExtractor &data, - lldb::offset_t data_offset, size_t data_byte_size, - uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset, - ExecutionContextScope *exe_scope, bool is_base_class) { - return m_swift_ast_context->DumpTypeValue( - ReconstructType(type), s, format, data, data_offset, data_byte_size, - bitfield_bit_size, bitfield_bit_offset, exe_scope, is_base_class); -} - -void TypeSystemSwiftTypeRef::DumpTypeDescription(void *type) { - return m_swift_ast_context->DumpTypeDescription(ReconstructType(type)); -} -void TypeSystemSwiftTypeRef::DumpTypeDescription(void *type, Stream *s) { - return m_swift_ast_context->DumpTypeDescription(ReconstructType(type), s); -} -bool TypeSystemSwiftTypeRef::IsRuntimeGeneratedType(void *type) { - return m_swift_ast_context->IsRuntimeGeneratedType(ReconstructType(type)); -} -void TypeSystemSwiftTypeRef::DumpSummary(void *type, ExecutionContext *exe_ctx, - Stream *s, const DataExtractor &data, - lldb::offset_t data_offset, - size_t data_byte_size) { - return m_swift_ast_context->DumpSummary(ReconstructType(type), exe_ctx, s, - data, data_offset, data_byte_size); -} -bool TypeSystemSwiftTypeRef::IsPointerOrReferenceType( - void *type, CompilerType *pointee_type) { - return m_swift_ast_context->IsPointerOrReferenceType(ReconstructType(type), - pointee_type); -} -unsigned TypeSystemSwiftTypeRef::GetTypeQualifiers(void *type) { - return m_swift_ast_context->GetTypeQualifiers(ReconstructType(type)); -} -bool TypeSystemSwiftTypeRef::IsCStringType(void *type, uint32_t &length) { - return m_swift_ast_context->IsCStringType(ReconstructType(type), length); -} -llvm::Optional -TypeSystemSwiftTypeRef::GetTypeBitAlign(void *type, - ExecutionContextScope *exe_scope) { - return m_swift_ast_context->GetTypeBitAlign(ReconstructType(type), exe_scope); -} -CompilerType -TypeSystemSwiftTypeRef::GetBasicTypeFromAST(lldb::BasicType basic_type) { - return m_swift_ast_context->GetBasicTypeFromAST(basic_type); -} -bool TypeSystemSwiftTypeRef::IsBeingDefined(void *type) { - return m_swift_ast_context->IsBeingDefined(ReconstructType(type)); -} -bool TypeSystemSwiftTypeRef::IsConst(void *type) { - return m_swift_ast_context->IsConst(ReconstructType(type)); -} -uint32_t -TypeSystemSwiftTypeRef::IsHomogeneousAggregate(void *type, - CompilerType *base_type_ptr) { - return m_swift_ast_context->IsHomogeneousAggregate(ReconstructType(type), - base_type_ptr); -} -bool TypeSystemSwiftTypeRef::IsPolymorphicClass(void *type) { - return m_swift_ast_context->IsPolymorphicClass(ReconstructType(type)); -} -bool TypeSystemSwiftTypeRef::IsTypedefType(void *type) { - return m_swift_ast_context->IsTypedefType(ReconstructType(type)); -} -CompilerType TypeSystemSwiftTypeRef::GetTypedefedType(void *type) { - return m_swift_ast_context->GetTypedefedType(ReconstructType(type)); -} -CompilerType TypeSystemSwiftTypeRef::GetTypeForDecl(void *opaque_decl) { - return m_swift_ast_context->GetTypeForDecl(opaque_decl); -} -bool TypeSystemSwiftTypeRef::IsVectorType(void *type, - CompilerType *element_type, - uint64_t *size) { - return m_swift_ast_context->IsVectorType(ReconstructType(type), element_type, - size); -} -CompilerType TypeSystemSwiftTypeRef::GetFullyUnqualifiedType(void *type) { - return m_swift_ast_context->GetFullyUnqualifiedType(ReconstructType(type)); -} -CompilerType TypeSystemSwiftTypeRef::GetNonReferenceType(void *type) { - return m_swift_ast_context->GetNonReferenceType(ReconstructType(type)); -} -CompilerType TypeSystemSwiftTypeRef::GetLValueReferenceType(void *type) { - return m_swift_ast_context->GetLValueReferenceType(ReconstructType(type)); -} -CompilerType TypeSystemSwiftTypeRef::GetRValueReferenceType(void *type) { - return m_swift_ast_context->GetRValueReferenceType(ReconstructType(type)); -} -uint32_t TypeSystemSwiftTypeRef::GetNumDirectBaseClasses(void *type) { - return m_swift_ast_context->GetNumDirectBaseClasses(ReconstructType(type)); -} -uint32_t TypeSystemSwiftTypeRef::GetNumVirtualBaseClasses(void *type) { - return m_swift_ast_context->GetNumVirtualBaseClasses(ReconstructType(type)); -} -CompilerType -TypeSystemSwiftTypeRef::GetDirectBaseClassAtIndex(void *type, size_t idx, - uint32_t *bit_offset_ptr) { - return m_swift_ast_context->GetDirectBaseClassAtIndex(ReconstructType(type), - idx, bit_offset_ptr); -} -CompilerType -TypeSystemSwiftTypeRef::GetVirtualBaseClassAtIndex(void *type, size_t idx, - uint32_t *bit_offset_ptr) { - return m_swift_ast_context->GetVirtualBaseClassAtIndex(ReconstructType(type), - idx, bit_offset_ptr); -} -bool TypeSystemSwiftTypeRef::IsReferenceType(void *type, - CompilerType *pointee_type, - bool *is_rvalue) { - return m_swift_ast_context->IsReferenceType(ReconstructType(type), - pointee_type, is_rvalue); -} -bool TypeSystemSwiftTypeRef::ShouldTreatScalarValueAsAddress( - lldb::opaque_compiler_type_t type) { - return m_swift_ast_context->ShouldTreatScalarValueAsAddress( - ReconstructType(type)); -} - typedef lldb_private::ThreadSafeDenseMap ThreadSafeSwiftASTMap; diff --git a/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp new file mode 100644 index 0000000000000..51b811e093692 --- /dev/null +++ b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp @@ -0,0 +1,530 @@ +//===-- TypeSystemSwiftTypeRef.cpp ----------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "lldb/Symbol/SwiftASTContext.h" +#include "lldb/Symbol/TypeList.h" +#include "lldb/Target/SwiftLanguageRuntime.h" +#include "lldb/Utility/Log.h" + +#include "swift/Demangling/Demangle.h" +#include "swift/Demangling/Demangler.h" +#include "swift/Strings.h" + +using namespace lldb; +using namespace lldb_private; + +char TypeSystemSwift::ID; +char TypeSystemSwiftTypeRef::ID; + +TypeSystemSwift::TypeSystemSwift() : TypeSystem() {} + +CompilerType TypeSystemSwift::GetInstanceType(CompilerType compiler_type) { + auto *ts = compiler_type.GetTypeSystem(); + if (auto *tr = llvm::dyn_cast_or_null(ts)) + return tr->GetInstanceType(compiler_type.GetOpaqueQualType()); + if (auto *ast = llvm::dyn_cast_or_null(ts)) + return ast->GetInstanceType(compiler_type.GetOpaqueQualType()); + return {}; +} + +TypeSystemSwiftTypeRef::TypeSystemSwiftTypeRef( + SwiftASTContext *swift_ast_context) + : m_swift_ast_context(swift_ast_context) { + m_description = "TypeSystemSwiftTypeRef"; +} + +const char *TypeSystemSwiftTypeRef::AsMangledName(void *type) { + assert(type && *reinterpret_cast(type) == '$' && + "wrong type system"); + return reinterpret_cast(type); +} + +ConstString TypeSystemSwiftTypeRef::GetMangledTypeName(void *type) { + // FIXME: Suboptimal performance, because the ConstString is looked up again. + return ConstString(AsMangledName(type)); +} + +void *TypeSystemSwiftTypeRef::ReconstructType(void *type) { + Status error; + return m_swift_ast_context->ReconstructType(GetMangledTypeName(type), error); +} + +CompilerType TypeSystemSwiftTypeRef::ReconstructType(CompilerType type) { + return {m_swift_ast_context, ReconstructType(type.GetOpaqueQualType())}; +} + +CompilerType TypeSystemSwiftTypeRef::GetTypeFromMangledTypename( + ConstString mangled_typename) { + return {this, (void *)mangled_typename.AsCString()}; +} + +lldb::TypeSP TypeSystemSwiftTypeRef::GetCachedType(ConstString mangled) { + return m_swift_ast_context->GetCachedType(mangled); +} + +void TypeSystemSwiftTypeRef::SetCachedType(ConstString mangled, + const lldb::TypeSP &type_sp) { + return m_swift_ast_context->SetCachedType(mangled, type_sp); +} + +Module *TypeSystemSwiftTypeRef::GetModule() const { + return m_swift_ast_context ? m_swift_ast_context->GetModule() : nullptr; +} + +ConstString TypeSystemSwiftTypeRef::GetPluginName() { + return ConstString("TypeSystemSwiftTypeRef"); +} +uint32_t TypeSystemSwiftTypeRef::GetPluginVersion() { return 1; } + +bool TypeSystemSwiftTypeRef::SupportsLanguage(lldb::LanguageType language) { + return language == eLanguageTypeSwift; +} + +Status TypeSystemSwiftTypeRef::IsCompatible() { + return m_swift_ast_context->IsCompatible(); +} + +void TypeSystemSwiftTypeRef::DiagnoseWarnings(Process &process, + Module &module) const { + m_swift_ast_context->DiagnoseWarnings(process, module); +} +DWARFASTParser *TypeSystemSwiftTypeRef::GetDWARFParser() { + return m_swift_ast_context->GetDWARFParser(); +} +ConstString TypeSystemSwiftTypeRef::DeclContextGetName(void *opaque_decl_ctx) { + return m_swift_ast_context->DeclContextGetName(opaque_decl_ctx); +} +ConstString TypeSystemSwiftTypeRef::DeclContextGetScopeQualifiedName( + void *opaque_decl_ctx) { + return m_swift_ast_context->DeclContextGetScopeQualifiedName(opaque_decl_ctx); +} +bool TypeSystemSwiftTypeRef::DeclContextIsClassMethod( + void *opaque_decl_ctx, lldb::LanguageType *language_ptr, + bool *is_instance_method_ptr, ConstString *language_object_name_ptr) { + return m_swift_ast_context->DeclContextIsClassMethod( + opaque_decl_ctx, language_ptr, is_instance_method_ptr, + language_object_name_ptr); +} + +// Tests + +#ifndef NDEBUG +bool TypeSystemSwiftTypeRef::Verify(lldb::opaque_compiler_type_t type) { + if (!type) + return true; + + const char *str = reinterpret_cast(type); + return SwiftLanguageRuntime::IsSwiftMangledName(str); +} +#endif + +bool TypeSystemSwiftTypeRef::IsArrayType(void *type, CompilerType *element_type, + uint64_t *size, bool *is_incomplete) { + return m_swift_ast_context->IsArrayType(ReconstructType(type), element_type, + size, is_incomplete); +} +bool TypeSystemSwiftTypeRef::IsAggregateType(void *type) { + return m_swift_ast_context->IsAggregateType(ReconstructType(type)); +} +bool TypeSystemSwiftTypeRef::IsCharType(void *type) { + return m_swift_ast_context->IsCharType(ReconstructType(type)); +} +bool TypeSystemSwiftTypeRef::IsCompleteType(void *type) { + return m_swift_ast_context->IsCompleteType(ReconstructType(type)); +} +bool TypeSystemSwiftTypeRef::IsDefined(void *type) { + return m_swift_ast_context->IsDefined(ReconstructType(type)); +} +bool TypeSystemSwiftTypeRef::IsFloatingPointType(void *type, uint32_t &count, + bool &is_complex) { + return m_swift_ast_context->IsFloatingPointType(ReconstructType(type), count, + is_complex); +} +bool TypeSystemSwiftTypeRef::IsFunctionType(void *type, bool *is_variadic_ptr) { + return m_swift_ast_context->IsFunctionType(ReconstructType(type), + is_variadic_ptr); +} +size_t TypeSystemSwiftTypeRef::GetNumberOfFunctionArguments(void *type) { + return m_swift_ast_context->GetNumberOfFunctionArguments( + ReconstructType(type)); +} +CompilerType +TypeSystemSwiftTypeRef::GetFunctionArgumentAtIndex(void *type, + const size_t index) { + return m_swift_ast_context->GetFunctionArgumentAtIndex(ReconstructType(type), + index); +} +bool TypeSystemSwiftTypeRef::IsFunctionPointerType(void *type) { + return m_swift_ast_context->IsFunctionPointerType(ReconstructType(type)); +} +bool TypeSystemSwiftTypeRef::IsBlockPointerType( + void *type, CompilerType *function_pointer_type_ptr) { + return m_swift_ast_context->IsBlockPointerType(ReconstructType(type), + function_pointer_type_ptr); +} +bool TypeSystemSwiftTypeRef::IsIntegerType(void *type, bool &is_signed) { + return m_swift_ast_context->IsIntegerType(ReconstructType(type), is_signed); +} +bool TypeSystemSwiftTypeRef::IsPossibleDynamicType(void *type, + CompilerType *target_type, + bool check_cplusplus, + bool check_objc) { + return m_swift_ast_context->IsPossibleDynamicType( + ReconstructType(type), target_type, check_cplusplus, check_objc); +} +bool TypeSystemSwiftTypeRef::IsPointerType(void *type, + CompilerType *pointee_type) { + return m_swift_ast_context->IsPointerType(ReconstructType(type), + pointee_type); +} +bool TypeSystemSwiftTypeRef::IsScalarType(void *type) { + return m_swift_ast_context->IsScalarType(ReconstructType(type)); +} +bool TypeSystemSwiftTypeRef::IsVoidType(void *type) { + return m_swift_ast_context->IsVoidType(ReconstructType(type)); +} +bool TypeSystemSwiftTypeRef::CanPassInRegisters(const CompilerType &type) { + return m_swift_ast_context->CanPassInRegisters( + {m_swift_ast_context, ReconstructType(type.GetOpaqueQualType())}); +} +// Type Completion +bool TypeSystemSwiftTypeRef::GetCompleteType(void *type) { + return m_swift_ast_context->GetCompleteType(ReconstructType(type)); +} +// AST related queries +uint32_t TypeSystemSwiftTypeRef::GetPointerByteSize() { + return m_swift_ast_context->GetPointerByteSize(); +} +// Accessors +ConstString TypeSystemSwiftTypeRef::GetTypeName(void *type) { + return m_swift_ast_context->GetTypeName(ReconstructType(type)); +} +ConstString +TypeSystemSwiftTypeRef::GetDisplayTypeName(void *type, + const SymbolContext *sc) { + return m_swift_ast_context->GetDisplayTypeName(ReconstructType(type), sc); +} +uint32_t TypeSystemSwiftTypeRef::GetTypeInfo( + void *type, CompilerType *pointee_or_element_clang_type) { + return m_swift_ast_context->GetTypeInfo(ReconstructType(type), + pointee_or_element_clang_type); +} +lldb::LanguageType TypeSystemSwiftTypeRef::GetMinimumLanguage(void *type) { + return m_swift_ast_context->GetMinimumLanguage(ReconstructType(type)); +} +lldb::TypeClass TypeSystemSwiftTypeRef::GetTypeClass(void *type) { + return m_swift_ast_context->GetTypeClass(ReconstructType(type)); +} + +// Creating related types +CompilerType TypeSystemSwiftTypeRef::GetArrayElementType(void *type, + uint64_t *stride) { + return m_swift_ast_context->GetArrayElementType(ReconstructType(type), + stride); +} +CompilerType TypeSystemSwiftTypeRef::GetCanonicalType(void *type) { + return m_swift_ast_context->GetCanonicalType(ReconstructType(type)); +} +int TypeSystemSwiftTypeRef::GetFunctionArgumentCount(void *type) { + return m_swift_ast_context->GetFunctionArgumentCount(ReconstructType(type)); +} +CompilerType +TypeSystemSwiftTypeRef::GetFunctionArgumentTypeAtIndex(void *type, size_t idx) { + return m_swift_ast_context->GetFunctionArgumentTypeAtIndex( + ReconstructType(type), idx); +} +CompilerType TypeSystemSwiftTypeRef::GetFunctionReturnType(void *type) { + return m_swift_ast_context->GetFunctionReturnType(ReconstructType(type)); +} +size_t TypeSystemSwiftTypeRef::GetNumMemberFunctions(void *type) { + return m_swift_ast_context->GetNumMemberFunctions(ReconstructType(type)); +} +TypeMemberFunctionImpl +TypeSystemSwiftTypeRef::GetMemberFunctionAtIndex(void *type, size_t idx) { + return m_swift_ast_context->GetMemberFunctionAtIndex(ReconstructType(type), + idx); +} +CompilerType TypeSystemSwiftTypeRef::GetPointeeType(void *type) { + return m_swift_ast_context->GetPointeeType(ReconstructType(type)); +} +CompilerType TypeSystemSwiftTypeRef::GetPointerType(void *type) { + return m_swift_ast_context->GetPointerType(ReconstructType(type)); +} + +// Exploring the type +const llvm::fltSemantics & +TypeSystemSwiftTypeRef::GetFloatTypeSemantics(size_t byte_size) { + return m_swift_ast_context->GetFloatTypeSemantics(byte_size); +} +llvm::Optional +TypeSystemSwiftTypeRef::GetBitSize(lldb::opaque_compiler_type_t type, + ExecutionContextScope *exe_scope) { + return m_swift_ast_context->GetBitSize(ReconstructType(type), exe_scope); +} +llvm::Optional +TypeSystemSwiftTypeRef::GetByteStride(lldb::opaque_compiler_type_t type, + ExecutionContextScope *exe_scope) { + return m_swift_ast_context->GetByteStride(ReconstructType(type), exe_scope); +} +lldb::Encoding TypeSystemSwiftTypeRef::GetEncoding(void *type, + uint64_t &count) { + return m_swift_ast_context->GetEncoding(ReconstructType(type), count); +} +lldb::Format TypeSystemSwiftTypeRef::GetFormat(void *type) { + return m_swift_ast_context->GetFormat(ReconstructType(type)); +} +uint32_t +TypeSystemSwiftTypeRef::GetNumChildren(void *type, bool omit_empty_base_classes, + const ExecutionContext *exe_ctx) { + return m_swift_ast_context->GetNumChildren(ReconstructType(type), + omit_empty_base_classes, exe_ctx); +} +lldb::BasicType TypeSystemSwiftTypeRef::GetBasicTypeEnumeration(void *type) { + return m_swift_ast_context->GetBasicTypeEnumeration(ReconstructType(type)); +} +uint32_t TypeSystemSwiftTypeRef::GetNumFields(void *type) { + return m_swift_ast_context->GetNumFields(ReconstructType(type)); +} +CompilerType TypeSystemSwiftTypeRef::GetFieldAtIndex( + void *type, size_t idx, std::string &name, uint64_t *bit_offset_ptr, + uint32_t *bitfield_bit_size_ptr, bool *is_bitfield_ptr) { + return m_swift_ast_context->GetFieldAtIndex( + ReconstructType(type), idx, name, bit_offset_ptr, bitfield_bit_size_ptr, + is_bitfield_ptr); +} +CompilerType TypeSystemSwiftTypeRef::GetChildCompilerTypeAtIndex( + void *type, ExecutionContext *exe_ctx, size_t idx, + bool transparent_pointers, bool omit_empty_base_classes, + bool ignore_array_bounds, std::string &child_name, + uint32_t &child_byte_size, int32_t &child_byte_offset, + uint32_t &child_bitfield_bit_size, uint32_t &child_bitfield_bit_offset, + bool &child_is_base_class, bool &child_is_deref_of_parent, + ValueObject *valobj, uint64_t &language_flags) { + return m_swift_ast_context->GetChildCompilerTypeAtIndex( + ReconstructType(type), exe_ctx, idx, transparent_pointers, + omit_empty_base_classes, ignore_array_bounds, child_name, child_byte_size, + child_byte_offset, child_bitfield_bit_size, child_bitfield_bit_offset, + child_is_base_class, child_is_deref_of_parent, valobj, language_flags); +} +uint32_t +TypeSystemSwiftTypeRef::GetIndexOfChildWithName(void *type, const char *name, + bool omit_empty_base_classes) { + return m_swift_ast_context->GetIndexOfChildWithName( + ReconstructType(type), name, omit_empty_base_classes); +} +size_t TypeSystemSwiftTypeRef::GetIndexOfChildMemberWithName( + void *type, const char *name, bool omit_empty_base_classes, + std::vector &child_indexes) { + return m_swift_ast_context->GetIndexOfChildMemberWithName( + ReconstructType(type), name, omit_empty_base_classes, child_indexes); +} +size_t TypeSystemSwiftTypeRef::GetNumTemplateArguments(void *type) { + return m_swift_ast_context->GetNumTemplateArguments(ReconstructType(type)); +} +CompilerType TypeSystemSwiftTypeRef::GetTypeForFormatters(void *type) { + return m_swift_ast_context->GetTypeForFormatters(ReconstructType(type)); +} +LazyBool TypeSystemSwiftTypeRef::ShouldPrintAsOneLiner(void *type, + ValueObject *valobj) { + return m_swift_ast_context->ShouldPrintAsOneLiner(ReconstructType(type), + valobj); +} +bool TypeSystemSwiftTypeRef::IsMeaninglessWithoutDynamicResolution(void *type) { + return m_swift_ast_context->IsMeaninglessWithoutDynamicResolution( + ReconstructType(type)); +} +bool TypeSystemSwiftTypeRef::IsImportedType(CompilerType type, + CompilerType *original_type) { + return m_swift_ast_context->IsImportedType( + {m_swift_ast_context, ReconstructType(type.GetOpaqueQualType())}, + original_type); +} +bool TypeSystemSwiftTypeRef::IsErrorType(CompilerType compiler_type) { + return m_swift_ast_context->IsErrorType( + {m_swift_ast_context, + ReconstructType(compiler_type.GetOpaqueQualType())}); +} +CompilerType TypeSystemSwiftTypeRef::GetErrorType() { + return m_swift_ast_context->GetErrorType(); +} + +CompilerType +TypeSystemSwiftTypeRef::GetReferentType(CompilerType compiler_type) { + return m_swift_ast_context->GetReferentType( + {m_swift_ast_context, + ReconstructType(compiler_type.GetOpaqueQualType())}); +} + +CompilerType TypeSystemSwiftTypeRef::GetInstanceType(void *type) { + return m_swift_ast_context->GetInstanceType(ReconstructType(type)); +} +TypeSystemSwift::TypeAllocationStrategy +TypeSystemSwiftTypeRef::GetAllocationStrategy(CompilerType type) { + return m_swift_ast_context->GetAllocationStrategy( + {m_swift_ast_context, ReconstructType(type.GetOpaqueQualType())}); +} +CompilerType TypeSystemSwiftTypeRef::CreateTupleType( + const std::vector &elements) { + return m_swift_ast_context->CreateTupleType(elements); +} +void TypeSystemSwiftTypeRef::DumpTypeDescription( + void *type, bool print_help_if_available, + bool print_extensions_if_available) { + return m_swift_ast_context->DumpTypeDescription( + ReconstructType(type), print_help_if_available, print_help_if_available); +} +void TypeSystemSwiftTypeRef::DumpTypeDescription( + void *type, Stream *s, bool print_help_if_available, + bool print_extensions_if_available) { + return m_swift_ast_context->DumpTypeDescription( + ReconstructType(type), s, print_help_if_available, + print_extensions_if_available); +} + +// Dumping types +#ifndef NDEBUG +/// Convenience LLVM-style dump method for use in the debugger only. +LLVM_DUMP_METHOD void +TypeSystemSwiftTypeRef::dump(lldb::opaque_compiler_type_t type) const { + llvm::dbgs() << reinterpret_cast(type) << "\n"; +} +#endif + +void TypeSystemSwiftTypeRef::DumpValue( + void *type, ExecutionContext *exe_ctx, Stream *s, lldb::Format format, + const DataExtractor &data, lldb::offset_t data_offset, + size_t data_byte_size, uint32_t bitfield_bit_size, + uint32_t bitfield_bit_offset, bool show_types, bool show_summary, + bool verbose, uint32_t depth) { + return m_swift_ast_context->DumpValue( + ReconstructType(type), exe_ctx, s, format, data, data_offset, + data_byte_size, bitfield_bit_size, bitfield_bit_offset, show_types, + show_summary, verbose, depth); +} + +bool TypeSystemSwiftTypeRef::DumpTypeValue( + void *type, Stream *s, lldb::Format format, const DataExtractor &data, + lldb::offset_t data_offset, size_t data_byte_size, + uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset, + ExecutionContextScope *exe_scope, bool is_base_class) { + return m_swift_ast_context->DumpTypeValue( + ReconstructType(type), s, format, data, data_offset, data_byte_size, + bitfield_bit_size, bitfield_bit_offset, exe_scope, is_base_class); +} + +void TypeSystemSwiftTypeRef::DumpTypeDescription(void *type) { + return m_swift_ast_context->DumpTypeDescription(ReconstructType(type)); +} +void TypeSystemSwiftTypeRef::DumpTypeDescription(void *type, Stream *s) { + return m_swift_ast_context->DumpTypeDescription(ReconstructType(type), s); +} +bool TypeSystemSwiftTypeRef::IsRuntimeGeneratedType(void *type) { + return m_swift_ast_context->IsRuntimeGeneratedType(ReconstructType(type)); +} +void TypeSystemSwiftTypeRef::DumpSummary(void *type, ExecutionContext *exe_ctx, + Stream *s, const DataExtractor &data, + lldb::offset_t data_offset, + size_t data_byte_size) { + return m_swift_ast_context->DumpSummary(ReconstructType(type), exe_ctx, s, + data, data_offset, data_byte_size); +} +bool TypeSystemSwiftTypeRef::IsPointerOrReferenceType( + void *type, CompilerType *pointee_type) { + return m_swift_ast_context->IsPointerOrReferenceType(ReconstructType(type), + pointee_type); +} +unsigned TypeSystemSwiftTypeRef::GetTypeQualifiers(void *type) { + return m_swift_ast_context->GetTypeQualifiers(ReconstructType(type)); +} +bool TypeSystemSwiftTypeRef::IsCStringType(void *type, uint32_t &length) { + return m_swift_ast_context->IsCStringType(ReconstructType(type), length); +} +llvm::Optional +TypeSystemSwiftTypeRef::GetTypeBitAlign(void *type, + ExecutionContextScope *exe_scope) { + return m_swift_ast_context->GetTypeBitAlign(ReconstructType(type), exe_scope); +} +CompilerType +TypeSystemSwiftTypeRef::GetBasicTypeFromAST(lldb::BasicType basic_type) { + return m_swift_ast_context->GetBasicTypeFromAST(basic_type); +} +bool TypeSystemSwiftTypeRef::IsBeingDefined(void *type) { + return m_swift_ast_context->IsBeingDefined(ReconstructType(type)); +} +bool TypeSystemSwiftTypeRef::IsConst(void *type) { + return m_swift_ast_context->IsConst(ReconstructType(type)); +} +uint32_t +TypeSystemSwiftTypeRef::IsHomogeneousAggregate(void *type, + CompilerType *base_type_ptr) { + return m_swift_ast_context->IsHomogeneousAggregate(ReconstructType(type), + base_type_ptr); +} +bool TypeSystemSwiftTypeRef::IsPolymorphicClass(void *type) { + return m_swift_ast_context->IsPolymorphicClass(ReconstructType(type)); +} +bool TypeSystemSwiftTypeRef::IsTypedefType(void *type) { + return m_swift_ast_context->IsTypedefType(ReconstructType(type)); +} +CompilerType TypeSystemSwiftTypeRef::GetTypedefedType(void *type) { + return m_swift_ast_context->GetTypedefedType(ReconstructType(type)); +} +CompilerType TypeSystemSwiftTypeRef::GetTypeForDecl(void *opaque_decl) { + return m_swift_ast_context->GetTypeForDecl(opaque_decl); +} +bool TypeSystemSwiftTypeRef::IsVectorType(void *type, + CompilerType *element_type, + uint64_t *size) { + return m_swift_ast_context->IsVectorType(ReconstructType(type), element_type, + size); +} +CompilerType TypeSystemSwiftTypeRef::GetFullyUnqualifiedType(void *type) { + return m_swift_ast_context->GetFullyUnqualifiedType(ReconstructType(type)); +} +CompilerType TypeSystemSwiftTypeRef::GetNonReferenceType(void *type) { + return m_swift_ast_context->GetNonReferenceType(ReconstructType(type)); +} +CompilerType TypeSystemSwiftTypeRef::GetLValueReferenceType(void *type) { + return m_swift_ast_context->GetLValueReferenceType(ReconstructType(type)); +} +CompilerType TypeSystemSwiftTypeRef::GetRValueReferenceType(void *type) { + return m_swift_ast_context->GetRValueReferenceType(ReconstructType(type)); +} +uint32_t TypeSystemSwiftTypeRef::GetNumDirectBaseClasses(void *type) { + return m_swift_ast_context->GetNumDirectBaseClasses(ReconstructType(type)); +} +uint32_t TypeSystemSwiftTypeRef::GetNumVirtualBaseClasses(void *type) { + return m_swift_ast_context->GetNumVirtualBaseClasses(ReconstructType(type)); +} +CompilerType +TypeSystemSwiftTypeRef::GetDirectBaseClassAtIndex(void *type, size_t idx, + uint32_t *bit_offset_ptr) { + return m_swift_ast_context->GetDirectBaseClassAtIndex(ReconstructType(type), + idx, bit_offset_ptr); +} +CompilerType +TypeSystemSwiftTypeRef::GetVirtualBaseClassAtIndex(void *type, size_t idx, + uint32_t *bit_offset_ptr) { + return m_swift_ast_context->GetVirtualBaseClassAtIndex(ReconstructType(type), + idx, bit_offset_ptr); +} +bool TypeSystemSwiftTypeRef::IsReferenceType(void *type, + CompilerType *pointee_type, + bool *is_rvalue) { + return m_swift_ast_context->IsReferenceType(ReconstructType(type), + pointee_type, is_rvalue); +} +bool TypeSystemSwiftTypeRef::ShouldTreatScalarValueAsAddress( + lldb::opaque_compiler_type_t type) { + return m_swift_ast_context->ShouldTreatScalarValueAsAddress( + ReconstructType(type)); +} From 7d07c5607e2eeac7cacee8eb6b8580f3a6ff15ab Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Sat, 21 Mar 2020 16:20:29 -0700 Subject: [PATCH 120/286] Implement TypeSystemSwiftTypeRef::IsArrayType() --- lldb/source/Symbol/SwiftASTContext.cpp | 9 +- lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp | 269 +++++++++++++++++- lldb/unittests/Symbol/CMakeLists.txt | 1 + .../Symbol/TestTypeSystemSwiftTypeRef.cpp | 84 ++++++ 4 files changed, 353 insertions(+), 10 deletions(-) create mode 100644 lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp diff --git a/lldb/source/Symbol/SwiftASTContext.cpp b/lldb/source/Symbol/SwiftASTContext.cpp index 129a03de679a7..d7e33b55b8611 100644 --- a/lldb/source/Symbol/SwiftASTContext.cpp +++ b/lldb/source/Symbol/SwiftASTContext.cpp @@ -178,7 +178,7 @@ CompilerType lldb_private::ToCompilerType(swift::Type qual_type) { } CompilerType SwiftASTContext::GetCompilerType(ConstString mangled_name) { - return {&m_typeref_typesystem, (void *)mangled_name.AsCString()}; + return m_typeref_typesystem.GetTypeFromMangledTypename(mangled_name); } CompilerType SwiftASTContext::GetCompilerType(swift::TypeBase *swift_type) { @@ -217,13 +217,6 @@ swift::CanType SwiftASTContext::GetCanonicalSwiftType(void *opaque_type) { return lldb_private::GetCanonicalSwiftType(CompilerType(this, opaque_type)); } -ConstString TypeSystemSwiftTypeRef::GetMangledTypeName(void *type) { - assert(type && *reinterpret_cast(type) == '$' && - "wrong type system"); - // FIXME: Suboptimal performance, because the ConstString is looked up again. - return ConstString(reinterpret_cast(type)); -} - ConstString SwiftASTContext::GetMangledTypeName(void *type) { return GetMangledTypeName(GetSwiftType({this, type}).getPointer()); } diff --git a/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp index 51b811e093692..5b72be20ff062 100644 --- a/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp +++ b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp @@ -27,6 +27,204 @@ char TypeSystemSwiftTypeRef::ID; TypeSystemSwift::TypeSystemSwift() : TypeSystem() {} +/// Create a mangled name for a type alias node. +static ConstString GetTypeAlias(swift::Demangle::Demangler &Dem, + swift::Demangle::NodePointer node) { + using namespace swift::Demangle; + auto global = Dem.createNode(Node::Kind::Global); + auto type_mangling = Dem.createNode(Node::Kind::TypeMangling); + global->addChild(type_mangling, Dem); + type_mangling->addChild(node, Dem); + return ConstString(mangleNode(global)); +} + +/// Iteratively resolve all type aliases in \p node by looking up their +/// desugared types in the debug info of module \p M. +static swift::Demangle::NodePointer +GetCanonicalNode(lldb_private::Module *M, swift::Demangle::Demangler &Dem, + swift::Demangle::NodePointer node) { + if (!node) + return node; + using namespace swift::Demangle; + auto getCanonicalNode = [&](NodePointer node) -> NodePointer { + return GetCanonicalNode(M, Dem, node); + }; + + NodePointer canonical = nullptr; + auto kind = node->getKind(); + switch (kind) { + case Node::Kind::SugaredOptional: + // FIXME: Factor these three cases out. + assert(node->getNumChildren() == 1); + if (node->getNumChildren() != 1) + return node; + + canonical = Dem.createNode(Node::Kind::BoundGenericEnum); + { + NodePointer type = Dem.createNode(Node::Kind::Type); + NodePointer e = Dem.createNode(Node::Kind::Enum); + NodePointer module = Dem.createNodeWithAllocatedText(Node::Kind::Module, + swift::STDLIB_NAME); + e->addChild(module, Dem); + NodePointer optional = + Dem.createNodeWithAllocatedText(Node::Kind::Module, "Optional"); + e->addChild(optional, Dem); + type->addChild(e, Dem); + canonical->addChild(type, Dem); + } + { + NodePointer typelist = Dem.createNode(Node::Kind::TypeList); + NodePointer type = Dem.createNode(Node::Kind::Type); + type->addChild(getCanonicalNode(node->getFirstChild()), Dem); + typelist->addChild(type, Dem); + canonical->addChild(typelist, Dem); + } + return canonical; + case Node::Kind::SugaredArray: { + assert(node->getNumChildren() == 1); + if (node->getNumChildren() != 1) + return node; + + canonical = Dem.createNode(Node::Kind::BoundGenericStructure); + { + NodePointer type = Dem.createNode(Node::Kind::Type); + NodePointer structure = Dem.createNode(Node::Kind::Structure); + NodePointer module = Dem.createNodeWithAllocatedText(Node::Kind::Module, + swift::STDLIB_NAME); + structure->addChild(module, Dem); + NodePointer array = + Dem.createNodeWithAllocatedText(Node::Kind::Module, "Array"); + structure->addChild(array, Dem); + type->addChild(structure, Dem); + canonical->addChild(type, Dem); + } + { + NodePointer typelist = Dem.createNode(Node::Kind::TypeList); + NodePointer type = Dem.createNode(Node::Kind::Type); + type->addChild(getCanonicalNode(node->getFirstChild()), Dem); + typelist->addChild(type, Dem); + canonical->addChild(typelist, Dem); + } + return canonical; + } + case Node::Kind::SugaredDictionary: + // FIXME: This isnt covered by any test. + assert(node->getNumChildren() == 2); + if (node->getNumChildren() != 2) + return node; + + canonical = Dem.createNode(Node::Kind::BoundGenericStructure); + { + NodePointer type = Dem.createNode(Node::Kind::Type); + NodePointer structure = Dem.createNode(Node::Kind::Structure); + NodePointer module = Dem.createNodeWithAllocatedText(Node::Kind::Module, + swift::STDLIB_NAME); + structure->addChild(module, Dem); + NodePointer dict = + Dem.createNodeWithAllocatedText(Node::Kind::Module, "Dictionary"); + structure->addChild(dict, Dem); + type->addChild(structure, Dem); + canonical->addChild(type, Dem); + } + { + NodePointer typelist = Dem.createNode(Node::Kind::TypeList); + { + NodePointer type = Dem.createNode(Node::Kind::Type); + type->addChild(getCanonicalNode(node->getChild(0)), Dem); + typelist->addChild(type, Dem); + } + { + NodePointer type = Dem.createNode(Node::Kind::Type); + type->addChild(getCanonicalNode(node->getChild(1)), Dem); + typelist->addChild(type, Dem); + } + canonical->addChild(typelist, Dem); + } + return canonical; + case Node::Kind::SugaredParen: + assert(node->getNumChildren() == 1); + if (node->getNumChildren() != 1) + return node; + return getCanonicalNode(node->getFirstChild()); + + case Node::Kind::BoundGenericTypeAlias: + case Node::Kind::TypeAlias: { + // Try to look this up as a Swift type alias. For each *Swift* + // type alias there is a debug info entry that has the mangled + // name as name and the aliased type as a type. + ConstString mangled = GetTypeAlias(Dem, node); + if (!M) { + LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES), + "No module. Couldn't resolve type alias %s", + mangled.AsCString()); + return node; + } + llvm::DenseSet searched_symbol_files; + TypeList types; + M->FindTypes({mangled}, false, 1, searched_symbol_files, types); + if (types.Empty()) { + // TODO: No Swift type found -- this could be a Clang typdef. + LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES), + "Couldn't resolve type alias %s", mangled.AsCString()); + return node; + } + auto type = types.GetTypeAtIndex(0); + if (!type) { + LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES), + "Found empty type alias %s", mangled.AsCString()); + return node; + } + + // DWARFASTParserSwift stashes the desugared mangled name of a + // type alias into the Type's name field. + ConstString desugared_name = type->GetName(); + if (!isMangledName(desugared_name.GetStringRef())) { + LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES), + "Found non-Swift type alias %s", mangled.AsCString()); + return node; + } + NodePointer n = Dem.demangleSymbol(desugared_name.GetStringRef()); + if (n && n->getKind() == Node::Kind::Global && n->hasChildren()) + n = n->getFirstChild(); + if (n && n->getKind() == Node::Kind::TypeMangling && n->hasChildren()) + n = n->getFirstChild(); + if (n && n->getKind() == Node::Kind::Type && n->hasChildren()) + n = n->getFirstChild(); + if (!n) { + LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES), + "Unrecognized demangling %s", desugared_name.AsCString()); + return node; + } + return getCanonicalNode(n); + } + default: + break; + } + + // Recurse through all children. + // FIXME: don't create new nodes if children don't change! + if (node->hasText()) + canonical = Dem.createNodeWithAllocatedText(kind, node->getText()); + else if (node->hasIndex()) + canonical = Dem.createNode(kind, node->getIndex()); + else + canonical = Dem.createNode(kind); + for (unsigned i = 0; i < node->getNumChildren(); ++i) + canonical->addChild(getCanonicalNode(node->getChild(i)), Dem); + return canonical; +} + +/// Return the demangle tree representation of this type's canonical +/// (type aliases resolved) type. +static swift::Demangle::NodePointer +GetCanonicalDemangleTree(lldb_private::Module *Module, + swift::Demangle::Demangler &Dem, + const char *mangled_name) { + NodePointer node = Dem.demangleSymbol(mangled_name); + NodePointer canonical = GetCanonicalNode(Module, Dem, node); + return canonical; +} + CompilerType TypeSystemSwift::GetInstanceType(CompilerType compiler_type) { auto *ts = compiler_type.GetTypeSystem(); if (auto *tr = llvm::dyn_cast_or_null(ts)) @@ -127,10 +325,77 @@ bool TypeSystemSwiftTypeRef::Verify(lldb::opaque_compiler_type_t type) { } #endif +// This can be removed once the transition is complete. +#define VALIDATE_AND_RETURN(IMPL, EXPECTED) \ + do { \ + auto result = IMPL(); \ + if (m_swift_ast_context) \ + assert(result == (EXPECTED) && \ + "TypeSystemSwiftTypeRef diverges from SwiftASTContext"); \ + return result; \ + } while (0) + bool TypeSystemSwiftTypeRef::IsArrayType(void *type, CompilerType *element_type, uint64_t *size, bool *is_incomplete) { - return m_swift_ast_context->IsArrayType(ReconstructType(type), element_type, - size, is_incomplete); + auto impl = [&]() { + using namespace swift::Demangle; + Demangler Dem; + NodePointer node = + GetCanonicalDemangleTree(GetModule(), Dem, AsMangledName(type)); + + if (!node || node->getNumChildren() != 1 || + node->getKind() != Node::Kind::Global) + return false; + node = node->getFirstChild(); + if (node->getNumChildren() != 1 || + node->getKind() != Node::Kind::TypeMangling) + return false; + node = node->getFirstChild(); + if (node->getNumChildren() != 1 || node->getKind() != Node::Kind::Type) + return false; + node = node->getFirstChild(); + if (node->getNumChildren() != 2 || + node->getKind() != Node::Kind::BoundGenericStructure) + return false; + auto elem_node = node->getChild(1); + node = node->getFirstChild(); + if (node->getNumChildren() != 1 || node->getKind() != Node::Kind::Type) + return false; + node = node->getFirstChild(); + if (node->getNumChildren() != 2 || + node->getKind() != Node::Kind::Structure || + node->getChild(0)->getKind() != Node::Kind::Module || + !node->getChild(0)->hasText() || + node->getChild(0)->getText() != swift::STDLIB_NAME || + node->getChild(1)->getKind() != Node::Kind::Identifier || + !node->getChild(1)->hasText() || + node->getChild(1)->getText() != "Array") + return false; + + if (elem_node->getNumChildren() != 1 || + elem_node->getKind() != Node::Kind::TypeList) + return false; + elem_node = elem_node->getFirstChild(); + + if (element_type) { + // Remangle the element type. + auto global = Dem.createNode(Node::Kind::Global); + auto type_mangling = Dem.createNode(Node::Kind::TypeMangling); + global->addChild(type_mangling, Dem); + type_mangling->addChild(elem_node, Dem); + ConstString mangled_element(mangleNode(global)); + *element_type = GetTypeFromMangledTypename(mangled_element); + } + if (is_incomplete) + *is_incomplete = true; + if (size) + *size = 0; + + return true; + }; + VALIDATE_AND_RETURN( + impl, m_swift_ast_context->IsArrayType(ReconstructType(type), nullptr, + nullptr, nullptr)); } bool TypeSystemSwiftTypeRef::IsAggregateType(void *type) { return m_swift_ast_context->IsAggregateType(ReconstructType(type)); diff --git a/lldb/unittests/Symbol/CMakeLists.txt b/lldb/unittests/Symbol/CMakeLists.txt index 18d44f6005116..e1b21bb7b2a7d 100644 --- a/lldb/unittests/Symbol/CMakeLists.txt +++ b/lldb/unittests/Symbol/CMakeLists.txt @@ -5,6 +5,7 @@ add_lldb_unittest(SymbolTests TestClangASTImporter.cpp TestDWARFCallFrameInfo.cpp TestType.cpp + TestTypeSystemSwiftTypeRef.cpp TestSwiftASTContext.cpp TestLineEntry.cpp diff --git a/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp b/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp new file mode 100644 index 0000000000000..4b80bb38a2824 --- /dev/null +++ b/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp @@ -0,0 +1,84 @@ +//===-- TestTypeSystemSwiftTypeRef.cpp ------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "gtest/gtest.h" + +#include "lldb/Symbol/SwiftASTContext.h" +#include "swift/Demangling/Demangle.h" +#include "swift/Demangling/Demangler.h" +#include "swift/Strings.h" + +using namespace lldb; +using namespace lldb_private; +using namespace llvm; + +struct TestTypeSystemSwiftTypeRef : public testing::Test { + TypeSystemSwiftTypeRef m_swift_ts = TypeSystemSwiftTypeRef(nullptr); + CompilerType GetCompilerType(const std::string &mangled_name) { + ConstString internalized(mangled_name); + return m_swift_ts.GetTypeFromMangledTypename(internalized); + } +}; + +/// Helper class to conveniently construct demangle tree hierarchies. +class NodeBuilder { + using NodePointer = swift::Demangle::NodePointer; + using Kind = swift::Demangle::Node::Kind; + + swift::Demangle::Demangler &m_dem; + +public: + NodeBuilder(swift::Demangle::Demangler &dem) : m_dem(dem) {} + NodePointer Node(Kind kind, StringRef text) { + return m_dem.createNode(kind, text); + } + NodePointer Node(Kind kind, NodePointer child0 = nullptr, + NodePointer child1 = nullptr) { + NodePointer node = m_dem.createNode(kind); + + if (child0) + node->addChild(child0, m_dem); + if (child1) + node->addChild(child1, m_dem); + return node; + } + + std::string Mangle(NodePointer node) { return mangleNode(node); } +}; + +TEST_F(TestTypeSystemSwiftTypeRef, Array) { + using namespace swift::Demangle; + Demangler dem; + NodeBuilder b(dem); + NodePointer n = b.Node( + Node::Kind::Global, + b.Node( + Node::Kind::TypeMangling, + b.Node( + Node::Kind::Type, + b.Node( + Node::Kind::BoundGenericStructure, + b.Node(Node::Kind::Type, + b.Node(Node::Kind::Structure, + b.Node(Node::Kind::Module, swift::STDLIB_NAME), + b.Node(Node::Kind::Identifier, "Array"))), + b.Node( + Node::Kind::TypeList, + b.Node( + Node::Kind::Type, + b.Node(Node::Kind::Structure, + b.Node(Node::Kind::Module, swift::STDLIB_NAME), + b.Node(Node::Kind::Identifier, + swift::BUILTIN_TYPE_NAME_INT)))))))); + CompilerType int_array = GetCompilerType(b.Mangle(n)); + ASSERT_TRUE(int_array.IsArrayType(nullptr, nullptr, nullptr)); +} From e234b4135ded008f7714aaa660c803719313e549 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Mon, 30 Mar 2020 16:55:10 -0700 Subject: [PATCH 121/286] Implement TypeSystemSwiftTypeRef::IsFunctionType() (NFC) --- lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp index 5b72be20ff062..1e5be8f677d6f 100644 --- a/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp +++ b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp @@ -415,8 +415,21 @@ bool TypeSystemSwiftTypeRef::IsFloatingPointType(void *type, uint32_t &count, is_complex); } bool TypeSystemSwiftTypeRef::IsFunctionType(void *type, bool *is_variadic_ptr) { - return m_swift_ast_context->IsFunctionType(ReconstructType(type), - is_variadic_ptr); + auto impl = [&]() { + using namespace swift::Demangle; + Demangler Dem; + NodePointer node = + GetCanonicalDemangleTree(GetModule(), Dem, AsMangledName(type)); + if (!node || node->getNumChildren() != 1 || + node->getKind() != Node::Kind::Global) + return false; + node = node->getFirstChild(); + if (node->getNumChildren() != 1 || node->getKind() != Node::Kind::Function) + return false; + return true; + }; + VALIDATE_AND_RETURN(impl, m_swift_ast_context->IsFunctionType( + ReconstructType(type), nullptr)); } size_t TypeSystemSwiftTypeRef::GetNumberOfFunctionArguments(void *type) { return m_swift_ast_context->GetNumberOfFunctionArguments( From 97bdf2b32d8bda943dd0d68d7cf32f92cfc49431 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Mon, 30 Mar 2020 17:43:48 -0700 Subject: [PATCH 122/286] Move all unimplemented Swift Typesystem functions into the base class (NFC) --- lldb/include/lldb/Symbol/SwiftASTContext.h | 127 ++++++++---------- lldb/source/Symbol/SwiftASTContext.cpp | 87 ------------ lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp | 78 ----------- 3 files changed, 53 insertions(+), 239 deletions(-) diff --git a/lldb/include/lldb/Symbol/SwiftASTContext.h b/lldb/include/lldb/Symbol/SwiftASTContext.h index 9f507e4cbda30..92f59db0011ee 100644 --- a/lldb/include/lldb/Symbol/SwiftASTContext.h +++ b/lldb/include/lldb/Symbol/SwiftASTContext.h @@ -126,6 +126,59 @@ class TypeSystemSwift : public TypeSystem { bool print_help_if_available, bool print_extensions_if_available) = 0; + /// Unavailable hardcoded functions that don't make sense for Swift. + /// \{ + ConstString DeclContextGetName(void *opaque_decl_ctx) override { return {}; } + ConstString DeclContextGetScopeQualifiedName(void *opaque_decl_ctx) override { + return {}; + } + bool + DeclContextIsClassMethod(void *opaque_decl_ctx, + lldb::LanguageType *language_ptr, + bool *is_instance_method_ptr, + ConstString *language_object_name_ptr) override { + return false; + } + bool IsRuntimeGeneratedType(void *type) override { return false; } + bool IsCharType(void *type) override { return false; } + bool IsCompleteType(void *type) override { return true; } + bool IsConst(void *type) override { return false; } + bool IsCStringType(void *type, uint32_t &length) override { return false; } + bool IsVectorType(void *type, CompilerType *element_type, + uint64_t *size) override { + return false; + } + uint32_t IsHomogeneousAggregate(void *type, + CompilerType *base_type_ptr) override { + return 0; + } + bool IsBlockPointerType(void *type, + CompilerType *function_pointer_type_ptr) override { + return false; + } + bool IsPolymorphicClass(void *type) override { return false; } + bool IsBeingDefined(void *type) override { return false; } + unsigned GetTypeQualifiers(void *type) override { return 0; } + CompilerType GetTypeForDecl(void *opaque_decl) override { + llvm_unreachable("GetTypeForDecl not implemented"); + } + CompilerType GetBasicTypeFromAST(lldb::BasicType basic_type) override { + return {}; + } + const llvm::fltSemantics &GetFloatTypeSemantics(size_t byte_size) override { + // See: https://reviews.llvm.org/D67239. At this time of writing this API + // is only used by DumpDataExtractor for the C type system. + llvm_unreachable("GetFloatTypeSemantics not implemented."); + } + lldb::BasicType GetBasicTypeEnumeration(void *type) override { + return lldb::eBasicTypeInvalid; + } + uint32_t GetNumVirtualBaseClasses(void *opaque_type) override { return 0; } + CompilerType GetVirtualBaseClassAtIndex(void *opaque_type, size_t idx, + uint32_t *bit_offset_ptr) override { + return {}; + } + /// \} protected: /// Used in the logs. std::string m_description; @@ -174,12 +227,6 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift { return {}; } - ConstString DeclContextGetName(void *opaque_decl_ctx) override; - ConstString DeclContextGetScopeQualifiedName(void *opaque_decl_ctx) override; - bool DeclContextIsClassMethod(void *opaque_decl_ctx, - lldb::LanguageType *language_ptr, - bool *is_instance_method_ptr, - ConstString *language_object_name_ptr) override; bool DeclContextIsContainedInLookup(void *opaque_decl_ctx, void *other_opaque_decl_ctx) override { if (opaque_decl_ctx == other_opaque_decl_ctx) @@ -194,8 +241,6 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift { bool IsArrayType(void *type, CompilerType *element_type, uint64_t *size, bool *is_incomplete) override; bool IsAggregateType(void *type) override; - bool IsCharType(void *type) override; - bool IsCompleteType(void *type) override; bool IsDefined(void *type) override; bool IsFloatingPointType(void *type, uint32_t &count, bool &is_complex) override; @@ -204,8 +249,6 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift { CompilerType GetFunctionArgumentAtIndex(void *type, const size_t index) override; bool IsFunctionPointerType(void *type) override; - bool IsBlockPointerType(void *type, - CompilerType *function_pointer_type_ptr) override; bool IsIntegerType(void *type, bool &is_signed) override; bool IsPossibleDynamicType(void *type, CompilerType *target_type, // Can pass NULL @@ -240,7 +283,6 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift { CompilerType GetPointerType(void *type) override; // Exploring the type - const llvm::fltSemantics &GetFloatTypeSemantics(size_t byte_size) override; llvm::Optional GetBitSize(lldb::opaque_compiler_type_t type, ExecutionContextScope *exe_scope) override; @@ -251,7 +293,6 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift { lldb::Format GetFormat(void *type) override; uint32_t GetNumChildren(void *type, bool omit_empty_base_classes, const ExecutionContext *exe_ctx) override; - lldb::BasicType GetBasicTypeEnumeration(void *type) override; uint32_t GetNumFields(void *type) override; CompilerType GetFieldAtIndex(void *type, size_t idx, std::string &name, uint64_t *bit_offset_ptr, @@ -299,41 +340,26 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift { void DumpTypeDescription(void *type) override; void DumpTypeDescription(void *type, Stream *s) override; - bool IsRuntimeGeneratedType(void *type) override; void DumpSummary(void *type, ExecutionContext *exe_ctx, Stream *s, const DataExtractor &data, lldb::offset_t data_offset, size_t data_byte_size) override; bool IsPointerOrReferenceType(void *type, CompilerType *pointee_type) override; - unsigned GetTypeQualifiers(void *type) override; - bool IsCStringType(void *type, uint32_t &length) override; llvm::Optional GetTypeBitAlign(void *type, ExecutionContextScope *exe_scope) override; - CompilerType GetBasicTypeFromAST(lldb::BasicType basic_type) override; CompilerType GetBuiltinTypeForEncodingAndBitSize(lldb::Encoding encoding, size_t bit_size) override { return CompilerType(); } - bool IsBeingDefined(void *type) override; - bool IsConst(void *type) override; - uint32_t IsHomogeneousAggregate(void *type, - CompilerType *base_type_ptr) override; - bool IsPolymorphicClass(void *type) override; bool IsTypedefType(void *type) override; CompilerType GetTypedefedType(void *type) override; - CompilerType GetTypeForDecl(void *opaque_decl) override; - bool IsVectorType(void *type, CompilerType *element_type, - uint64_t *size) override; CompilerType GetFullyUnqualifiedType(void *type) override; CompilerType GetNonReferenceType(void *type) override; CompilerType GetLValueReferenceType(void *type) override; CompilerType GetRValueReferenceType(void *opaque_type) override; uint32_t GetNumDirectBaseClasses(void *opaque_type) override; - uint32_t GetNumVirtualBaseClasses(void *opaque_type) override; CompilerType GetDirectBaseClassAtIndex(void *opaque_type, size_t idx, uint32_t *bit_offset_ptr) override; - CompilerType GetVirtualBaseClassAtIndex(void *opaque_type, size_t idx, - uint32_t *bit_offset_ptr) override; bool IsReferenceType(void *type, CompilerType *pointee_type, bool *is_rvalue) override; bool @@ -698,15 +724,6 @@ class SwiftASTContext : public TypeSystemSwift { return {}; } - ConstString DeclContextGetName(void *opaque_decl_ctx) override; - - ConstString DeclContextGetScopeQualifiedName(void *opaque_decl_ctx) override; - - bool DeclContextIsClassMethod(void *opaque_decl_ctx, - lldb::LanguageType *language_ptr, - bool *is_instance_method_ptr, - ConstString *language_object_name_ptr) override; - bool DeclContextIsContainedInLookup(void *opaque_decl_ctx, void *other_opaque_decl_ctx) override { if (opaque_decl_ctx == other_opaque_decl_ctx) @@ -725,10 +742,6 @@ class SwiftASTContext : public TypeSystemSwift { bool IsAggregateType(void *type) override; - bool IsCharType(void *type) override; - - bool IsCompleteType(void *type) override; - bool IsDefined(void *type) override; bool IsFloatingPointType(void *type, uint32_t &count, @@ -743,9 +756,6 @@ class SwiftASTContext : public TypeSystemSwift { bool IsFunctionPointerType(void *type) override; - bool IsBlockPointerType(void *type, - CompilerType *function_pointer_type_ptr) override; - bool IsIntegerType(void *type, bool &is_signed) override; bool IsPossibleDynamicType(void *type, @@ -852,8 +862,6 @@ class SwiftASTContext : public TypeSystemSwift { // Exploring the type - const llvm::fltSemantics &GetFloatTypeSemantics(size_t byte_size) override; - llvm::Optional GetBitSize(lldb::opaque_compiler_type_t type, ExecutionContextScope *exe_scope) override; @@ -869,8 +877,6 @@ class SwiftASTContext : public TypeSystemSwift { uint32_t GetNumChildren(void *type, bool omit_empty_base_classes, const ExecutionContext *exe_ctx) override; - lldb::BasicType GetBasicTypeEnumeration(void *type) override; - uint32_t GetNumFields(void *type) override; CompilerType GetFieldAtIndex(void *type, size_t idx, std::string &name, @@ -955,8 +961,6 @@ class SwiftASTContext : public TypeSystemSwift { // TODO: These methods appear unused. Should they be removed? - bool IsRuntimeGeneratedType(void *type) override; - void DumpSummary(void *type, ExecutionContext *exe_ctx, Stream *s, const DataExtractor &data, lldb::offset_t data_offset, size_t data_byte_size) override; @@ -966,29 +970,14 @@ class SwiftASTContext : public TypeSystemSwift { bool IsPointerOrReferenceType(void *type, CompilerType *pointee_type) override; - unsigned GetTypeQualifiers(void *type) override; - - bool IsCStringType(void *type, uint32_t &length) override; - llvm::Optional GetTypeBitAlign(void *type, ExecutionContextScope *exe_scope) override; - CompilerType GetBasicTypeFromAST(lldb::BasicType basic_type) override; - CompilerType GetBuiltinTypeForEncodingAndBitSize(lldb::Encoding encoding, size_t bit_size) override { return CompilerType(); } - bool IsBeingDefined(void *type) override; - - bool IsConst(void *type) override; - - uint32_t IsHomogeneousAggregate(void *type, - CompilerType *base_type_ptr) override; - - bool IsPolymorphicClass(void *type) override; - bool IsTypedefType(void *type) override; // If the current object represents a typedef type, get the underlying type @@ -998,11 +987,6 @@ class SwiftASTContext : public TypeSystemSwift { std::string GetSuperclassName(const CompilerType &superclass_type); - CompilerType GetTypeForDecl(void *opaque_decl) override; - - bool IsVectorType(void *type, CompilerType *element_type, - uint64_t *size) override; - CompilerType GetFullyUnqualifiedType(void *type) override; CompilerType GetNonReferenceType(void *type) override; @@ -1013,14 +997,9 @@ class SwiftASTContext : public TypeSystemSwift { uint32_t GetNumDirectBaseClasses(void *opaque_type) override; - uint32_t GetNumVirtualBaseClasses(void *opaque_type) override; - CompilerType GetDirectBaseClassAtIndex(void *opaque_type, size_t idx, uint32_t *bit_offset_ptr) override; - CompilerType GetVirtualBaseClassAtIndex(void *opaque_type, size_t idx, - uint32_t *bit_offset_ptr) override; - bool IsReferenceType(void *type, CompilerType *pointee_type, bool *is_rvalue) override; diff --git a/lldb/source/Symbol/SwiftASTContext.cpp b/lldb/source/Symbol/SwiftASTContext.cpp index d7e33b55b8611..1f3ed99d21c5e 100644 --- a/lldb/source/Symbol/SwiftASTContext.cpp +++ b/lldb/source/Symbol/SwiftASTContext.cpp @@ -5163,25 +5163,6 @@ void SwiftASTContext::AddDebuggerClient( std::unique_ptr(debugger_client)); } -ConstString SwiftASTContext::DeclContextGetName(void *opaque_decl_ctx) { - return ConstString(); -} - -ConstString -SwiftASTContext::DeclContextGetScopeQualifiedName(void *opaque_decl_ctx) { - return ConstString(); -} - -bool SwiftASTContext::DeclContextIsClassMethod( - void *opaque_decl_ctx, lldb::LanguageType *language_ptr, - bool *is_instance_method_ptr, ConstString *language_object_name_ptr) { - return false; -} - -/////////// -//////////////////// -/////////// - #ifndef NDEBUG bool SwiftASTContext::Verify(lldb::opaque_compiler_type_t type) { // Manual casting to avoid construction a temporary CompilerType @@ -5232,23 +5213,6 @@ bool SwiftASTContext::IsAggregateType(void *type) { return false; } -bool SwiftASTContext::IsVectorType(void *type, CompilerType *element_type, - uint64_t *size) { - return false; -} - -bool SwiftASTContext::IsRuntimeGeneratedType(void *type) { return false; } - -bool SwiftASTContext::IsCharType(void *type) { return false; } - -bool SwiftASTContext::IsCompleteType(void *type) { return true; } - -bool SwiftASTContext::IsConst(void *type) { return false; } - -bool SwiftASTContext::IsCStringType(void *type, uint32_t &length) { - return false; -} - bool SwiftASTContext::IsFunctionType(void *type, bool *is_variadic_ptr) { if (type) { swift::CanType swift_can_type(GetCanonicalSwiftType(type)); @@ -5266,12 +5230,6 @@ bool SwiftASTContext::IsFunctionType(void *type, bool *is_variadic_ptr) { return false; } -/// Used to detect "Homogeneous Floating-point Aggregates" -uint32_t SwiftASTContext::IsHomogeneousAggregate(void *type, - CompilerType *base_type_ptr) { - return 0; -} - size_t SwiftASTContext::GetNumberOfFunctionArguments(void *type) { if (type) { swift::CanType swift_can_type(GetCanonicalSwiftType(type)); @@ -5305,11 +5263,6 @@ bool SwiftASTContext::IsFunctionPointerType(void *type) { return IsFunctionType(type, nullptr); // FIXME: think about this } -bool SwiftASTContext::IsBlockPointerType( - void *type, CompilerType *function_pointer_type_ptr) { - return false; -} - bool SwiftASTContext::IsIntegerType(void *type, bool &is_signed) { return (GetTypeInfo(type, nullptr) & eTypeIsInteger); } @@ -5383,8 +5336,6 @@ bool SwiftASTContext::IsDefined(void *type) { return true; } -bool SwiftASTContext::IsPolymorphicClass(void *type) { return false; } - bool SwiftASTContext::IsPossibleDynamicType(void *type, CompilerType *dynamic_pointee_type, bool check_cplusplus, @@ -5572,8 +5523,6 @@ SwiftASTContext::GetAllocationStrategy(CompilerType type) { return TypeAllocationStrategy::eUnknown; } -bool SwiftASTContext::IsBeingDefined(void *type) { return false; } - //---------------------------------------------------------------------- // Type Completion //---------------------------------------------------------------------- @@ -5893,8 +5842,6 @@ lldb::TypeClass SwiftASTContext::GetTypeClass(void *type) { return lldb::eTypeClassOther; } -unsigned SwiftASTContext::GetTypeQualifiers(void *type) { return 0; } - //---------------------------------------------------------------------- // Creating related types //---------------------------------------------------------------------- @@ -6147,19 +6094,6 @@ SwiftASTContext::GetUnboundType(lldb::opaque_compiler_type_t type) { return ToCompilerType({GetSwiftType(type)}); } -CompilerType SwiftASTContext::GetTypeForDecl(void *opaque_decl) { - assert("not yet implemented"); - return {}; -} - -//---------------------------------------------------------------------- -// Create related types using the current type's AST -//---------------------------------------------------------------------- - -CompilerType SwiftASTContext::GetBasicTypeFromAST(lldb::BasicType basic_type) { - return {}; -} - //---------------------------------------------------------------------- // Exploring the type //---------------------------------------------------------------------- @@ -6197,13 +6131,6 @@ bool SwiftASTContext::IsFixedSize(CompilerType compiler_type) { return false; } -const llvm::fltSemantics & -SwiftASTContext::GetFloatTypeSemantics(size_t byte_size) { - // See: https://reviews.llvm.org/D67239. At this time of writing this API - // is only used by DumpDataExtractor for the C type system. - llvm_unreachable("SwiftASTContext::GetFloatTypeSemantics not implemented."); -} - llvm::Optional SwiftASTContext::GetBitSize(lldb::opaque_compiler_type_t type, ExecutionContextScope *exe_scope) { @@ -6602,10 +6529,6 @@ uint32_t SwiftASTContext::GetNumChildren(void *type, return num_children; } -lldb::BasicType SwiftASTContext::GetBasicTypeEnumeration(void *type) { - return eBasicTypeInvalid; -} - #pragma mark Aggregate Types uint32_t SwiftASTContext::GetNumDirectBaseClasses(void *opaque_type) { @@ -6622,10 +6545,6 @@ uint32_t SwiftASTContext::GetNumDirectBaseClasses(void *opaque_type) { return 0; } -uint32_t SwiftASTContext::GetNumVirtualBaseClasses(void *opaque_type) { - return 0; -} - uint32_t SwiftASTContext::GetNumFields(void *type) { VALID_OR_RETURN(0); @@ -6742,12 +6661,6 @@ SwiftASTContext::GetDirectBaseClassAtIndex(void *opaque_type, size_t idx, return {}; } -CompilerType -SwiftASTContext::GetVirtualBaseClassAtIndex(void *opaque_type, size_t idx, - uint32_t *bit_offset_ptr) { - return {}; -} - /// Retrieve the printable name of a tuple element. static std::string GetTupleElementName(const swift::TupleType *tuple_type, unsigned index, diff --git a/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp index 1e5be8f677d6f..f487f7d6c345f 100644 --- a/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp +++ b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp @@ -298,20 +298,6 @@ void TypeSystemSwiftTypeRef::DiagnoseWarnings(Process &process, DWARFASTParser *TypeSystemSwiftTypeRef::GetDWARFParser() { return m_swift_ast_context->GetDWARFParser(); } -ConstString TypeSystemSwiftTypeRef::DeclContextGetName(void *opaque_decl_ctx) { - return m_swift_ast_context->DeclContextGetName(opaque_decl_ctx); -} -ConstString TypeSystemSwiftTypeRef::DeclContextGetScopeQualifiedName( - void *opaque_decl_ctx) { - return m_swift_ast_context->DeclContextGetScopeQualifiedName(opaque_decl_ctx); -} -bool TypeSystemSwiftTypeRef::DeclContextIsClassMethod( - void *opaque_decl_ctx, lldb::LanguageType *language_ptr, - bool *is_instance_method_ptr, ConstString *language_object_name_ptr) { - return m_swift_ast_context->DeclContextIsClassMethod( - opaque_decl_ctx, language_ptr, is_instance_method_ptr, - language_object_name_ptr); -} // Tests @@ -400,12 +386,6 @@ bool TypeSystemSwiftTypeRef::IsArrayType(void *type, CompilerType *element_type, bool TypeSystemSwiftTypeRef::IsAggregateType(void *type) { return m_swift_ast_context->IsAggregateType(ReconstructType(type)); } -bool TypeSystemSwiftTypeRef::IsCharType(void *type) { - return m_swift_ast_context->IsCharType(ReconstructType(type)); -} -bool TypeSystemSwiftTypeRef::IsCompleteType(void *type) { - return m_swift_ast_context->IsCompleteType(ReconstructType(type)); -} bool TypeSystemSwiftTypeRef::IsDefined(void *type) { return m_swift_ast_context->IsDefined(ReconstructType(type)); } @@ -444,11 +424,6 @@ TypeSystemSwiftTypeRef::GetFunctionArgumentAtIndex(void *type, bool TypeSystemSwiftTypeRef::IsFunctionPointerType(void *type) { return m_swift_ast_context->IsFunctionPointerType(ReconstructType(type)); } -bool TypeSystemSwiftTypeRef::IsBlockPointerType( - void *type, CompilerType *function_pointer_type_ptr) { - return m_swift_ast_context->IsBlockPointerType(ReconstructType(type), - function_pointer_type_ptr); -} bool TypeSystemSwiftTypeRef::IsIntegerType(void *type, bool &is_signed) { return m_swift_ast_context->IsIntegerType(ReconstructType(type), is_signed); } @@ -539,10 +514,6 @@ CompilerType TypeSystemSwiftTypeRef::GetPointerType(void *type) { } // Exploring the type -const llvm::fltSemantics & -TypeSystemSwiftTypeRef::GetFloatTypeSemantics(size_t byte_size) { - return m_swift_ast_context->GetFloatTypeSemantics(byte_size); -} llvm::Optional TypeSystemSwiftTypeRef::GetBitSize(lldb::opaque_compiler_type_t type, ExecutionContextScope *exe_scope) { @@ -566,9 +537,6 @@ TypeSystemSwiftTypeRef::GetNumChildren(void *type, bool omit_empty_base_classes, return m_swift_ast_context->GetNumChildren(ReconstructType(type), omit_empty_base_classes, exe_ctx); } -lldb::BasicType TypeSystemSwiftTypeRef::GetBasicTypeEnumeration(void *type) { - return m_swift_ast_context->GetBasicTypeEnumeration(ReconstructType(type)); -} uint32_t TypeSystemSwiftTypeRef::GetNumFields(void *type) { return m_swift_ast_context->GetNumFields(ReconstructType(type)); } @@ -705,9 +673,6 @@ void TypeSystemSwiftTypeRef::DumpTypeDescription(void *type) { void TypeSystemSwiftTypeRef::DumpTypeDescription(void *type, Stream *s) { return m_swift_ast_context->DumpTypeDescription(ReconstructType(type), s); } -bool TypeSystemSwiftTypeRef::IsRuntimeGeneratedType(void *type) { - return m_swift_ast_context->IsRuntimeGeneratedType(ReconstructType(type)); -} void TypeSystemSwiftTypeRef::DumpSummary(void *type, ExecutionContext *exe_ctx, Stream *s, const DataExtractor &data, lldb::offset_t data_offset, @@ -720,51 +685,17 @@ bool TypeSystemSwiftTypeRef::IsPointerOrReferenceType( return m_swift_ast_context->IsPointerOrReferenceType(ReconstructType(type), pointee_type); } -unsigned TypeSystemSwiftTypeRef::GetTypeQualifiers(void *type) { - return m_swift_ast_context->GetTypeQualifiers(ReconstructType(type)); -} -bool TypeSystemSwiftTypeRef::IsCStringType(void *type, uint32_t &length) { - return m_swift_ast_context->IsCStringType(ReconstructType(type), length); -} llvm::Optional TypeSystemSwiftTypeRef::GetTypeBitAlign(void *type, ExecutionContextScope *exe_scope) { return m_swift_ast_context->GetTypeBitAlign(ReconstructType(type), exe_scope); } -CompilerType -TypeSystemSwiftTypeRef::GetBasicTypeFromAST(lldb::BasicType basic_type) { - return m_swift_ast_context->GetBasicTypeFromAST(basic_type); -} -bool TypeSystemSwiftTypeRef::IsBeingDefined(void *type) { - return m_swift_ast_context->IsBeingDefined(ReconstructType(type)); -} -bool TypeSystemSwiftTypeRef::IsConst(void *type) { - return m_swift_ast_context->IsConst(ReconstructType(type)); -} -uint32_t -TypeSystemSwiftTypeRef::IsHomogeneousAggregate(void *type, - CompilerType *base_type_ptr) { - return m_swift_ast_context->IsHomogeneousAggregate(ReconstructType(type), - base_type_ptr); -} -bool TypeSystemSwiftTypeRef::IsPolymorphicClass(void *type) { - return m_swift_ast_context->IsPolymorphicClass(ReconstructType(type)); -} bool TypeSystemSwiftTypeRef::IsTypedefType(void *type) { return m_swift_ast_context->IsTypedefType(ReconstructType(type)); } CompilerType TypeSystemSwiftTypeRef::GetTypedefedType(void *type) { return m_swift_ast_context->GetTypedefedType(ReconstructType(type)); } -CompilerType TypeSystemSwiftTypeRef::GetTypeForDecl(void *opaque_decl) { - return m_swift_ast_context->GetTypeForDecl(opaque_decl); -} -bool TypeSystemSwiftTypeRef::IsVectorType(void *type, - CompilerType *element_type, - uint64_t *size) { - return m_swift_ast_context->IsVectorType(ReconstructType(type), element_type, - size); -} CompilerType TypeSystemSwiftTypeRef::GetFullyUnqualifiedType(void *type) { return m_swift_ast_context->GetFullyUnqualifiedType(ReconstructType(type)); } @@ -780,21 +711,12 @@ CompilerType TypeSystemSwiftTypeRef::GetRValueReferenceType(void *type) { uint32_t TypeSystemSwiftTypeRef::GetNumDirectBaseClasses(void *type) { return m_swift_ast_context->GetNumDirectBaseClasses(ReconstructType(type)); } -uint32_t TypeSystemSwiftTypeRef::GetNumVirtualBaseClasses(void *type) { - return m_swift_ast_context->GetNumVirtualBaseClasses(ReconstructType(type)); -} CompilerType TypeSystemSwiftTypeRef::GetDirectBaseClassAtIndex(void *type, size_t idx, uint32_t *bit_offset_ptr) { return m_swift_ast_context->GetDirectBaseClassAtIndex(ReconstructType(type), idx, bit_offset_ptr); } -CompilerType -TypeSystemSwiftTypeRef::GetVirtualBaseClassAtIndex(void *type, size_t idx, - uint32_t *bit_offset_ptr) { - return m_swift_ast_context->GetVirtualBaseClassAtIndex(ReconstructType(type), - idx, bit_offset_ptr); -} bool TypeSystemSwiftTypeRef::IsReferenceType(void *type, CompilerType *pointee_type, bool *is_rvalue) { From b3c8ec228ef082e123f6a0391dedea41be554942 Mon Sep 17 00:00:00 2001 From: Med Ismail Bennani Date: Tue, 31 Mar 2020 02:33:42 +0200 Subject: [PATCH 123/286] [lldb/DWARF] Fix evaluator crash when accessing empty stack. This patch fixes a crash that happens on the DWARF expression evaluator when trying to access the top of the stack while it's empty. rdar://60512489 Differential Revision: https://reviews.llvm.org/D77108 Signed-off-by: Med Ismail Bennani --- lldb/source/Expression/DWARFExpression.cpp | 6 ++++++ lldb/unittests/Expression/DWARFExpressionTest.cpp | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp index c67e35b145189..3f2b3a87426d7 100644 --- a/lldb/source/Expression/DWARFExpression.cpp +++ b/lldb/source/Expression/DWARFExpression.cpp @@ -2332,6 +2332,12 @@ bool DWARFExpression::Evaluate( // rather is a constant value. The value from the top of the stack is the // value to be used. This is the actual object value and not the location. case DW_OP_stack_value: + if (stack.empty()) { + if (error_ptr) + error_ptr->SetErrorString( + "Expression stack needs at least 1 item for DW_OP_stack_value."); + return false; + } stack.back().SetValueType(Value::eValueTypeScalar); break; diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp b/lldb/unittests/Expression/DWARFExpressionTest.cpp index 8fad88a93e114..0340db2d026f8 100644 --- a/lldb/unittests/Expression/DWARFExpressionTest.cpp +++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp @@ -335,3 +335,7 @@ TEST(DWARFExpression, DW_OP_convert) { t.Eval({DW_OP_const1s, 'X', DW_OP_convert, 0x1d}).takeError(), llvm::Failed()); } + +TEST(DWARFExpression, DW_OP_stack_value) { + EXPECT_THAT_EXPECTED(Evaluate({DW_OP_stack_value}), llvm::Failed()); +} From 6676c3a90de3adac3bd226bae8a8f0ec1a0ff87e Mon Sep 17 00:00:00 2001 From: Davide Italiano Date: Tue, 31 Mar 2020 13:55:36 -0700 Subject: [PATCH 124/286] [debugserver/ARM64] Make sure watchpoints hit are attributed correctly. This didn't happen for arm64 if you have watches for variables that are contigous in memory. --- .../watchpoints/watchpoint_count/Makefile | 3 ++ .../watchpoint_count/TestWatchpointCount.py | 43 +++++++++++++++++++ .../watchpoints/watchpoint_count/main.c | 13 ++++++ .../source/MacOSX/arm64/DNBArchImplARM64.cpp | 43 ++++++++++--------- 4 files changed, 82 insertions(+), 20 deletions(-) create mode 100644 lldb/test/API/commands/watchpoints/watchpoint_count/Makefile create mode 100644 lldb/test/API/commands/watchpoints/watchpoint_count/TestWatchpointCount.py create mode 100644 lldb/test/API/commands/watchpoints/watchpoint_count/main.c diff --git a/lldb/test/API/commands/watchpoints/watchpoint_count/Makefile b/lldb/test/API/commands/watchpoints/watchpoint_count/Makefile new file mode 100644 index 0000000000000..10495940055b6 --- /dev/null +++ b/lldb/test/API/commands/watchpoints/watchpoint_count/Makefile @@ -0,0 +1,3 @@ +C_SOURCES := main.c + +include Makefile.rules diff --git a/lldb/test/API/commands/watchpoints/watchpoint_count/TestWatchpointCount.py b/lldb/test/API/commands/watchpoints/watchpoint_count/TestWatchpointCount.py new file mode 100644 index 0000000000000..18667e913a944 --- /dev/null +++ b/lldb/test/API/commands/watchpoints/watchpoint_count/TestWatchpointCount.py @@ -0,0 +1,43 @@ +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class TestWatchpointCount(TestBase): + mydir = TestBase.compute_mydir(__file__) + NO_DEBUG_INFO_TESTCASE = True + + def setUp(self): + TestBase.setUp(self) + + def test_watchpoint_count(self): + self.build() + (_, process, thread, _) = lldbutil.run_to_source_breakpoint(self, "patatino", lldb.SBFileSpec("main.c")) + frame = thread.GetFrameAtIndex(0) + first_var = frame.FindVariable("x1") + second_var = frame.FindVariable("x2") + + error = lldb.SBError() + first_watch = first_var.Watch(True, False, True, error) + if not error.Success(): + self.fail( + "Failed to make watchpoint for x1: %s" % + (error.GetCString())) + + second_watch = second_var.Watch(True, False, True, error) + if not error.Success(): + self.fail( + "Failed to make watchpoint for x2: %s" % + (error.GetCString())) + process.Continue() + + stop_reason = thread.GetStopReason() + self.assertEqual(stop_reason, lldb.eStopReasonWatchpoint, "watchpoint for x1 not hit") + stop_reason_descr = thread.GetStopDescription(256) + self.assertEqual(stop_reason_descr, "watchpoint 1") + + process.Continue() + stop_reason = thread.GetStopReason() + self.assertEqual(stop_reason, lldb.eStopReasonWatchpoint, "watchpoint for x2 not hit") + stop_reason_descr = thread.GetStopDescription(256) + self.assertEqual(stop_reason_descr, "watchpoint 2") diff --git a/lldb/test/API/commands/watchpoints/watchpoint_count/main.c b/lldb/test/API/commands/watchpoints/watchpoint_count/main.c new file mode 100644 index 0000000000000..fc9a370e41f31 --- /dev/null +++ b/lldb/test/API/commands/watchpoints/watchpoint_count/main.c @@ -0,0 +1,13 @@ +#include +#include + +int main() { + uint8_t x1 = 0; + uint16_t x2 = 0; + + printf("patatino\n"); + + x1 += 1; + x2 += 2; + return 0; +} diff --git a/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp b/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp index e5d4b05d987c1..3e7bda88e6af3 100644 --- a/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp +++ b/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp @@ -1067,31 +1067,34 @@ uint32_t DNBArchMachARM64::GetHardwareWatchpointHit(nub_addr_t &addr) { "DNBArchMachARM64::GetHardwareWatchpointHit() addr = 0x%llx", (uint64_t)addr); - // This is the watchpoint value to match against, i.e., word address. - nub_addr_t wp_val = addr & ~((nub_addr_t)3); if (kret == KERN_SUCCESS) { DBG &debug_state = m_state.dbg; uint32_t i, num = NumSupportedHardwareWatchpoints(); for (i = 0; i < num; ++i) { nub_addr_t wp_addr = GetWatchAddress(debug_state, i); - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::" - "GetHardwareWatchpointHit() slot: %u " - "(addr = 0x%llx).", - i, (uint64_t)wp_addr); - if (wp_val == wp_addr) { - uint32_t byte_mask = bits(debug_state.__wcr[i], 12, 5); - - // Sanity check the byte_mask, first. - if (LowestBitSet(byte_mask) < 0) - continue; - - // Check that the watchpoint is enabled. - if (!IsWatchpointEnabled(debug_state, i)) - continue; - - // Compute the starting address (from the point of view of the - // debugger). - addr = wp_addr + LowestBitSet(byte_mask); + uint32_t byte_mask = bits(debug_state.__wcr[i], 12, 5); + + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplX86_64::" + "GetHardwareWatchpointHit() slot: %u " + "(addr = 0x%llx; byte_mask = 0x%x)", + i, static_cast(wp_addr), + byte_mask); + + if (!IsWatchpointEnabled(debug_state, i)) + continue; + + if (bits(wp_addr, 48, 3) != bits(addr, 48, 3)) + continue; + + // Sanity check the byte_mask + uint32_t lsb = LowestBitSet(byte_mask); + if (lsb < 0) + continue; + + uint64_t byte_to_match = bits(addr, 2, 0); + + if (byte_mask & (1 << byte_to_match)) { + addr = wp_addr + lsb; return i; } } From a24b128a96da0fbb14fad38b0785548badf204f7 Mon Sep 17 00:00:00 2001 From: Ben Langmuir Date: Tue, 31 Mar 2020 09:26:59 -0700 Subject: [PATCH 125/286] [pch] Honour -fallow-pch-with-compiler-errors for overall compilation status Previously we would emit a PCH with errors, but fail the overall compilation. If run using the driver, that would result in removing the just-produced PCH. Instead, we should have the compilation result match whether we were able to emit the PCH. Differential Revision: https://reviews.llvm.org/D77159 rdar://61110294 --- clang/lib/Serialization/GeneratePCH.cpp | 5 +++++ clang/test/Index/pch-with-errors.c | 3 +++ 2 files changed, 8 insertions(+) diff --git a/clang/lib/Serialization/GeneratePCH.cpp b/clang/lib/Serialization/GeneratePCH.cpp index 002233e49bb06..d869796b82c12 100644 --- a/clang/lib/Serialization/GeneratePCH.cpp +++ b/clang/lib/Serialization/GeneratePCH.cpp @@ -57,6 +57,11 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) { } } + // Errors that do not prevent the PCH from being written should not cause the + // overall compilation to fail either. + if (AllowASTWithErrors) + PP.getDiagnostics().getClient()->clear(); + // Emit the PCH file to the Buffer. assert(SemaPtr && "No Sema?"); Buffer->Signature = diff --git a/clang/test/Index/pch-with-errors.c b/clang/test/Index/pch-with-errors.c index 5c94a8a8e4d38..e8711c8e26a9b 100644 --- a/clang/test/Index/pch-with-errors.c +++ b/clang/test/Index/pch-with-errors.c @@ -42,3 +42,6 @@ void foo(void) { // RUN: not c-index-test -write-pch %t.pch foobar.c 2>&1 | FileCheck -check-prefix=NONEXISTENT %s // NONEXISTENT: Unable to load translation unit + +// RUN: %clang -x c-header %s -o %t-clang.h.pch -Xclang -detailed-preprocessing-record -Xclang -fallow-pch-with-compiler-errors +// RUN: c-index-test -index-file %s -include %t-clang.h -Xclang -detailed-preprocessing-record | FileCheck -check-prefix=CHECK-INDEX %s From 3c890c2b44ac0c8c805c5d38eb844e4caeedc783 Mon Sep 17 00:00:00 2001 From: Ben Langmuir Date: Tue, 31 Mar 2020 15:23:01 -0700 Subject: [PATCH 126/286] Forward WrapperFrontendAction::shouldEraseOutputFiles() Per the documentation, this class is supposed to forward every virtual method, but we had missed on (shouldEraseOutputFiles). This fixes using a wrapped frontend action over the PCH generator when using -fallow-pch-with-compiler-errors. I do not think any upstream wrapper actions can test this. Differential Revision: https://reviews.llvm.org/D77180 rdar://61110294 --- clang/include/clang/Frontend/FrontendAction.h | 1 + clang/lib/Frontend/FrontendAction.cpp | 3 +++ 2 files changed, 4 insertions(+) diff --git a/clang/include/clang/Frontend/FrontendAction.h b/clang/include/clang/Frontend/FrontendAction.h index e994e24cf5afa..c9f9f080c1413 100644 --- a/clang/include/clang/Frontend/FrontendAction.h +++ b/clang/include/clang/Frontend/FrontendAction.h @@ -312,6 +312,7 @@ class WrapperFrontendAction : public FrontendAction { bool BeginSourceFileAction(CompilerInstance &CI) override; void ExecuteAction() override; void EndSourceFileAction() override; + bool shouldEraseOutputFiles() override; public: /// Construct a WrapperFrontendAction from an existing action, taking diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp index 204597354282d..31988d5155be8 100644 --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -1096,6 +1096,9 @@ void WrapperFrontendAction::ExecuteAction() { void WrapperFrontendAction::EndSourceFileAction() { WrappedAction->EndSourceFileAction(); } +bool WrapperFrontendAction::shouldEraseOutputFiles() { + return WrappedAction->shouldEraseOutputFiles(); +} bool WrapperFrontendAction::usesPreprocessorOnly() const { return WrappedAction->usesPreprocessorOnly(); From ab1ec7cd3f611bfeeea05d85b276ca0025449300 Mon Sep 17 00:00:00 2001 From: Augusto Noronha Date: Fri, 27 Mar 2020 21:31:46 -0300 Subject: [PATCH 127/286] Fix crash when dyn_casting a potentially null value --- .../Plugins/ExpressionParser/Swift/SwiftUserExpression.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/source/Plugins/ExpressionParser/Swift/SwiftUserExpression.cpp b/lldb/source/Plugins/ExpressionParser/Swift/SwiftUserExpression.cpp index 3b4d3b764389d..26b819836d601 100644 --- a/lldb/source/Plugins/ExpressionParser/Swift/SwiftUserExpression.cpp +++ b/lldb/source/Plugins/ExpressionParser/Swift/SwiftUserExpression.cpp @@ -244,7 +244,7 @@ void SwiftUserExpression::ScanContext(ExecutionContext &exe_ctx, Status &err) { self_type = ToCompilerType(object_type.getPointer()); // Handle weak self. - if (auto *ref_type = llvm::dyn_cast( + if (auto *ref_type = llvm::dyn_cast_or_null( GetSwiftType(self_type).getPointer())) { if (ref_type->getOwnership() == swift::ReferenceOwnership::Weak) { m_is_class = true; From 0718eea2e2e55f030616a00ab15bd2a2e7a17e08 Mon Sep 17 00:00:00 2001 From: Augusto Noronha Date: Tue, 31 Mar 2020 21:28:14 -0300 Subject: [PATCH 128/286] Improve reporting when type reconstruction fails --- lldb/include/lldb/Symbol/SwiftASTContext.h | 2 + lldb/source/Symbol/SwiftASTContext.cpp | 59 +++++++++++++++++----- 2 files changed, 48 insertions(+), 13 deletions(-) diff --git a/lldb/include/lldb/Symbol/SwiftASTContext.h b/lldb/include/lldb/Symbol/SwiftASTContext.h index 92f59db0011ee..919a29caeec54 100644 --- a/lldb/include/lldb/Symbol/SwiftASTContext.h +++ b/lldb/include/lldb/Symbol/SwiftASTContext.h @@ -612,6 +612,7 @@ class SwiftASTContext : public TypeSystemSwift { /// Reconstruct a Swift AST type from a mangled name by looking its /// components up in Swift modules. + swift::TypeBase *ReconstructType(ConstString mangled_typename); swift::TypeBase *ReconstructType(ConstString mangled_typename, Status &error); CompilerType GetTypeFromMangledTypename(ConstString mangled_typename); @@ -667,6 +668,7 @@ class SwiftASTContext : public TypeSystemSwift { void ClearDiagnostics(); bool SetColorizeDiagnostics(bool b); + void AddErrorStatusAsGenericDiagnostic(Status error); void PrintDiagnostics(DiagnosticManager &diagnostic_manager, uint32_t bufferID = UINT32_MAX, uint32_t first_line = 0, diff --git a/lldb/source/Symbol/SwiftASTContext.cpp b/lldb/source/Symbol/SwiftASTContext.cpp index 1f3ed99d21c5e..09456442cbfc7 100644 --- a/lldb/source/Symbol/SwiftASTContext.cpp +++ b/lldb/source/Symbol/SwiftASTContext.cpp @@ -191,11 +191,10 @@ swift::Type TypeSystemSwiftTypeRef::GetSwiftType(CompilerType compiler_type) { if (!ts) return {}; - Status error; // FIXME: Suboptimal performance, because the ConstString is looked up again. ConstString mangled_name( reinterpret_cast(compiler_type.GetOpaqueQualType())); - return ts->m_swift_ast_context->ReconstructType(mangled_name, error); + return ts->m_swift_ast_context->ReconstructType(mangled_name); } swift::Type SwiftASTContext::GetSwiftType(CompilerType compiler_type) { @@ -2853,8 +2852,8 @@ class ANSIColorStringStream : public llvm::raw_string_ostream { class StoringDiagnosticConsumer : public swift::DiagnosticConsumer { public: StoringDiagnosticConsumer(SwiftASTContext &ast_context) - : m_ast_context(ast_context), m_diagnostics(), m_num_errors(0), - m_colorize(false) { + : m_ast_context(ast_context), m_raw_diagnostics(), m_diagnostics(), + m_num_errors(0), m_colorize(false) { m_ast_context.GetDiagnosticEngine().resetHadAnyError(); m_ast_context.GetDiagnosticEngine().addConsumer(*this); } @@ -2926,19 +2925,19 @@ class StoringDiagnosticConsumer : public swift::DiagnosticConsumer { std::string &message_ref = os.str(); if (message_ref.empty()) - m_diagnostics.push_back(RawDiagnostic( + m_raw_diagnostics.push_back(RawDiagnostic( text.str(), info.Kind, bufferName, bufferID, line_col.first, line_col.second, use_fixits ? info.FixIts : llvm::ArrayRef())); else - m_diagnostics.push_back(RawDiagnostic( + m_raw_diagnostics.push_back(RawDiagnostic( message_ref, info.Kind, bufferName, bufferID, line_col.first, line_col.second, use_fixits ? info.FixIts : llvm::ArrayRef())); } else { - m_diagnostics.push_back(RawDiagnostic( + m_raw_diagnostics.push_back(RawDiagnostic( text.str(), info.Kind, bufferName, bufferID, line_col.first, line_col.second, llvm::ArrayRef())); } @@ -2949,6 +2948,7 @@ class StoringDiagnosticConsumer : public swift::DiagnosticConsumer { void Clear() { m_ast_context.GetDiagnosticEngine().resetHadAnyError(); + m_raw_diagnostics.clear(); m_diagnostics.clear(); m_num_errors = 0; } @@ -2980,8 +2980,13 @@ class StoringDiagnosticConsumer : public swift::DiagnosticConsumer { void PrintDiagnostics(DiagnosticManager &diagnostic_manager, uint32_t bufferID = UINT32_MAX, uint32_t first_line = 0, uint32_t last_line = UINT32_MAX) { - bool added_one_diagnostic = false; - for (const RawDiagnostic &diagnostic : m_diagnostics) { + bool added_one_diagnostic = !m_diagnostics.empty(); + + for (std::unique_ptr &diagnostic : m_diagnostics) { + diagnostic_manager.AddDiagnostic(std::move(diagnostic)); + } + + for (const RawDiagnostic &diagnostic : m_raw_diagnostics) { // We often make expressions and wrap them in some code. When // we see errors we want the line numbers to be correct so we // correct them below. LLVM stores in SourceLoc objects as @@ -3053,7 +3058,7 @@ class StoringDiagnosticConsumer : public swift::DiagnosticConsumer { // This will report diagnostic errors from outside the // expression's source range. Those are not interesting to // users, so we only emit them in debug builds. - for (const RawDiagnostic &diagnostic : m_diagnostics) { + for (const RawDiagnostic &diagnostic : m_raw_diagnostics) { const DiagnosticSeverity severity = SeverityForKind(diagnostic.kind); const DiagnosticOrigin origin = eDiagnosticOriginSwift; diagnostic_manager.AddDiagnostic(diagnostic.description.c_str(), @@ -3070,6 +3075,10 @@ class StoringDiagnosticConsumer : public swift::DiagnosticConsumer { return old; } + void AddDiagnostic(std::unique_ptr diagnostic) { + m_diagnostics.push_back(std::move(diagnostic)); + } + private: // We don't currently use lldb_private::Diagostic or any of the lldb // DiagnosticManager machinery to store diagnostics as they @@ -3095,9 +3104,12 @@ class StoringDiagnosticConsumer : public swift::DiagnosticConsumer { std::vector fixits; }; typedef std::vector RawDiagnosticBuffer; + typedef std::vector> DiagnosticList; SwiftASTContext &m_ast_context; - RawDiagnosticBuffer m_diagnostics; + RawDiagnosticBuffer m_raw_diagnostics; + DiagnosticList m_diagnostics; + unsigned m_num_errors = 0; bool m_colorize; }; @@ -4360,9 +4372,8 @@ swift::Type convertSILFunctionTypesToASTFunctionTypes(swift::Type t) { CompilerType SwiftASTContext::GetTypeFromMangledTypename(ConstString mangled_typename) { - Status error; if (llvm::isa(this)) - return GetCompilerType(ReconstructType(mangled_typename, error)); + return GetCompilerType(ReconstructType(mangled_typename)); return GetCompilerType(mangled_typename); } @@ -4410,6 +4421,17 @@ CompilerType SwiftASTContext::GetAsClangType(ConstString mangled_name) { return clang_type; } +swift::TypeBase *SwiftASTContext::ReconstructType(ConstString mangled_typename) { + Status error; + + auto reconstructed_type = + this->ReconstructType(mangled_typename, error); + if (!error.Success()) { + this->AddErrorStatusAsGenericDiagnostic(error); + } + return reconstructed_type; +} + swift::TypeBase *SwiftASTContext::ReconstructType(ConstString mangled_typename, Status &error) { VALID_OR_RETURN(nullptr); @@ -5001,6 +5023,17 @@ bool SwiftASTContext::SetColorizeDiagnostics(bool b) { return false; } +void SwiftASTContext::AddErrorStatusAsGenericDiagnostic(Status error) { + assert(!error.Success() && "status should be in an error state"); + + auto diagnostic = std::make_unique( + error.AsCString(), eDiagnosticSeverityError, eDiagnosticOriginLLDB, + LLDB_INVALID_COMPILER_ID); + if (m_diagnostic_consumer_ap.get()) + static_cast(m_diagnostic_consumer_ap.get()) + ->AddDiagnostic(std::move(diagnostic)); +} + void SwiftASTContext::PrintDiagnostics(DiagnosticManager &diagnostic_manager, uint32_t bufferID, uint32_t first_line, uint32_t last_line) { From 860d0e8a8ba2583edcd53fa80851ae6a16308823 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Tue, 31 Mar 2020 10:52:51 -0700 Subject: [PATCH 129/286] [llvm-locstats] Fix labels on x-axis of comparison chart Summary: This change makes the labels on the x-axis of a comparison chart look like: "0%", "(0%, 10%)", "[10%, 20%)", and so on. Previously, each label was the same (a concatenation of all the possible coverage buckets). Reviewers: djtodoro Subscribers: llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D77155 (cherry picked from commit 3a7865df626c061fa72cb731f0af763254ed3beb) --- llvm/utils/llvm-locstats/llvm-locstats.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/llvm/utils/llvm-locstats/llvm-locstats.py b/llvm/utils/llvm-locstats/llvm-locstats.py index 7b2f706fca943..dec87f9caf7d3 100755 --- a/llvm/utils/llvm-locstats/llvm-locstats.py +++ b/llvm/utils/llvm-locstats/llvm-locstats.py @@ -121,14 +121,16 @@ def draw_location_diff(self, locstats_to_compare): ax = fig.add_subplot(111) init_plot(plt) + comparison_keys = list(coverage_buckets()) ax.bar(buckets, self.variables_coverage_map.values(), align='edge', - tick_label=self.variables_coverage_map.keys(), width=0.4, + width=0.4, label='variables of {}'.format(self.file_name)) ax.bar(buckets_to_compare, locstats_to_compare.variables_coverage_map.values(), color='r', align='edge', width=-0.4, - tick_label=locstats_to_compare.variables_coverage_map.keys(), label='variables of {}'.format(locstats_to_compare.file_name)) + ax.set_xticks(range(len(comparison_keys))) + ax.set_xticklabels(comparison_keys) props = dict(boxstyle='round', facecolor='wheat', alpha=0.5) plt.text(0.02, 0.88, From 5f738ffbd8b9dc4655fd0afb1e3865749b7b690d Mon Sep 17 00:00:00 2001 From: Daniel Sanders Date: Wed, 1 Apr 2020 12:42:23 -0700 Subject: [PATCH 130/286] [globalisel][legalizer] Fix DebugLoc bugs caught by a prototype lost-location verifier The legalizer has a tendency to lose DebugLoc's when expanding or combining instructions. The verifier that detected these isn't ready for upstreaming yet but this patch fixes the cases that came up when applying it to our out-of-tree backend's CodeGen tests. This pattern comes up a few more times in this file and probably in the backends too but I'd prefer to fix the others separately (and preferably when the lost-location verifier detects them). (cherry picked from commit e65e677ee4eed83a31503b1a7db3fca56f617eae) --- llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp index 53bda81d6a5e1..7f6b0d87d72f1 100644 --- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -493,6 +493,7 @@ LegalizerHelper::libcall(MachineInstr &MI) { auto &Ctx = MIRBuilder.getMF().getFunction().getContext(); MIRBuilder.setInstr(MI); + MIRBuilder.setDebugLoc(MI.getDebugLoc()); switch (MI.getOpcode()) { default: @@ -598,6 +599,7 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy) { MIRBuilder.setInstr(MI); + MIRBuilder.setDebugLoc(MI.getDebugLoc()); uint64_t SizeOp0 = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits(); uint64_t NarrowSize = NarrowTy.getSizeInBits(); @@ -1428,6 +1430,7 @@ LegalizerHelper::widenScalarInsert(MachineInstr &MI, unsigned TypeIdx, LegalizerHelper::LegalizeResult LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) { MIRBuilder.setInstr(MI); + MIRBuilder.setDebugLoc(MI.getDebugLoc()); switch (MI.getOpcode()) { default: @@ -1939,6 +1942,7 @@ LegalizerHelper::LegalizeResult LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT Ty) { using namespace TargetOpcode; MIRBuilder.setInstr(MI); + MIRBuilder.setDebugLoc(MI.getDebugLoc()); switch(MI.getOpcode()) { default: @@ -2984,6 +2988,7 @@ LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx, using namespace TargetOpcode; MIRBuilder.setInstr(MI); + MIRBuilder.setDebugLoc(MI.getDebugLoc()); switch (MI.getOpcode()) { case G_IMPLICIT_DEF: return fewerElementsVectorImplicitDef(MI, TypeIdx, NarrowTy); From 70f3475f10d4b616b2e5a33ed3972e2dc06e0ec6 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Mon, 10 Feb 2020 14:35:00 -0800 Subject: [PATCH 131/286] Reapply: [Host.mm] Check for the right macro instead of inlining it Previously, this was reverted in bf65f19b becuase it checked whether TARGET_OS_EMBEDDED is defined, but that macro is always defined. Update the condition to check that TARGET_OS_OSX is true. (cherry picked from commit f203100ebe22bf97a4268a562cdbef22d14db915) --- lldb/source/Host/macosx/objcxx/Host.mm | 28 +++++++++++--------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/lldb/source/Host/macosx/objcxx/Host.mm b/lldb/source/Host/macosx/objcxx/Host.mm index 2475338a37fd5..f106bc1005b0e 100644 --- a/lldb/source/Host/macosx/objcxx/Host.mm +++ b/lldb/source/Host/macosx/objcxx/Host.mm @@ -9,13 +9,9 @@ #include "lldb/Host/Host.h" #include +#include -// On device doesn't have supporty for XPC. -#if defined(__APPLE__) && (defined(__arm64__) || defined(__aarch64__)) -#define NO_XPC_SERVICES 1 -#endif - -#if !defined(NO_XPC_SERVICES) +#if TARGET_OS_OSX #define __XPC_PRIVATE_H__ #include @@ -135,6 +131,8 @@ return false; } +#if TARGET_OS_OSX + static void *AcceptPIDFromInferior(void *arg) { const char *connect_url = (const char *)arg; ConnectionFileDescriptor file_conn; @@ -153,8 +151,6 @@ return NULL; } -#if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__) - const char *applscript_in_new_tty = "tell application \"Terminal\"\n" " activate\n" " do script \"/bin/bash -c '%s';exit\"\n" @@ -307,13 +303,13 @@ repeat with the_window in (get windows)\n\ return error; } -#endif // #if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__) +#endif // TARGET_OS_OSX bool Host::OpenFileInExternalEditor(const FileSpec &file_spec, uint32_t line_no) { -#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) +#if !TARGET_OS_OSX return false; -#else +#else // !TARGET_OS_OSX // We attach this to an 'odoc' event to specify a particular selection typedef struct { int16_t reserved0; // must be zero @@ -404,7 +400,7 @@ repeat with the_window in (get windows)\n\ } return true; -#endif // #if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__) +#endif // TARGET_OS_OSX } Environment Host::GetEnvironment() { return Environment(*_NSGetEnviron()); } @@ -689,7 +685,7 @@ static bool GetMacOSXProcessUserAndGroup(ProcessInstanceInfo &process_info) { return false; } -#if !NO_XPC_SERVICES +#if TARGET_OS_OSX static void PackageXPCArguments(xpc_object_t message, const char *prefix, const Args &args) { size_t count = args.GetArgumentCount(); @@ -841,7 +837,7 @@ static short GetPosixspawnFlags(const ProcessLaunchInfo &launch_info) { static Status LaunchProcessXPC(const char *exe_path, ProcessLaunchInfo &launch_info, lldb::pid_t &pid) { -#if !NO_XPC_SERVICES +#if TARGET_OS_OSX Status error = getXPCAuthorization(launch_info); if (error.Fail()) return error; @@ -1231,7 +1227,7 @@ static Status LaunchProcessPosixSpawn(const char *exe_path, static bool ShouldLaunchUsingXPC(ProcessLaunchInfo &launch_info) { bool result = false; -#if !NO_XPC_SERVICES +#if TARGET_OS_OSX bool launchingAsRoot = launch_info.GetUserID() == 0; bool currentUserIsRoot = HostInfo::GetEffectiveUserID() == 0; @@ -1263,7 +1259,7 @@ static bool ShouldLaunchUsingXPC(ProcessLaunchInfo &launch_info) { } if (launch_info.GetFlags().Test(eLaunchFlagLaunchInTTY)) { -#if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__) +#if TARGET_OS_OSX return LaunchInNewTerminalWithAppleScript(exe_spec.GetPath().c_str(), launch_info); #else From 187b3314ba3de083c7e54931d31486beab557441 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Wed, 1 Apr 2020 14:56:46 -0700 Subject: [PATCH 132/286] Target: print the message with formatting The message has a format specifier but was being printed unformatted. This corrects the macro usage to use the formatting version. Improves the debug logging only. --- lldb/source/Target/SwiftLanguageRuntime.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lldb/source/Target/SwiftLanguageRuntime.cpp b/lldb/source/Target/SwiftLanguageRuntime.cpp index 56d0be4f827f0..5675fa4db9d45 100644 --- a/lldb/source/Target/SwiftLanguageRuntime.cpp +++ b/lldb/source/Target/SwiftLanguageRuntime.cpp @@ -190,9 +190,10 @@ class SwiftLanguageRuntimeStub { #define STUB_LOG() \ do { \ - LLDB_LOG(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS | \ - LIBLLDB_LOG_TYPES), \ - g_stub_log_message, GetStandardLibraryName(m_process)); \ + LLDB_LOGF(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS | \ + LIBLLDB_LOG_TYPES), \ + g_stub_log_message, \ + GetStandardLibraryName(m_process).AsCString()); \ assert(false && "called into swift language runtime stub"); \ } while (0) From 8aa134fba3fe1b5046ead27002c70e1cb27e9579 Mon Sep 17 00:00:00 2001 From: Jan Korous Date: Mon, 16 Mar 2020 16:35:48 -0700 Subject: [PATCH 133/286] [Refactor] Speculative fix for assert in isBeforeInTranslationUnit() I don't have a reproducer but the failing assert is that LHS.isValid() && RHS.isValid() in SourceManager::isBeforeInTranslationUnit() which is called from ASTSlice constructor. We might be hitting some implicit declarations. rdar://problem/59811864 --- clang/lib/Tooling/Refactor/ASTSlice.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/clang/lib/Tooling/Refactor/ASTSlice.cpp b/clang/lib/Tooling/Refactor/ASTSlice.cpp index de6de11485c82..f096876fe97e8 100644 --- a/clang/lib/Tooling/Refactor/ASTSlice.cpp +++ b/clang/lib/Tooling/Refactor/ASTSlice.cpp @@ -182,6 +182,9 @@ ASTSlice::ASTSlice(SourceLocation Location, SourceRange SelectionRange, ASTSliceFinder Visitor(Location, SelectionRange, Context); SourceLocation EndLoc; for (auto *CurrDecl : Context.getTranslationUnitDecl()->decls()) { + if (CurrDecl->getBeginLoc().isInvalid()) + continue; + if (EndLoc.isValid() && !Context.getSourceManager().isBeforeInTranslationUnit( CurrDecl->getBeginLoc(), EndLoc)) From 9bf6c87bbca590e368de4f097a40ec38f7202f7a Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Wed, 1 Apr 2020 20:43:01 -0700 Subject: [PATCH 134/286] [Sema] Check that return and argument types of a virtual member function (#993) * [Sema] Check that return and argument types of a virtual member function are complete if the address of the member function is taken If they aren't complete, reject the code. rdar://problem/60888064 * Address review comments Explain why the types must be complete when pointer authentication is enabled. Check that virual function pointers aren't diagnosed in unevaluated contexts. Change the variable and diagnostic names to improve indentation. * Check that a pointer to a virtual function pointer with a dependent noexcept clause isn't diagnosed Test virtual functions of templated classes. (cherry picked from commit 7cd35e28affde4988126a2e08fb2bdd1e3381ed8) --- .../clang/Basic/DiagnosticSemaKinds.td | 5 ++ clang/lib/Sema/SemaExpr.cpp | 33 +++++++++++++ clang/test/SemaCXX/ptrauth.cpp | 46 ++++++++++++++++++- 3 files changed, 83 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index c5a6b466ca79b..5b9f764443fe2 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -770,6 +770,11 @@ def err_ptrauth_string_not_literal : Error< def err_ptrauth_type_disc_variably_modified : Error< "cannot pass variably-modified type %0 to " "'__builtin_ptrauth_type_discriminator'">; +def note_ptrauth_virtual_function_pointer_incomplete_arg_ret : + Note<"cannot take an address of a virtual member function if its return or " + "argument types are incomplete">; +def note_ptrauth_virtual_function_incomplete_arg_ret_type : + Note<"%0 is incomplete">; // __ptrauth qualifier def err_ptrauth_qualifier_return : Error< diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 95d5e25515321..68f3c6284068e 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -12529,6 +12529,39 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { QualType MPTy = Context.getMemberPointerType( op->getType(), Context.getTypeDeclType(MD->getParent()).getTypePtr()); + + if (getLangOpts().PointerAuthCalls && MD->isVirtual() && + !isUnevaluatedContext() && !MPTy->isDependentType()) { + // When pointer authentication is enabled, argument and return types of + // vitual member functions must be complete. This is because vitrual + // member function pointers are implemented using virtual dispatch + // thunks and the thunks cannot be emitted if the argument or return + // types are incomplete. + auto ReturnOrParamTypeIsIncomplete = [&](QualType T, + SourceLocation DeclRefLoc, + SourceLocation RetArgTypeLoc) { + if (RequireCompleteType(DeclRefLoc, T, diag::err_incomplete_type)) { + Diag(DeclRefLoc, + diag::note_ptrauth_virtual_function_pointer_incomplete_arg_ret); + Diag(RetArgTypeLoc, + diag::note_ptrauth_virtual_function_incomplete_arg_ret_type) + << T; + return true; + } + return false; + }; + QualType RetTy = MD->getReturnType(); + bool IsIncomplete = + !RetTy->isVoidType() && + ReturnOrParamTypeIsIncomplete( + RetTy, OpLoc, MD->getReturnTypeSourceRange().getBegin()); + for (auto *PVD : MD->parameters()) + IsIncomplete |= ReturnOrParamTypeIsIncomplete(PVD->getType(), OpLoc, + PVD->getBeginLoc()); + if (IsIncomplete) + return QualType(); + } + // Under the MS ABI, lock down the inheritance model now. if (Context.getTargetInfo().getCXXABI().isMicrosoft()) (void)isCompleteType(OpLoc, MPTy); diff --git a/clang/test/SemaCXX/ptrauth.cpp b/clang/test/SemaCXX/ptrauth.cpp index 691edc9a2e576..48763f7160d76 100644 --- a/clang/test/SemaCXX/ptrauth.cpp +++ b/clang/test/SemaCXX/ptrauth.cpp @@ -1,7 +1,41 @@ -// RUN: %clang_cc1 -triple arm64-apple-ios -std=c++17 -fsyntax-only -verify -fptrauth-intrinsics %s +// RUN: %clang_cc1 -triple arm64-apple-ios -std=c++17 -fsyntax-only -verify -fptrauth-intrinsics -fptrauth-calls %s + +struct Incomplete0; // expected-note 3 {{forward declaration of 'Incomplete0'}} + +template +struct Incomplete1; // expected-note {{template is declared here}} + +struct Complete0 { +}; + +template +struct Complete1 { +}; struct S { virtual int foo(); + virtual Incomplete0 virtual0(); // expected-note 2 {{'Incomplete0' is incomplete}} + virtual void virtual1(Incomplete1); // expected-note {{'Incomplete1' is incomplete}} + virtual Complete0 virtual2(); + virtual Complete1 virtual3(); + Incomplete0 nonvirtual0(); + template + void m0() { + (void)&S::virtual0; // expected-error {{incomplete type 'Incomplete0'}} expected-note {{cannot take an address of a virtual}} + } +}; + +template +struct S2 { + virtual Incomplete0 virtual0() noexcept(T); // expected-note {{'Incomplete0' is incomplete}} + + void m0() { + (void)&S2::virtual0; + } + + void m1() { + (void)&S2::virtual0; // expected-error {{incomplete type 'Incomplete0'}} expected-note {{cannot take an address of a virtual}} + } }; template @@ -31,3 +65,13 @@ void test_builtin_ptrauth_type_discriminator(unsigned s) { __builtin_ptrauth_type_discriminator(&t); // expected-error {{expected a type}} __builtin_ptrauth_type_discriminator(decltype(vmarray)); // expected-error {{cannot pass variably-modified type 'decltype(vmarray)'}} } + +void test_incomplete_virtual_member_function_return_arg_type() { + (void)&S::virtual0; // expected-error {{incomplete type 'Incomplete0}} expected-note {{cannot take an address of a virtual member function}} + (void)&S::virtual1; // expected-error {{implicit instantiation of undefined template 'Incomplete1'}} expected-note {{cannot take an address of a virtual member function}} + (void)&S::virtual2; + (void)&S::virtual3; + (void)&S::nonvirtual0; + int s = sizeof(&S::virtual0); + S2().m1(); // expected-note {{in instantiation of}} +} From 83cc6df48e47952b13b3c2dd2c6f65e58502bbad Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Thu, 2 Apr 2020 11:07:37 -0700 Subject: [PATCH 135/286] SwiftASTContext: Fix crash in GetArchetypeNames with missing debug info When a swiftmodule cannot be found, we may crash when attempting to find the display name for a generic type. rdar://59228966 --- lldb/source/Symbol/SwiftASTContext.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lldb/source/Symbol/SwiftASTContext.cpp b/lldb/source/Symbol/SwiftASTContext.cpp index 573d3376fadf6..f8826c8d145b7 100644 --- a/lldb/source/Symbol/SwiftASTContext.cpp +++ b/lldb/source/Symbol/SwiftASTContext.cpp @@ -5604,6 +5604,8 @@ GetArchetypeNames(swift::Type swift_type, swift::ASTContext &ast_ctx, if (!type->isTypeParameter() || dict.count(type->getCanonicalType())) return; auto *param = type->getAs(); + if (!param) + return; auto it = names.find({param->getDepth(), param->getIndex()}); if (it != names.end()) { swift::Identifier ident = ast_ctx.getIdentifier(it->second); From 6c7419ecc56527cefce3e482b395f6ec94d0c347 Mon Sep 17 00:00:00 2001 From: "Duncan P. N. Exon Smith" Date: Thu, 2 Apr 2020 10:27:42 -0700 Subject: [PATCH 136/286] utils: Tweak clang-parse-diagnostics-file for modules includes Diagnostics from modules do not have a `main-file` listed. Tweak `clang-parse-diagnostics-file` to patch this up. Previously, the call to `os.path.basename` would crash. Radar-Id: rdar://problem/59000292 --- llvm/utils/clang-parse-diagnostics-file | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/llvm/utils/clang-parse-diagnostics-file b/llvm/utils/clang-parse-diagnostics-file index 59b13f306505a..1f720c34544a7 100755 --- a/llvm/utils/clang-parse-diagnostics-file +++ b/llvm/utils/clang-parse-diagnostics-file @@ -66,6 +66,10 @@ Utility for dumping Clang-style logged diagnostics.\ for file_diags in diags: file = file_diags.get('main-file') + # Diagnostics from modules don't have a main-file listed. + if not file: + file = '' + # Ignore diagnostics for 'conftest.c', which is the file autoconf uses # for its tests (which frequently will have warnings). if os.path.basename(file) == 'conftest.c': From fe7314d3bb1bd4d19c105f192840a55c4404c3ea Mon Sep 17 00:00:00 2001 From: Erik Pilkington Date: Tue, 24 Mar 2020 12:36:19 -0400 Subject: [PATCH 137/286] [CodeGen] Add an alignment attribute to all sret parameters This fixes a miscompile when the parameter is actually underaligned. rdar://58316406 Differential revision: https://reviews.llvm.org/D74183 Conflicts: clang/test/CodeGen/systemz-abi.c clang/test/CodeGen/systemz-abi.cpp clang/test/CodeGen/wasm-arguments.c clang/test/CodeGenObjC/arc.m --- clang/lib/CodeGen/CGCall.cpp | 1 + .../test/CodeGen/2006-05-19-SingleEltReturn.c | 4 +- clang/test/CodeGen/aarch64-varargs.c | 4 +- clang/test/CodeGen/aggregate-assign-call.c | 8 +- clang/test/CodeGen/aligned-sret.c | 10 ++ clang/test/CodeGen/arc/arguments.c | 8 +- clang/test/CodeGen/arm-aapcs-vfp.c | 2 +- clang/test/CodeGen/arm-homogenous.c | 8 +- clang/test/CodeGen/arm-neon-vld.c | 144 +++++++++--------- clang/test/CodeGen/arm-varargs.c | 18 +-- clang/test/CodeGen/arm-vector-arguments.c | 6 +- clang/test/CodeGen/arm-vfp16-arguments.c | 2 +- clang/test/CodeGen/arm-vfp16-arguments2.cpp | 10 +- clang/test/CodeGen/arm64-arguments.c | 4 +- .../CodeGen/arm64-microsoft-arguments.cpp | 34 ++--- clang/test/CodeGen/arm64_32.c | 2 +- clang/test/CodeGen/arm_neon_intrinsics.c | 108 ++++++------- clang/test/CodeGen/blocks.c | 2 +- clang/test/CodeGen/c11atomics-ios.c | 4 +- clang/test/CodeGen/c11atomics.c | 4 +- clang/test/CodeGen/lanai-arguments.c | 4 +- clang/test/CodeGen/le32-arguments.c | 2 +- clang/test/CodeGen/mcu-struct-return.c | 4 +- clang/test/CodeGen/mingw-long-double.c | 8 +- clang/test/CodeGen/mips-zero-sized-struct.c | 2 +- clang/test/CodeGen/mips64-padding-arg.c | 6 +- clang/test/CodeGen/ms_abi.c | 4 +- clang/test/CodeGen/ppc64-align-struct.c | 12 +- clang/test/CodeGen/ppc64-elf-abi.c | 2 +- clang/test/CodeGen/ppc64-qpx-vector.c | 2 +- clang/test/CodeGen/ppc64-soft-float.c | 46 +++--- clang/test/CodeGen/ppc64-vector.c | 4 +- clang/test/CodeGen/ppc64le-aggregates.c | 12 +- clang/test/CodeGen/ppc64le-f128Aggregates.c | 4 +- clang/test/CodeGen/ptrauth-in-c-struct.c | 2 +- clang/test/CodeGen/regparm-struct.c | 2 +- clang/test/CodeGen/renderscript.c | 18 +-- clang/test/CodeGen/riscv32-ilp32-abi.c | 2 +- clang/test/CodeGen/riscv32-ilp32-ilp32f-abi.c | 2 +- .../CodeGen/riscv32-ilp32-ilp32f-ilp32d-abi.c | 6 +- clang/test/CodeGen/riscv32-ilp32d-abi.c | 8 +- clang/test/CodeGen/riscv32-ilp32f-abi.c | 4 +- .../test/CodeGen/riscv32-ilp32f-ilp32d-abi.c | 6 +- clang/test/CodeGen/riscv64-lp64-abi.c | 2 +- clang/test/CodeGen/riscv64-lp64-lp64f-abi.c | 2 +- .../CodeGen/riscv64-lp64-lp64f-lp64d-abi.c | 6 +- clang/test/CodeGen/riscv64-lp64d-abi.c | 2 +- clang/test/CodeGen/sparcv9-abi.c | 2 +- clang/test/CodeGen/struct-passing.c | 4 +- clang/test/CodeGen/systemz-abi-vector.c | 124 +++++++-------- clang/test/CodeGen/systemz-abi.c | 84 +++++----- clang/test/CodeGen/systemz-abi.cpp | 3 +- clang/test/CodeGen/systemz-inline-asm.c | 2 +- clang/test/CodeGen/vectorcall.c | 4 +- clang/test/CodeGen/wasm-arguments.c | 4 +- clang/test/CodeGen/wasm-varargs.c | 4 +- clang/test/CodeGen/windows-struct-abi.c | 2 +- clang/test/CodeGen/x86_32-arguments-darwin.c | 18 +-- clang/test/CodeGen/x86_32-arguments-iamcu.c | 2 +- clang/test/CodeGen/x86_64-arguments-nacl.c | 2 +- clang/test/CodeGen/x86_64-arguments-win32.c | 2 +- clang/test/CodeGen/x86_64-arguments.c | 6 +- clang/test/CodeGenCXX/arm-cc.cpp | 2 +- .../CodeGenCXX/builtin-source-location.cpp | 20 +-- .../CodeGenCXX/call-with-static-chain.cpp | 4 +- clang/test/CodeGenCXX/conditional-gnu-ext.cpp | 8 +- clang/test/CodeGenCXX/cxx1z-copy-omission.cpp | 4 +- .../CodeGenCXX/cxx1z-lambda-star-this.cpp | 4 +- clang/test/CodeGenCXX/exceptions.cpp | 6 +- .../CodeGenCXX/homogeneous-aggregates.cpp | 14 +- clang/test/CodeGenCXX/lambda-expressions.cpp | 4 +- .../CodeGenCXX/microsoft-abi-byval-sret.cpp | 4 +- .../CodeGenCXX/microsoft-abi-byval-thunks.cpp | 4 +- .../microsoft-abi-cdecl-method-sret.cpp | 8 +- .../CodeGenCXX/microsoft-abi-eh-cleanups.cpp | 4 +- .../microsoft-abi-sret-and-byval.cpp | 64 ++++---- .../microsoft-abi-vmemptr-conflicts.cpp | 2 +- .../ptrauth-member-function-pointer.cpp | 4 +- clang/test/CodeGenCXX/regcall.cpp | 8 +- .../CodeGenCXX/stack-reuse-miscompile.cpp | 2 +- clang/test/CodeGenCXX/stack-reuse.cpp | 2 +- clang/test/CodeGenCXX/temporaries.cpp | 12 +- .../CodeGenCXX/thiscall-struct-return.cpp | 4 +- .../CodeGenCXX/thunk-returning-memptr.cpp | 4 +- clang/test/CodeGenCXX/thunks.cpp | 6 +- clang/test/CodeGenCXX/trivial_abi.cpp | 8 +- clang/test/CodeGenCXX/unknown-anytype.cpp | 2 +- clang/test/CodeGenCXX/wasm-args-returns.cpp | 18 +-- clang/test/CodeGenCXX/x86_32-arguments.cpp | 8 +- clang/test/CodeGenCXX/x86_64-arguments.cpp | 4 +- clang/test/CodeGenCoroutines/coro-await.cpp | 10 +- .../test/CodeGenCoroutines/coro-gro-nrvo.cpp | 10 +- clang/test/CodeGenObjC/arc.m | 4 +- clang/test/CodeGenObjC/direct-method.m | 2 +- .../nontrivial-c-struct-exception.m | 4 +- .../objc-non-trivial-struct-nrvo.m | 6 +- clang/test/CodeGenObjC/stret-1.m | 8 +- clang/test/CodeGenObjC/weak-in-c-struct.m | 2 +- .../test/CodeGenObjCXX/objc-struct-cxx-abi.mm | 2 +- .../CodeGenOpenCL/addr-space-struct-arg.cl | 6 +- .../CodeGenOpenCL/amdgpu-abi-struct-coerce.cl | 6 +- .../CodeGenOpenCLCXX/addrspace-of-this.cl | 4 +- clang/test/Modules/templates.mm | 2 +- 103 files changed, 565 insertions(+), 555 deletions(-) create mode 100644 clang/test/CodeGen/aligned-sret.c diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 5375f45e09924..6cb0d8e5142cb 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -2080,6 +2080,7 @@ void CodeGenModule::ConstructAttributeList( hasUsedSRet = true; if (RetAI.getInReg()) SRETAttrs.addAttribute(llvm::Attribute::InReg); + SRETAttrs.addAlignmentAttr(RetAI.getIndirectAlign().getQuantity()); ArgAttrs[IRFunctionArgs.getSRetArgNo()] = llvm::AttributeSet::get(getLLVMContext(), SRETAttrs); } diff --git a/clang/test/CodeGen/2006-05-19-SingleEltReturn.c b/clang/test/CodeGen/2006-05-19-SingleEltReturn.c index dfc23f84ab424..d3f9e4e00acde 100644 --- a/clang/test/CodeGen/2006-05-19-SingleEltReturn.c +++ b/clang/test/CodeGen/2006-05-19-SingleEltReturn.c @@ -24,7 +24,7 @@ struct Y bar() { // X86_32: define void @foo(%struct.Y* %P) -// X86_32: call void @bar(%struct.Y* sret %{{[^),]*}}) +// X86_32: call void @bar(%struct.Y* sret align 4 %{{[^),]*}}) -// X86_32: define void @bar(%struct.Y* noalias sret %{{[^,)]*}}) +// X86_32: define void @bar(%struct.Y* noalias sret align 4 %{{[^,)]*}}) // X86_32: ret void diff --git a/clang/test/CodeGen/aarch64-varargs.c b/clang/test/CodeGen/aarch64-varargs.c index c213f5b9375ba..27bb602e75de1 100644 --- a/clang/test/CodeGen/aarch64-varargs.c +++ b/clang/test/CodeGen/aarch64-varargs.c @@ -639,7 +639,7 @@ typedef struct __attribute__((aligned(32))) { __int128 val; } overaligned_int128_struct; overaligned_int128_struct overaligned_int128_struct_test() { -// CHECK-LABEL: define void @overaligned_int128_struct_test(%struct.overaligned_int128_struct* noalias sret %agg.result) +// CHECK-LABEL: define void @overaligned_int128_struct_test(%struct.overaligned_int128_struct* noalias sret align 32 %agg.result) return va_arg(the_list, overaligned_int128_struct); // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, i32* getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 3) // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0 @@ -853,7 +853,7 @@ typedef struct { __int128 val __attribute__((aligned(32))); } overaligned_int128_struct_member; overaligned_int128_struct_member overaligned_int128_struct_member_test() { -// CHECK-LABEL: define void @overaligned_int128_struct_member_test(%struct.overaligned_int128_struct_member* noalias sret %agg.result) +// CHECK-LABEL: define void @overaligned_int128_struct_member_test(%struct.overaligned_int128_struct_member* noalias sret align 32 %agg.result) return va_arg(the_list, overaligned_int128_struct_member); // CHECK: [[GR_OFFS:%[a-z_0-9]+]] = load i32, i32* getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 3) // CHECK: [[EARLY_ONSTACK:%[a-z_0-9]+]] = icmp sge i32 [[GR_OFFS]], 0 diff --git a/clang/test/CodeGen/aggregate-assign-call.c b/clang/test/CodeGen/aggregate-assign-call.c index d00cb90c09407..9616e6d22562f 100644 --- a/clang/test/CodeGen/aggregate-assign-call.c +++ b/clang/test/CodeGen/aggregate-assign-call.c @@ -62,8 +62,8 @@ struct S baz(int i, volatile int *j) { // O1-NEWPM: %[[TMP3:.*]] = bitcast %struct.S* %[[TMP2_ALLOCA]] to i8* // O1-NEWPM: call void @llvm.lifetime.end.p0i8({{[^,]*}}, i8* nonnull %[[P]]) // - // O1-LEGACY: call void @foo_int(%struct.S* sret %[[TMP1_ALLOCA]], - // O1-NEWPM: call void @foo_int(%struct.S* nonnull sret %[[TMP1_ALLOCA]], + // O1-LEGACY: call void @foo_int(%struct.S* sret align 4 %[[TMP1_ALLOCA]], + // O1-NEWPM: call void @foo_int(%struct.S* nonnull sret align 4 %[[TMP1_ALLOCA]], // O1: call void @llvm.memcpy // O1-LEGACY: %[[P:[^ ]+]] = bitcast %struct.S* %[[TMP1_ALLOCA]] to i8* // O1-LEGACY: call void @llvm.lifetime.end.p0i8({{[^,]*}}, i8* %[[P]]) @@ -71,8 +71,8 @@ struct S baz(int i, volatile int *j) { // O1-LEGACY: %[[P:[^ ]+]] = bitcast %struct.S* %[[TMP2_ALLOCA]] to i8* // O1-LEGACY: call void @llvm.lifetime.start.p0i8({{[^,]*}}, i8* %[[P]]) // O1-NEWPM: call void @llvm.lifetime.start.p0i8({{[^,]*}}, i8* nonnull %[[TMP3]]) - // O1-LEGACY: call void @foo_int(%struct.S* sret %[[TMP2_ALLOCA]], - // O1-NEWPM: call void @foo_int(%struct.S* nonnull sret %[[TMP2_ALLOCA]], + // O1-LEGACY: call void @foo_int(%struct.S* sret align 4 %[[TMP2_ALLOCA]], + // O1-NEWPM: call void @foo_int(%struct.S* nonnull sret align 4 %[[TMP2_ALLOCA]], // O1: call void @llvm.memcpy // O1-LEGACY: %[[P:[^ ]+]] = bitcast %struct.S* %[[TMP2_ALLOCA]] to i8* // O1-LEGACY: call void @llvm.lifetime.end.p0i8({{[^,]*}}, i8* %[[P]]) diff --git a/clang/test/CodeGen/aligned-sret.c b/clang/test/CodeGen/aligned-sret.c new file mode 100644 index 0000000000000..c459fe730163c --- /dev/null +++ b/clang/test/CodeGen/aligned-sret.c @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos %s -S -emit-llvm -o- | FileCheck %s + +typedef __attribute__((__ext_vector_type__(4),__aligned__(16))) double simd_double4; +typedef struct { simd_double4 columns[4]; } simd_double4x4; +typedef simd_double4x4 matrix_double4x4; + +// CHECK: define void @ident(%struct.simd_double4x4* noalias sret align 16 %agg.result +matrix_double4x4 ident(matrix_double4x4 x) { + return x; +} diff --git a/clang/test/CodeGen/arc/arguments.c b/clang/test/CodeGen/arc/arguments.c index fdc6037da730a..9c9b553b1be45 100644 --- a/clang/test/CodeGen/arc/arguments.c +++ b/clang/test/CodeGen/arc/arguments.c @@ -22,7 +22,7 @@ void cf1(cs1 i) {} typedef struct { int cc; } s2; -// CHECK: define void @f2(%struct.s2* noalias sret %agg.result) +// CHECK: define void @f2(%struct.s2* noalias sret align 4 %agg.result) s2 f2() { s2 foo; return foo; @@ -32,7 +32,7 @@ typedef struct { int cc; int dd; } s3; -// CHECK: define void @f3(%struct.s3* noalias sret %agg.result) +// CHECK: define void @f3(%struct.s3* noalias sret align 4 %agg.result) s3 f3() { s3 foo; return foo; @@ -128,8 +128,8 @@ void st3(s16 a, s16 b, s16 c) {} // 1 sret + 1 i32 + 2*(i32 coerce) + 4*(i32 coerce) + 1 byval s16 st4(int x, s8 a, s16 b, s16 c) { return b; } -// CHECK: define void @st4(%struct.s16* noalias sret %agg.result, i32 inreg %x, i32 inreg %a.coerce0, i32 inreg %a.coerce1, i32 inreg %b.coerce0, i32 inreg %b.coerce1, i32 inreg %b.coerce2, i32 inreg %b.coerce3, { i32, i32, i32, i32 } %c.coerce) +// CHECK: define void @st4(%struct.s16* noalias sret align 4 %agg.result, i32 inreg %x, i32 inreg %a.coerce0, i32 inreg %a.coerce1, i32 inreg %b.coerce0, i32 inreg %b.coerce1, i32 inreg %b.coerce2, i32 inreg %b.coerce3, { i32, i32, i32, i32 } %c.coerce) // 1 sret + 2*(i32 coerce) + 4*(i32 coerce) + 4*(i32 coerce) s16 st5(s8 a, s16 b, s16 c) { return b; } -// CHECK: define void @st5(%struct.s16* noalias sret %agg.result, i32 inreg %a.coerce0, i32 inreg %a.coerce1, i32 inreg %b.coerce0, i32 inreg %b.coerce1, i32 inreg %b.coerce2, i32 inreg %b.coerce3, { i32, i32, i32, i32 } %c.coerce) +// CHECK: define void @st5(%struct.s16* noalias sret align 4 %agg.result, i32 inreg %a.coerce0, i32 inreg %a.coerce1, i32 inreg %b.coerce0, i32 inreg %b.coerce1, i32 inreg %b.coerce2, i32 inreg %b.coerce3, { i32, i32, i32, i32 } %c.coerce) diff --git a/clang/test/CodeGen/arm-aapcs-vfp.c b/clang/test/CodeGen/arm-aapcs-vfp.c index 69581fcab2479..486ed6ab94fd4 100644 --- a/clang/test/CodeGen/arm-aapcs-vfp.c +++ b/clang/test/CodeGen/arm-aapcs-vfp.c @@ -125,7 +125,7 @@ void test_vfp_stack_gpr_split_1(double a, double b, double c, double d, double e // CHECK: define arm_aapcs_vfpcc void @test_vfp_stack_gpr_split_2(double %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, double %i, i32 %j, [2 x i64] %k.coerce) void test_vfp_stack_gpr_split_2(double a, double b, double c, double d, double e, double f, double g, double h, double i, int j, struct_long_long_int k) {} -// CHECK: define arm_aapcs_vfpcc void @test_vfp_stack_gpr_split_3(%struct.struct_long_long_int* noalias sret %agg.result, double %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, double %i, [2 x i64] %k.coerce) +// CHECK: define arm_aapcs_vfpcc void @test_vfp_stack_gpr_split_3(%struct.struct_long_long_int* noalias sret align 8 %agg.result, double %a, double %b, double %c, double %d, double %e, double %f, double %g, double %h, double %i, [2 x i64] %k.coerce) struct_long_long_int test_vfp_stack_gpr_split_3(double a, double b, double c, double d, double e, double f, double g, double h, double i, struct_long_long_int k) {} typedef struct { int a; int b:4; int c; } struct_int_bitfield_int; diff --git a/clang/test/CodeGen/arm-homogenous.c b/clang/test/CodeGen/arm-homogenous.c index 42a9bc1c16435..d321fc974c52e 100644 --- a/clang/test/CodeGen/arm-homogenous.c +++ b/clang/test/CodeGen/arm-homogenous.c @@ -27,7 +27,7 @@ void test_union_with_first_floats(void) { void test_return_union_with_first_floats(void) { g_u_f = returns_union_with_first_floats(); } -// CHECK: declare arm_aapcs_vfpcc void @returns_union_with_first_floats(%union.union_with_first_floats* sret) +// CHECK: declare arm_aapcs_vfpcc void @returns_union_with_first_floats(%union.union_with_first_floats* sret align 4) /* This is not a homogenous aggregate - fundamental types are different */ typedef union { @@ -47,7 +47,7 @@ void test_union_with_non_first_floats(void) { void test_return_union_with_non_first_floats(void) { g_u_nf_f = returns_union_with_non_first_floats(); } -// CHECK: declare arm_aapcs_vfpcc void @returns_union_with_non_first_floats(%union.union_with_non_first_floats* sret) +// CHECK: declare arm_aapcs_vfpcc void @returns_union_with_non_first_floats(%union.union_with_non_first_floats* sret align 4) /* This is not a homogenous aggregate - fundamental types are different */ typedef struct { @@ -67,7 +67,7 @@ void test_struct_with_union_with_first_floats(void) { void test_return_struct_with_union_with_first_floats(void) { g_s_f = returns_struct_with_union_with_first_floats(); } -// CHECK: declare arm_aapcs_vfpcc void @returns_struct_with_union_with_first_floats(%struct.struct_with_union_with_first_floats* sret) +// CHECK: declare arm_aapcs_vfpcc void @returns_struct_with_union_with_first_floats(%struct.struct_with_union_with_first_floats* sret align 4) /* This is not a homogenous aggregate - fundamental types are different */ typedef struct { @@ -87,7 +87,7 @@ void test_struct_with_union_with_non_first_floats(void) { void test_return_struct_with_union_with_non_first_floats(void) { g_s_nf_f = returns_struct_with_union_with_non_first_floats(); } -// CHECK: declare arm_aapcs_vfpcc void @returns_struct_with_union_with_non_first_floats(%struct.struct_with_union_with_non_first_floats* sret) +// CHECK: declare arm_aapcs_vfpcc void @returns_struct_with_union_with_non_first_floats(%struct.struct_with_union_with_non_first_floats* sret align 4) /* Plain array is not a homogenous aggregate */ extern void takes_array_of_floats(float a[4]); diff --git a/clang/test/CodeGen/arm-neon-vld.c b/clang/test/CodeGen/arm-neon-vld.c index 2c7af92f4796a..8d3d61c250a92 100644 --- a/clang/test/CodeGen/arm-neon-vld.c +++ b/clang/test/CodeGen/arm-neon-vld.c @@ -9,7 +9,7 @@ // CHECK-LABEL: @test_vld1_f16_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.float16x4x2_t, align 8 -// CHECK-A32: %struct.float16x4x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.float16x4x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.float16x4x2_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* @@ -29,7 +29,7 @@ float16x4x2_t test_vld1_f16_x2(float16_t const *a) { // CHECK-LABEL: @test_vld1_f16_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.float16x4x3_t, align 8 -// CHECK-A32: %struct.float16x4x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.float16x4x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.float16x4x3_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* @@ -49,7 +49,7 @@ float16x4x3_t test_vld1_f16_x3(float16_t const *a) { // CHECK-LABEL: @test_vld1_f16_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.float16x4x4_t, align 8 -// CHECK-A32: %struct.float16x4x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.float16x4x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.float16x4x4_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* @@ -69,7 +69,7 @@ float16x4x4_t test_vld1_f16_x4(float16_t const *a) { // CHECK-LABEL: @test_vld1_f32_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.float32x2x2_t, align 8 -// CHECK-A32: %struct.float32x2x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.float32x2x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.float32x2x2_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.float32x2x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast float* %a to i8* @@ -89,7 +89,7 @@ float32x2x2_t test_vld1_f32_x2(float32_t const *a) { // CHECK-LABEL: @test_vld1_f32_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.float32x2x3_t, align 8 -// CHECK-A32: %struct.float32x2x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.float32x2x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.float32x2x3_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.float32x2x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast float* %a to i8* @@ -108,7 +108,7 @@ float32x2x3_t test_vld1_f32_x3(float32_t const *a) { // CHECK-LABEL: @test_vld1_f32_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.float32x2x4_t, align 8 -// CHECK-A32: %struct.float32x2x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.float32x2x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.float32x2x4_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.float32x2x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast float* %a to i8* @@ -128,7 +128,7 @@ float32x2x4_t test_vld1_f32_x4(float32_t const *a) { // CHECK-LABEL: @test_vld1_p16_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.poly16x4x2_t, align 8 -// CHECK-A32: %struct.poly16x4x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.poly16x4x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.poly16x4x2_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.poly16x4x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -148,7 +148,7 @@ poly16x4x2_t test_vld1_p16_x2(poly16_t const *a) { // CHECK-LABEL: @test_vld1_p16_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.poly16x4x3_t, align 8 -// CHECK-A32: %struct.poly16x4x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.poly16x4x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.poly16x4x3_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.poly16x4x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -168,7 +168,7 @@ poly16x4x3_t test_vld1_p16_x3(poly16_t const *a) { // CHECK-LABEL: @test_vld1_p16_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.poly16x4x4_t, align 8 -// CHECK-A32: %struct.poly16x4x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.poly16x4x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.poly16x4x4_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.poly16x4x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -188,7 +188,7 @@ poly16x4x4_t test_vld1_p16_x4(poly16_t const *a) { // CHECK-LABEL: @test_vld1_p8_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.poly8x8x2_t, align 8 -// CHECK-A32: %struct.poly8x8x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.poly8x8x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.poly8x8x2_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.poly8x8x2_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <8 x i8>, <8 x i8> } @llvm.{{aarch64.neon.ld1x2|arm.neon.vld1x2}}.v8i8.p0i8(i8* %a) @@ -206,7 +206,7 @@ poly8x8x2_t test_vld1_p8_x2(poly8_t const *a) { // CHECK-LABEL: @test_vld1_p8_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.poly8x8x3_t, align 8 -// CHECK-A32: %struct.poly8x8x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.poly8x8x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.poly8x8x3_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.poly8x8x3_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <8 x i8>, <8 x i8>, <8 x i8> } @llvm.{{aarch64.neon.ld1x3|arm.neon.vld1x3}}.v8i8.p0i8(i8* %a) @@ -224,7 +224,7 @@ poly8x8x3_t test_vld1_p8_x3(poly8_t const *a) { // CHECK-LABEL: @test_vld1_p8_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.poly8x8x4_t, align 8 -// CHECK-A32: %struct.poly8x8x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.poly8x8x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.poly8x8x4_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.poly8x8x4_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <8 x i8>, <8 x i8>, <8 x i8>, <8 x i8> } @llvm.{{aarch64.neon.ld1x4|arm.neon.vld1x4}}.v8i8.p0i8(i8* %a) @@ -242,7 +242,7 @@ poly8x8x4_t test_vld1_p8_x4(poly8_t const *a) { // CHECK-LABEL: @test_vld1_s16_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int16x4x2_t, align 8 -// CHECK-A32: %struct.int16x4x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int16x4x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int16x4x2_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.int16x4x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -262,7 +262,7 @@ int16x4x2_t test_vld1_s16_x2(int16_t const *a) { // CHECK-LABEL: @test_vld1_s16_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int16x4x3_t, align 8 -// CHECK-A32: %struct.int16x4x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int16x4x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int16x4x3_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.int16x4x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -282,7 +282,7 @@ int16x4x3_t test_vld1_s16_x3(int16_t const *a) { // CHECK-LABEL: @test_vld1_s16_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int16x4x4_t, align 8 -// CHECK-A32: %struct.int16x4x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int16x4x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int16x4x4_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.int16x4x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -302,7 +302,7 @@ int16x4x4_t test_vld1_s16_x4(int16_t const *a) { // CHECK-LABEL: @test_vld1_s32_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int32x2x2_t, align 8 -// CHECK-A32: %struct.int32x2x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int32x2x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int32x2x2_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.int32x2x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i32* %a to i8* @@ -322,7 +322,7 @@ int32x2x2_t test_vld1_s32_x2(int32_t const *a) { // CHECK-LABEL: @test_vld1_s32_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int32x2x3_t, align 8 -// CHECK-A32: %struct.int32x2x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int32x2x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int32x2x3_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.int32x2x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i32* %a to i8* @@ -342,7 +342,7 @@ int32x2x3_t test_vld1_s32_x3(int32_t const *a) { // CHECK-LABEL: @test_vld1_s32_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int32x2x4_t, align 8 -// CHECK-A32: %struct.int32x2x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int32x2x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int32x2x4_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.int32x2x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i32* %a to i8* @@ -362,7 +362,7 @@ int32x2x4_t test_vld1_s32_x4(int32_t const *a) { // CHECK-LABEL: @test_vld1_s64_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int64x1x2_t, align 8 -// CHECK-A32: %struct.int64x1x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int64x1x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int64x1x2_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.int64x1x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i64* %a to i8* @@ -382,7 +382,7 @@ int64x1x2_t test_vld1_s64_x2(int64_t const *a) { // CHECK-LABEL: @test_vld1_s64_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int64x1x3_t, align 8 -// CHECK-A32: %struct.int64x1x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int64x1x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int64x1x3_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.int64x1x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i64* %a to i8* @@ -402,7 +402,7 @@ int64x1x3_t test_vld1_s64_x3(int64_t const *a) { // CHECK-LABEL: @test_vld1_s64_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int64x1x4_t, align 8 -// CHECK-A32: %struct.int64x1x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int64x1x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int64x1x4_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.int64x1x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i64* %a to i8* @@ -422,7 +422,7 @@ int64x1x4_t test_vld1_s64_x4(int64_t const *a) { // CHECK-LABEL: @test_vld1_s8_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int8x8x2_t, align 8 -// CHECK-A32: %struct.int8x8x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int8x8x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int8x8x2_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.int8x8x2_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <8 x i8>, <8 x i8> } @llvm.{{aarch64.neon.ld1x2|arm.neon.vld1x2}}.v8i8.p0i8(i8* %a) @@ -440,7 +440,7 @@ int8x8x2_t test_vld1_s8_x2(int8_t const *a) { // CHECK-LABEL: @test_vld1_s8_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int8x8x3_t, align 8 -// CHECK-A32: %struct.int8x8x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int8x8x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int8x8x3_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.int8x8x3_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <8 x i8>, <8 x i8>, <8 x i8> } @llvm.{{aarch64.neon.ld1x3|arm.neon.vld1x3}}.v8i8.p0i8(i8* %a) @@ -458,7 +458,7 @@ int8x8x3_t test_vld1_s8_x3(int8_t const *a) { // CHECK-LABEL: @test_vld1_s8_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int8x8x4_t, align 8 -// CHECK-A32: %struct.int8x8x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int8x8x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int8x8x4_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.int8x8x4_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <8 x i8>, <8 x i8>, <8 x i8>, <8 x i8> } @llvm.{{aarch64.neon.ld1x4|arm.neon.vld1x4}}.v8i8.p0i8(i8* %a) @@ -476,7 +476,7 @@ int8x8x4_t test_vld1_s8_x4(int8_t const *a) { // CHECK-LABEL: @test_vld1_u16_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint16x4x2_t, align 8 -// CHECK-A32: %struct.uint16x4x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint16x4x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint16x4x2_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.uint16x4x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -496,7 +496,7 @@ uint16x4x2_t test_vld1_u16_x2(uint16_t const *a) { // CHECK-LABEL: @test_vld1_u16_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint16x4x3_t, align 8 -// CHECK-A32: %struct.uint16x4x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint16x4x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint16x4x3_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.uint16x4x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -516,7 +516,7 @@ uint16x4x3_t test_vld1_u16_x3(uint16_t const *a) { // CHECK-LABEL: @test_vld1_u16_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint16x4x4_t, align 8 -// CHECK-A32: %struct.uint16x4x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint16x4x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint16x4x4_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.uint16x4x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -536,7 +536,7 @@ uint16x4x4_t test_vld1_u16_x4(uint16_t const *a) { // CHECK-LABEL: @test_vld1_u32_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint32x2x2_t, align 8 -// CHECK-A32: %struct.uint32x2x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint32x2x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint32x2x2_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.uint32x2x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i32* %a to i8* @@ -556,7 +556,7 @@ uint32x2x2_t test_vld1_u32_x2(uint32_t const *a) { // CHECK-LABEL: @test_vld1_u32_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint32x2x3_t, align 8 -// CHECK-A32: %struct.uint32x2x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint32x2x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint32x2x3_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.uint32x2x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i32* %a to i8* @@ -576,7 +576,7 @@ uint32x2x3_t test_vld1_u32_x3(uint32_t const *a) { // CHECK-LABEL: @test_vld1_u32_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint32x2x4_t, align 8 -// CHECK-A32: %struct.uint32x2x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint32x2x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint32x2x4_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.uint32x2x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i32* %a to i8* @@ -596,7 +596,7 @@ uint32x2x4_t test_vld1_u32_x4(uint32_t const *a) { // CHECK-LABEL: @test_vld1_u64_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint64x1x2_t, align 8 -// CHECK-A32: %struct.uint64x1x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint64x1x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint64x1x2_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.uint64x1x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i64* %a to i8* @@ -616,7 +616,7 @@ uint64x1x2_t test_vld1_u64_x2(uint64_t const *a) { // CHECK-LABEL: @test_vld1_u64_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint64x1x3_t, align 8 -// CHECK-A32: %struct.uint64x1x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint64x1x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint64x1x3_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.uint64x1x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i64* %a to i8* @@ -636,7 +636,7 @@ uint64x1x3_t test_vld1_u64_x3(uint64_t const *a) { // CHECK-LABEL: @test_vld1_u64_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint64x1x4_t, align 8 -// CHECK-A32: %struct.uint64x1x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint64x1x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint64x1x4_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.uint64x1x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i64* %a to i8* @@ -656,7 +656,7 @@ uint64x1x4_t test_vld1_u64_x4(uint64_t const *a) { // CHECK-LABEL: @test_vld1_u8_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint8x8x2_t, align 8 -// CHECK-A32: %struct.uint8x8x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint8x8x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint8x8x2_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.uint8x8x2_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <8 x i8>, <8 x i8> } @llvm.{{aarch64.neon.ld1x2|arm.neon.vld1x2}}.v8i8.p0i8(i8* %a) @@ -674,7 +674,7 @@ uint8x8x2_t test_vld1_u8_x2(uint8_t const *a) { // CHECK-LABEL: @test_vld1_u8_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint8x8x3_t, align 8 -// CHECK-A32: %struct.uint8x8x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint8x8x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint8x8x3_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.uint8x8x3_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <8 x i8>, <8 x i8>, <8 x i8> } @llvm.{{aarch64.neon.ld1x3|arm.neon.vld1x3}}.v8i8.p0i8(i8* %a) @@ -692,7 +692,7 @@ uint8x8x3_t test_vld1_u8_x3(uint8_t const *a) { // CHECK-LABEL: @test_vld1_u8_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint8x8x4_t, align 8 -// CHECK-A32: %struct.uint8x8x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint8x8x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint8x8x4_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.uint8x8x4_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <8 x i8>, <8 x i8>, <8 x i8>, <8 x i8> } @llvm.{{aarch64.neon.ld1x4|arm.neon.vld1x4}}.v8i8.p0i8(i8* %a) @@ -710,7 +710,7 @@ uint8x8x4_t test_vld1_u8_x4(uint8_t const *a) { // CHECK-LABEL: @test_vld1q_f16_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.float16x8x2_t, align 16 -// CHECK-A32: %struct.float16x8x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.float16x8x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.float16x8x2_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* @@ -730,7 +730,7 @@ float16x8x2_t test_vld1q_f16_x2(float16_t const *a) { // CHECK-LABEL: @test_vld1q_f16_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.float16x8x3_t, align 16 -// CHECK-A32: %struct.float16x8x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.float16x8x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.float16x8x3_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* @@ -750,7 +750,7 @@ float16x8x3_t test_vld1q_f16_x3(float16_t const *a) { // CHECK-LABEL: @test_vld1q_f16_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.float16x8x4_t, align 16 -// CHECK-A32: %struct.float16x8x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.float16x8x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.float16x8x4_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* @@ -770,7 +770,7 @@ float16x8x4_t test_vld1q_f16_x4(float16_t const *a) { // CHECK-LABEL: @test_vld1q_f32_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.float32x4x2_t, align 16 -// CHECK-A32: %struct.float32x4x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.float32x4x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.float32x4x2_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.float32x4x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast float* %a to i8* @@ -790,7 +790,7 @@ float32x4x2_t test_vld1q_f32_x2(float32_t const *a) { // CHECK-LABEL: @test_vld1q_f32_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.float32x4x3_t, align 16 -// CHECK-A32: %struct.float32x4x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.float32x4x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.float32x4x3_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.float32x4x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast float* %a to i8* @@ -810,7 +810,7 @@ float32x4x3_t test_vld1q_f32_x3(float32_t const *a) { // CHECK-LABEL: @test_vld1q_f32_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.float32x4x4_t, align 16 -// CHECK-A32: %struct.float32x4x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.float32x4x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.float32x4x4_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.float32x4x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast float* %a to i8* @@ -830,7 +830,7 @@ float32x4x4_t test_vld1q_f32_x4(float32_t const *a) { // CHECK-LABEL: @test_vld1q_p16_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.poly16x8x2_t, align 16 -// CHECK-A32: %struct.poly16x8x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.poly16x8x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.poly16x8x2_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.poly16x8x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -850,7 +850,7 @@ poly16x8x2_t test_vld1q_p16_x2(poly16_t const *a) { // CHECK-LABEL: @test_vld1q_p16_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.poly16x8x3_t, align 16 -// CHECK-A32: %struct.poly16x8x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.poly16x8x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.poly16x8x3_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.poly16x8x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -870,7 +870,7 @@ poly16x8x3_t test_vld1q_p16_x3(poly16_t const *a) { // CHECK-LABEL: @test_vld1q_p16_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.poly16x8x4_t, align 16 -// CHECK-A32: %struct.poly16x8x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.poly16x8x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.poly16x8x4_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.poly16x8x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -890,7 +890,7 @@ poly16x8x4_t test_vld1q_p16_x4(poly16_t const *a) { // CHECK-LABEL: @test_vld1q_p8_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.poly8x16x2_t, align 16 -// CHECK-A32: %struct.poly8x16x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.poly8x16x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.poly8x16x2_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.poly8x16x2_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <16 x i8>, <16 x i8> } @llvm.{{aarch64.neon.ld1x2|arm.neon.vld1x2}}.v16i8.p0i8(i8* %a) @@ -908,7 +908,7 @@ poly8x16x2_t test_vld1q_p8_x2(poly8_t const *a) { // CHECK-LABEL: @test_vld1q_p8_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.poly8x16x3_t, align 16 -// CHECK-A32: %struct.poly8x16x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.poly8x16x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.poly8x16x3_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.poly8x16x3_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <16 x i8>, <16 x i8>, <16 x i8> } @llvm.{{aarch64.neon.ld1x3|arm.neon.vld1x3}}.v16i8.p0i8(i8* %a) @@ -926,7 +926,7 @@ poly8x16x3_t test_vld1q_p8_x3(poly8_t const *a) { // CHECK-LABEL: @test_vld1q_p8_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.poly8x16x4_t, align 16 -// CHECK-A32: %struct.poly8x16x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.poly8x16x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.poly8x16x4_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.poly8x16x4_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } @llvm.{{aarch64.neon.ld1x4|arm.neon.vld1x4}}.v16i8.p0i8(i8* %a) @@ -944,7 +944,7 @@ poly8x16x4_t test_vld1q_p8_x4(poly8_t const *a) { // CHECK-LABEL: @test_vld1q_s16_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int16x8x2_t, align 16 -// CHECK-A32: %struct.int16x8x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int16x8x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int16x8x2_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.int16x8x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -964,7 +964,7 @@ int16x8x2_t test_vld1q_s16_x2(int16_t const *a) { // CHECK-LABEL: @test_vld1q_s16_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int16x8x3_t, align 16 -// CHECK-A32: %struct.int16x8x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int16x8x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int16x8x3_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.int16x8x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -984,7 +984,7 @@ int16x8x3_t test_vld1q_s16_x3(int16_t const *a) { // CHECK-LABEL: @test_vld1q_s16_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int16x8x4_t, align 16 -// CHECK-A32: %struct.int16x8x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int16x8x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int16x8x4_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.int16x8x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -1004,7 +1004,7 @@ int16x8x4_t test_vld1q_s16_x4(int16_t const *a) { // CHECK-LABEL: @test_vld1q_s32_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int32x4x2_t, align 16 -// CHECK-A32: %struct.int32x4x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int32x4x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int32x4x2_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.int32x4x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i32* %a to i8* @@ -1024,7 +1024,7 @@ int32x4x2_t test_vld1q_s32_x2(int32_t const *a) { // CHECK-LABEL: @test_vld1q_s32_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int32x4x3_t, align 16 -// CHECK-A32: %struct.int32x4x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int32x4x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int32x4x3_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.int32x4x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i32* %a to i8* @@ -1044,7 +1044,7 @@ int32x4x3_t test_vld1q_s32_x3(int32_t const *a) { // CHECK-LABEL: @test_vld1q_s32_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int32x4x4_t, align 16 -// CHECK-A32: %struct.int32x4x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int32x4x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int32x4x4_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.int32x4x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i32* %a to i8* @@ -1064,7 +1064,7 @@ int32x4x4_t test_vld1q_s32_x4(int32_t const *a) { // CHECK-LABEL: @test_vld1q_s64_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int64x2x2_t, align 16 -// CHECK-A32: %struct.int64x2x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int64x2x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int64x2x2_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.int64x2x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i64* %a to i8* @@ -1084,7 +1084,7 @@ int64x2x2_t test_vld1q_s64_x2(int64_t const *a) { // CHECK-LABEL: @test_vld1q_s64_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int64x2x3_t, align 16 -// CHECK-A32: %struct.int64x2x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int64x2x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int64x2x3_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.int64x2x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i64* %a to i8* @@ -1104,7 +1104,7 @@ int64x2x3_t test_vld1q_s64_x3(int64_t const *a) { // CHECK-LABEL: @test_vld1q_s64_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int64x2x4_t, align 16 -// CHECK-A32: %struct.int64x2x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int64x2x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int64x2x4_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.int64x2x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i64* %a to i8* @@ -1124,7 +1124,7 @@ int64x2x4_t test_vld1q_s64_x4(int64_t const *a) { // CHECK-LABEL: @test_vld1q_s8_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int8x16x2_t, align 16 -// CHECK-A32: %struct.int8x16x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int8x16x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int8x16x2_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.int8x16x2_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <16 x i8>, <16 x i8> } @llvm.{{aarch64.neon.ld1x2|arm.neon.vld1x2}}.v16i8.p0i8(i8* %a) @@ -1142,7 +1142,7 @@ int8x16x2_t test_vld1q_s8_x2(int8_t const *a) { // CHECK-LABEL: @test_vld1q_s8_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int8x16x3_t, align 16 -// CHECK-A32: %struct.int8x16x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int8x16x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int8x16x3_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.int8x16x3_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <16 x i8>, <16 x i8>, <16 x i8> } @llvm.{{aarch64.neon.ld1x3|arm.neon.vld1x3}}.v16i8.p0i8(i8* %a) @@ -1160,7 +1160,7 @@ int8x16x3_t test_vld1q_s8_x3(int8_t const *a) { // CHECK-LABEL: @test_vld1q_s8_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.int8x16x4_t, align 16 -// CHECK-A32: %struct.int8x16x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.int8x16x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.int8x16x4_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.int8x16x4_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } @llvm.{{aarch64.neon.ld1x4|arm.neon.vld1x4}}.v16i8.p0i8(i8* %a) @@ -1178,7 +1178,7 @@ int8x16x4_t test_vld1q_s8_x4(int8_t const *a) { // CHECK-LABEL: @test_vld1q_u16_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint16x8x2_t, align 16 -// CHECK-A32: %struct.uint16x8x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint16x8x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint16x8x2_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.uint16x8x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -1198,7 +1198,7 @@ uint16x8x2_t test_vld1q_u16_x2(uint16_t const *a) { // CHECK-LABEL: @test_vld1q_u16_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint16x8x3_t, align 16 -// CHECK-A32: %struct.uint16x8x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint16x8x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint16x8x3_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.uint16x8x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -1218,7 +1218,7 @@ uint16x8x3_t test_vld1q_u16_x3(uint16_t const *a) { // CHECK-LABEL: @test_vld1q_u16_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint16x8x4_t, align 16 -// CHECK-A32: %struct.uint16x8x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint16x8x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint16x8x4_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.uint16x8x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i16* %a to i8* @@ -1238,7 +1238,7 @@ uint16x8x4_t test_vld1q_u16_x4(uint16_t const *a) { // CHECK-LABEL: @test_vld1q_u32_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint32x4x2_t, align 16 -// CHECK-A32: %struct.uint32x4x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint32x4x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint32x4x2_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.uint32x4x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i32* %a to i8* @@ -1258,7 +1258,7 @@ uint32x4x2_t test_vld1q_u32_x2(uint32_t const *a) { // CHECK-LABEL: @test_vld1q_u32_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint32x4x3_t, align 16 -// CHECK-A32: %struct.uint32x4x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint32x4x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint32x4x3_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.uint32x4x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i32* %a to i8* @@ -1278,7 +1278,7 @@ uint32x4x3_t test_vld1q_u32_x3(uint32_t const *a) { // CHECK-LABEL: @test_vld1q_u32_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint32x4x4_t, align 16 -// CHECK-A32: %struct.uint32x4x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint32x4x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint32x4x4_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.uint32x4x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i32* %a to i8* @@ -1298,7 +1298,7 @@ uint32x4x4_t test_vld1q_u32_x4(uint32_t const *a) { // CHECK-LABEL: @test_vld1q_u64_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint64x2x2_t, align 16 -// CHECK-A32: %struct.uint64x2x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint64x2x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint64x2x2_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.uint64x2x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i64* %a to i8* @@ -1318,7 +1318,7 @@ uint64x2x2_t test_vld1q_u64_x2(uint64_t const *a) { // CHECK-LABEL: @test_vld1q_u64_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint64x2x3_t, align 16 -// CHECK-A32: %struct.uint64x2x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint64x2x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint64x2x3_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.uint64x2x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i64* %a to i8* @@ -1338,7 +1338,7 @@ uint64x2x3_t test_vld1q_u64_x3(uint64_t const *a) { // CHECK-LABEL: @test_vld1q_u64_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint64x2x4_t, align 16 -// CHECK-A32: %struct.uint64x2x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint64x2x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint64x2x4_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.uint64x2x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i64* %a to i8* @@ -1358,7 +1358,7 @@ uint64x2x4_t test_vld1q_u64_x4(uint64_t const *a) { // CHECK-LABEL: @test_vld1q_u8_x2( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint8x16x2_t, align 16 -// CHECK-A32: %struct.uint8x16x2_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint8x16x2_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint8x16x2_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.uint8x16x2_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <16 x i8>, <16 x i8> } @llvm.{{aarch64.neon.ld1x2|arm.neon.vld1x2}}.v16i8.p0i8(i8* %a) @@ -1376,7 +1376,7 @@ uint8x16x2_t test_vld1q_u8_x2(uint8_t const *a) { // CHECK-LABEL: @test_vld1q_u8_x3( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint8x16x3_t, align 16 -// CHECK-A32: %struct.uint8x16x3_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint8x16x3_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint8x16x3_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.uint8x16x3_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <16 x i8>, <16 x i8>, <16 x i8> } @llvm.{{aarch64.neon.ld1x3|arm.neon.vld1x3}}.v16i8.p0i8(i8* %a) @@ -1394,7 +1394,7 @@ uint8x16x3_t test_vld1q_u8_x3(uint8_t const *a) { // CHECK-LABEL: @test_vld1q_u8_x4( // CHECK-A64: [[RETVAL:%.*]] = alloca %struct.uint8x16x4_t, align 16 -// CHECK-A32: %struct.uint8x16x4_t* noalias sret [[RETVAL:%.*]], +// CHECK-A32: %struct.uint8x16x4_t* noalias sret align 8 [[RETVAL:%.*]], // CHECK: [[__RET:%.*]] = alloca %struct.uint8x16x4_t, align {{16|8}} // CHECK: [[TMP0:%.*]] = bitcast %struct.uint8x16x4_t* [[__RET]] to i8* // CHECK: [[VLD1XN:%.*]] = call { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } @llvm.{{aarch64.neon.ld1x4|arm.neon.vld1x4}}.v16i8.p0i8(i8* %a) diff --git a/clang/test/CodeGen/arm-varargs.c b/clang/test/CodeGen/arm-varargs.c index 1f5c07ef57dad..dff62568b6cae 100644 --- a/clang/test/CodeGen/arm-varargs.c +++ b/clang/test/CodeGen/arm-varargs.c @@ -24,7 +24,7 @@ struct bigstruct { }; struct bigstruct simple_struct(void) { -// CHECK-LABEL: define void @simple_struct(%struct.bigstruct* noalias sret %agg.result) +// CHECK-LABEL: define void @simple_struct(%struct.bigstruct* noalias sret align 4 %agg.result) return va_arg(the_list, struct bigstruct); // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR]], i32 40 @@ -42,7 +42,7 @@ struct aligned_bigstruct { }; struct aligned_bigstruct simple_aligned_struct(void) { -// CHECK-LABEL: define void @simple_aligned_struct(%struct.aligned_bigstruct* noalias sret %agg.result) +// CHECK-LABEL: define void @simple_aligned_struct(%struct.aligned_bigstruct* noalias sret align 8 %agg.result) return va_arg(the_list, struct aligned_bigstruct); // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 // CHECK: [[CUR_INT:%[a-z0-9._]+]] = ptrtoint i8* [[CUR]] to i32 @@ -78,7 +78,7 @@ struct hfa { }; struct hfa simple_hfa(void) { -// CHECK-LABEL: define void @simple_hfa(%struct.hfa* noalias sret %agg.result) +// CHECK-LABEL: define void @simple_hfa(%struct.hfa* noalias sret align 4 %agg.result) return va_arg(the_list, struct hfa); // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR]], i32 8 @@ -185,7 +185,7 @@ typedef struct __attribute__((aligned(16))) { int val; } overaligned_int_struct; overaligned_int_struct overaligned_int_struct_test() { -// CHECK-LABEL: define void @overaligned_int_struct_test(%struct.overaligned_int_struct* noalias sret %agg.result) +// CHECK-LABEL: define void @overaligned_int_struct_test(%struct.overaligned_int_struct* noalias sret align 16 %agg.result) return va_arg(the_list, overaligned_int_struct); // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR]], i32 16 @@ -201,7 +201,7 @@ typedef struct __attribute__((packed,aligned(2))) { long long val; } underaligned_long_long_struct; underaligned_long_long_struct underaligned_long_long_struct_test() { -// CHECK-LABEL: define void @underaligned_long_long_struct_test(%struct.underaligned_long_long_struct* noalias sret %agg.result) +// CHECK-LABEL: define void @underaligned_long_long_struct_test(%struct.underaligned_long_long_struct* noalias sret align 2 %agg.result) return va_arg(the_list, underaligned_long_long_struct); // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR]], i32 8 @@ -217,7 +217,7 @@ typedef struct __attribute__((aligned(16))) { long long val; } overaligned_long_long_struct; overaligned_long_long_struct overaligned_long_long_struct_test() { -// CHECK-LABEL: define void @overaligned_long_long_struct_test(%struct.overaligned_long_long_struct* noalias sret %agg.result) +// CHECK-LABEL: define void @overaligned_long_long_struct_test(%struct.overaligned_long_long_struct* noalias sret align 16 %agg.result) return va_arg(the_list, overaligned_long_long_struct); // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 // CHECK: [[CUR_INT:%[a-z0-9._]+]] = ptrtoint i8* [[CUR]] to i32 @@ -259,7 +259,7 @@ typedef struct { int val __attribute__((aligned(16))); } overaligned_int_struct_member; overaligned_int_struct_member overaligned_int_struct_member_test() { -// CHECK-LABEL: define void @overaligned_int_struct_member_test(%struct.overaligned_int_struct_member* noalias sret %agg.result) +// CHECK-LABEL: define void @overaligned_int_struct_member_test(%struct.overaligned_int_struct_member* noalias sret align 16 %agg.result) return va_arg(the_list, overaligned_int_struct_member); // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 // CHECK: [[CUR_INT:%[a-z0-9._]+]] = ptrtoint i8* [[CUR]] to i32 @@ -279,7 +279,7 @@ typedef struct { long long val __attribute__((packed,aligned(2))); } underaligned_long_long_struct_member; underaligned_long_long_struct_member underaligned_long_long_struct_member_test() { -// CHECK-LABEL: define void @underaligned_long_long_struct_member_test(%struct.underaligned_long_long_struct_member* noalias sret %agg.result) +// CHECK-LABEL: define void @underaligned_long_long_struct_member_test(%struct.underaligned_long_long_struct_member* noalias sret align 2 %agg.result) return va_arg(the_list, underaligned_long_long_struct_member); // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 // CHECK: [[NEXT:%[a-z0-9._]+]] = getelementptr inbounds i8, i8* [[CUR]], i32 8 @@ -295,7 +295,7 @@ typedef struct { long long val __attribute__((aligned(16))); } overaligned_long_long_struct_member; overaligned_long_long_struct_member overaligned_long_long_struct_member_test() { -// CHECK-LABEL: define void @overaligned_long_long_struct_member_test(%struct.overaligned_long_long_struct_member* noalias sret %agg.result) +// CHECK-LABEL: define void @overaligned_long_long_struct_member_test(%struct.overaligned_long_long_struct_member* noalias sret align 16 %agg.result) return va_arg(the_list, overaligned_long_long_struct_member); // CHECK: [[CUR:%[a-z0-9._]+]] = load i8*, i8** getelementptr inbounds (%struct.__va_list, %struct.__va_list* @the_list, i32 0, i32 0), align 4 // CHECK: [[CUR_INT:%[a-z0-9._]+]] = ptrtoint i8* [[CUR]] to i32 diff --git a/clang/test/CodeGen/arm-vector-arguments.c b/clang/test/CodeGen/arm-vector-arguments.c index 9bdddb72696e3..aa8e65ba366f4 100644 --- a/clang/test/CodeGen/arm-vector-arguments.c +++ b/clang/test/CodeGen/arm-vector-arguments.c @@ -9,7 +9,7 @@ #include -// CHECK: define void @f0(%struct.int8x16x2_t* noalias sret %agg.result, <16 x i8> %{{.*}}, <16 x i8> %{{.*}}) +// CHECK: define void @f0(%struct.int8x16x2_t* noalias sret align 16 %agg.result, <16 x i8> %{{.*}}, <16 x i8> %{{.*}}) int8x16x2_t f0(int8x16_t a0, int8x16_t a1) { return vzipq_s8(a0, a1); } @@ -25,7 +25,7 @@ typedef float T_float32x16 __attribute__ ((__vector_size__ (64))); T_float32x2 f1_0(T_float32x2 a0) { return a0; } // CHECK: define <4 x float> @f1_1(<4 x float> %{{.*}}) T_float32x4 f1_1(T_float32x4 a0) { return a0; } -// CHECK: define void @f1_2(<8 x float>* noalias sret %{{.*}}, <8 x float> %{{.*}}) +// CHECK: define void @f1_2(<8 x float>* noalias sret align 32 %{{.*}}, <8 x float> %{{.*}}) T_float32x8 f1_2(T_float32x8 a0) { return a0; } -// CHECK: define void @f1_3(<16 x float>* noalias sret %{{.*}}, <16 x float> %{{.*}}) +// CHECK: define void @f1_3(<16 x float>* noalias sret align 64 %{{.*}}, <16 x float> %{{.*}}) T_float32x16 f1_3(T_float32x16 a0) { return a0; } diff --git a/clang/test/CodeGen/arm-vfp16-arguments.c b/clang/test/CodeGen/arm-vfp16-arguments.c index 32f1bb7b2a775..42d990d970862 100644 --- a/clang/test/CodeGen/arm-vfp16-arguments.c +++ b/clang/test/CodeGen/arm-vfp16-arguments.c @@ -71,6 +71,6 @@ void test_hfa(hfa_t a) {} hfa_t ghfa; hfa_t test_ret_hfa(void) { return ghfa; } -// CHECK-SOFT: define void @test_ret_hfa(%struct.hfa_t* noalias nocapture sret %agg.result) +// CHECK-SOFT: define void @test_ret_hfa(%struct.hfa_t* noalias nocapture sret align 8 %agg.result) // CHECK-HARD: define arm_aapcs_vfpcc [2 x <2 x i32>] @test_ret_hfa() // CHECK-FULL: define arm_aapcs_vfpcc %struct.hfa_t @test_ret_hfa() diff --git a/clang/test/CodeGen/arm-vfp16-arguments2.cpp b/clang/test/CodeGen/arm-vfp16-arguments2.cpp index e436a5ecd6abd..ccc81a3bfdd92 100644 --- a/clang/test/CodeGen/arm-vfp16-arguments2.cpp +++ b/clang/test/CodeGen/arm-vfp16-arguments2.cpp @@ -37,27 +37,27 @@ struct S5 : B1 { B1 M[1]; }; -// CHECK-SOFT: define void @_Z2f12S1(%struct.S1* noalias nocapture sret %agg.result, [2 x i64] %s1.coerce) +// CHECK-SOFT: define void @_Z2f12S1(%struct.S1* noalias nocapture sret align 8 %agg.result, [2 x i64] %s1.coerce) // CHECK-HARD: define arm_aapcs_vfpcc [2 x <2 x i32>] @_Z2f12S1([2 x <2 x i32>] returned %s1.coerce) // CHECK-FULL: define arm_aapcs_vfpcc %struct.S1 @_Z2f12S1(%struct.S1 returned %s1.coerce) struct S1 f1(struct S1 s1) { return s1; } -// CHECK-SOFT: define void @_Z2f22S2(%struct.S2* noalias nocapture sret %agg.result, [4 x i32] %s2.coerce) +// CHECK-SOFT: define void @_Z2f22S2(%struct.S2* noalias nocapture sret align 8 %agg.result, [4 x i32] %s2.coerce) // CHECK-HARD: define arm_aapcs_vfpcc [2 x <2 x i32>] @_Z2f22S2([2 x <2 x i32>] returned %s2.coerce) // CHECK-FULL: define arm_aapcs_vfpcc %struct.S2 @_Z2f22S2(%struct.S2 returned %s2.coerce) struct S2 f2(struct S2 s2) { return s2; } -// CHECK-SOFT: define void @_Z2f32S3(%struct.S3* noalias nocapture sret %agg.result, [2 x i64] %s3.coerce) +// CHECK-SOFT: define void @_Z2f32S3(%struct.S3* noalias nocapture sret align 8 %agg.result, [2 x i64] %s3.coerce) // CHECK-HARD: define arm_aapcs_vfpcc [2 x <2 x i32>] @_Z2f32S3([2 x <2 x i32>] returned %s3.coerce) // CHECK-FULL: define arm_aapcs_vfpcc %struct.S3 @_Z2f32S3(%struct.S3 returned %s3.coerce) struct S3 f3(struct S3 s3) { return s3; } -// CHECK-SOFT: define void @_Z2f42S4(%struct.S4* noalias nocapture sret %agg.result, [2 x i64] %s4.coerce) +// CHECK-SOFT: define void @_Z2f42S4(%struct.S4* noalias nocapture sret align 8 %agg.result, [2 x i64] %s4.coerce) // CHECK-HARD: define arm_aapcs_vfpcc [2 x <2 x i32>] @_Z2f42S4([2 x <2 x i32>] returned %s4.coerce) // CHECK-FULL: define arm_aapcs_vfpcc %struct.S4 @_Z2f42S4(%struct.S4 returned %s4.coerce) struct S4 f4(struct S4 s4) { return s4; } -// CHECK-SOFT: define void @_Z2f52S5(%struct.S5* noalias nocapture sret %agg.result, [2 x i64] %s5.coerce) +// CHECK-SOFT: define void @_Z2f52S5(%struct.S5* noalias nocapture sret align 8 %agg.result, [2 x i64] %s5.coerce) // CHECK-HARD: define arm_aapcs_vfpcc %struct.S5 @_Z2f52S5(%struct.S5 returned %s5.coerce) // CHECK-FULL: define arm_aapcs_vfpcc %struct.S5 @_Z2f52S5(%struct.S5 returned %s5.coerce) struct S5 f5(struct S5 s5) { return s5; } diff --git a/clang/test/CodeGen/arm64-arguments.c b/clang/test/CodeGen/arm64-arguments.c index 5c8474cae7be8..97332deb7c807 100644 --- a/clang/test/CodeGen/arm64-arguments.c +++ b/clang/test/CodeGen/arm64-arguments.c @@ -181,9 +181,9 @@ T_float32x2 f1_0(T_float32x2 a0) { return a0; } // CHECK: define <4 x float> @f1_1(<4 x float> %{{.*}}) T_float32x4 f1_1(T_float32x4 a0) { return a0; } // Vector with length bigger than 16-byte is illegal and is passed indirectly. -// CHECK: define void @f1_2(<8 x float>* noalias sret %{{.*}}, <8 x float>* %0) +// CHECK: define void @f1_2(<8 x float>* noalias sret align 16 %{{.*}}, <8 x float>* %0) T_float32x8 f1_2(T_float32x8 a0) { return a0; } -// CHECK: define void @f1_3(<16 x float>* noalias sret %{{.*}}, <16 x float>* %0) +// CHECK: define void @f1_3(<16 x float>* noalias sret align 16 %{{.*}}, <16 x float>* %0) T_float32x16 f1_3(T_float32x16 a0) { return a0; } // Testing alignment with aggregates: HFA, aggregates with size <= 16 bytes and diff --git a/clang/test/CodeGen/arm64-microsoft-arguments.cpp b/clang/test/CodeGen/arm64-microsoft-arguments.cpp index bca7cc94b3937..f5bcda756b061 100644 --- a/clang/test/CodeGen/arm64-microsoft-arguments.cpp +++ b/clang/test/CodeGen/arm64-microsoft-arguments.cpp @@ -28,8 +28,8 @@ S2 f2() { } // Pass and return for type size > 16 bytes. -// CHECK: define {{.*}} void @{{.*}}f3{{.*}}(%struct.S3* noalias sret %agg.result) -// CHECK: call void {{.*}}func3{{.*}}(%struct.S3* sret %agg.result, %struct.S3* %agg.tmp) +// CHECK: define {{.*}} void @{{.*}}f3{{.*}}(%struct.S3* noalias sret align 4 %agg.result) +// CHECK: call void {{.*}}func3{{.*}}(%struct.S3* sret align 4 %agg.result, %struct.S3* %agg.tmp) struct S3 { int a[5]; }; @@ -42,8 +42,8 @@ S3 f3() { // Pass and return aggregate (of size < 16 bytes) with non-trivial destructor. // Passed directly but returned indirectly. -// CHECK: define {{.*}} void {{.*}}f4{{.*}}(%struct.S4* inreg noalias sret %agg.result) -// CHECK: call void {{.*}}func4{{.*}}(%struct.S4* inreg sret %agg.result, [2 x i64] %5) +// CHECK: define {{.*}} void {{.*}}f4{{.*}}(%struct.S4* inreg noalias sret align 4 %agg.result) +// CHECK: call void {{.*}}func4{{.*}}(%struct.S4* inreg sret align 4 %agg.result, [2 x i64] %5) struct S4 { int a[3]; ~S4(); @@ -56,8 +56,8 @@ S4 f4() { } // Pass and return from instance method called from instance method. -// CHECK: define {{.*}} void @{{.*}}bar@Q1{{.*}}(%class.Q1* %this, %class.P1* inreg noalias sret %agg.result) -// CHECK: call void {{.*}}foo@P1{{.*}}(%class.P1* %ref.tmp, %class.P1* inreg sret %agg.result, i8 %1) +// CHECK: define {{.*}} void @{{.*}}bar@Q1{{.*}}(%class.Q1* %this, %class.P1* inreg noalias sret align 1 %agg.result) +// CHECK: call void {{.*}}foo@P1{{.*}}(%class.P1* %ref.tmp, %class.P1* inreg sret align 1 %agg.result, i8 %1) class P1 { public: @@ -76,7 +76,7 @@ P1 Q1::bar() { // Pass and return from instance method called from free function. // CHECK: define {{.*}} void {{.*}}bar{{.*}}() -// CHECK: call void {{.*}}foo@P2{{.*}}(%class.P2* %ref.tmp, %class.P2* inreg sret %retval, i8 %0) +// CHECK: call void {{.*}}foo@P2{{.*}}(%class.P2* %ref.tmp, %class.P2* inreg sret align 1 %retval, i8 %0) class P2 { public: P2 foo(P2 x); @@ -89,8 +89,8 @@ P2 bar() { // Pass and return an object with a user-provided constructor (passed directly, // returned indirectly) -// CHECK: define {{.*}} void @{{.*}}f5{{.*}}(%struct.S5* inreg noalias sret %agg.result) -// CHECK: call void {{.*}}func5{{.*}}(%struct.S5* inreg sret %agg.result, i64 {{.*}}) +// CHECK: define {{.*}} void @{{.*}}f5{{.*}}(%struct.S5* inreg noalias sret align 4 %agg.result) +// CHECK: call void {{.*}}func5{{.*}}(%struct.S5* inreg sret align 4 %agg.result, i64 {{.*}}) struct S5 { S5(); int x; @@ -146,8 +146,8 @@ struct S8 { int y; }; -// CHECK: define {{.*}} void {{.*}}?f8{{.*}}(%struct.S8* inreg noalias sret {{.*}}) -// CHECK: call void {{.*}}func8{{.*}}(%struct.S8* inreg sret {{.*}}, i64 {{.*}}) +// CHECK: define {{.*}} void {{.*}}?f8{{.*}}(%struct.S8* inreg noalias sret align 4 {{.*}}) +// CHECK: call void {{.*}}func8{{.*}}(%struct.S8* inreg sret align 4 {{.*}}, i64 {{.*}}) S8 func8(S8 x); S8 f8() { S8 x; @@ -157,8 +157,8 @@ S8 f8() { // Pass and return an object with a non-trivial copy-assignment operator and // a trivial copy constructor (passed directly, returned indirectly) -// CHECK: define {{.*}} void @"?f9@@YA?AUS9@@XZ"(%struct.S9* inreg noalias sret {{.*}}) -// CHECK: call void {{.*}}func9{{.*}}(%struct.S9* inreg sret {{.*}}, i64 {{.*}}) +// CHECK: define {{.*}} void @"?f9@@YA?AUS9@@XZ"(%struct.S9* inreg noalias sret align 4 {{.*}}) +// CHECK: call void {{.*}}func9{{.*}}(%struct.S9* inreg sret align 4 {{.*}}, i64 {{.*}}) struct S9 { S9& operator=(const S9&); int x; @@ -174,8 +174,8 @@ S9 f9() { // Pass and return an object with a base class (passed directly, returned // indirectly). -// CHECK: define dso_local void {{.*}}f10{{.*}}(%struct.S10* inreg noalias sret {{.*}}) -// CHECK: call void {{.*}}func10{{.*}}(%struct.S10* inreg sret {{.*}}, [2 x i64] {{.*}}) +// CHECK: define dso_local void {{.*}}f10{{.*}}(%struct.S10* inreg noalias sret align 4 {{.*}}) +// CHECK: call void {{.*}}func10{{.*}}(%struct.S10* inreg sret align 4 {{.*}}, [2 x i64] {{.*}}) struct S10 : public S1 { int x; }; @@ -189,8 +189,8 @@ S10 f10() { // Pass and return a non aggregate object exceeding > 128 bits (passed // indirectly, returned indirectly) -// CHECK: define dso_local void {{.*}}f11{{.*}}(%struct.S11* inreg noalias sret {{.*}}) -// CHECK: call void {{.*}}func11{{.*}}(%struct.S11* inreg sret {{.*}}, %struct.S11* {{.*}}) +// CHECK: define dso_local void {{.*}}f11{{.*}}(%struct.S11* inreg noalias sret align 8 {{.*}}) +// CHECK: call void {{.*}}func11{{.*}}(%struct.S11* inreg sret align 8 {{.*}}, %struct.S11* {{.*}}) struct S11 { virtual void f(); int a[5]; diff --git a/clang/test/CodeGen/arm64_32.c b/clang/test/CodeGen/arm64_32.c index 245dfefc99e3b..1fb121cfcfb14 100644 --- a/clang/test/CodeGen/arm64_32.c +++ b/clang/test/CodeGen/arm64_32.c @@ -27,4 +27,4 @@ long double LongDoubleVar = 0.0; typedef float __attribute__((ext_vector_type(16))) v16f32; v16f32 func(v16f32 in) { return in; } -// CHECK: define void @func(<16 x float>* noalias sret {{%.*}}, <16 x float> {{%.*}}) +// CHECK: define void @func(<16 x float>* noalias sret align 16 {{%.*}}, <16 x float> {{%.*}}) diff --git a/clang/test/CodeGen/arm_neon_intrinsics.c b/clang/test/CodeGen/arm_neon_intrinsics.c index 9f1a64554155c..17aa39fb4ae19 100644 --- a/clang/test/CodeGen/arm_neon_intrinsics.c +++ b/clang/test/CodeGen/arm_neon_intrinsics.c @@ -20079,7 +20079,7 @@ poly8x8_t test_vtbx4_p8(poly8x8_t a, poly8x8x4_t b, uint8x8_t c) { return vtbx4_p8(a, b, c); } -// CHECK: @test_vtrn_s8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrn_s8({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int8x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <8 x i8>* // CHECK: [[VTRN_I:%.*]] = shufflevector <8 x i8> %a, <8 x i8> %b, <8 x i32> @@ -20092,7 +20092,7 @@ int8x8x2_t test_vtrn_s8(int8x8_t a, int8x8_t b) { return vtrn_s8(a, b); } -// CHECK: @test_vtrn_s16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrn_s16({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int16x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x i16> %b to <8 x i8> @@ -20107,7 +20107,7 @@ int16x4x2_t test_vtrn_s16(int16x4_t a, int16x4_t b) { return vtrn_s16(a, b); } -// CHECK: @test_vtrn_s32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrn_s32({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int32x2x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <2 x i32> %b to <8 x i8> @@ -20122,7 +20122,7 @@ int32x2x2_t test_vtrn_s32(int32x2_t a, int32x2_t b) { return vtrn_s32(a, b); } -// CHECK: @test_vtrn_u8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrn_u8({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint8x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <8 x i8>* // CHECK: [[VTRN_I:%.*]] = shufflevector <8 x i8> %a, <8 x i8> %b, <8 x i32> @@ -20135,7 +20135,7 @@ uint8x8x2_t test_vtrn_u8(uint8x8_t a, uint8x8_t b) { return vtrn_u8(a, b); } -// CHECK: @test_vtrn_u16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrn_u16({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint16x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x i16> %b to <8 x i8> @@ -20150,7 +20150,7 @@ uint16x4x2_t test_vtrn_u16(uint16x4_t a, uint16x4_t b) { return vtrn_u16(a, b); } -// CHECK: @test_vtrn_u32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrn_u32({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint32x2x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <2 x i32> %b to <8 x i8> @@ -20165,7 +20165,7 @@ uint32x2x2_t test_vtrn_u32(uint32x2_t a, uint32x2_t b) { return vtrn_u32(a, b); } -// CHECK: @test_vtrn_f32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrn_f32({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.float32x2x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <2 x float> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <2 x float> %b to <8 x i8> @@ -20180,7 +20180,7 @@ float32x2x2_t test_vtrn_f32(float32x2_t a, float32x2_t b) { return vtrn_f32(a, b); } -// CHECK: @test_vtrn_p8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrn_p8({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.poly8x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <8 x i8>* // CHECK: [[VTRN_I:%.*]] = shufflevector <8 x i8> %a, <8 x i8> %b, <8 x i32> @@ -20193,7 +20193,7 @@ poly8x8x2_t test_vtrn_p8(poly8x8_t a, poly8x8_t b) { return vtrn_p8(a, b); } -// CHECK: @test_vtrn_p16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrn_p16({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.poly16x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x i16> %b to <8 x i8> @@ -20208,7 +20208,7 @@ poly16x4x2_t test_vtrn_p16(poly16x4_t a, poly16x4_t b) { return vtrn_p16(a, b); } -// CHECK: @test_vtrnq_s8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrnq_s8({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int8x16x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <16 x i8>* // CHECK: [[VTRN_I:%.*]] = shufflevector <16 x i8> %a, <16 x i8> %b, <16 x i32> @@ -20221,7 +20221,7 @@ int8x16x2_t test_vtrnq_s8(int8x16_t a, int8x16_t b) { return vtrnq_s8(a, b); } -// CHECK: @test_vtrnq_s16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrnq_s16({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int16x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <8 x i16> %b to <16 x i8> @@ -20236,7 +20236,7 @@ int16x8x2_t test_vtrnq_s16(int16x8_t a, int16x8_t b) { return vtrnq_s16(a, b); } -// CHECK: @test_vtrnq_s32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrnq_s32({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int32x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x i32> %b to <16 x i8> @@ -20251,7 +20251,7 @@ int32x4x2_t test_vtrnq_s32(int32x4_t a, int32x4_t b) { return vtrnq_s32(a, b); } -// CHECK: @test_vtrnq_u8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrnq_u8({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint8x16x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <16 x i8>* // CHECK: [[VTRN_I:%.*]] = shufflevector <16 x i8> %a, <16 x i8> %b, <16 x i32> @@ -20264,7 +20264,7 @@ uint8x16x2_t test_vtrnq_u8(uint8x16_t a, uint8x16_t b) { return vtrnq_u8(a, b); } -// CHECK: @test_vtrnq_u16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrnq_u16({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint16x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <8 x i16> %b to <16 x i8> @@ -20279,7 +20279,7 @@ uint16x8x2_t test_vtrnq_u16(uint16x8_t a, uint16x8_t b) { return vtrnq_u16(a, b); } -// CHECK: @test_vtrnq_u32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrnq_u32({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint32x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x i32> %b to <16 x i8> @@ -20294,7 +20294,7 @@ uint32x4x2_t test_vtrnq_u32(uint32x4_t a, uint32x4_t b) { return vtrnq_u32(a, b); } -// CHECK: @test_vtrnq_f32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrnq_f32({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.float32x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x float> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x float> %b to <16 x i8> @@ -20309,7 +20309,7 @@ float32x4x2_t test_vtrnq_f32(float32x4_t a, float32x4_t b) { return vtrnq_f32(a, b); } -// CHECK: @test_vtrnq_p8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrnq_p8({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.poly8x16x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <16 x i8>* // CHECK: [[VTRN_I:%.*]] = shufflevector <16 x i8> %a, <16 x i8> %b, <16 x i32> @@ -20322,7 +20322,7 @@ poly8x16x2_t test_vtrnq_p8(poly8x16_t a, poly8x16_t b) { return vtrnq_p8(a, b); } -// CHECK: @test_vtrnq_p16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vtrnq_p16({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.poly16x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <8 x i16> %b to <16 x i8> @@ -20501,7 +20501,7 @@ uint16x8_t test_vtstq_p16(poly16x8_t a, poly16x8_t b) { return vtstq_p16(a, b); } -// CHECK: @test_vuzp_s8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzp_s8({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int8x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <8 x i8>* // CHECK: [[VUZP_I:%.*]] = shufflevector <8 x i8> %a, <8 x i8> %b, <8 x i32> @@ -20514,7 +20514,7 @@ int8x8x2_t test_vuzp_s8(int8x8_t a, int8x8_t b) { return vuzp_s8(a, b); } -// CHECK: @test_vuzp_s16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzp_s16({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int16x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x i16> %b to <8 x i8> @@ -20529,7 +20529,7 @@ int16x4x2_t test_vuzp_s16(int16x4_t a, int16x4_t b) { return vuzp_s16(a, b); } -// CHECK: @test_vuzp_s32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzp_s32({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int32x2x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <2 x i32> %b to <8 x i8> @@ -20544,7 +20544,7 @@ int32x2x2_t test_vuzp_s32(int32x2_t a, int32x2_t b) { return vuzp_s32(a, b); } -// CHECK: @test_vuzp_u8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzp_u8({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint8x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <8 x i8>* // CHECK: [[VUZP_I:%.*]] = shufflevector <8 x i8> %a, <8 x i8> %b, <8 x i32> @@ -20557,7 +20557,7 @@ uint8x8x2_t test_vuzp_u8(uint8x8_t a, uint8x8_t b) { return vuzp_u8(a, b); } -// CHECK: @test_vuzp_u16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzp_u16({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint16x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x i16> %b to <8 x i8> @@ -20572,7 +20572,7 @@ uint16x4x2_t test_vuzp_u16(uint16x4_t a, uint16x4_t b) { return vuzp_u16(a, b); } -// CHECK: @test_vuzp_u32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzp_u32({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint32x2x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <2 x i32> %b to <8 x i8> @@ -20587,7 +20587,7 @@ uint32x2x2_t test_vuzp_u32(uint32x2_t a, uint32x2_t b) { return vuzp_u32(a, b); } -// CHECK: @test_vuzp_f32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzp_f32({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.float32x2x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <2 x float> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <2 x float> %b to <8 x i8> @@ -20602,7 +20602,7 @@ float32x2x2_t test_vuzp_f32(float32x2_t a, float32x2_t b) { return vuzp_f32(a, b); } -// CHECK: @test_vuzp_p8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzp_p8({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.poly8x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <8 x i8>* // CHECK: [[VUZP_I:%.*]] = shufflevector <8 x i8> %a, <8 x i8> %b, <8 x i32> @@ -20615,7 +20615,7 @@ poly8x8x2_t test_vuzp_p8(poly8x8_t a, poly8x8_t b) { return vuzp_p8(a, b); } -// CHECK: @test_vuzp_p16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzp_p16({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.poly16x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x i16> %b to <8 x i8> @@ -20630,7 +20630,7 @@ poly16x4x2_t test_vuzp_p16(poly16x4_t a, poly16x4_t b) { return vuzp_p16(a, b); } -// CHECK: @test_vuzpq_s8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzpq_s8({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int8x16x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <16 x i8>* // CHECK: [[VUZP_I:%.*]] = shufflevector <16 x i8> %a, <16 x i8> %b, <16 x i32> @@ -20643,7 +20643,7 @@ int8x16x2_t test_vuzpq_s8(int8x16_t a, int8x16_t b) { return vuzpq_s8(a, b); } -// CHECK: @test_vuzpq_s16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzpq_s16({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int16x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <8 x i16> %b to <16 x i8> @@ -20658,7 +20658,7 @@ int16x8x2_t test_vuzpq_s16(int16x8_t a, int16x8_t b) { return vuzpq_s16(a, b); } -// CHECK: @test_vuzpq_s32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzpq_s32({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int32x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x i32> %b to <16 x i8> @@ -20673,7 +20673,7 @@ int32x4x2_t test_vuzpq_s32(int32x4_t a, int32x4_t b) { return vuzpq_s32(a, b); } -// CHECK: @test_vuzpq_u8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzpq_u8({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint8x16x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <16 x i8>* // CHECK: [[VUZP_I:%.*]] = shufflevector <16 x i8> %a, <16 x i8> %b, <16 x i32> @@ -20686,7 +20686,7 @@ uint8x16x2_t test_vuzpq_u8(uint8x16_t a, uint8x16_t b) { return vuzpq_u8(a, b); } -// CHECK: @test_vuzpq_u16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzpq_u16({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint16x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <8 x i16> %b to <16 x i8> @@ -20701,7 +20701,7 @@ uint16x8x2_t test_vuzpq_u16(uint16x8_t a, uint16x8_t b) { return vuzpq_u16(a, b); } -// CHECK: @test_vuzpq_u32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzpq_u32({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint32x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x i32> %b to <16 x i8> @@ -20716,7 +20716,7 @@ uint32x4x2_t test_vuzpq_u32(uint32x4_t a, uint32x4_t b) { return vuzpq_u32(a, b); } -// CHECK: @test_vuzpq_f32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzpq_f32({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.float32x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x float> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x float> %b to <16 x i8> @@ -20731,7 +20731,7 @@ float32x4x2_t test_vuzpq_f32(float32x4_t a, float32x4_t b) { return vuzpq_f32(a, b); } -// CHECK: @test_vuzpq_p8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzpq_p8({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.poly8x16x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <16 x i8>* // CHECK: [[VUZP_I:%.*]] = shufflevector <16 x i8> %a, <16 x i8> %b, <16 x i32> @@ -20744,7 +20744,7 @@ poly8x16x2_t test_vuzpq_p8(poly8x16_t a, poly8x16_t b) { return vuzpq_p8(a, b); } -// CHECK: @test_vuzpq_p16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vuzpq_p16({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.poly16x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <8 x i16> %b to <16 x i8> @@ -20759,7 +20759,7 @@ poly16x8x2_t test_vuzpq_p16(poly16x8_t a, poly16x8_t b) { return vuzpq_p16(a, b); } -// CHECK: @test_vzip_s8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzip_s8({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int8x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <8 x i8>* // CHECK: [[VZIP_I:%.*]] = shufflevector <8 x i8> %a, <8 x i8> %b, <8 x i32> @@ -20772,7 +20772,7 @@ int8x8x2_t test_vzip_s8(int8x8_t a, int8x8_t b) { return vzip_s8(a, b); } -// CHECK: @test_vzip_s16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzip_s16({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int16x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x i16> %b to <8 x i8> @@ -20787,7 +20787,7 @@ int16x4x2_t test_vzip_s16(int16x4_t a, int16x4_t b) { return vzip_s16(a, b); } -// CHECK: @test_vzip_s32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzip_s32({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int32x2x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <2 x i32> %b to <8 x i8> @@ -20802,7 +20802,7 @@ int32x2x2_t test_vzip_s32(int32x2_t a, int32x2_t b) { return vzip_s32(a, b); } -// CHECK: @test_vzip_u8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzip_u8({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint8x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <8 x i8>* // CHECK: [[VZIP_I:%.*]] = shufflevector <8 x i8> %a, <8 x i8> %b, <8 x i32> @@ -20815,7 +20815,7 @@ uint8x8x2_t test_vzip_u8(uint8x8_t a, uint8x8_t b) { return vzip_u8(a, b); } -// CHECK: @test_vzip_u16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzip_u16({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint16x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x i16> %b to <8 x i8> @@ -20830,7 +20830,7 @@ uint16x4x2_t test_vzip_u16(uint16x4_t a, uint16x4_t b) { return vzip_u16(a, b); } -// CHECK: @test_vzip_u32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzip_u32({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint32x2x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <2 x i32> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <2 x i32> %b to <8 x i8> @@ -20845,7 +20845,7 @@ uint32x2x2_t test_vzip_u32(uint32x2_t a, uint32x2_t b) { return vzip_u32(a, b); } -// CHECK: @test_vzip_f32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzip_f32({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.float32x2x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <2 x float> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <2 x float> %b to <8 x i8> @@ -20860,7 +20860,7 @@ float32x2x2_t test_vzip_f32(float32x2_t a, float32x2_t b) { return vzip_f32(a, b); } -// CHECK: @test_vzip_p8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzip_p8({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.poly8x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <8 x i8>* // CHECK: [[VZIP_I:%.*]] = shufflevector <8 x i8> %a, <8 x i8> %b, <8 x i32> @@ -20873,7 +20873,7 @@ poly8x8x2_t test_vzip_p8(poly8x8_t a, poly8x8_t b) { return vzip_p8(a, b); } -// CHECK: @test_vzip_p16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzip_p16({{.*}} sret align 8 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.poly16x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x i16> %a to <8 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x i16> %b to <8 x i8> @@ -20888,7 +20888,7 @@ poly16x4x2_t test_vzip_p16(poly16x4_t a, poly16x4_t b) { return vzip_p16(a, b); } -// CHECK: @test_vzipq_s8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzipq_s8({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int8x16x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <16 x i8>* // CHECK: [[VZIP_I:%.*]] = shufflevector <16 x i8> %a, <16 x i8> %b, <16 x i32> @@ -20901,7 +20901,7 @@ int8x16x2_t test_vzipq_s8(int8x16_t a, int8x16_t b) { return vzipq_s8(a, b); } -// CHECK: @test_vzipq_s16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzipq_s16({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int16x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <8 x i16> %b to <16 x i8> @@ -20916,7 +20916,7 @@ int16x8x2_t test_vzipq_s16(int16x8_t a, int16x8_t b) { return vzipq_s16(a, b); } -// CHECK: @test_vzipq_s32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzipq_s32({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.int32x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x i32> %b to <16 x i8> @@ -20931,7 +20931,7 @@ int32x4x2_t test_vzipq_s32(int32x4_t a, int32x4_t b) { return vzipq_s32(a, b); } -// CHECK: @test_vzipq_u8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzipq_u8({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint8x16x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <16 x i8>* // CHECK: [[VZIP_I:%.*]] = shufflevector <16 x i8> %a, <16 x i8> %b, <16 x i32> @@ -20944,7 +20944,7 @@ uint8x16x2_t test_vzipq_u8(uint8x16_t a, uint8x16_t b) { return vzipq_u8(a, b); } -// CHECK: @test_vzipq_u16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzipq_u16({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint16x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <8 x i16> %b to <16 x i8> @@ -20959,7 +20959,7 @@ uint16x8x2_t test_vzipq_u16(uint16x8_t a, uint16x8_t b) { return vzipq_u16(a, b); } -// CHECK: @test_vzipq_u32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzipq_u32({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.uint32x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x i32> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x i32> %b to <16 x i8> @@ -20974,7 +20974,7 @@ uint32x4x2_t test_vzipq_u32(uint32x4_t a, uint32x4_t b) { return vzipq_u32(a, b); } -// CHECK: @test_vzipq_f32({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzipq_f32({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.float32x4x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x float> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <4 x float> %b to <16 x i8> @@ -20989,7 +20989,7 @@ float32x4x2_t test_vzipq_f32(float32x4_t a, float32x4_t b) { return vzipq_f32(a, b); } -// CHECK: @test_vzipq_p8({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzipq_p8({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.poly8x16x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <16 x i8>* // CHECK: [[VZIP_I:%.*]] = shufflevector <16 x i8> %a, <16 x i8> %b, <16 x i32> @@ -21002,7 +21002,7 @@ poly8x16x2_t test_vzipq_p8(poly8x16_t a, poly8x16_t b) { return vzipq_p8(a, b); } -// CHECK: @test_vzipq_p16({{.*}} sret [[AGG_RESULT:%[0-9a-zA-Z.]+]], +// CHECK: @test_vzipq_p16({{.*}} sret align 16 [[AGG_RESULT:%[0-9a-zA-Z.]+]], // CHECK: [[TMP0:%.*]] = bitcast %struct.poly16x8x2_t* [[AGG_RESULT]] to i8* // CHECK: [[TMP1:%.*]] = bitcast <8 x i16> %a to <16 x i8> // CHECK: [[TMP2:%.*]] = bitcast <8 x i16> %b to <16 x i8> diff --git a/clang/test/CodeGen/blocks.c b/clang/test/CodeGen/blocks.c index fd348c98f65fe..3f1f2502652cd 100644 --- a/clang/test/CodeGen/blocks.c +++ b/clang/test/CodeGen/blocks.c @@ -18,7 +18,7 @@ struct s0 { int a[64]; }; -// CHECK: define internal void @__f2_block_invoke(%struct.s0* noalias sret {{%.*}}, i8* {{%.*}}, %struct.s0* byval(%struct.s0) align 4 {{.*}}) +// CHECK: define internal void @__f2_block_invoke(%struct.s0* noalias sret align 4 {{%.*}}, i8* {{%.*}}, %struct.s0* byval(%struct.s0) align 4 {{.*}}) struct s0 f2(struct s0 a0) { return ^(struct s0 a1){ return a1; }(a0); } diff --git a/clang/test/CodeGen/c11atomics-ios.c b/clang/test/CodeGen/c11atomics-ios.c index f48e10e4aa430..92d318dac1c35 100644 --- a/clang/test/CodeGen/c11atomics-ios.c +++ b/clang/test/CodeGen/c11atomics-ios.c @@ -203,7 +203,7 @@ void testPromotedStruct(_Atomic(PS) *fp) { } PS test_promoted_load(_Atomic(PS) *addr) { - // CHECK-LABEL: @test_promoted_load(%struct.PS* noalias sret %agg.result, { %struct.PS, [2 x i8] }* %addr) + // CHECK-LABEL: @test_promoted_load(%struct.PS* noalias sret align 2 %agg.result, { %struct.PS, [2 x i8] }* %addr) // CHECK: [[ADDR_ARG:%.*]] = alloca { %struct.PS, [2 x i8] }*, align 4 // CHECK: [[ATOMIC_RES:%.*]] = alloca { %struct.PS, [2 x i8] }, align 8 // CHECK: store { %struct.PS, [2 x i8] }* %addr, { %struct.PS, [2 x i8] }** [[ADDR_ARG]], align 4 @@ -245,7 +245,7 @@ void test_promoted_store(_Atomic(PS) *addr, PS *val) { } PS test_promoted_exchange(_Atomic(PS) *addr, PS *val) { - // CHECK-LABEL: @test_promoted_exchange(%struct.PS* noalias sret %agg.result, { %struct.PS, [2 x i8] }* %addr, %struct.PS* %val) + // CHECK-LABEL: @test_promoted_exchange(%struct.PS* noalias sret align 2 %agg.result, { %struct.PS, [2 x i8] }* %addr, %struct.PS* %val) // CHECK: [[ADDR_ARG:%.*]] = alloca { %struct.PS, [2 x i8] }*, align 4 // CHECK: [[VAL_ARG:%.*]] = alloca %struct.PS*, align 4 // CHECK: [[NONATOMIC_TMP:%.*]] = alloca %struct.PS, align 2 diff --git a/clang/test/CodeGen/c11atomics.c b/clang/test/CodeGen/c11atomics.c index cf251738be55e..cb97c67e485f8 100644 --- a/clang/test/CodeGen/c11atomics.c +++ b/clang/test/CodeGen/c11atomics.c @@ -368,7 +368,7 @@ void testPromotedStruct(_Atomic(PS) *fp) { } PS test_promoted_load(_Atomic(PS) *addr) { - // CHECK-LABEL: @test_promoted_load(%struct.PS* noalias sret %agg.result, { %struct.PS, [2 x i8] }* %addr) + // CHECK-LABEL: @test_promoted_load(%struct.PS* noalias sret align 2 %agg.result, { %struct.PS, [2 x i8] }* %addr) // CHECK: [[ADDR_ARG:%.*]] = alloca { %struct.PS, [2 x i8] }*, align 4 // CHECK: [[ATOMIC_RES:%.*]] = alloca { %struct.PS, [2 x i8] }, align 8 // CHECK: store { %struct.PS, [2 x i8] }* %addr, { %struct.PS, [2 x i8] }** [[ADDR_ARG]], align 4 @@ -411,7 +411,7 @@ void test_promoted_store(_Atomic(PS) *addr, PS *val) { } PS test_promoted_exchange(_Atomic(PS) *addr, PS *val) { - // CHECK-LABEL: @test_promoted_exchange(%struct.PS* noalias sret %agg.result, { %struct.PS, [2 x i8] }* %addr, %struct.PS* %val) + // CHECK-LABEL: @test_promoted_exchange(%struct.PS* noalias sret align 2 %agg.result, { %struct.PS, [2 x i8] }* %addr, %struct.PS* %val) // CHECK: [[ADDR_ARG:%.*]] = alloca { %struct.PS, [2 x i8] }*, align 4 // CHECK: [[VAL_ARG:%.*]] = alloca %struct.PS*, align 4 // CHECK: [[NONATOMIC_TMP:%.*]] = alloca %struct.PS, align 2 diff --git a/clang/test/CodeGen/lanai-arguments.c b/clang/test/CodeGen/lanai-arguments.c index 9ce4ed98a78ce..ef06b3221bc52 100644 --- a/clang/test/CodeGen/lanai-arguments.c +++ b/clang/test/CodeGen/lanai-arguments.c @@ -16,7 +16,7 @@ void f1(s1 i) {} typedef struct { int cc; } s2; -// CHECK: define void @f2(%struct.s2* noalias sret %agg.result) +// CHECK: define void @f2(%struct.s2* noalias sret align 4 %agg.result) s2 f2() { s2 foo; return foo; @@ -26,7 +26,7 @@ typedef struct { int cc; int dd; } s3; -// CHECK: define void @f3(%struct.s3* noalias sret %agg.result) +// CHECK: define void @f3(%struct.s3* noalias sret align 4 %agg.result) s3 f3() { s3 foo; return foo; diff --git a/clang/test/CodeGen/le32-arguments.c b/clang/test/CodeGen/le32-arguments.c index 9e6908d7fc41c..ad368e1a3941a 100644 --- a/clang/test/CodeGen/le32-arguments.c +++ b/clang/test/CodeGen/le32-arguments.c @@ -17,7 +17,7 @@ typedef struct { int cc; } s2; // Structs should be returned sret and not simplified by the frontend -// CHECK-LABEL: define void @f2(%struct.s2* noalias sret %agg.result) +// CHECK-LABEL: define void @f2(%struct.s2* noalias sret align 4 %agg.result) s2 f2() { s2 foo; return foo; diff --git a/clang/test/CodeGen/mcu-struct-return.c b/clang/test/CodeGen/mcu-struct-return.c index 353c963dadb01..93325254bc8db 100644 --- a/clang/test/CodeGen/mcu-struct-return.c +++ b/clang/test/CodeGen/mcu-struct-return.c @@ -42,7 +42,7 @@ struct S1 bar1() { return s1; } struct S2 bar2() { return s2; } struct S1 bar3(union U1 u) { return s1; } // CHECK: define void @foo1() -// CHECK: define void @foo2([[UNION2_TYPE]]* noalias sret %{{.+}}) +// CHECK: define void @foo2([[UNION2_TYPE]]* noalias sret align 4 %{{.+}}) // CHECK: define i32 @foo3() // CHECK: define void @bar1() // CHECK: define i32 @bar2() @@ -62,7 +62,7 @@ void run() { // CHECK: [[Y1:%.+]] = alloca [[STRUCT1_TYPE]] // CHECK: [[Y2:%.+]] = alloca [[STRUCT2_TYPE]] // CHECK: call void @foo1() - // CHECK: call void @foo2([[UNION2_TYPE]]* sret [[X2]]) + // CHECK: call void @foo2([[UNION2_TYPE]]* sret align 4 [[X2]]) // CHECK: {{.+}} = call i32 @foo3() // CHECK: call void @bar1() // CHECK: {{.+}} = call i32 @bar2() diff --git a/clang/test/CodeGen/mingw-long-double.c b/clang/test/CodeGen/mingw-long-double.c index 57e4adaa5fabe..08e3ac754d6b3 100644 --- a/clang/test/CodeGen/mingw-long-double.c +++ b/clang/test/CodeGen/mingw-long-double.c @@ -32,15 +32,15 @@ long double TestLD(long double x) { return x * x; } // GNU32: define dso_local x86_fp80 @TestLD(x86_fp80 %x) -// GNU64: define dso_local void @TestLD(x86_fp80* noalias sret %agg.result, x86_fp80* %0) +// GNU64: define dso_local void @TestLD(x86_fp80* noalias sret align 16 %agg.result, x86_fp80* %0) // MSC64: define dso_local double @TestLD(double %x) long double _Complex TestLDC(long double _Complex x) { return x * x; } -// GNU32: define dso_local void @TestLDC({ x86_fp80, x86_fp80 }* noalias sret %agg.result, { x86_fp80, x86_fp80 }* byval({ x86_fp80, x86_fp80 }) align 4 %x) -// GNU64: define dso_local void @TestLDC({ x86_fp80, x86_fp80 }* noalias sret %agg.result, { x86_fp80, x86_fp80 }* %x) -// MSC64: define dso_local void @TestLDC({ double, double }* noalias sret %agg.result, { double, double }* %x) +// GNU32: define dso_local void @TestLDC({ x86_fp80, x86_fp80 }* noalias sret align 4 %agg.result, { x86_fp80, x86_fp80 }* byval({ x86_fp80, x86_fp80 }) align 4 %x) +// GNU64: define dso_local void @TestLDC({ x86_fp80, x86_fp80 }* noalias sret align 16 %agg.result, { x86_fp80, x86_fp80 }* %x) +// MSC64: define dso_local void @TestLDC({ double, double }* noalias sret align 8 %agg.result, { double, double }* %x) // GNU32: declare dso_local void @__mulxc3 // GNU64: declare dso_local void @__mulxc3 diff --git a/clang/test/CodeGen/mips-zero-sized-struct.c b/clang/test/CodeGen/mips-zero-sized-struct.c index 08ebf9df3e93b..5f0e660cf395b 100644 --- a/clang/test/CodeGen/mips-zero-sized-struct.c +++ b/clang/test/CodeGen/mips-zero-sized-struct.c @@ -19,7 +19,7 @@ // RUN: %clang_cc1 -triple mipsisa64r6-unknown-linux-gnuabi64 -S -emit-llvm -o - %s | FileCheck -check-prefix=N64 %s // RUN: %clang_cc1 -triple mipsisa64r6el-unknown-linux-gnuabi64 -S -emit-llvm -o - %s | FileCheck -check-prefix=N64 %s -// O32: define void @fn28(%struct.T2* noalias sret %agg.result, i8 signext %arg0) +// O32: define void @fn28(%struct.T2* noalias sret align 1 %agg.result, i8 signext %arg0) // N32: define void @fn28(i8 signext %arg0) // N64: define void @fn28(i8 signext %arg0) diff --git a/clang/test/CodeGen/mips64-padding-arg.c b/clang/test/CodeGen/mips64-padding-arg.c index a7c8f0ff6fdc0..d440743fd7238 100644 --- a/clang/test/CodeGen/mips64-padding-arg.c +++ b/clang/test/CodeGen/mips64-padding-arg.c @@ -33,9 +33,9 @@ void foo3(int a0, long double a1) { // Insert padding after hidden argument. // -// N64-LABEL: define void @foo5(%struct.S0* noalias sret %agg.result, i64 %0, fp128 %a0) -// N64: call void @foo6(%struct.S0* sret %agg.result, i32 signext 1, i32 signext 2, i64 undef, fp128 %a0) -// N64: declare void @foo6(%struct.S0* sret, i32 signext, i32 signext, i64, fp128) +// N64-LABEL: define void @foo5(%struct.S0* noalias sret align 16 %agg.result, i64 %0, fp128 %a0) +// N64: call void @foo6(%struct.S0* sret align 16 %agg.result, i32 signext 1, i32 signext 2, i64 undef, fp128 %a0) +// N64: declare void @foo6(%struct.S0* sret align 16, i32 signext, i32 signext, i64, fp128) extern S0 foo6(int, int, long double); diff --git a/clang/test/CodeGen/ms_abi.c b/clang/test/CodeGen/ms_abi.c index 75e1caf922df9..8c66c5dc43610 100644 --- a/clang/test/CodeGen/ms_abi.c +++ b/clang/test/CodeGen/ms_abi.c @@ -155,7 +155,7 @@ struct i128 { }; __attribute__((ms_abi)) struct i128 f7(struct i128 a) { - // WIN64: define dso_local void @f7(%struct.i128* noalias sret %agg.result, %struct.i128* %a) - // FREEBSD: define win64cc void @f7(%struct.i128* noalias sret %agg.result, %struct.i128* %a) + // WIN64: define dso_local void @f7(%struct.i128* noalias sret align 8 %agg.result, %struct.i128* %a) + // FREEBSD: define win64cc void @f7(%struct.i128* noalias sret align 8 %agg.result, %struct.i128* %a) return a; } diff --git a/clang/test/CodeGen/ppc64-align-struct.c b/clang/test/CodeGen/ppc64-align-struct.c index bcff4920d0c49..3435a6e429396 100644 --- a/clang/test/CodeGen/ppc64-align-struct.c +++ b/clang/test/CodeGen/ppc64-align-struct.c @@ -48,7 +48,7 @@ void test7 (int x, struct test7 y) { } -// CHECK: define void @test1va(%struct.test1* noalias sret %[[AGG_RESULT:.*]], i32 signext %x, ...) +// CHECK: define void @test1va(%struct.test1* noalias sret align 4 %[[AGG_RESULT:.*]], i32 signext %x, ...) // CHECK: %[[CUR:[^ ]+]] = load i8*, i8** %ap // CHECK: %[[NEXT:[^ ]+]] = getelementptr inbounds i8, i8* %[[CUR]], i64 8 // CHECK: store i8* %[[NEXT]], i8** %ap @@ -66,7 +66,7 @@ struct test1 test1va (int x, ...) return y; } -// CHECK: define void @test2va(%struct.test2* noalias sret %[[AGG_RESULT:.*]], i32 signext %x, ...) +// CHECK: define void @test2va(%struct.test2* noalias sret align 16 %[[AGG_RESULT:.*]], i32 signext %x, ...) // CHECK: %[[CUR:[^ ]+]] = load i8*, i8** %ap // CHECK: %[[TMP0:[^ ]+]] = ptrtoint i8* %[[CUR]] to i64 // CHECK: %[[TMP1:[^ ]+]] = add i64 %[[TMP0]], 15 @@ -88,7 +88,7 @@ struct test2 test2va (int x, ...) return y; } -// CHECK: define void @test3va(%struct.test3* noalias sret %[[AGG_RESULT:.*]], i32 signext %x, ...) +// CHECK: define void @test3va(%struct.test3* noalias sret align 32 %[[AGG_RESULT:.*]], i32 signext %x, ...) // CHECK: %[[CUR:[^ ]+]] = load i8*, i8** %ap // CHECK: %[[TMP0:[^ ]+]] = ptrtoint i8* %[[CUR]] to i64 // CHECK: %[[TMP1:[^ ]+]] = add i64 %[[TMP0]], 15 @@ -110,7 +110,7 @@ struct test3 test3va (int x, ...) return y; } -// CHECK: define void @test4va(%struct.test4* noalias sret %[[AGG_RESULT:.*]], i32 signext %x, ...) +// CHECK: define void @test4va(%struct.test4* noalias sret align 4 %[[AGG_RESULT:.*]], i32 signext %x, ...) // CHECK: %[[CUR:[^ ]+]] = load i8*, i8** %ap // CHECK: %[[NEXT:[^ ]+]] = getelementptr inbounds i8, i8* %[[CUR]], i64 16 // CHECK: store i8* %[[NEXT]], i8** %ap @@ -128,7 +128,7 @@ struct test4 test4va (int x, ...) return y; } -// CHECK: define void @testva_longdouble(%struct.test_longdouble* noalias sret %[[AGG_RESULT:.*]], i32 signext %x, ...) +// CHECK: define void @testva_longdouble(%struct.test_longdouble* noalias sret align 16 %[[AGG_RESULT:.*]], i32 signext %x, ...) // CHECK: %[[CUR:[^ ]+]] = load i8*, i8** %ap // CHECK: %[[NEXT:[^ ]+]] = getelementptr inbounds i8, i8* %[[CUR]], i64 16 // CHECK: store i8* %[[NEXT]], i8** %ap @@ -147,7 +147,7 @@ struct test_longdouble testva_longdouble (int x, ...) return y; } -// CHECK: define void @testva_vector(%struct.test_vector* noalias sret %[[AGG_RESULT:.*]], i32 signext %x, ...) +// CHECK: define void @testva_vector(%struct.test_vector* noalias sret align 16 %[[AGG_RESULT:.*]], i32 signext %x, ...) // CHECK: %[[CUR:[^ ]+]] = load i8*, i8** %ap // CHECK: %[[TMP0:[^ ]+]] = ptrtoint i8* %[[CUR]] to i64 // CHECK: %[[TMP1:[^ ]+]] = add i64 %[[TMP0]], 15 diff --git a/clang/test/CodeGen/ppc64-elf-abi.c b/clang/test/CodeGen/ppc64-elf-abi.c index 59112a0baf4a7..4270ba2c799b8 100644 --- a/clang/test/CodeGen/ppc64-elf-abi.c +++ b/clang/test/CodeGen/ppc64-elf-abi.c @@ -17,7 +17,7 @@ // RUN: %clang_cc1 -triple powerpc64le-unknown-linux-gnu -emit-llvm -o - %s \ // RUN: -target-abi elfv2 | FileCheck %s --check-prefix=CHECK-ELFv2 -// CHECK-ELFv1: define void @func_fab(%struct.fab* noalias sret %agg.result, i64 %x.coerce) +// CHECK-ELFv1: define void @func_fab(%struct.fab* noalias sret align 4 %agg.result, i64 %x.coerce) // CHECK-ELFv2: define [2 x float] @func_fab([2 x float] %x.coerce) struct fab { float a; float b; }; struct fab func_fab(struct fab x) { return x; } diff --git a/clang/test/CodeGen/ppc64-qpx-vector.c b/clang/test/CodeGen/ppc64-qpx-vector.c index e7c009328b232..0e55851b9f33e 100644 --- a/clang/test/CodeGen/ppc64-qpx-vector.c +++ b/clang/test/CodeGen/ppc64-qpx-vector.c @@ -24,6 +24,6 @@ v4df foo2(struct sdf a, v4df b, struct sdf2 c) { // QPX-LABEL: define <4 x double> @foo2(<4 x double> inreg %a.coerce, <4 x double> %b, [2 x i256] %c.coerce) // QPX: ret <4 x double> -// NORMAL-LABEL: define void @foo2(<4 x double>* noalias sret %agg.result, [2 x i128] %a.coerce, <4 x double>* %0, [4 x i128] %c.coerce) +// NORMAL-LABEL: define void @foo2(<4 x double>* noalias sret align 32 %agg.result, [2 x i128] %a.coerce, <4 x double>* %0, [4 x i128] %c.coerce) // NORMAL: ret void diff --git a/clang/test/CodeGen/ppc64-soft-float.c b/clang/test/CodeGen/ppc64-soft-float.c index 84ac2d55b636f..b033dea68fe20 100644 --- a/clang/test/CodeGen/ppc64-soft-float.c +++ b/clang/test/CodeGen/ppc64-soft-float.c @@ -30,53 +30,53 @@ struct fabc { float a; float b; float c; }; struct f2a2b { float a[2]; float b[2]; }; // CHECK-LE: define i32 @func_f1(float inreg %x.coerce) -// CHECK-BE: define void @func_f1(%struct.f1* noalias sret %agg.result, float inreg %x.coerce) +// CHECK-BE: define void @func_f1(%struct.f1* noalias sret align 4 %agg.result, float inreg %x.coerce) struct f1 func_f1(struct f1 x) { return x; } // CHECK-LE: define i64 @func_f2(i64 %x.coerce) -// CHECK-BE: define void @func_f2(%struct.f2* noalias sret %agg.result, i64 %x.coerce) +// CHECK-BE: define void @func_f2(%struct.f2* noalias sret align 4 %agg.result, i64 %x.coerce) struct f2 func_f2(struct f2 x) { return x; } // CHECK-LE: define { i64, i64 } @func_f3([2 x i64] %x.coerce) -// CHECK-BE: define void @func_f3(%struct.f3* noalias sret %agg.result, [2 x i64] %x.coerce) +// CHECK-BE: define void @func_f3(%struct.f3* noalias sret align 4 %agg.result, [2 x i64] %x.coerce) struct f3 func_f3(struct f3 x) { return x; } // CHECK-LE: define { i64, i64 } @func_f4([2 x i64] %x.coerce) -// CHECK-BE: define void @func_f4(%struct.f4* noalias sret %agg.result, [2 x i64] %x.coerce) +// CHECK-BE: define void @func_f4(%struct.f4* noalias sret align 4 %agg.result, [2 x i64] %x.coerce) struct f4 func_f4(struct f4 x) { return x; } -// CHECK: define void @func_f5(%struct.f5* noalias sret %agg.result, [3 x i64] %x.coerce) +// CHECK: define void @func_f5(%struct.f5* noalias sret align 4 %agg.result, [3 x i64] %x.coerce) struct f5 func_f5(struct f5 x) { return x; } -// CHECK: define void @func_f6(%struct.f6* noalias sret %agg.result, [3 x i64] %x.coerce) +// CHECK: define void @func_f6(%struct.f6* noalias sret align 4 %agg.result, [3 x i64] %x.coerce) struct f6 func_f6(struct f6 x) { return x; } -// CHECK: define void @func_f7(%struct.f7* noalias sret %agg.result, [4 x i64] %x.coerce) +// CHECK: define void @func_f7(%struct.f7* noalias sret align 4 %agg.result, [4 x i64] %x.coerce) struct f7 func_f7(struct f7 x) { return x; } -// CHECK: define void @func_f8(%struct.f8* noalias sret %agg.result, [4 x i64] %x.coerce) +// CHECK: define void @func_f8(%struct.f8* noalias sret align 4 %agg.result, [4 x i64] %x.coerce) struct f8 func_f8(struct f8 x) { return x; } -// CHECK: define void @func_f9(%struct.f9* noalias sret %agg.result, [5 x i64] %x.coerce) +// CHECK: define void @func_f9(%struct.f9* noalias sret align 4 %agg.result, [5 x i64] %x.coerce) struct f9 func_f9(struct f9 x) { return x; } // CHECK-LE: define i64 @func_fab(i64 %x.coerce) -// CHECK-BE: define void @func_fab(%struct.fab* noalias sret %agg.result, i64 %x.coerce) +// CHECK-BE: define void @func_fab(%struct.fab* noalias sret align 4 %agg.result, i64 %x.coerce) struct fab func_fab(struct fab x) { return x; } // CHECK-LE: define { i64, i64 } @func_fabc([2 x i64] %x.coerce) -// CHECK-BE: define void @func_fabc(%struct.fabc* noalias sret %agg.result, [2 x i64] %x.coerce) +// CHECK-BE: define void @func_fabc(%struct.fabc* noalias sret align 4 %agg.result, [2 x i64] %x.coerce) struct fabc func_fabc(struct fabc x) { return x; } // CHECK-LE: define { i64, i64 } @func_f2a2b([2 x i64] %x.coerce) -// CHECK-BE: define void @func_f2a2b(%struct.f2a2b* noalias sret %agg.result, [2 x i64] %x.coerce) +// CHECK-BE: define void @func_f2a2b(%struct.f2a2b* noalias sret align 4 %agg.result, [2 x i64] %x.coerce) struct f2a2b func_f2a2b(struct f2a2b x) { return x; } // CHECK-LABEL: @call_f1 // CHECK-BE: %[[TMP0:[^ ]+]] = alloca %struct.f1, align 4 // CHECK: %[[TMP:[^ ]+]] = load float, float* getelementptr inbounds (%struct.f1, %struct.f1* @global_f1, i32 0, i32 0, i32 0), align 4 // CHECK-LE: call i32 @func_f1(float inreg %[[TMP]]) -// CHECK-BE: call void @func_f1(%struct.f1* sret %[[TMP0]], float inreg %[[TMP]]) +// CHECK-BE: call void @func_f1(%struct.f1* sret align 4 %[[TMP0]], float inreg %[[TMP]]) struct f1 global_f1; void call_f1(void) { global_f1 = func_f1(global_f1); } @@ -84,7 +84,7 @@ void call_f1(void) { global_f1 = func_f1(global_f1); } // CHECK-BE: %[[TMP0:[^ ]+]] = alloca %struct.f2, align 4 // CHECK: %[[TMP:[^ ]+]] = load i64, i64* bitcast (%struct.f2* @global_f2 to i64*), align 4 // CHECK-LE: call i64 @func_f2(i64 %[[TMP]]) -// CHECK-BE: call void @func_f2(%struct.f2* sret %[[TMP0]], i64 %[[TMP]]) +// CHECK-BE: call void @func_f2(%struct.f2* sret align 4 %[[TMP0]], i64 %[[TMP]]) struct f2 global_f2; void call_f2(void) { global_f2 = func_f2(global_f2); } @@ -95,7 +95,7 @@ void call_f2(void) { global_f2 = func_f2(global_f2); } // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %[[TMP2]], i8* align 4 bitcast (%struct.f3* @global_f3 to i8*), i64 12, i1 false) // CHECK: %[[TMP3:[^ ]+]] = load [2 x i64], [2 x i64]* %[[TMP1]] // CHECK-LE: call { i64, i64 } @func_f3([2 x i64] %[[TMP3]]) -// CHECK-BE: call void @func_f3(%struct.f3* sret %[[TMP0]], [2 x i64] %[[TMP3]]) +// CHECK-BE: call void @func_f3(%struct.f3* sret align 4 %[[TMP0]], [2 x i64] %[[TMP3]]) struct f3 global_f3; void call_f3(void) { global_f3 = func_f3(global_f3); } @@ -103,7 +103,7 @@ void call_f3(void) { global_f3 = func_f3(global_f3); } // CHECK-BE: %[[TMP0:[^ ]+]] = alloca %struct.f4, align 4 // CHECK: %[[TMP:[^ ]+]] = load [2 x i64], [2 x i64]* bitcast (%struct.f4* @global_f4 to [2 x i64]*), align 4 // CHECK-LE: call { i64, i64 } @func_f4([2 x i64] %[[TMP]]) -// CHECK-BE: call void @func_f4(%struct.f4* sret %[[TMP0]], [2 x i64] %[[TMP]]) +// CHECK-BE: call void @func_f4(%struct.f4* sret align 4 %[[TMP0]], [2 x i64] %[[TMP]]) struct f4 global_f4; void call_f4(void) { global_f4 = func_f4(global_f4); } @@ -113,14 +113,14 @@ void call_f4(void) { global_f4 = func_f4(global_f4); } // CHECK: %[[TMP2:[^ ]+]] = bitcast [3 x i64]* %[[TMP1]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %[[TMP2]], i8* align 4 bitcast (%struct.f5* @global_f5 to i8*), i64 20, i1 false) // CHECK: %[[TMP3:[^ ]+]] = load [3 x i64], [3 x i64]* %[[TMP1]] -// CHECK: call void @func_f5(%struct.f5* sret %[[TMP0]], [3 x i64] %[[TMP3]]) +// CHECK: call void @func_f5(%struct.f5* sret align 4 %[[TMP0]], [3 x i64] %[[TMP3]]) struct f5 global_f5; void call_f5(void) { global_f5 = func_f5(global_f5); } // CHECK-LABEL: @call_f6 // CHECK: %[[TMP0:[^ ]+]] = alloca %struct.f6, align 4 // CHECK: %[[TMP:[^ ]+]] = load [3 x i64], [3 x i64]* bitcast (%struct.f6* @global_f6 to [3 x i64]*), align 4 -// CHECK: call void @func_f6(%struct.f6* sret %[[TMP0]], [3 x i64] %[[TMP]]) +// CHECK: call void @func_f6(%struct.f6* sret align 4 %[[TMP0]], [3 x i64] %[[TMP]]) struct f6 global_f6; void call_f6(void) { global_f6 = func_f6(global_f6); } @@ -130,14 +130,14 @@ void call_f6(void) { global_f6 = func_f6(global_f6); } // CHECK: %[[TMP2:[^ ]+]] = bitcast [4 x i64]* %[[TMP1]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %[[TMP2]], i8* align 4 bitcast (%struct.f7* @global_f7 to i8*), i64 28, i1 false) // CHECK: %[[TMP3:[^ ]+]] = load [4 x i64], [4 x i64]* %[[TMP1]], align 8 -// CHECK: call void @func_f7(%struct.f7* sret %[[TMP0]], [4 x i64] %[[TMP3]]) +// CHECK: call void @func_f7(%struct.f7* sret align 4 %[[TMP0]], [4 x i64] %[[TMP3]]) struct f7 global_f7; void call_f7(void) { global_f7 = func_f7(global_f7); } // CHECK-LABEL: @call_f8 // CHECK: %[[TMP0:[^ ]+]] = alloca %struct.f8, align 4 // CHECK: %[[TMP:[^ ]+]] = load [4 x i64], [4 x i64]* bitcast (%struct.f8* @global_f8 to [4 x i64]*), align 4 -// CHECK: call void @func_f8(%struct.f8* sret %[[TMP0]], [4 x i64] %[[TMP]]) +// CHECK: call void @func_f8(%struct.f8* sret align 4 %[[TMP0]], [4 x i64] %[[TMP]]) struct f8 global_f8; void call_f8(void) { global_f8 = func_f8(global_f8); } @@ -146,7 +146,7 @@ void call_f8(void) { global_f8 = func_f8(global_f8); } // CHECK: %[[TMP2:[^ ]+]] = bitcast [5 x i64]* %[[TMP1]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %[[TMP2]], i8* align 4 bitcast (%struct.f9* @global_f9 to i8*), i64 36, i1 false) // CHECK: %[[TMP3:[^ ]+]] = load [5 x i64], [5 x i64]* %[[TMP1]] -// CHECK: call void @func_f9(%struct.f9* sret %{{[^ ]+}}, [5 x i64] %[[TMP3]]) +// CHECK: call void @func_f9(%struct.f9* sret align 4 %{{[^ ]+}}, [5 x i64] %[[TMP3]]) struct f9 global_f9; void call_f9(void) { global_f9 = func_f9(global_f9); } @@ -154,7 +154,7 @@ void call_f9(void) { global_f9 = func_f9(global_f9); } // CHECK: %[[TMP0:[^ ]+]] = alloca %struct.fab, align 4 // CHECK: %[[TMP:[^ ]+]] = load i64, i64* bitcast (%struct.fab* @global_fab to i64*), align 4 // CHECK-LE: %call = call i64 @func_fab(i64 %[[TMP]]) -// CHECK-BE: call void @func_fab(%struct.fab* sret %[[TMP0]], i64 %[[TMP]]) +// CHECK-BE: call void @func_fab(%struct.fab* sret align 4 %[[TMP0]], i64 %[[TMP]]) struct fab global_fab; void call_fab(void) { global_fab = func_fab(global_fab); } @@ -165,7 +165,7 @@ void call_fab(void) { global_fab = func_fab(global_fab); } // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %[[TMP2]], i8* align 4 bitcast (%struct.fabc* @global_fabc to i8*), i64 12, i1 false) // CHECK: %[[TMP3:[^ ]+]] = load [2 x i64], [2 x i64]* %[[TMP0]], align 8 // CHECK-LE: %call = call { i64, i64 } @func_fabc([2 x i64] %[[TMP3]]) -// CHECK-BE: call void @func_fabc(%struct.fabc* sret %[[TMPX]], [2 x i64] %[[TMP3]]) +// CHECK-BE: call void @func_fabc(%struct.fabc* sret align 4 %[[TMPX]], [2 x i64] %[[TMP3]]) struct fabc global_fabc; void call_fabc(void) { global_fabc = func_fabc(global_fabc); } diff --git a/clang/test/CodeGen/ppc64-vector.c b/clang/test/CodeGen/ppc64-vector.c index 7ed0beade4cd0..7ea5b007d5bfc 100644 --- a/clang/test/CodeGen/ppc64-vector.c +++ b/clang/test/CodeGen/ppc64-vector.c @@ -39,13 +39,13 @@ v8i16 test_v8i16(v8i16 x) return x; } -// CHECK: define void @test_v16i16(<16 x i16>* noalias sret %agg.result, <16 x i16>* %0) +// CHECK: define void @test_v16i16(<16 x i16>* noalias sret align 32 %agg.result, <16 x i16>* %0) v16i16 test_v16i16(v16i16 x) { return x; } -// CHECK: define void @test_struct_v16i16(%struct.v16i16* noalias sret %agg.result, [2 x i128] %x.coerce) +// CHECK: define void @test_struct_v16i16(%struct.v16i16* noalias sret align 32 %agg.result, [2 x i128] %x.coerce) struct v16i16 test_struct_v16i16(struct v16i16 x) { return x; diff --git a/clang/test/CodeGen/ppc64le-aggregates.c b/clang/test/CodeGen/ppc64le-aggregates.c index e36faa2b80258..ea32d69b7cf95 100644 --- a/clang/test/CodeGen/ppc64le-aggregates.c +++ b/clang/test/CodeGen/ppc64le-aggregates.c @@ -41,7 +41,7 @@ struct f7 func_f7(struct f7 x) { return x; } // CHECK: define [8 x float] @func_f8([8 x float] %x.coerce) struct f8 func_f8(struct f8 x) { return x; } -// CHECK: define void @func_f9(%struct.f9* noalias sret %agg.result, [5 x i64] %x.coerce) +// CHECK: define void @func_f9(%struct.f9* noalias sret align 4 %agg.result, [5 x i64] %x.coerce) struct f9 func_f9(struct f9 x) { return x; } // CHECK: define [2 x float] @func_fab([2 x float] %x.coerce) @@ -106,7 +106,7 @@ void call_f8(void) { global_f8 = func_f8(global_f8); } // CHECK: %[[TMP2:[^ ]+]] = bitcast [5 x i64]* %[[TMP1]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %[[TMP2]], i8* align 4 bitcast (%struct.f9* @global_f9 to i8*), i64 36, i1 false) // CHECK: %[[TMP3:[^ ]+]] = load [5 x i64], [5 x i64]* %[[TMP1]] -// CHECK: call void @func_f9(%struct.f9* sret %{{[^ ]+}}, [5 x i64] %[[TMP3]]) +// CHECK: call void @func_f9(%struct.f9* sret align 4 %{{[^ ]+}}, [5 x i64] %[[TMP3]]) struct f9 global_f9; void call_f9(void) { global_f9 = func_f9(global_f9); } @@ -162,7 +162,7 @@ struct v7 func_v7(struct v7 x) { return x; } // CHECK: define [8 x <4 x i32>] @func_v8([8 x <4 x i32>] %x.coerce) struct v8 func_v8(struct v8 x) { return x; } -// CHECK: define void @func_v9(%struct.v9* noalias sret %agg.result, %struct.v9* byval(%struct.v9) align 16 %x) +// CHECK: define void @func_v9(%struct.v9* noalias sret align 16 %agg.result, %struct.v9* byval(%struct.v9) align 16 %x) struct v9 func_v9(struct v9 x) { return x; } // CHECK: define [2 x <4 x i32>] @func_vab([2 x <4 x i32>] %x.coerce) @@ -220,7 +220,7 @@ struct v8 global_v8; void call_v8(void) { global_v8 = func_v8(global_v8); } // CHECK-LABEL: @call_v9 -// CHECK: call void @func_v9(%struct.v9* sret %{{[^ ]+}}, %struct.v9* byval(%struct.v9) align 16 @global_v9) +// CHECK: call void @func_v9(%struct.v9* sret align 16 %{{[^ ]+}}, %struct.v9* byval(%struct.v9) align 16 @global_v9) struct v9 global_v9; void call_v9(void) { global_v9 = func_v9(global_v9); } @@ -279,7 +279,7 @@ struct v3f7 func_v3f7(struct v3f7 x) { return x; } // CHECK: define [8 x <4 x float>] @func_v3f8([8 x <4 x float>] %x.coerce) struct v3f8 func_v3f8(struct v3f8 x) { return x; } -// CHECK: define void @func_v3f9(%struct.v3f9* noalias sret %agg.result, %struct.v3f9* byval(%struct.v3f9) align 16 %x) +// CHECK: define void @func_v3f9(%struct.v3f9* noalias sret align 16 %agg.result, %struct.v3f9* byval(%struct.v3f9) align 16 %x) struct v3f9 func_v3f9(struct v3f9 x) { return x; } // CHECK: define [2 x <4 x float>] @func_v3fab([2 x <4 x float>] %x.coerce) @@ -337,7 +337,7 @@ struct v3f8 global_v3f8; void call_v3f8(void) { global_v3f8 = func_v3f8(global_v3f8); } // CHECK-LABEL: @call_v3f9 -// CHECK: call void @func_v3f9(%struct.v3f9* sret %{{[^ ]+}}, %struct.v3f9* byval(%struct.v3f9) align 16 @global_v3f9) +// CHECK: call void @func_v3f9(%struct.v3f9* sret align 16 %{{[^ ]+}}, %struct.v3f9* byval(%struct.v3f9) align 16 @global_v3f9) struct v3f9 global_v3f9; void call_v3f9(void) { global_v3f9 = func_v3f9(global_v3f9); } diff --git a/clang/test/CodeGen/ppc64le-f128Aggregates.c b/clang/test/CodeGen/ppc64le-f128Aggregates.c index 3b363bf0f2eac..acebea69b31dc 100644 --- a/clang/test/CodeGen/ppc64le-f128Aggregates.c +++ b/clang/test/CodeGen/ppc64le-f128Aggregates.c @@ -42,7 +42,7 @@ struct fp7 func_f7(struct fp7 x) { return x; } // CHECK: define [8 x fp128] @func_f8([8 x fp128] %x.coerce) struct fp8 func_f8(struct fp8 x) { return x; } -// CHECK: define void @func_f9(%struct.fp9* noalias sret %agg.result, %struct.fp9* byval(%struct.fp9) align 16 %x) +// CHECK: define void @func_f9(%struct.fp9* noalias sret align 16 %agg.result, %struct.fp9* byval(%struct.fp9) align 16 %x) struct fp9 func_f9(struct fp9 x) { return x; } // CHECK: define [2 x fp128] @func_fab([2 x fp128] %x.coerce) @@ -104,7 +104,7 @@ void call_fp8(void) { global_f8 = func_f8(global_f8); } // CHECK-LABEL: @call_fp9 // CHECK: %[[TMP1:[^ ]+]] = alloca %struct.fp9, align 16 -// CHECK: call void @func_f9(%struct.fp9* sret %[[TMP2:[^ ]+]], %struct.fp9* byval(%struct.fp9) align 16 @global_f9 +// CHECK: call void @func_f9(%struct.fp9* sret align 16 %[[TMP2:[^ ]+]], %struct.fp9* byval(%struct.fp9) align 16 @global_f9 // CHECK: %[[TMP3:[^ ]+]] = bitcast %struct.fp9* %[[TMP2]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 bitcast (%struct.fp9* @global_f9 to i8*), i8* align 16 %[[TMP3]], i64 144, i1 false // CHECK: ret void diff --git a/clang/test/CodeGen/ptrauth-in-c-struct.c b/clang/test/CodeGen/ptrauth-in-c-struct.c index a6fd4ba2bd7c9..1b914d29b662d 100644 --- a/clang/test/CodeGen/ptrauth-in-c-struct.c +++ b/clang/test/CodeGen/ptrauth-in-c-struct.c @@ -132,7 +132,7 @@ void test_argument_SA(SA *a) { calleeSA(*a); } -// CHECK: define void @test_return_SA(%[[STRUCT_SA]]* noalias sret %[[AGG_RESULT:.*]], %[[STRUCT_SA]]* %[[A:.*]]) +// CHECK: define void @test_return_SA(%[[STRUCT_SA]]* noalias sret align 8 %[[AGG_RESULT:.*]], %[[STRUCT_SA]]* %[[A:.*]]) // CHECK: %[[A_ADDR:.*]] = alloca %[[STRUCT_SA]]*, align 8 // CHECK: store %[[STRUCT_SA]]* %[[A]], %[[STRUCT_SA]]** %[[A_ADDR]], align 8 // CHECK: %[[V0:.*]] = load %[[STRUCT_SA]]*, %[[STRUCT_SA]]** %[[A_ADDR]], align 8 diff --git a/clang/test/CodeGen/regparm-struct.c b/clang/test/CodeGen/regparm-struct.c index 7f56ae094a69c..8c74c8b1f0586 100644 --- a/clang/test/CodeGen/regparm-struct.c +++ b/clang/test/CodeGen/regparm-struct.c @@ -159,7 +159,7 @@ void g16(void) { } __attribute__((regparm(3))) struct s12 f17(int a, int b, int c); -// CHECK: declare void @f17(%struct.s12* inreg sret, i32 inreg, i32 inreg, i32) +// CHECK: declare void @f17(%struct.s12* inreg sret align 4, i32 inreg, i32 inreg, i32) void g17(void) { f17(41, 42, 43); } diff --git a/clang/test/CodeGen/renderscript.c b/clang/test/CodeGen/renderscript.c index a85dc35c61496..fee97a154344e 100644 --- a/clang/test/CodeGen/renderscript.c +++ b/clang/test/CodeGen/renderscript.c @@ -83,15 +83,15 @@ void argLongInt(sLongInt s) {} // and coerced to [a x iNN] for 64-bit RenderScript // ============================================================================= -// CHECK-RS32: void @retShortCharShort(%struct.sShortCharShort* noalias sret %agg.result) +// CHECK-RS32: void @retShortCharShort(%struct.sShortCharShort* noalias sret align 2 %agg.result) // CHECK-RS64: [3 x i16] @retShortCharShort() sShortCharShort retShortCharShort() { sShortCharShort r; return r; } -// CHECK-RS32: void @retIntShortChar(%struct.sIntShortChar* noalias sret %agg.result) +// CHECK-RS32: void @retIntShortChar(%struct.sIntShortChar* noalias sret align 4 %agg.result) // CHECK-RS64: [2 x i32] @retIntShortChar() sIntShortChar retIntShortChar() { sIntShortChar r; return r; } -// CHECK-RS32: void @retLongInt(%struct.sLongInt* noalias sret %agg.result) +// CHECK-RS32: void @retLongInt(%struct.sLongInt* noalias sret align 8 %agg.result) // CHECK-RS64: [2 x i64] @retLongInt() sLongInt retLongInt() { sLongInt r; return r; } @@ -116,12 +116,12 @@ void argLong2Char(sLong2Char s) {} // 64-bit RenderScript // ============================================================================= -// CHECK-RS32: void @retInt5(%struct.sInt5* noalias sret %agg.result) -// CHECK-RS64: void @retInt5(%struct.sInt5* noalias sret %agg.result) +// CHECK-RS32: void @retInt5(%struct.sInt5* noalias sret align 4 %agg.result) +// CHECK-RS64: void @retInt5(%struct.sInt5* noalias sret align 4 %agg.result) sInt5 retInt5() { sInt5 r; return r;} -// CHECK-RS32: void @retLong2Char(%struct.sLong2Char* noalias sret %agg.result) -// CHECK-RS64: void @retLong2Char(%struct.sLong2Char* noalias sret %agg.result) +// CHECK-RS32: void @retLong2Char(%struct.sLong2Char* noalias sret align 8 %agg.result) +// CHECK-RS64: void @retLong2Char(%struct.sLong2Char* noalias sret align 8 %agg.result) sLong2Char retLong2Char() { sLong2Char r; return r;} // ============================================================================= @@ -135,6 +135,6 @@ typedef struct {long l1, l2, l3, l4, l5, l6, l7, l8, l9; } sLong9; // CHECK-RS64: void @argLong9(%struct.sLong9* %s) void argLong9(sLong9 s) {} -// CHECK-RS32: void @retLong9(%struct.sLong9* noalias sret %agg.result) -// CHECK-RS64: void @retLong9(%struct.sLong9* noalias sret %agg.result) +// CHECK-RS32: void @retLong9(%struct.sLong9* noalias sret align 8 %agg.result) +// CHECK-RS64: void @retLong9(%struct.sLong9* noalias sret align 8 %agg.result) sLong9 retLong9() { sLong9 r; return r; } diff --git a/clang/test/CodeGen/riscv32-ilp32-abi.c b/clang/test/CodeGen/riscv32-ilp32-abi.c index 59f0bb5683726..1b32024f51582 100644 --- a/clang/test/CodeGen/riscv32-ilp32-abi.c +++ b/clang/test/CodeGen/riscv32-ilp32-abi.c @@ -35,7 +35,7 @@ int f_scalar_stack_1(int32_t a, int64_t b, float c, double d, long double e, // the presence of large return values that consume a register due to the need // to pass a pointer. -// CHECK-LABEL: define void @f_scalar_stack_2(%struct.large* noalias sret %agg.result, float %a, i64 %b, double %c, fp128 %d, i8 zeroext %e, i8 %f, i8 %g) +// CHECK-LABEL: define void @f_scalar_stack_2(%struct.large* noalias sret align 4 %agg.result, float %a, i64 %b, double %c, fp128 %d, i8 zeroext %e, i8 %f, i8 %g) struct large f_scalar_stack_2(float a, int64_t b, double c, long double d, uint8_t e, int8_t f, uint8_t g) { return (struct large){a, e, f, g}; diff --git a/clang/test/CodeGen/riscv32-ilp32-ilp32f-abi.c b/clang/test/CodeGen/riscv32-ilp32-ilp32f-abi.c index 677040626f578..225b12358a0e3 100644 --- a/clang/test/CodeGen/riscv32-ilp32-ilp32f-abi.c +++ b/clang/test/CodeGen/riscv32-ilp32-ilp32f-abi.c @@ -37,7 +37,7 @@ int f_scalar_stack_1(int32_t a, int64_t b, int32_t c, double d, long double e, // the presence of large return values that consume a register due to the need // to pass a pointer. -// CHECK-LABEL: define void @f_scalar_stack_2(%struct.large* noalias sret %agg.result, i32 %a, i64 %b, double %c, fp128 %d, i8 zeroext %e, i8 %f, i8 %g) +// CHECK-LABEL: define void @f_scalar_stack_2(%struct.large* noalias sret align 4 %agg.result, i32 %a, i64 %b, double %c, fp128 %d, i8 zeroext %e, i8 %f, i8 %g) struct large f_scalar_stack_2(int32_t a, int64_t b, double c, long double d, uint8_t e, int8_t f, uint8_t g) { return (struct large){a, e, f, g}; diff --git a/clang/test/CodeGen/riscv32-ilp32-ilp32f-ilp32d-abi.c b/clang/test/CodeGen/riscv32-ilp32-ilp32f-ilp32d-abi.c index 86ad8fd370bca..740079d28d3be 100644 --- a/clang/test/CodeGen/riscv32-ilp32-ilp32f-ilp32d-abi.c +++ b/clang/test/CodeGen/riscv32-ilp32-ilp32f-ilp32d-abi.c @@ -177,7 +177,7 @@ void f_agg_large(struct large x) { // The address where the struct should be written to will be the first // argument -// CHECK-LABEL: define void @f_agg_large_ret(%struct.large* noalias sret %agg.result, i32 %i, i8 signext %j) +// CHECK-LABEL: define void @f_agg_large_ret(%struct.large* noalias sret align 4 %agg.result, i32 %i, i8 signext %j) struct large f_agg_large_ret(int32_t i, int8_t j) { return (struct large){1, 2, 3, 4}; } @@ -189,7 +189,7 @@ void f_vec_large_v16i8(v16i8 x) { x[0] = x[7]; } -// CHECK-LABEL: define void @f_vec_large_v16i8_ret(<16 x i8>* noalias sret %agg.result) +// CHECK-LABEL: define void @f_vec_large_v16i8_ret(<16 x i8>* noalias sret align 16 %agg.result) v16i8 f_vec_large_v16i8_ret() { return (v16i8){1, 2, 3, 4, 5, 6, 7, 8}; } @@ -207,7 +207,7 @@ int f_scalar_stack_1(struct tiny a, struct small b, struct small_aligned c, // the presence of large return values that consume a register due to the need // to pass a pointer. -// CHECK-LABEL: define void @f_scalar_stack_2(%struct.large* noalias sret %agg.result, i32 %a, i64 %b, i64 %c, fp128 %d, i8 zeroext %e, i8 %f, i8 %g) +// CHECK-LABEL: define void @f_scalar_stack_2(%struct.large* noalias sret align 4 %agg.result, i32 %a, i64 %b, i64 %c, fp128 %d, i8 zeroext %e, i8 %f, i8 %g) struct large f_scalar_stack_2(int32_t a, int64_t b, int64_t c, long double d, uint8_t e, int8_t f, uint8_t g) { return (struct large){a, e, f, g}; diff --git a/clang/test/CodeGen/riscv32-ilp32d-abi.c b/clang/test/CodeGen/riscv32-ilp32d-abi.c index 078fcb6b5ab11..bc4a1b58aaf83 100644 --- a/clang/test/CodeGen/riscv32-ilp32d-abi.c +++ b/clang/test/CodeGen/riscv32-ilp32d-abi.c @@ -119,7 +119,7 @@ struct double_int32_s f_ret_double_int32_s() { // CHECK: define void @f_double_int64_s_arg(%struct.double_int64_s* %a) void f_double_int64_s_arg(struct double_int64_s a) {} -// CHECK: define void @f_ret_double_int64_s(%struct.double_int64_s* noalias sret %agg.result) +// CHECK: define void @f_ret_double_int64_s(%struct.double_int64_s* noalias sret align 8 %agg.result) struct double_int64_s f_ret_double_int64_s() { return (struct double_int64_s){1.0, 2}; } @@ -243,7 +243,7 @@ struct int_double_int_s { int a; double b; int c; }; // CHECK: define void @f_int_double_int_s_arg(%struct.int_double_int_s* %a) void f_int_double_int_s_arg(struct int_double_int_s a) {} -// CHECK: define void @f_ret_int_double_int_s(%struct.int_double_int_s* noalias sret %agg.result) +// CHECK: define void @f_ret_int_double_int_s(%struct.int_double_int_s* noalias sret align 8 %agg.result) struct int_double_int_s f_ret_int_double_int_s() { return (struct int_double_int_s){1, 2.0, 3}; } @@ -253,7 +253,7 @@ struct int64_double_s { int64_t a; double b; }; // CHECK: define void @f_int64_double_s_arg(%struct.int64_double_s* %a) void f_int64_double_s_arg(struct int64_double_s a) {} -// CHECK: define void @f_ret_int64_double_s(%struct.int64_double_s* noalias sret %agg.result) +// CHECK: define void @f_ret_int64_double_s(%struct.int64_double_s* noalias sret align 8 %agg.result) struct int64_double_s f_ret_int64_double_s() { return (struct int64_double_s){1, 2.0}; } @@ -263,7 +263,7 @@ struct char_char_double_s { char a; char b; double c; }; // CHECK-LABEL: define void @f_char_char_double_s_arg(%struct.char_char_double_s* %a) void f_char_char_double_s_arg(struct char_char_double_s a) {} -// CHECK: define void @f_ret_char_char_double_s(%struct.char_char_double_s* noalias sret %agg.result) +// CHECK: define void @f_ret_char_char_double_s(%struct.char_char_double_s* noalias sret align 8 %agg.result) struct char_char_double_s f_ret_char_char_double_s() { return (struct char_char_double_s){1, 2, 3.0}; } diff --git a/clang/test/CodeGen/riscv32-ilp32f-abi.c b/clang/test/CodeGen/riscv32-ilp32f-abi.c index 76092958aeddf..c8e6418b9daae 100644 --- a/clang/test/CodeGen/riscv32-ilp32f-abi.c +++ b/clang/test/CodeGen/riscv32-ilp32f-abi.c @@ -26,7 +26,7 @@ struct double_double_s { double d; double e; }; // CHECK: define void @f_double_double_s_arg(%struct.double_double_s* %a) void f_double_double_s_arg(struct double_double_s a) {} -// CHECK: define void @f_ret_double_double_s(%struct.double_double_s* noalias sret %agg.result) +// CHECK: define void @f_ret_double_double_s(%struct.double_double_s* noalias sret align 8 %agg.result) struct double_double_s f_ret_double_double_s() { return (struct double_double_s){1.0, 2.0}; } @@ -38,7 +38,7 @@ struct int_double_s { int a; double b; }; // CHECK: define void @f_int_double_s_arg(%struct.int_double_s* %a) void f_int_double_s_arg(struct int_double_s a) {} -// CHECK: define void @f_ret_int_double_s(%struct.int_double_s* noalias sret %agg.result) +// CHECK: define void @f_ret_int_double_s(%struct.int_double_s* noalias sret align 8 %agg.result) struct int_double_s f_ret_int_double_s() { return (struct int_double_s){1, 2.0}; } diff --git a/clang/test/CodeGen/riscv32-ilp32f-ilp32d-abi.c b/clang/test/CodeGen/riscv32-ilp32f-ilp32d-abi.c index e9705ca3d62b3..419bd87fdecfa 100644 --- a/clang/test/CodeGen/riscv32-ilp32f-ilp32d-abi.c +++ b/clang/test/CodeGen/riscv32-ilp32f-ilp32d-abi.c @@ -112,7 +112,7 @@ struct float_int32_s f_ret_float_int32_s() { // CHECK: define void @f_float_int64_s_arg(%struct.float_int64_s* %a) void f_float_int64_s_arg(struct float_int64_s a) {} -// CHECK: define void @f_ret_float_int64_s(%struct.float_int64_s* noalias sret %agg.result) +// CHECK: define void @f_ret_float_int64_s(%struct.float_int64_s* noalias sret align 8 %agg.result) struct float_int64_s f_ret_float_int64_s() { return (struct float_int64_s){1.0, 2}; } @@ -236,7 +236,7 @@ struct int_float_int_s { int a; float b; int c; }; // CHECK: define void @f_int_float_int_s_arg(%struct.int_float_int_s* %a) void f_int_float_int_s_arg(struct int_float_int_s a) {} -// CHECK: define void @f_ret_int_float_int_s(%struct.int_float_int_s* noalias sret %agg.result) +// CHECK: define void @f_ret_int_float_int_s(%struct.int_float_int_s* noalias sret align 4 %agg.result) struct int_float_int_s f_ret_int_float_int_s() { return (struct int_float_int_s){1, 2.0, 3}; } @@ -246,7 +246,7 @@ struct int64_float_s { int64_t a; float b; }; // CHECK: define void @f_int64_float_s_arg(%struct.int64_float_s* %a) void f_int64_float_s_arg(struct int64_float_s a) {} -// CHECK: define void @f_ret_int64_float_s(%struct.int64_float_s* noalias sret %agg.result) +// CHECK: define void @f_ret_int64_float_s(%struct.int64_float_s* noalias sret align 8 %agg.result) struct int64_float_s f_ret_int64_float_s() { return (struct int64_float_s){1, 2.0}; } diff --git a/clang/test/CodeGen/riscv64-lp64-abi.c b/clang/test/CodeGen/riscv64-lp64-abi.c index bae5470c377d9..8347056c54d35 100644 --- a/clang/test/CodeGen/riscv64-lp64-abi.c +++ b/clang/test/CodeGen/riscv64-lp64-abi.c @@ -25,7 +25,7 @@ int f_scalar_stack_1(int32_t a, __int128_t b, float c, long double d, v32i8 e, // the presence of large return values that consume a register due to the need // to pass a pointer. -// CHECK-LABEL: define void @f_scalar_stack_2(%struct.large* noalias sret %agg.result, double %a, i128 %b, fp128 %c, <32 x i8>* %0, i8 zeroext %e, i8 %f, i8 %g) +// CHECK-LABEL: define void @f_scalar_stack_2(%struct.large* noalias sret align 8 %agg.result, double %a, i128 %b, fp128 %c, <32 x i8>* %0, i8 zeroext %e, i8 %f, i8 %g) struct large f_scalar_stack_2(double a, __int128_t b, long double c, v32i8 d, uint8_t e, int8_t f, uint8_t g) { return (struct large){a, e, f, g}; diff --git a/clang/test/CodeGen/riscv64-lp64-lp64f-abi.c b/clang/test/CodeGen/riscv64-lp64-lp64f-abi.c index d9c909e88bd8f..489d0e83dcbc5 100644 --- a/clang/test/CodeGen/riscv64-lp64-lp64f-abi.c +++ b/clang/test/CodeGen/riscv64-lp64-lp64f-abi.c @@ -27,7 +27,7 @@ int f_scalar_stack_1(int32_t a, __int128_t b, double c, long double d, v32i8 e, // the presence of large return values that consume a register due to the need // to pass a pointer. -// CHECK-LABEL: define void @f_scalar_stack_2(%struct.large* noalias sret %agg.result, double %a, i128 %b, fp128 %c, <32 x i8>* %0, i8 zeroext %e, i8 %f, i8 %g) +// CHECK-LABEL: define void @f_scalar_stack_2(%struct.large* noalias sret align 8 %agg.result, double %a, i128 %b, fp128 %c, <32 x i8>* %0, i8 zeroext %e, i8 %f, i8 %g) struct large f_scalar_stack_2(double a, __int128_t b, long double c, v32i8 d, uint8_t e, int8_t f, uint8_t g) { return (struct large){a, e, f, g}; diff --git a/clang/test/CodeGen/riscv64-lp64-lp64f-lp64d-abi.c b/clang/test/CodeGen/riscv64-lp64-lp64f-lp64d-abi.c index f50a8ca905757..8e263aeba25c5 100644 --- a/clang/test/CodeGen/riscv64-lp64-lp64f-lp64d-abi.c +++ b/clang/test/CodeGen/riscv64-lp64-lp64f-lp64d-abi.c @@ -166,7 +166,7 @@ void f_agg_large(struct large x) { // The address where the struct should be written to will be the first // argument -// CHECK-LABEL: define void @f_agg_large_ret(%struct.large* noalias sret %agg.result, i32 signext %i, i8 signext %j) +// CHECK-LABEL: define void @f_agg_large_ret(%struct.large* noalias sret align 8 %agg.result, i32 signext %i, i8 signext %j) struct large f_agg_large_ret(int32_t i, int8_t j) { return (struct large){1, 2, 3, 4}; } @@ -178,7 +178,7 @@ void f_vec_large_v32i8(v32i8 x) { x[0] = x[7]; } -// CHECK-LABEL: define void @f_vec_large_v32i8_ret(<32 x i8>* noalias sret %agg.result) +// CHECK-LABEL: define void @f_vec_large_v32i8_ret(<32 x i8>* noalias sret align 32 %agg.result) v32i8 f_vec_large_v32i8_ret() { return (v32i8){1, 2, 3, 4, 5, 6, 7, 8}; } @@ -202,7 +202,7 @@ int f_scalar_stack_2(int32_t a, __int128_t b, int64_t c, long double d, v32i8 e, // the presence of large return values that consume a register due to the need // to pass a pointer. -// CHECK-LABEL: define void @f_scalar_stack_3(%struct.large* noalias sret %agg.result, i32 signext %a, i128 %b, fp128 %c, <32 x i8>* %0, i8 zeroext %e, i8 %f, i8 %g) +// CHECK-LABEL: define void @f_scalar_stack_3(%struct.large* noalias sret align 8 %agg.result, i32 signext %a, i128 %b, fp128 %c, <32 x i8>* %0, i8 zeroext %e, i8 %f, i8 %g) struct large f_scalar_stack_3(uint32_t a, __int128_t b, long double c, v32i8 d, uint8_t e, int8_t f, uint8_t g) { return (struct large){a, e, f, g}; diff --git a/clang/test/CodeGen/riscv64-lp64d-abi.c b/clang/test/CodeGen/riscv64-lp64d-abi.c index 83947def30851..ec47428e6ccab 100644 --- a/clang/test/CodeGen/riscv64-lp64d-abi.c +++ b/clang/test/CodeGen/riscv64-lp64d-abi.c @@ -243,7 +243,7 @@ struct int_double_int_s { int a; double b; int c; }; // CHECK: define void @f_int_double_int_s_arg(%struct.int_double_int_s* %a) void f_int_double_int_s_arg(struct int_double_int_s a) {} -// CHECK: define void @f_ret_int_double_int_s(%struct.int_double_int_s* noalias sret %agg.result) +// CHECK: define void @f_ret_int_double_int_s(%struct.int_double_int_s* noalias sret align 8 %agg.result) struct int_double_int_s f_ret_int_double_int_s() { return (struct int_double_int_s){1, 2.0, 3}; } diff --git a/clang/test/CodeGen/sparcv9-abi.c b/clang/test/CodeGen/sparcv9-abi.c index 5984fa558c83c..2d97001ab1ae4 100644 --- a/clang/test/CodeGen/sparcv9-abi.c +++ b/clang/test/CodeGen/sparcv9-abi.c @@ -53,7 +53,7 @@ struct large { int x; }; -// CHECK-LABEL: define void @f_large(%struct.large* noalias sret %agg.result, %struct.large* %x) +// CHECK-LABEL: define void @f_large(%struct.large* noalias sret align 8 %agg.result, %struct.large* %x) struct large f_large(struct large x) { x.a += *x.b; x.b = 0; diff --git a/clang/test/CodeGen/struct-passing.c b/clang/test/CodeGen/struct-passing.c index 80847b9fea64f..e3108b964bd26 100644 --- a/clang/test/CodeGen/struct-passing.c +++ b/clang/test/CodeGen/struct-passing.c @@ -18,8 +18,8 @@ void *ps[] = { f0, f1, f2, f3, f4, f5 }; // CHECK: declare i32 @f0() [[RN:#[0-9]+]] // CHECK: declare i32 @f1() [[RO:#[0-9]+]] -// CHECK: declare void @f2({{.*}} sret) -// CHECK: declare void @f3({{.*}} sret) +// CHECK: declare void @f2({{.*}} sret align 4) +// CHECK: declare void @f3({{.*}} sret align 4) // CHECK: declare void @f4({{.*}} byval({{.*}}) align 4) // CHECK: declare void @f5({{.*}} byval({{.*}}) align 4) diff --git a/clang/test/CodeGen/systemz-abi-vector.c b/clang/test/CodeGen/systemz-abi-vector.c index f2e6c13c718f5..896cc0994d6df 100644 --- a/clang/test/CodeGen/systemz-abi-vector.c +++ b/clang/test/CodeGen/systemz-abi-vector.c @@ -50,91 +50,91 @@ unsigned int align = __alignof__ (v16i8); // CHECK-VECTOR: @align = global i32 8 v1i8 pass_v1i8(v1i8 arg) { return arg; } -// CHECK-LABEL: define void @pass_v1i8(<1 x i8>* noalias sret %{{.*}}, <1 x i8>* %0) +// CHECK-LABEL: define void @pass_v1i8(<1 x i8>* noalias sret align 1 %{{.*}}, <1 x i8>* %0) // CHECK-VECTOR-LABEL: define <1 x i8> @pass_v1i8(<1 x i8> %{{.*}}) v2i8 pass_v2i8(v2i8 arg) { return arg; } -// CHECK-LABEL: define void @pass_v2i8(<2 x i8>* noalias sret %{{.*}}, <2 x i8>* %0) +// CHECK-LABEL: define void @pass_v2i8(<2 x i8>* noalias sret align 2 %{{.*}}, <2 x i8>* %0) // CHECK-VECTOR-LABEL: define <2 x i8> @pass_v2i8(<2 x i8> %{{.*}}) v4i8 pass_v4i8(v4i8 arg) { return arg; } -// CHECK-LABEL: define void @pass_v4i8(<4 x i8>* noalias sret %{{.*}}, <4 x i8>* %0) +// CHECK-LABEL: define void @pass_v4i8(<4 x i8>* noalias sret align 4 %{{.*}}, <4 x i8>* %0) // CHECK-VECTOR-LABEL: define <4 x i8> @pass_v4i8(<4 x i8> %{{.*}}) v8i8 pass_v8i8(v8i8 arg) { return arg; } -// CHECK-LABEL: define void @pass_v8i8(<8 x i8>* noalias sret %{{.*}}, <8 x i8>* %0) +// CHECK-LABEL: define void @pass_v8i8(<8 x i8>* noalias sret align 8 %{{.*}}, <8 x i8>* %0) // CHECK-VECTOR-LABEL: define <8 x i8> @pass_v8i8(<8 x i8> %{{.*}}) v16i8 pass_v16i8(v16i8 arg) { return arg; } -// CHECK-LABEL: define void @pass_v16i8(<16 x i8>* noalias sret %{{.*}}, <16 x i8>* %0) +// CHECK-LABEL: define void @pass_v16i8(<16 x i8>* noalias sret align 16 %{{.*}}, <16 x i8>* %0) // CHECK-VECTOR-LABEL: define <16 x i8> @pass_v16i8(<16 x i8> %{{.*}}) v32i8 pass_v32i8(v32i8 arg) { return arg; } -// CHECK-LABEL: define void @pass_v32i8(<32 x i8>* noalias sret %{{.*}}, <32 x i8>* %0) -// CHECK-VECTOR-LABEL: define void @pass_v32i8(<32 x i8>* noalias sret %{{.*}}, <32 x i8>* %0) +// CHECK-LABEL: define void @pass_v32i8(<32 x i8>* noalias sret align 32 %{{.*}}, <32 x i8>* %0) +// CHECK-VECTOR-LABEL: define void @pass_v32i8(<32 x i8>* noalias sret align 8 %{{.*}}, <32 x i8>* %0) v1i16 pass_v1i16(v1i16 arg) { return arg; } -// CHECK-LABEL: define void @pass_v1i16(<1 x i16>* noalias sret %{{.*}}, <1 x i16>* %0) +// CHECK-LABEL: define void @pass_v1i16(<1 x i16>* noalias sret align 2 %{{.*}}, <1 x i16>* %0) // CHECK-VECTOR-LABEL: define <1 x i16> @pass_v1i16(<1 x i16> %{{.*}}) v2i16 pass_v2i16(v2i16 arg) { return arg; } -// CHECK-LABEL: define void @pass_v2i16(<2 x i16>* noalias sret %{{.*}}, <2 x i16>* %0) +// CHECK-LABEL: define void @pass_v2i16(<2 x i16>* noalias sret align 4 %{{.*}}, <2 x i16>* %0) // CHECK-VECTOR-LABEL: define <2 x i16> @pass_v2i16(<2 x i16> %{{.*}}) v4i16 pass_v4i16(v4i16 arg) { return arg; } -// CHECK-LABEL: define void @pass_v4i16(<4 x i16>* noalias sret %{{.*}}, <4 x i16>* %0) +// CHECK-LABEL: define void @pass_v4i16(<4 x i16>* noalias sret align 8 %{{.*}}, <4 x i16>* %0) // CHECK-VECTOR-LABEL: define <4 x i16> @pass_v4i16(<4 x i16> %{{.*}}) v8i16 pass_v8i16(v8i16 arg) { return arg; } -// CHECK-LABEL: define void @pass_v8i16(<8 x i16>* noalias sret %{{.*}}, <8 x i16>* %0) +// CHECK-LABEL: define void @pass_v8i16(<8 x i16>* noalias sret align 16 %{{.*}}, <8 x i16>* %0) // CHECK-VECTOR-LABEL: define <8 x i16> @pass_v8i16(<8 x i16> %{{.*}}) v1i32 pass_v1i32(v1i32 arg) { return arg; } -// CHECK-LABEL: define void @pass_v1i32(<1 x i32>* noalias sret %{{.*}}, <1 x i32>* %0) +// CHECK-LABEL: define void @pass_v1i32(<1 x i32>* noalias sret align 4 %{{.*}}, <1 x i32>* %0) // CHECK-VECTOR-LABEL: define <1 x i32> @pass_v1i32(<1 x i32> %{{.*}}) v2i32 pass_v2i32(v2i32 arg) { return arg; } -// CHECK-LABEL: define void @pass_v2i32(<2 x i32>* noalias sret %{{.*}}, <2 x i32>* %0) +// CHECK-LABEL: define void @pass_v2i32(<2 x i32>* noalias sret align 8 %{{.*}}, <2 x i32>* %0) // CHECK-VECTOR-LABEL: define <2 x i32> @pass_v2i32(<2 x i32> %{{.*}}) v4i32 pass_v4i32(v4i32 arg) { return arg; } -// CHECK-LABEL: define void @pass_v4i32(<4 x i32>* noalias sret %{{.*}}, <4 x i32>* %0) +// CHECK-LABEL: define void @pass_v4i32(<4 x i32>* noalias sret align 16 %{{.*}}, <4 x i32>* %0) // CHECK-VECTOR-LABEL: define <4 x i32> @pass_v4i32(<4 x i32> %{{.*}}) v1i64 pass_v1i64(v1i64 arg) { return arg; } -// CHECK-LABEL: define void @pass_v1i64(<1 x i64>* noalias sret %{{.*}}, <1 x i64>* %0) +// CHECK-LABEL: define void @pass_v1i64(<1 x i64>* noalias sret align 8 %{{.*}}, <1 x i64>* %0) // CHECK-VECTOR-LABEL: define <1 x i64> @pass_v1i64(<1 x i64> %{{.*}}) v2i64 pass_v2i64(v2i64 arg) { return arg; } -// CHECK-LABEL: define void @pass_v2i64(<2 x i64>* noalias sret %{{.*}}, <2 x i64>* %0) +// CHECK-LABEL: define void @pass_v2i64(<2 x i64>* noalias sret align 16 %{{.*}}, <2 x i64>* %0) // CHECK-VECTOR-LABEL: define <2 x i64> @pass_v2i64(<2 x i64> %{{.*}}) v1i128 pass_v1i128(v1i128 arg) { return arg; } -// CHECK-LABEL: define void @pass_v1i128(<1 x i128>* noalias sret %{{.*}}, <1 x i128>* %0) +// CHECK-LABEL: define void @pass_v1i128(<1 x i128>* noalias sret align 16 %{{.*}}, <1 x i128>* %0) // CHECK-VECTOR-LABEL: define <1 x i128> @pass_v1i128(<1 x i128> %{{.*}}) v1f32 pass_v1f32(v1f32 arg) { return arg; } -// CHECK-LABEL: define void @pass_v1f32(<1 x float>* noalias sret %{{.*}}, <1 x float>* %0) +// CHECK-LABEL: define void @pass_v1f32(<1 x float>* noalias sret align 4 %{{.*}}, <1 x float>* %0) // CHECK-VECTOR-LABEL: define <1 x float> @pass_v1f32(<1 x float> %{{.*}}) v2f32 pass_v2f32(v2f32 arg) { return arg; } -// CHECK-LABEL: define void @pass_v2f32(<2 x float>* noalias sret %{{.*}}, <2 x float>* %0) +// CHECK-LABEL: define void @pass_v2f32(<2 x float>* noalias sret align 8 %{{.*}}, <2 x float>* %0) // CHECK-VECTOR-LABEL: define <2 x float> @pass_v2f32(<2 x float> %{{.*}}) v4f32 pass_v4f32(v4f32 arg) { return arg; } -// CHECK-LABEL: define void @pass_v4f32(<4 x float>* noalias sret %{{.*}}, <4 x float>* %0) +// CHECK-LABEL: define void @pass_v4f32(<4 x float>* noalias sret align 16 %{{.*}}, <4 x float>* %0) // CHECK-VECTOR-LABEL: define <4 x float> @pass_v4f32(<4 x float> %{{.*}}) v1f64 pass_v1f64(v1f64 arg) { return arg; } -// CHECK-LABEL: define void @pass_v1f64(<1 x double>* noalias sret %{{.*}}, <1 x double>* %0) +// CHECK-LABEL: define void @pass_v1f64(<1 x double>* noalias sret align 8 %{{.*}}, <1 x double>* %0) // CHECK-VECTOR-LABEL: define <1 x double> @pass_v1f64(<1 x double> %{{.*}}) v2f64 pass_v2f64(v2f64 arg) { return arg; } -// CHECK-LABEL: define void @pass_v2f64(<2 x double>* noalias sret %{{.*}}, <2 x double>* %0) +// CHECK-LABEL: define void @pass_v2f64(<2 x double>* noalias sret align 16 %{{.*}}, <2 x double>* %0) // CHECK-VECTOR-LABEL: define <2 x double> @pass_v2f64(<2 x double> %{{.*}}) v1f128 pass_v1f128(v1f128 arg) { return arg; } -// CHECK-LABEL: define void @pass_v1f128(<1 x fp128>* noalias sret %{{.*}}, <1 x fp128>* %0) +// CHECK-LABEL: define void @pass_v1f128(<1 x fp128>* noalias sret align 16 %{{.*}}, <1 x fp128>* %0) // CHECK-VECTOR-LABEL: define <1 x fp128> @pass_v1f128(<1 x fp128> %{{.*}}) @@ -142,62 +142,62 @@ v1f128 pass_v1f128(v1f128 arg) { return arg; } struct agg_v1i8 { v1i8 a; }; struct agg_v1i8 pass_agg_v1i8(struct agg_v1i8 arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_v1i8(%struct.agg_v1i8* noalias sret %{{.*}}, i8 %{{.*}}) -// CHECK-VECTOR-LABEL: define void @pass_agg_v1i8(%struct.agg_v1i8* noalias sret %{{.*}}, <1 x i8> %{{.*}}) +// CHECK-LABEL: define void @pass_agg_v1i8(%struct.agg_v1i8* noalias sret align 1 %{{.*}}, i8 %{{.*}}) +// CHECK-VECTOR-LABEL: define void @pass_agg_v1i8(%struct.agg_v1i8* noalias sret align 1 %{{.*}}, <1 x i8> %{{.*}}) struct agg_v2i8 { v2i8 a; }; struct agg_v2i8 pass_agg_v2i8(struct agg_v2i8 arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_v2i8(%struct.agg_v2i8* noalias sret %{{.*}}, i16 %{{.*}}) -// CHECK-VECTOR-LABEL: define void @pass_agg_v2i8(%struct.agg_v2i8* noalias sret %{{.*}}, <2 x i8> %{{.*}}) +// CHECK-LABEL: define void @pass_agg_v2i8(%struct.agg_v2i8* noalias sret align 2 %{{.*}}, i16 %{{.*}}) +// CHECK-VECTOR-LABEL: define void @pass_agg_v2i8(%struct.agg_v2i8* noalias sret align 2 %{{.*}}, <2 x i8> %{{.*}}) struct agg_v4i8 { v4i8 a; }; struct agg_v4i8 pass_agg_v4i8(struct agg_v4i8 arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_v4i8(%struct.agg_v4i8* noalias sret %{{.*}}, i32 %{{.*}}) -// CHECK-VECTOR-LABEL: define void @pass_agg_v4i8(%struct.agg_v4i8* noalias sret %{{.*}}, <4 x i8> %{{.*}}) +// CHECK-LABEL: define void @pass_agg_v4i8(%struct.agg_v4i8* noalias sret align 4 %{{.*}}, i32 %{{.*}}) +// CHECK-VECTOR-LABEL: define void @pass_agg_v4i8(%struct.agg_v4i8* noalias sret align 4 %{{.*}}, <4 x i8> %{{.*}}) struct agg_v8i8 { v8i8 a; }; struct agg_v8i8 pass_agg_v8i8(struct agg_v8i8 arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_v8i8(%struct.agg_v8i8* noalias sret %{{.*}}, i64 %{{.*}}) -// CHECK-VECTOR-LABEL: define void @pass_agg_v8i8(%struct.agg_v8i8* noalias sret %{{.*}}, <8 x i8> %{{.*}}) +// CHECK-LABEL: define void @pass_agg_v8i8(%struct.agg_v8i8* noalias sret align 8 %{{.*}}, i64 %{{.*}}) +// CHECK-VECTOR-LABEL: define void @pass_agg_v8i8(%struct.agg_v8i8* noalias sret align 8 %{{.*}}, <8 x i8> %{{.*}}) struct agg_v16i8 { v16i8 a; }; struct agg_v16i8 pass_agg_v16i8(struct agg_v16i8 arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_v16i8(%struct.agg_v16i8* noalias sret %{{.*}}, %struct.agg_v16i8* %{{.*}}) -// CHECK-VECTOR-LABEL: define void @pass_agg_v16i8(%struct.agg_v16i8* noalias sret %{{.*}}, <16 x i8> %{{.*}}) +// CHECK-LABEL: define void @pass_agg_v16i8(%struct.agg_v16i8* noalias sret align 16 %{{.*}}, %struct.agg_v16i8* %{{.*}}) +// CHECK-VECTOR-LABEL: define void @pass_agg_v16i8(%struct.agg_v16i8* noalias sret align 8 %{{.*}}, <16 x i8> %{{.*}}) struct agg_v32i8 { v32i8 a; }; struct agg_v32i8 pass_agg_v32i8(struct agg_v32i8 arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_v32i8(%struct.agg_v32i8* noalias sret %{{.*}}, %struct.agg_v32i8* %{{.*}}) -// CHECK-VECTOR-LABEL: define void @pass_agg_v32i8(%struct.agg_v32i8* noalias sret %{{.*}}, %struct.agg_v32i8* %{{.*}}) +// CHECK-LABEL: define void @pass_agg_v32i8(%struct.agg_v32i8* noalias sret align 32 %{{.*}}, %struct.agg_v32i8* %{{.*}}) +// CHECK-VECTOR-LABEL: define void @pass_agg_v32i8(%struct.agg_v32i8* noalias sret align 8 %{{.*}}, %struct.agg_v32i8* %{{.*}}) // Verify that the following are *not* vector-like aggregate types struct agg_novector1 { v4i8 a; v4i8 b; }; struct agg_novector1 pass_agg_novector1(struct agg_novector1 arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_novector1(%struct.agg_novector1* noalias sret %{{.*}}, i64 %{{.*}}) -// CHECK-VECTOR-LABEL: define void @pass_agg_novector1(%struct.agg_novector1* noalias sret %{{.*}}, i64 %{{.*}}) +// CHECK-LABEL: define void @pass_agg_novector1(%struct.agg_novector1* noalias sret align 4 %{{.*}}, i64 %{{.*}}) +// CHECK-VECTOR-LABEL: define void @pass_agg_novector1(%struct.agg_novector1* noalias sret align 4 %{{.*}}, i64 %{{.*}}) struct agg_novector2 { v4i8 a; float b; }; struct agg_novector2 pass_agg_novector2(struct agg_novector2 arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_novector2(%struct.agg_novector2* noalias sret %{{.*}}, i64 %{{.*}}) -// CHECK-VECTOR-LABEL: define void @pass_agg_novector2(%struct.agg_novector2* noalias sret %{{.*}}, i64 %{{.*}}) +// CHECK-LABEL: define void @pass_agg_novector2(%struct.agg_novector2* noalias sret align 4 %{{.*}}, i64 %{{.*}}) +// CHECK-VECTOR-LABEL: define void @pass_agg_novector2(%struct.agg_novector2* noalias sret align 4 %{{.*}}, i64 %{{.*}}) struct agg_novector3 { v4i8 a; int : 0; }; struct agg_novector3 pass_agg_novector3(struct agg_novector3 arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_novector3(%struct.agg_novector3* noalias sret %{{.*}}, i32 %{{.*}}) -// CHECK-VECTOR-LABEL: define void @pass_agg_novector3(%struct.agg_novector3* noalias sret %{{.*}}, i32 %{{.*}}) +// CHECK-LABEL: define void @pass_agg_novector3(%struct.agg_novector3* noalias sret align 4 %{{.*}}, i32 %{{.*}}) +// CHECK-VECTOR-LABEL: define void @pass_agg_novector3(%struct.agg_novector3* noalias sret align 4 %{{.*}}, i32 %{{.*}}) struct agg_novector4 { v4i8 a __attribute__((aligned (8))); }; struct agg_novector4 pass_agg_novector4(struct agg_novector4 arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_novector4(%struct.agg_novector4* noalias sret %{{.*}}, i64 %{{.*}}) -// CHECK-VECTOR-LABEL: define void @pass_agg_novector4(%struct.agg_novector4* noalias sret %{{.*}}, i64 %{{.*}}) +// CHECK-LABEL: define void @pass_agg_novector4(%struct.agg_novector4* noalias sret align 8 %{{.*}}, i64 %{{.*}}) +// CHECK-VECTOR-LABEL: define void @pass_agg_novector4(%struct.agg_novector4* noalias sret align 8 %{{.*}}, i64 %{{.*}}) // Accessing variable argument lists v1i8 va_v1i8(__builtin_va_list l) { return __builtin_va_arg(l, v1i8); } -// CHECK-LABEL: define void @va_v1i8(<1 x i8>* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-LABEL: define void @va_v1i8(<1 x i8>* noalias sret align 1 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -229,7 +229,7 @@ v1i8 va_v1i8(__builtin_va_list l) { return __builtin_va_arg(l, v1i8); } // CHECK-VECTOR: ret <1 x i8> [[RET]] v2i8 va_v2i8(__builtin_va_list l) { return __builtin_va_arg(l, v2i8); } -// CHECK-LABEL: define void @va_v2i8(<2 x i8>* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-LABEL: define void @va_v2i8(<2 x i8>* noalias sret align 2 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -261,7 +261,7 @@ v2i8 va_v2i8(__builtin_va_list l) { return __builtin_va_arg(l, v2i8); } // CHECK-VECTOR: ret <2 x i8> [[RET]] v4i8 va_v4i8(__builtin_va_list l) { return __builtin_va_arg(l, v4i8); } -// CHECK-LABEL: define void @va_v4i8(<4 x i8>* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-LABEL: define void @va_v4i8(<4 x i8>* noalias sret align 4 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -293,7 +293,7 @@ v4i8 va_v4i8(__builtin_va_list l) { return __builtin_va_arg(l, v4i8); } // CHECK-VECTOR: ret <4 x i8> [[RET]] v8i8 va_v8i8(__builtin_va_list l) { return __builtin_va_arg(l, v8i8); } -// CHECK-LABEL: define void @va_v8i8(<8 x i8>* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-LABEL: define void @va_v8i8(<8 x i8>* noalias sret align 8 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -325,7 +325,7 @@ v8i8 va_v8i8(__builtin_va_list l) { return __builtin_va_arg(l, v8i8); } // CHECK-VECTOR: ret <8 x i8> [[RET]] v16i8 va_v16i8(__builtin_va_list l) { return __builtin_va_arg(l, v16i8); } -// CHECK-LABEL: define void @va_v16i8(<16 x i8>* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-LABEL: define void @va_v16i8(<16 x i8>* noalias sret align 16 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -357,7 +357,7 @@ v16i8 va_v16i8(__builtin_va_list l) { return __builtin_va_arg(l, v16i8); } // CHECK-VECTOR: ret <16 x i8> [[RET]] v32i8 va_v32i8(__builtin_va_list l) { return __builtin_va_arg(l, v32i8); } -// CHECK-LABEL: define void @va_v32i8(<32 x i8>* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-LABEL: define void @va_v32i8(<32 x i8>* noalias sret align 32 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -379,7 +379,7 @@ v32i8 va_v32i8(__builtin_va_list l) { return __builtin_va_arg(l, v32i8); } // CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi <32 x i8>** [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ] // CHECK: [[INDIRECT_ARG:%[^ ]+]] = load <32 x i8>*, <32 x i8>** [[VA_ARG_ADDR]] // CHECK: ret void -// CHECK-VECTOR-LABEL: define void @va_v32i8(<32 x i8>* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-VECTOR-LABEL: define void @va_v32i8(<32 x i8>* noalias sret align 8 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK-VECTOR: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK-VECTOR: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK-VECTOR: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -403,7 +403,7 @@ v32i8 va_v32i8(__builtin_va_list l) { return __builtin_va_arg(l, v32i8); } // CHECK-VECTOR: ret void struct agg_v1i8 va_agg_v1i8(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_v1i8); } -// CHECK-LABEL: define void @va_agg_v1i8(%struct.agg_v1i8* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-LABEL: define void @va_agg_v1i8(%struct.agg_v1i8* noalias sret align 1 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -424,7 +424,7 @@ struct agg_v1i8 va_agg_v1i8(__builtin_va_list l) { return __builtin_va_arg(l, st // CHECK: store i8* [[OVERFLOW_ARG_AREA2]], i8** [[OVERFLOW_ARG_AREA_PTR]] // CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi %struct.agg_v1i8* [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ] // CHECK: ret void -// CHECK-VECTOR-LABEL: define void @va_agg_v1i8(%struct.agg_v1i8* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-VECTOR-LABEL: define void @va_agg_v1i8(%struct.agg_v1i8* noalias sret align 1 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK-VECTOR: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2 // CHECK-VECTOR: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]] // CHECK-VECTOR: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[OVERFLOW_ARG_AREA]] to %struct.agg_v1i8* @@ -433,7 +433,7 @@ struct agg_v1i8 va_agg_v1i8(__builtin_va_list l) { return __builtin_va_arg(l, st // CHECK-VECTOR: ret void struct agg_v2i8 va_agg_v2i8(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_v2i8); } -// CHECK-LABEL: define void @va_agg_v2i8(%struct.agg_v2i8* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-LABEL: define void @va_agg_v2i8(%struct.agg_v2i8* noalias sret align 2 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -454,7 +454,7 @@ struct agg_v2i8 va_agg_v2i8(__builtin_va_list l) { return __builtin_va_arg(l, st // CHECK: store i8* [[OVERFLOW_ARG_AREA2]], i8** [[OVERFLOW_ARG_AREA_PTR]] // CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi %struct.agg_v2i8* [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ] // CHECK: ret void -// CHECK-VECTOR-LABEL: define void @va_agg_v2i8(%struct.agg_v2i8* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-VECTOR-LABEL: define void @va_agg_v2i8(%struct.agg_v2i8* noalias sret align 2 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK-VECTOR: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2 // CHECK-VECTOR: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]] // CHECK-VECTOR: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[OVERFLOW_ARG_AREA]] to %struct.agg_v2i8* @@ -463,7 +463,7 @@ struct agg_v2i8 va_agg_v2i8(__builtin_va_list l) { return __builtin_va_arg(l, st // CHECK-VECTOR: ret void struct agg_v4i8 va_agg_v4i8(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_v4i8); } -// CHECK-LABEL: define void @va_agg_v4i8(%struct.agg_v4i8* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-LABEL: define void @va_agg_v4i8(%struct.agg_v4i8* noalias sret align 4 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -484,7 +484,7 @@ struct agg_v4i8 va_agg_v4i8(__builtin_va_list l) { return __builtin_va_arg(l, st // CHECK: store i8* [[OVERFLOW_ARG_AREA2]], i8** [[OVERFLOW_ARG_AREA_PTR]] // CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi %struct.agg_v4i8* [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ] // CHECK: ret void -// CHECK-VECTOR-LABEL: define void @va_agg_v4i8(%struct.agg_v4i8* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-VECTOR-LABEL: define void @va_agg_v4i8(%struct.agg_v4i8* noalias sret align 4 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK-VECTOR: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2 // CHECK-VECTOR: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]] // CHECK-VECTOR: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[OVERFLOW_ARG_AREA]] to %struct.agg_v4i8* @@ -493,7 +493,7 @@ struct agg_v4i8 va_agg_v4i8(__builtin_va_list l) { return __builtin_va_arg(l, st // CHECK-VECTOR: ret void struct agg_v8i8 va_agg_v8i8(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_v8i8); } -// CHECK-LABEL: define void @va_agg_v8i8(%struct.agg_v8i8* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-LABEL: define void @va_agg_v8i8(%struct.agg_v8i8* noalias sret align 8 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -514,7 +514,7 @@ struct agg_v8i8 va_agg_v8i8(__builtin_va_list l) { return __builtin_va_arg(l, st // CHECK: store i8* [[OVERFLOW_ARG_AREA2]], i8** [[OVERFLOW_ARG_AREA_PTR]] // CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi %struct.agg_v8i8* [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ] // CHECK: ret void -// CHECK-VECTOR-LABEL: define void @va_agg_v8i8(%struct.agg_v8i8* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-VECTOR-LABEL: define void @va_agg_v8i8(%struct.agg_v8i8* noalias sret align 8 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK-VECTOR: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2 // CHECK-VECTOR: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]] // CHECK-VECTOR: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[OVERFLOW_ARG_AREA]] to %struct.agg_v8i8* @@ -523,7 +523,7 @@ struct agg_v8i8 va_agg_v8i8(__builtin_va_list l) { return __builtin_va_arg(l, st // CHECK-VECTOR: ret void struct agg_v16i8 va_agg_v16i8(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_v16i8); } -// CHECK-LABEL: define void @va_agg_v16i8(%struct.agg_v16i8* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-LABEL: define void @va_agg_v16i8(%struct.agg_v16i8* noalias sret align 16 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -545,7 +545,7 @@ struct agg_v16i8 va_agg_v16i8(__builtin_va_list l) { return __builtin_va_arg(l, // CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi %struct.agg_v16i8** [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ] // CHECK: [[INDIRECT_ARG:%[^ ]+]] = load %struct.agg_v16i8*, %struct.agg_v16i8** [[VA_ARG_ADDR]] // CHECK: ret void -// CHECK-VECTOR-LABEL: define void @va_agg_v16i8(%struct.agg_v16i8* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-VECTOR-LABEL: define void @va_agg_v16i8(%struct.agg_v16i8* noalias sret align 8 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK-VECTOR: [[OVERFLOW_ARG_AREA_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 2 // CHECK-VECTOR: [[OVERFLOW_ARG_AREA:%[^ ]+]] = load i8*, i8** [[OVERFLOW_ARG_AREA_PTR]] // CHECK-VECTOR: [[MEM_ADDR:%[^ ]+]] = bitcast i8* [[OVERFLOW_ARG_AREA]] to %struct.agg_v16i8* @@ -554,7 +554,7 @@ struct agg_v16i8 va_agg_v16i8(__builtin_va_list l) { return __builtin_va_arg(l, // CHECK-VECTOR: ret void struct agg_v32i8 va_agg_v32i8(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_v32i8); } -// CHECK-LABEL: define void @va_agg_v32i8(%struct.agg_v32i8* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-LABEL: define void @va_agg_v32i8(%struct.agg_v32i8* noalias sret align 32 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -576,7 +576,7 @@ struct agg_v32i8 va_agg_v32i8(__builtin_va_list l) { return __builtin_va_arg(l, // CHECK: [[VA_ARG_ADDR:%[^ ]+]] = phi %struct.agg_v32i8** [ [[REG_ADDR]], %{{.*}} ], [ [[MEM_ADDR]], %{{.*}} ] // CHECK: [[INDIRECT_ARG:%[^ ]+]] = load %struct.agg_v32i8*, %struct.agg_v32i8** [[VA_ARG_ADDR]] // CHECK: ret void -// CHECK-VECTOR-LABEL: define void @va_agg_v32i8(%struct.agg_v32i8* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-VECTOR-LABEL: define void @va_agg_v32i8(%struct.agg_v32i8* noalias sret align 8 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK-VECTOR: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK-VECTOR: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK-VECTOR: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 diff --git a/clang/test/CodeGen/systemz-abi.c b/clang/test/CodeGen/systemz-abi.c index 3511983e32d76..88fd4bf9c1269 100644 --- a/clang/test/CodeGen/systemz-abi.c +++ b/clang/test/CodeGen/systemz-abi.c @@ -33,7 +33,7 @@ long long pass_longlong(long long arg) { return arg; } // CHECK-LABEL: define i64 @pass_longlong(i64 %{{.*}}) __int128 pass_int128(__int128 arg) { return arg; } -// CHECK-LABEL: define void @pass_int128(i128* noalias sret %{{.*}}, i128* %0) +// CHECK-LABEL: define void @pass_int128(i128* noalias sret align 16 %{{.*}}, i128* %0) float pass_float(float arg) { return arg; } // CHECK-LABEL: define float @pass_float(float %{{.*}}) @@ -42,111 +42,111 @@ double pass_double(double arg) { return arg; } // CHECK-LABEL: define double @pass_double(double %{{.*}}) long double pass_longdouble(long double arg) { return arg; } -// CHECK-LABEL: define void @pass_longdouble(fp128* noalias sret %{{.*}}, fp128* %0) +// CHECK-LABEL: define void @pass_longdouble(fp128* noalias sret align 8 %{{.*}}, fp128* %0) // Complex types _Complex char pass_complex_char(_Complex char arg) { return arg; } -// CHECK-LABEL: define void @pass_complex_char({ i8, i8 }* noalias sret %{{.*}}, { i8, i8 }* %{{.*}}arg) +// CHECK-LABEL: define void @pass_complex_char({ i8, i8 }* noalias sret align 1 %{{.*}}, { i8, i8 }* %{{.*}}arg) _Complex short pass_complex_short(_Complex short arg) { return arg; } -// CHECK-LABEL: define void @pass_complex_short({ i16, i16 }* noalias sret %{{.*}}, { i16, i16 }* %{{.*}}arg) +// CHECK-LABEL: define void @pass_complex_short({ i16, i16 }* noalias sret align 2 %{{.*}}, { i16, i16 }* %{{.*}}arg) _Complex int pass_complex_int(_Complex int arg) { return arg; } -// CHECK-LABEL: define void @pass_complex_int({ i32, i32 }* noalias sret %{{.*}}, { i32, i32 }* %{{.*}}arg) +// CHECK-LABEL: define void @pass_complex_int({ i32, i32 }* noalias sret align 4 %{{.*}}, { i32, i32 }* %{{.*}}arg) _Complex long pass_complex_long(_Complex long arg) { return arg; } -// CHECK-LABEL: define void @pass_complex_long({ i64, i64 }* noalias sret %{{.*}}, { i64, i64 }* %{{.*}}arg) +// CHECK-LABEL: define void @pass_complex_long({ i64, i64 }* noalias sret align 8 %{{.*}}, { i64, i64 }* %{{.*}}arg) _Complex long long pass_complex_longlong(_Complex long long arg) { return arg; } -// CHECK-LABEL: define void @pass_complex_longlong({ i64, i64 }* noalias sret %{{.*}}, { i64, i64 }* %{{.*}}arg) +// CHECK-LABEL: define void @pass_complex_longlong({ i64, i64 }* noalias sret align 8 %{{.*}}, { i64, i64 }* %{{.*}}arg) _Complex float pass_complex_float(_Complex float arg) { return arg; } -// CHECK-LABEL: define void @pass_complex_float({ float, float }* noalias sret %{{.*}}, { float, float }* %{{.*}}arg) +// CHECK-LABEL: define void @pass_complex_float({ float, float }* noalias sret align 4 %{{.*}}, { float, float }* %{{.*}}arg) _Complex double pass_complex_double(_Complex double arg) { return arg; } -// CHECK-LABEL: define void @pass_complex_double({ double, double }* noalias sret %{{.*}}, { double, double }* %{{.*}}arg) +// CHECK-LABEL: define void @pass_complex_double({ double, double }* noalias sret align 8 %{{.*}}, { double, double }* %{{.*}}arg) _Complex long double pass_complex_longdouble(_Complex long double arg) { return arg; } -// CHECK-LABEL: define void @pass_complex_longdouble({ fp128, fp128 }* noalias sret %{{.*}}, { fp128, fp128 }* %{{.*}}arg) +// CHECK-LABEL: define void @pass_complex_longdouble({ fp128, fp128 }* noalias sret align 8 %{{.*}}, { fp128, fp128 }* %{{.*}}arg) // Aggregate types struct agg_1byte { char a[1]; }; struct agg_1byte pass_agg_1byte(struct agg_1byte arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_1byte(%struct.agg_1byte* noalias sret %{{.*}}, i8 %{{.*}}) +// CHECK-LABEL: define void @pass_agg_1byte(%struct.agg_1byte* noalias sret align 1 %{{.*}}, i8 %{{.*}}) struct agg_2byte { char a[2]; }; struct agg_2byte pass_agg_2byte(struct agg_2byte arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_2byte(%struct.agg_2byte* noalias sret %{{.*}}, i16 %{{.*}}) +// CHECK-LABEL: define void @pass_agg_2byte(%struct.agg_2byte* noalias sret align 1 %{{.*}}, i16 %{{.*}}) struct agg_3byte { char a[3]; }; struct agg_3byte pass_agg_3byte(struct agg_3byte arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_3byte(%struct.agg_3byte* noalias sret %{{.*}}, %struct.agg_3byte* %{{.*}}) +// CHECK-LABEL: define void @pass_agg_3byte(%struct.agg_3byte* noalias sret align 1 %{{.*}}, %struct.agg_3byte* %{{.*}}) struct agg_4byte { char a[4]; }; struct agg_4byte pass_agg_4byte(struct agg_4byte arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_4byte(%struct.agg_4byte* noalias sret %{{.*}}, i32 %{{.*}}) +// CHECK-LABEL: define void @pass_agg_4byte(%struct.agg_4byte* noalias sret align 1 %{{.*}}, i32 %{{.*}}) struct agg_5byte { char a[5]; }; struct agg_5byte pass_agg_5byte(struct agg_5byte arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_5byte(%struct.agg_5byte* noalias sret %{{.*}}, %struct.agg_5byte* %{{.*}}) +// CHECK-LABEL: define void @pass_agg_5byte(%struct.agg_5byte* noalias sret align 1 %{{.*}}, %struct.agg_5byte* %{{.*}}) struct agg_6byte { char a[6]; }; struct agg_6byte pass_agg_6byte(struct agg_6byte arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_6byte(%struct.agg_6byte* noalias sret %{{.*}}, %struct.agg_6byte* %{{.*}}) +// CHECK-LABEL: define void @pass_agg_6byte(%struct.agg_6byte* noalias sret align 1 %{{.*}}, %struct.agg_6byte* %{{.*}}) struct agg_7byte { char a[7]; }; struct agg_7byte pass_agg_7byte(struct agg_7byte arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_7byte(%struct.agg_7byte* noalias sret %{{.*}}, %struct.agg_7byte* %{{.*}}) +// CHECK-LABEL: define void @pass_agg_7byte(%struct.agg_7byte* noalias sret align 1 %{{.*}}, %struct.agg_7byte* %{{.*}}) struct agg_8byte { char a[8]; }; struct agg_8byte pass_agg_8byte(struct agg_8byte arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_8byte(%struct.agg_8byte* noalias sret %{{.*}}, i64 %{{.*}}) +// CHECK-LABEL: define void @pass_agg_8byte(%struct.agg_8byte* noalias sret align 1 %{{.*}}, i64 %{{.*}}) struct agg_16byte { char a[16]; }; struct agg_16byte pass_agg_16byte(struct agg_16byte arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_16byte(%struct.agg_16byte* noalias sret %{{.*}}, %struct.agg_16byte* %{{.*}}) +// CHECK-LABEL: define void @pass_agg_16byte(%struct.agg_16byte* noalias sret align 1 %{{.*}}, %struct.agg_16byte* %{{.*}}) // Float-like aggregate types struct agg_float { float a; }; struct agg_float pass_agg_float(struct agg_float arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_float(%struct.agg_float* noalias sret %{{.*}}, float %{{.*}}) +// CHECK-LABEL: define void @pass_agg_float(%struct.agg_float* noalias sret align 4 %{{.*}}, float %{{.*}}) struct agg_double { double a; }; struct agg_double pass_agg_double(struct agg_double arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_double(%struct.agg_double* noalias sret %{{.*}}, double %{{.*}}) +// CHECK-LABEL: define void @pass_agg_double(%struct.agg_double* noalias sret align 8 %{{.*}}, double %{{.*}}) struct agg_longdouble { long double a; }; struct agg_longdouble pass_agg_longdouble(struct agg_longdouble arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_longdouble(%struct.agg_longdouble* noalias sret %{{.*}}, %struct.agg_longdouble* %{{.*}}) +// CHECK-LABEL: define void @pass_agg_longdouble(%struct.agg_longdouble* noalias sret align 8 %{{.*}}, %struct.agg_longdouble* %{{.*}}) struct agg_float_a8 { float a __attribute__((aligned (8))); }; struct agg_float_a8 pass_agg_float_a8(struct agg_float_a8 arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_float_a8(%struct.agg_float_a8* noalias sret %{{.*}}, double %{{.*}}) +// CHECK-LABEL: define void @pass_agg_float_a8(%struct.agg_float_a8* noalias sret align 8 %{{.*}}, double %{{.*}}) struct agg_float_a16 { float a __attribute__((aligned (16))); }; struct agg_float_a16 pass_agg_float_a16(struct agg_float_a16 arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_float_a16(%struct.agg_float_a16* noalias sret %{{.*}}, %struct.agg_float_a16* %{{.*}}) +// CHECK-LABEL: define void @pass_agg_float_a16(%struct.agg_float_a16* noalias sret align 16 %{{.*}}, %struct.agg_float_a16* %{{.*}}) // Verify that the following are *not* float-like aggregate types struct agg_nofloat1 { float a; float b; }; struct agg_nofloat1 pass_agg_nofloat1(struct agg_nofloat1 arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_nofloat1(%struct.agg_nofloat1* noalias sret %{{.*}}, i64 %{{.*}}) +// CHECK-LABEL: define void @pass_agg_nofloat1(%struct.agg_nofloat1* noalias sret align 4 %{{.*}}, i64 %{{.*}}) struct agg_nofloat2 { float a; int b; }; struct agg_nofloat2 pass_agg_nofloat2(struct agg_nofloat2 arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_nofloat2(%struct.agg_nofloat2* noalias sret %{{.*}}, i64 %{{.*}}) +// CHECK-LABEL: define void @pass_agg_nofloat2(%struct.agg_nofloat2* noalias sret align 4 %{{.*}}, i64 %{{.*}}) struct agg_nofloat3 { float a; int : 0; }; struct agg_nofloat3 pass_agg_nofloat3(struct agg_nofloat3 arg) { return arg; } -// CHECK-LABEL: define void @pass_agg_nofloat3(%struct.agg_nofloat3* noalias sret %{{.*}}, i32 %{{.*}}) +// CHECK-LABEL: define void @pass_agg_nofloat3(%struct.agg_nofloat3* noalias sret align 4 %{{.*}}, i32 %{{.*}}) // Accessing variable argument lists @@ -248,7 +248,7 @@ double va_double(__builtin_va_list l) { return __builtin_va_arg(l, double); } // CHECK: ret double [[RET]] long double va_longdouble(__builtin_va_list l) { return __builtin_va_arg(l, long double); } -// CHECK-LABEL: define void @va_longdouble(fp128* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}}) +// CHECK-LABEL: define void @va_longdouble(fp128* noalias sret align 8 %{{.*}}, %struct.__va_list_tag* %{{.*}}) // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -274,7 +274,7 @@ long double va_longdouble(__builtin_va_list l) { return __builtin_va_arg(l, long // CHECK: ret void _Complex char va_complex_char(__builtin_va_list l) { return __builtin_va_arg(l, _Complex char); } -// CHECK-LABEL: define void @va_complex_char({ i8, i8 }* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK-LABEL: define void @va_complex_char({ i8, i8 }* noalias sret align 1 %{{.*}}, %struct.__va_list_tag* %{{.*}} // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -298,7 +298,7 @@ _Complex char va_complex_char(__builtin_va_list l) { return __builtin_va_arg(l, // CHECK: ret void struct agg_1byte va_agg_1byte(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_1byte); } -// CHECK-LABEL: define void @va_agg_1byte(%struct.agg_1byte* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK-LABEL: define void @va_agg_1byte(%struct.agg_1byte* noalias sret align 1 %{{.*}}, %struct.__va_list_tag* %{{.*}} // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -321,7 +321,7 @@ struct agg_1byte va_agg_1byte(__builtin_va_list l) { return __builtin_va_arg(l, // CHECK: ret void struct agg_2byte va_agg_2byte(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_2byte); } -// CHECK-LABEL: define void @va_agg_2byte(%struct.agg_2byte* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK-LABEL: define void @va_agg_2byte(%struct.agg_2byte* noalias sret align 1 %{{.*}}, %struct.__va_list_tag* %{{.*}} // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -344,7 +344,7 @@ struct agg_2byte va_agg_2byte(__builtin_va_list l) { return __builtin_va_arg(l, // CHECK: ret void struct agg_3byte va_agg_3byte(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_3byte); } -// CHECK-LABEL: define void @va_agg_3byte(%struct.agg_3byte* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK-LABEL: define void @va_agg_3byte(%struct.agg_3byte* noalias sret align 1 %{{.*}}, %struct.__va_list_tag* %{{.*}} // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -368,7 +368,7 @@ struct agg_3byte va_agg_3byte(__builtin_va_list l) { return __builtin_va_arg(l, // CHECK: ret void struct agg_4byte va_agg_4byte(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_4byte); } -// CHECK-LABEL: define void @va_agg_4byte(%struct.agg_4byte* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK-LABEL: define void @va_agg_4byte(%struct.agg_4byte* noalias sret align 1 %{{.*}}, %struct.__va_list_tag* %{{.*}} // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -391,7 +391,7 @@ struct agg_4byte va_agg_4byte(__builtin_va_list l) { return __builtin_va_arg(l, // CHECK: ret void struct agg_8byte va_agg_8byte(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_8byte); } -// CHECK-LABEL: define void @va_agg_8byte(%struct.agg_8byte* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK-LABEL: define void @va_agg_8byte(%struct.agg_8byte* noalias sret align 1 %{{.*}}, %struct.__va_list_tag* %{{.*}} // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -414,7 +414,7 @@ struct agg_8byte va_agg_8byte(__builtin_va_list l) { return __builtin_va_arg(l, // CHECK: ret void struct agg_float va_agg_float(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_float); } -// CHECK-LABEL: define void @va_agg_float(%struct.agg_float* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK-LABEL: define void @va_agg_float(%struct.agg_float* noalias sret align 4 %{{.*}}, %struct.__va_list_tag* %{{.*}} // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 1 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 4 @@ -437,7 +437,7 @@ struct agg_float va_agg_float(__builtin_va_list l) { return __builtin_va_arg(l, // CHECK: ret void struct agg_double va_agg_double(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_double); } -// CHECK-LABEL: define void @va_agg_double(%struct.agg_double* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK-LABEL: define void @va_agg_double(%struct.agg_double* noalias sret align 8 %{{.*}}, %struct.__va_list_tag* %{{.*}} // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 1 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 4 @@ -460,7 +460,7 @@ struct agg_double va_agg_double(__builtin_va_list l) { return __builtin_va_arg(l // CHECK: ret void struct agg_longdouble va_agg_longdouble(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_longdouble); } -// CHECK-LABEL: define void @va_agg_longdouble(%struct.agg_longdouble* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK-LABEL: define void @va_agg_longdouble(%struct.agg_longdouble* noalias sret align 8 %{{.*}}, %struct.__va_list_tag* %{{.*}} // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -484,7 +484,7 @@ struct agg_longdouble va_agg_longdouble(__builtin_va_list l) { return __builtin_ // CHECK: ret void struct agg_float_a8 va_agg_float_a8(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_float_a8); } -// CHECK-LABEL: define void @va_agg_float_a8(%struct.agg_float_a8* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK-LABEL: define void @va_agg_float_a8(%struct.agg_float_a8* noalias sret align 8 %{{.*}}, %struct.__va_list_tag* %{{.*}} // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 1 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 4 @@ -507,7 +507,7 @@ struct agg_float_a8 va_agg_float_a8(__builtin_va_list l) { return __builtin_va_a // CHECK: ret void struct agg_float_a16 va_agg_float_a16(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_float_a16); } -// CHECK-LABEL: define void @va_agg_float_a16(%struct.agg_float_a16* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK-LABEL: define void @va_agg_float_a16(%struct.agg_float_a16* noalias sret align 16 %{{.*}}, %struct.__va_list_tag* %{{.*}} // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -531,7 +531,7 @@ struct agg_float_a16 va_agg_float_a16(__builtin_va_list l) { return __builtin_va // CHECK: ret void struct agg_nofloat1 va_agg_nofloat1(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_nofloat1); } -// CHECK-LABEL: define void @va_agg_nofloat1(%struct.agg_nofloat1* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK-LABEL: define void @va_agg_nofloat1(%struct.agg_nofloat1* noalias sret align 4 %{{.*}}, %struct.__va_list_tag* %{{.*}} // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -554,7 +554,7 @@ struct agg_nofloat1 va_agg_nofloat1(__builtin_va_list l) { return __builtin_va_a // CHECK: ret void struct agg_nofloat2 va_agg_nofloat2(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_nofloat2); } -// CHECK-LABEL: define void @va_agg_nofloat2(%struct.agg_nofloat2* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK-LABEL: define void @va_agg_nofloat2(%struct.agg_nofloat2* noalias sret align 4 %{{.*}}, %struct.__va_list_tag* %{{.*}} // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 @@ -577,7 +577,7 @@ struct agg_nofloat2 va_agg_nofloat2(__builtin_va_list l) { return __builtin_va_a // CHECK: ret void struct agg_nofloat3 va_agg_nofloat3(__builtin_va_list l) { return __builtin_va_arg(l, struct agg_nofloat3); } -// CHECK-LABEL: define void @va_agg_nofloat3(%struct.agg_nofloat3* noalias sret %{{.*}}, %struct.__va_list_tag* %{{.*}} +// CHECK-LABEL: define void @va_agg_nofloat3(%struct.agg_nofloat3* noalias sret align 4 %{{.*}}, %struct.__va_list_tag* %{{.*}} // CHECK: [[REG_COUNT_PTR:%[^ ]+]] = getelementptr inbounds %struct.__va_list_tag, %struct.__va_list_tag* %{{.*}}, i32 0, i32 0 // CHECK: [[REG_COUNT:%[^ ]+]] = load i64, i64* [[REG_COUNT_PTR]] // CHECK: [[FITS_IN_REGS:%[^ ]+]] = icmp ult i64 [[REG_COUNT]], 5 diff --git a/clang/test/CodeGen/systemz-abi.cpp b/clang/test/CodeGen/systemz-abi.cpp index 0249e9f63c9bf..5589c7eba1abd 100644 --- a/clang/test/CodeGen/systemz-abi.cpp +++ b/clang/test/CodeGen/systemz-abi.cpp @@ -5,5 +5,4 @@ struct agg_float_cpp { float a; int : 0; }; struct agg_float_cpp pass_agg_float_cpp(struct agg_float_cpp arg) { return arg; } -// CHECK-LABEL: define void @_Z18pass_agg_float_cpp13agg_float_cpp(%struct.agg_float_cpp* noalias sret %{{.*}}, float %{{.*}}) - +// CHECK-LABEL: define void @_Z18pass_agg_float_cpp13agg_float_cpp(%struct.agg_float_cpp* noalias sret align 4 %{{.*}}, float %{{.*}}) diff --git a/clang/test/CodeGen/systemz-inline-asm.c b/clang/test/CodeGen/systemz-inline-asm.c index 7c273dac579e8..2dc5023c55cb0 100644 --- a/clang/test/CodeGen/systemz-inline-asm.c +++ b/clang/test/CodeGen/systemz-inline-asm.c @@ -123,7 +123,7 @@ double test_f64(double f, double g) { long double test_f128(long double f, long double g) { asm("axbr %0, %2" : "=f" (f) : "0" (f), "f" (g)); return f; -// CHECK: define void @test_f128(fp128* noalias nocapture sret [[DEST:%.*]], fp128* nocapture readonly %0, fp128* nocapture readonly %1) +// CHECK: define void @test_f128(fp128* noalias nocapture sret align 8 [[DEST:%.*]], fp128* nocapture readonly %0, fp128* nocapture readonly %1) // CHECK: %f = load fp128, fp128* %0 // CHECK: %g = load fp128, fp128* %1 // CHECK: [[RESULT:%.*]] = tail call fp128 asm "axbr $0, $2", "=f,0,f"(fp128 %f, fp128 %g) diff --git a/clang/test/CodeGen/vectorcall.c b/clang/test/CodeGen/vectorcall.c index c8e8931a084c5..0aa4346fcc5c2 100644 --- a/clang/test/CodeGen/vectorcall.c +++ b/clang/test/CodeGen/vectorcall.c @@ -86,8 +86,8 @@ struct HVA4 __vectorcall hva6(struct HVA4 a, struct HVA4 b) { return b;} // X64: define dso_local x86_vectorcallcc %struct.HVA4 @"\01hva6@@128"(%struct.HVA4 inreg %a.coerce, %struct.HVA4* %b) struct HVA5 __vectorcall hva7() {struct HVA5 a = {}; return a;} -// X32: define dso_local x86_vectorcallcc void @"\01hva7@@0"(%struct.HVA5* inreg noalias sret %agg.result) -// X64: define dso_local x86_vectorcallcc void @"\01hva7@@0"(%struct.HVA5* noalias sret %agg.result) +// X32: define dso_local x86_vectorcallcc void @"\01hva7@@0"(%struct.HVA5* inreg noalias sret align 16 %agg.result) +// X64: define dso_local x86_vectorcallcc void @"\01hva7@@0"(%struct.HVA5* noalias sret align 16 %agg.result) v4f32 __vectorcall hva8(v4f32 a, v4f32 b, v4f32 c, v4f32 d, int e, v4f32 f) {return f;} // X32: define dso_local x86_vectorcallcc <4 x float> @"\01hva8@@84"(<4 x float> %a, <4 x float> %b, <4 x float> %c, <4 x float> %d, i32 inreg %e, <4 x float> %f) diff --git a/clang/test/CodeGen/wasm-arguments.c b/clang/test/CodeGen/wasm-arguments.c index c92028bae2db0..2ee3c3f4cecfb 100644 --- a/clang/test/CodeGen/wasm-arguments.c +++ b/clang/test/CodeGen/wasm-arguments.c @@ -34,8 +34,8 @@ typedef struct { int dd; } s3; // Structs should be returned sret and not simplified by the frontend. -// WEBASSEMBLY32: define void @f3(%struct.s3* noalias sret %agg.result) -// WEBASSEMBLY64: define void @f3(%struct.s3* noalias sret %agg.result) +// WEBASSEMBLY32: define void @f3(%struct.s3* noalias sret align 4 %agg.result) +// WEBASSEMBLY64: define void @f3(%struct.s3* noalias sret align 4 %agg.result) s3 f3(void) { s3 foo; return foo; diff --git a/clang/test/CodeGen/wasm-varargs.c b/clang/test/CodeGen/wasm-varargs.c index 23506875ac9d7..ba1f2d632b4ec 100644 --- a/clang/test/CodeGen/wasm-varargs.c +++ b/clang/test/CodeGen/wasm-varargs.c @@ -80,7 +80,7 @@ struct S test_struct(char *fmt, ...) { return v; } -// CHECK: define void @test_struct([[STRUCT_S:%[^,=]+]]*{{.*}} noalias sret [[AGG_RESULT:%.*]], i8*{{.*}} %fmt, ...) {{.*}} { +// CHECK: define void @test_struct([[STRUCT_S:%[^,=]+]]*{{.*}} noalias sret align 4 [[AGG_RESULT:%.*]], i8*{{.*}} %fmt, ...) {{.*}} { // CHECK: [[FMT_ADDR:%[^,=]+]] = alloca i8*, align 4 // CHECK-NEXT: [[VA:%[^,=]+]] = alloca i8*, align 4 // CHECK-NEXT: store i8* %fmt, i8** [[FMT_ADDR]], align 4 @@ -112,7 +112,7 @@ struct S test_empty_struct(char *fmt, ...) { return v; } -// CHECK: define void @test_empty_struct([[STRUCT_S:%[^,=]+]]*{{.*}} noalias sret [[AGG_RESULT:%.*]], i8*{{.*}} %fmt, ...) {{.*}} { +// CHECK: define void @test_empty_struct([[STRUCT_S:%[^,=]+]]*{{.*}} noalias sret align 4 [[AGG_RESULT:%.*]], i8*{{.*}} %fmt, ...) {{.*}} { // CHECK: [[FMT_ADDR:%[^,=]+]] = alloca i8*, align 4 // CHECK-NEXT: [[VA:%[^,=]+]] = alloca i8*, align 4 // CHECK-NEXT: [[U:%[^,=]+]] = alloca [[STRUCT_Z:%[^,=]+]], align 1 diff --git a/clang/test/CodeGen/windows-struct-abi.c b/clang/test/CodeGen/windows-struct-abi.c index 5ffc4fad64730..9fa175f136587 100644 --- a/clang/test/CodeGen/windows-struct-abi.c +++ b/clang/test/CodeGen/windows-struct-abi.c @@ -34,7 +34,7 @@ struct f4 { struct f4 return_f4(void) { while (1); } -// CHECK: define dso_local void @return_f4(%struct.f4* noalias sret %agg.result) +// CHECK: define dso_local void @return_f4(%struct.f4* noalias sret align 4 %agg.result) void receive_f4(struct f4 a0) { } diff --git a/clang/test/CodeGen/x86_32-arguments-darwin.c b/clang/test/CodeGen/x86_32-arguments-darwin.c index 71b8a2b9fc848..c88c1b8603b67 100644 --- a/clang/test/CodeGen/x86_32-arguments-darwin.c +++ b/clang/test/CodeGen/x86_32-arguments-darwin.c @@ -71,7 +71,7 @@ struct s10 { // Small vectors and 1 x {i64,double} are returned in registers // CHECK: i32 @f11() -// CHECK: void @f12(<2 x i32>* noalias sret %agg.result) +// CHECK: void @f12(<2 x i32>* noalias sret align 8 %agg.result) // CHECK: i64 @f13() // CHECK: i64 @f14() // CHECK: <2 x i64> @f15() @@ -93,11 +93,11 @@ T16 f16(void) { while (1) {} } // 128-bits). // CHECK: i32 @f17() -// CHECK: void @f18(%{{.*}}* noalias sret %agg.result) -// CHECK: void @f19(%{{.*}}* noalias sret %agg.result) -// CHECK: void @f20(%{{.*}}* noalias sret %agg.result) -// CHECK: void @f21(%{{.*}}* noalias sret %agg.result) -// CHECK: void @f22(%{{.*}}* noalias sret %agg.result) +// CHECK: void @f18(%{{.*}}* noalias sret align 8 %agg.result) +// CHECK: void @f19(%{{.*}}* noalias sret align 8 %agg.result) +// CHECK: void @f20(%{{.*}}* noalias sret align 8 %agg.result) +// CHECK: void @f21(%{{.*}}* noalias sret align 16 %agg.result) +// CHECK: void @f22(%{{.*}}* noalias sret align 16 %agg.result) struct { T11 a; } f17(void) { while (1) {} } struct { T12 a; } f18(void) { while (1) {} } struct { T13 a; } f19(void) { while (1) {} } @@ -116,11 +116,11 @@ struct { struct {} a; struct { float a[1]; } b; } f25(void) { while (1) {} } // Small structures are handled recursively // CHECK: i32 @f26() -// CHECK: void @f27(%struct.s27* noalias sret %agg.result) +// CHECK: void @f27(%struct.s27* noalias sret align 1 %agg.result) struct s26 { struct { char a, b; } a; struct { char a, b; } b; } f26(void) { while (1) {} } struct s27 { struct { char a, b, c; } a; struct { char a; } b; } f27(void) { while (1) {} } -// CHECK: void @f28(%struct.s28* noalias sret %agg.result) +// CHECK: void @f28(%struct.s28* noalias sret align 4 %agg.result) struct s28 { int a; int b[]; } f28(void) { while (1) {} } // CHECK-LABEL: define i16 @f29() @@ -150,7 +150,7 @@ struct s36 { struct { int : 0; } a[2][10]; char b; char c; } f36(void) { while ( // CHECK-LABEL: define float @f37() struct s37 { float c[1][1]; } f37(void) { while (1) {} } -// CHECK-LABEL: define void @f38(%struct.s38* noalias sret %agg.result) +// CHECK-LABEL: define void @f38(%struct.s38* noalias sret align 2 %agg.result) struct s38 { char a[3]; short b; } f38(void) { while (1) {} } // CHECK-LABEL: define void @f39(%struct.s39* byval(%struct.s39) align 16 %x) diff --git a/clang/test/CodeGen/x86_32-arguments-iamcu.c b/clang/test/CodeGen/x86_32-arguments-iamcu.c index e391c711ea101..a134f5d84a77b 100644 --- a/clang/test/CodeGen/x86_32-arguments-iamcu.c +++ b/clang/test/CodeGen/x86_32-arguments-iamcu.c @@ -58,7 +58,7 @@ st4_t retSmallStruct(st4_t r) { return r; } // CHECK-LABEL: define i64 @retPaddedStruct(i32 %r.coerce0, i32 %r.coerce1) st5_t retPaddedStruct(st5_t r) { return r; } -// CHECK-LABEL: define void @retLargeStruct(%struct.st12_t* noalias sret %agg.result, i32 %i1, %struct.st12_t* byval(%struct.st12_t) align 4 %r) +// CHECK-LABEL: define void @retLargeStruct(%struct.st12_t* noalias sret align 4 %agg.result, i32 %i1, %struct.st12_t* byval(%struct.st12_t) align 4 %r) st12_t retLargeStruct(int i1, st12_t r) { return r; } // CHECK-LABEL: define i32 @varArgs(i32 %i1, ...) diff --git a/clang/test/CodeGen/x86_64-arguments-nacl.c b/clang/test/CodeGen/x86_64-arguments-nacl.c index ea4483422dfe2..e7287a90765bd 100644 --- a/clang/test/CodeGen/x86_64-arguments-nacl.c +++ b/clang/test/CodeGen/x86_64-arguments-nacl.c @@ -61,7 +61,7 @@ void f12_1(struct s12 a0) {} // Check that sret parameter is accounted for when checking available integer // registers. -// CHECK: define void @f13(%struct.s13_0* noalias sret %agg.result, i32 %a, i32 %b, i32 %c, i32 %d, {{.*}}* byval({{.*}}) align 8 %e, i32 %f) +// CHECK: define void @f13(%struct.s13_0* noalias sret align 8 %agg.result, i32 %a, i32 %b, i32 %c, i32 %d, {{.*}}* byval({{.*}}) align 8 %e, i32 %f) struct s13_0 { long long f0[3]; }; struct s13_1 { long long f0[2]; }; diff --git a/clang/test/CodeGen/x86_64-arguments-win32.c b/clang/test/CodeGen/x86_64-arguments-win32.c index b43107c65ef64..4f7c4ded4b167 100644 --- a/clang/test/CodeGen/x86_64-arguments-win32.c +++ b/clang/test/CodeGen/x86_64-arguments-win32.c @@ -27,5 +27,5 @@ void f6(_Complex double a) {} // CHECK-LABEL: define dso_local i64 @f7() _Complex float f7() { return 1.0; } -// CHECK-LABEL: define dso_local void @f8({ double, double }* noalias sret %agg.result) +// CHECK-LABEL: define dso_local void @f8({ double, double }* noalias sret align 8 %agg.result) _Complex double f8() { return 1.0; } diff --git a/clang/test/CodeGen/x86_64-arguments.c b/clang/test/CodeGen/x86_64-arguments.c index 107571d8140bb..273b2706f10a9 100644 --- a/clang/test/CodeGen/x86_64-arguments.c +++ b/clang/test/CodeGen/x86_64-arguments.c @@ -47,7 +47,7 @@ void f7(e7 a0) { // Test merging/passing of upper eightbyte with X87 class. // -// CHECK-LABEL: define void @f8_1(%union.u8* noalias sret %agg.result) +// CHECK-LABEL: define void @f8_1(%union.u8* noalias sret align 16 %agg.result) // CHECK-LABEL: define void @f8_2(%union.u8* byval(%union.u8) align 16 %a0) union u8 { long double a; @@ -63,7 +63,7 @@ struct s9 { int a; int b; int : 0; } f9(void) { while (1) {} } struct s10 { int a; int b; int : 0; }; void f10(struct s10 a0) {} -// CHECK-LABEL: define void @f11(%union.anon* noalias sret %agg.result) +// CHECK-LABEL: define void @f11(%union.anon* noalias sret align 16 %agg.result) union { long double a; float b; } f11() { while (1) {} } // CHECK-LABEL: define i32 @f12_0() @@ -74,7 +74,7 @@ void f12_1(struct s12 a0) {} // Check that sret parameter is accounted for when checking available integer // registers. -// CHECK: define void @f13(%struct.s13_0* noalias sret %agg.result, i32 %a, i32 %b, i32 %c, i32 %d, {{.*}}* byval({{.*}}) align 8 %e, i32 %f) +// CHECK: define void @f13(%struct.s13_0* noalias sret align 8 %agg.result, i32 %a, i32 %b, i32 %c, i32 %d, {{.*}}* byval({{.*}}) align 8 %e, i32 %f) struct s13_0 { long long f0[3]; }; struct s13_1 { long long f0[2]; }; diff --git a/clang/test/CodeGenCXX/arm-cc.cpp b/clang/test/CodeGenCXX/arm-cc.cpp index 6027746b9ae80..e738cd31fb544 100644 --- a/clang/test/CodeGenCXX/arm-cc.cpp +++ b/clang/test/CodeGenCXX/arm-cc.cpp @@ -16,5 +16,5 @@ void baz() { zed(a); } -// CHECK: declare void @_Z3fooPv(%class.SMLoc* sret, i8*) +// CHECK: declare void @_Z3fooPv(%class.SMLoc* sret align 4, i8*) // CHECK: declare void @_Z3zed5SMLoc(%class.SMLoc*) diff --git a/clang/test/CodeGenCXX/builtin-source-location.cpp b/clang/test/CodeGenCXX/builtin-source-location.cpp index f8bfd7d940b91..cdc896209c85b 100644 --- a/clang/test/CodeGenCXX/builtin-source-location.cpp +++ b/clang/test/CodeGenCXX/builtin-source-location.cpp @@ -65,7 +65,7 @@ SL const_init_global = SL::current(); // // CHECK-GLOBAL-TWO: define internal void @__cxx_global_var_init() // CHECK-GLOBAL-TWO-NOT: ret -// CHECK-GLOBAL-TWO: call void @_ZN15source_location11bad_currentEjjPKcS1_(%struct.source_location* sret @runtime_init_global, +// CHECK-GLOBAL-TWO: call void @_ZN15source_location11bad_currentEjjPKcS1_(%struct.source_location* sret align 8 @runtime_init_global, // CHECK-GLOBAL-TWO-SAME: i32 1100, i32 {{[0-9]+}}, {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]], #line 1100 "test_runtime_init.cpp" SL runtime_init_global = SL::bad_current(); @@ -77,7 +77,7 @@ extern "C" void test_function() { // CHECK-LOCAL-ONE-DAG: @[[FILE:.*]] = {{.*}}c"test_current.cpp\00" // CHECK-LOCAL-ONE-DAG: @[[FUNC:.*]] = {{.*}}c"test_function\00" // -// CHECK-LOCAL-ONE: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret %local, +// CHECK-LOCAL-ONE: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret align 8 %local, // CHECK-LOCAL-ONE-SAME: i32 2100, i32 {{[0-9]+}}, // CHECK-LOCAL-ONE-SAME: {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]], #line 2100 "test_current.cpp" @@ -102,7 +102,7 @@ struct TestInit { // CHECK-CTOR-GLOBAL: define internal void @__cxx_global_var_init.{{[0-9]+}}() // CHECK-CTOR-GLOBAL-NOT: ret // -// CHECK-CTOR-GLOBAL: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret %[[TMP_ONE:[^,]*]], +// CHECK-CTOR-GLOBAL: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret align 8 %[[TMP_ONE:[^,]*]], // CHECK-CTOR-GLOBAL-SAME: i32 3400, i32 {{[0-9]+}}, {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]], // CHECK-CTOR-GLOBAL-NEXT: call void @_ZN8TestInitC1E15source_location(%struct.TestInit* @GlobalInitVal, %struct.source_location* {{.*}}%[[TMP_ONE]]) #line 3400 "GlobalInitVal.cpp" @@ -117,7 +117,7 @@ extern "C" void test_init_function() { // CHECK-CTOR-LOCAL: define void @test_init_function() // CHECK-CTOR-LOCAL-NOT: ret // -// CHECK-CTOR-LOCAL: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret %[[TMP:[^,]*]], +// CHECK-CTOR-LOCAL: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret align 8 %[[TMP:[^,]*]], // CHECK-CTOR-LOCAL-SAME: i32 3500, i32 {{[0-9]+}}, {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]], // CHECK-CTOR-LOCAL-NEXT: call void @_ZN8TestInitC1E15source_location(%struct.TestInit* %init_local, %struct.source_location* {{.*}}%[[TMP]]) #line 3500 "LocalInitVal.cpp" @@ -153,7 +153,7 @@ extern "C" void test_init_function_constexpr() { // CHECK-CONSTEXPR-LOCAL-DAG: @[[FILE:.*]] = {{.*}}c"ConstexprLocal.cpp\00" // // CHECK-CONSTEXPR-LOCAL: define void @test_init_function_constexpr() -// CHECK-CONSTEXPR-LOCAL: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret %[[TMP:[^,]*]], +// CHECK-CONSTEXPR-LOCAL: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret align 8 %[[TMP:[^,]*]], // CHECK-CONSTEXPR-LOCAL-SAME: i32 4600, i32 {{[0-9]+}}, {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]] // CHECK-CONSTEXPR-LOCAL: call void @_ZN17TestInitConstexprC1E15source_location(%struct.TestInitConstexpr* %local_val, {{.*}}%[[TMP]]) #line 4600 "ConstexprLocal.cpp" @@ -189,7 +189,7 @@ extern "C" void test_agg_init() { // // CHECK-AGG-BRACE: define void @test_agg_init() // CHECK-AGG-BRACE: %[[I2:.*]] = getelementptr inbounds %struct.TestInitAgg, %struct.TestInitAgg* %local_brace_init, i32 0, i32 1 -// CHECK-AGG-BRACE-NEXT: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret %[[I2]], +// CHECK-AGG-BRACE-NEXT: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret align 8 %[[I2]], // CHECK-AGG-BRACE-SAME: i32 5700, i32 {{[0-9]+}}, {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]] #line 5600 "BraceInitStart.cpp" TestInitAgg local_brace_init{ @@ -203,7 +203,7 @@ extern "C" void test_agg_init() { // // CHECK-AGG-EQUAL: define void @test_agg_init() // CHECK-AGG-EQUAL: %[[I2:.*]] = getelementptr inbounds %struct.TestInitAgg, %struct.TestInitAgg* %local_equal_init, i32 0, i32 1 -// CHECK-AGG-EQUAL-NEXT: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret %[[I2]], +// CHECK-AGG-EQUAL-NEXT: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret align 8 %[[I2]], // CHECK-AGG-EQUAL-SAME: i32 5900, i32 {{[0-9]+}}, {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]] #line 5800 "EqualInitStart.cpp" TestInitAgg local_equal_init = @@ -220,11 +220,11 @@ extern "C" void test_agg_init() { // CHECK-AGG-LIST: define void @test_agg_init() // // CHECK-AGG-LIST: %[[I1:.*]] = getelementptr inbounds %struct.TestInitAgg, %struct.TestInitAgg* %local_list_init, i32 0, i32 0 -// CHECK-AGG-LIST-NEXT: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret %[[I1]], +// CHECK-AGG-LIST-NEXT: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret align 8 %[[I1]], // CHECK-AGG-LIST-SAME: i32 6100, i32 {{[0-9]+}}, {{[^@]*}}@[[FILE_ELEM]], {{[^@]*}}@[[FUNC]] // // CHECK-AGG-LIST: %[[I2:.*]] = getelementptr inbounds %struct.TestInitAgg, %struct.TestInitAgg* %local_list_init, i32 0, i32 1 -// CHECK-AGG-LIST-NEXT: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret %[[I2]], +// CHECK-AGG-LIST-NEXT: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret align 8 %[[I2]], // CHECK-AGG-LIST-SAME: i32 6200, i32 {{[0-9]+}}, {{[^@]*}}@[[FILE_DEFAULT]], {{[^@]*}}@[[FUNC]] #line 6000 "InitListStart.cpp" TestInitAgg local_list_init = @@ -258,7 +258,7 @@ void test_template() { // CHECK-TEMPL-NEXT: entry: // CHECK-TEMPL-NOT: ret // -// CHECK-TEMPL: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret %[[TMP:[^,]*]], +// CHECK-TEMPL: call void @_ZN15source_location7currentEjjPKcS1_(%struct.source_location* sret align 8 %[[TMP:[^,]*]], // CHECK-TEMPL-SAME: i32 7300, i32 {{[0-9]+}}, {{[^@]*}}@[[FILE]], {{[^@]*}}@[[FUNC]] #line 7300 "local_templ.cpp" TestTemplate local_templ; diff --git a/clang/test/CodeGenCXX/call-with-static-chain.cpp b/clang/test/CodeGenCXX/call-with-static-chain.cpp index ac1149b52eddf..17e676433e1a4 100644 --- a/clang/test/CodeGenCXX/call-with-static-chain.cpp +++ b/clang/test/CodeGenCXX/call-with-static-chain.cpp @@ -25,8 +25,8 @@ void test() { // CHECK64: call i32 bitcast (i32 (i64, i64, i64, i64, i64, i64, %struct.A*)* @f1 to i32 (i8*, i64, i64, i64, i64, i64, i64, %struct.A*)*)(i8* nest bitcast (i32 (i64, i64, i64, i64, i64, i64, %struct.A*)* @f1 to i8*) __builtin_call_with_static_chain(f1(a, a, a, a), f1); - // CHECK32: call void bitcast (void (%struct.B*)* @f2 to void (%struct.B*, i8*)*)(%struct.B* sret %{{[0-9a-z]+}}, i8* nest bitcast (void (%struct.B*)* @f2 to i8*)) - // CHECK64: call void bitcast (void (%struct.B*)* @f2 to void (%struct.B*, i8*)*)(%struct.B* sret %{{[0-9a-z]+}}, i8* nest bitcast (void (%struct.B*)* @f2 to i8*)) + // CHECK32: call void bitcast (void (%struct.B*)* @f2 to void (%struct.B*, i8*)*)(%struct.B* sret align 4 %{{[0-9a-z]+}}, i8* nest bitcast (void (%struct.B*)* @f2 to i8*)) + // CHECK64: call void bitcast (void (%struct.B*)* @f2 to void (%struct.B*, i8*)*)(%struct.B* sret align 8 %{{[0-9a-z]+}}, i8* nest bitcast (void (%struct.B*)* @f2 to i8*)) __builtin_call_with_static_chain(f2(), f2); // CHECK32: call i64 bitcast (i64 ()* @f3 to i64 (i8*)*)(i8* nest bitcast (i64 ()* @f3 to i8*)) diff --git a/clang/test/CodeGenCXX/conditional-gnu-ext.cpp b/clang/test/CodeGenCXX/conditional-gnu-ext.cpp index 613dd65ee7c96..ec6d097994183 100644 --- a/clang/test/CodeGenCXX/conditional-gnu-ext.cpp +++ b/clang/test/CodeGenCXX/conditional-gnu-ext.cpp @@ -94,7 +94,7 @@ namespace test3 { B test1() { // CHECK-LABEL: define void @_ZN5test35test1Ev( // CHECK: [[TEMP:%.*]] = alloca [[B]], - // CHECK: call void @_ZN5test312test1_helperEv([[B]]* sret [[TEMP]]) + // CHECK: call void @_ZN5test312test1_helperEv([[B]]* sret align 1 [[TEMP]]) // CHECK-NEXT: [[BOOL:%.*]] = call zeroext i1 @_ZN5test31BcvbEv([[B]]* [[TEMP]]) // CHECK-NEXT: br i1 [[BOOL]] // CHECK: call void @_ZN5test31BC1ERKS0_([[B]]* [[RESULT:%.*]], [[B]]* dereferenceable({{[0-9]+}}) [[TEMP]]) @@ -115,7 +115,7 @@ namespace test3 { // CHECK-NEXT: [[T0:%.*]] = load [[B]]*, [[B]]** [[X]] // CHECK-NEXT: [[BOOL:%.*]] = call zeroext i1 @_ZN5test31BcvbEv([[B]]* [[T0]]) // CHECK-NEXT: br i1 [[BOOL]] - // CHECK: call void @_ZN5test31BcvNS_1AEEv([[A:%.*]]* sret [[RESULT:%.*]], [[B]]* [[T0]]) + // CHECK: call void @_ZN5test31BcvNS_1AEEv([[A:%.*]]* sret align 1 [[RESULT:%.*]], [[B]]* [[T0]]) // CHECK-NEXT: br label // CHECK: call void @_ZN5test31AC1Ev([[A]]* [[RESULT]]) // CHECK-NEXT: br label @@ -126,10 +126,10 @@ namespace test3 { A test3() { // CHECK-LABEL: define void @_ZN5test35test3Ev( // CHECK: [[TEMP:%.*]] = alloca [[B]], - // CHECK: call void @_ZN5test312test3_helperEv([[B]]* sret [[TEMP]]) + // CHECK: call void @_ZN5test312test3_helperEv([[B]]* sret align 1 [[TEMP]]) // CHECK-NEXT: [[BOOL:%.*]] = call zeroext i1 @_ZN5test31BcvbEv([[B]]* [[TEMP]]) // CHECK-NEXT: br i1 [[BOOL]] - // CHECK: call void @_ZN5test31BcvNS_1AEEv([[A]]* sret [[RESULT:%.*]], [[B]]* [[TEMP]]) + // CHECK: call void @_ZN5test31BcvNS_1AEEv([[A]]* sret align 1 [[RESULT:%.*]], [[B]]* [[TEMP]]) // CHECK-NEXT: br label // CHECK: call void @_ZN5test31AC1Ev([[A]]* [[RESULT]]) // CHECK-NEXT: br label diff --git a/clang/test/CodeGenCXX/cxx1z-copy-omission.cpp b/clang/test/CodeGenCXX/cxx1z-copy-omission.cpp index b33a21808175a..dd821949772a7 100644 --- a/clang/test/CodeGenCXX/cxx1z-copy-omission.cpp +++ b/clang/test/CodeGenCXX/cxx1z-copy-omission.cpp @@ -19,7 +19,7 @@ void g() { // CHECK: %[[A:.*]] = alloca // CHECK-NOT: alloca // CHECK-NOT: call - // CHECK: call {{.*}} @_Z1fv({{.*}}* sret %[[A]]) + // CHECK: call {{.*}} @_Z1fv({{.*}}* sret align 4 %[[A]]) A a = A( A{ f() } ); // CHECK-NOT: call @@ -40,7 +40,7 @@ void h() { // CHECK-NOT: alloca // CHECK-NOT: call - // CHECK: call {{.*}} @_Z1fv({{.*}}* sret %[[A]]) + // CHECK: call {{.*}} @_Z1fv({{.*}}* sret align 4 %[[A]]) // CHECK-NOT: call // CHECK: call {{.*}} @_Z1f1A({{.*}}* %[[A]]) f(f()); diff --git a/clang/test/CodeGenCXX/cxx1z-lambda-star-this.cpp b/clang/test/CodeGenCXX/cxx1z-lambda-star-this.cpp index 114791c6558b3..fc13c197076f4 100644 --- a/clang/test/CodeGenCXX/cxx1z-lambda-star-this.cpp +++ b/clang/test/CodeGenCXX/cxx1z-lambda-star-this.cpp @@ -10,7 +10,7 @@ namespace ns1 { int X = A{}.foo()(); } //end ns1 -//CHECK: @"?foo@A@@QAE?A?@@XZ"(%struct.A* %this, %class.anon* noalias sret %[[A_LAMBDA_RETVAL:.*]]) +//CHECK: @"?foo@A@@QAE?A?@@XZ"(%struct.A* %this, %class.anon* noalias sret align 8 %[[A_LAMBDA_RETVAL:.*]]) // get the first object with the closure type, which is of type 'struct.A' //CHECK: %[[I0:.+]] = getelementptr inbounds %[[A_LAMBDA]], %[[A_LAMBDA]]* %[[A_LAMBDA_RETVAL]], i32 0, i32 0 //CHECK: %[[I1:.+]] = bitcast %struct.A* %[[I0]] to i8* @@ -26,6 +26,6 @@ struct B { namespace ns2 { int X = B{}.bar()(); } -//CHECK: @"?bar@B@@QAE?A?@@XZ"(%struct.B* %this, %class.anon.0* noalias sret %agg.result) +//CHECK: @"?bar@B@@QAE?A?@@XZ"(%struct.B* %this, %class.anon.0* noalias sret align 4 %agg.result) //CHECK: %[[I20:.+]] = getelementptr inbounds %class.anon.0, %class.anon.0* %agg.result, i32 0, i32 0 //CHECK: store %struct.B* %this1, %struct.B** %[[I20]], align 4 diff --git a/clang/test/CodeGenCXX/exceptions.cpp b/clang/test/CodeGenCXX/exceptions.cpp index 302488aa568d2..da3a87a4b0da3 100644 --- a/clang/test/CodeGenCXX/exceptions.cpp +++ b/clang/test/CodeGenCXX/exceptions.cpp @@ -146,12 +146,12 @@ namespace test1 { // CHECK: [[NEW:%.*]] = call i8* @_Znwm(i64 8) // CHECK-NEXT: store i1 true, i1* [[ACTIVE]] // CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[NEW]] to [[A]]* - // CHECK-NEXT: invoke void @_ZN5test15makeBEv([[B:%.*]]* sret [[T0:%.*]]) + // CHECK-NEXT: invoke void @_ZN5test15makeBEv([[B:%.*]]* sret align 4 [[T0:%.*]]) // CHECK: [[T1:%.*]] = invoke i32 @_ZN5test11BcviEv([[B]]* [[T0]]) // CHECK: invoke void @_ZN5test11AC1Ei([[A]]* [[CAST]], i32 [[T1]]) // CHECK: store i1 false, i1* [[ACTIVE]] // CHECK-NEXT: store [[A]]* [[CAST]], [[A]]** [[X]], align 8 - // CHECK: invoke void @_ZN5test15makeBEv([[B:%.*]]* sret [[T2:%.*]]) + // CHECK: invoke void @_ZN5test15makeBEv([[B:%.*]]* sret align 4 [[T2:%.*]]) // CHECK: [[RET:%.*]] = load [[A]]*, [[A]]** [[X]], align 8 // CHECK98: invoke void @_ZN5test11BD1Ev([[B]]* [[T2]]) @@ -239,7 +239,7 @@ namespace test3 { // CHECK-NEXT: store i8* [[FOO]], i8** [[SAVED1]] // CHECK-NEXT: store i1 true, i1* [[CLEANUPACTIVE]] // CHECK-NEXT: [[CAST:%.*]] = bitcast i8* [[NEW]] to [[A]]* - // CHECK-NEXT: invoke void @_ZN5test35makeAEv([[A]]* sret [[CAST]]) + // CHECK-NEXT: invoke void @_ZN5test35makeAEv([[A]]* sret align 8 [[CAST]]) // CHECK: br label // -> cond.end new(foo(),10.0) A(makeA()) : diff --git a/clang/test/CodeGenCXX/homogeneous-aggregates.cpp b/clang/test/CodeGenCXX/homogeneous-aggregates.cpp index 05fb7f1d20a4b..51a4549d38d76 100644 --- a/clang/test/CodeGenCXX/homogeneous-aggregates.cpp +++ b/clang/test/CodeGenCXX/homogeneous-aggregates.cpp @@ -38,10 +38,10 @@ struct I2 : Base2 {}; struct I3 : Base2 {}; struct D5 : I1, I2, I3 {}; // homogeneous aggregate -// PPC: define void @_Z7func_D12D1(%struct.D1* noalias sret %agg.result, [3 x i64] %x.coerce) -// ARM32: define arm_aapcs_vfpcc void @_Z7func_D12D1(%struct.D1* noalias sret %agg.result, [3 x i64] %x.coerce) -// ARM64: define void @_Z7func_D12D1(%struct.D1* noalias sret %agg.result, %struct.D1* %x) -// X64: define dso_local x86_vectorcallcc void @"\01_Z7func_D12D1@@24"(%struct.D1* noalias sret %agg.result, %struct.D1* %x) +// PPC: define void @_Z7func_D12D1(%struct.D1* noalias sret align 8 %agg.result, [3 x i64] %x.coerce) +// ARM32: define arm_aapcs_vfpcc void @_Z7func_D12D1(%struct.D1* noalias sret align 8 %agg.result, [3 x i64] %x.coerce) +// ARM64: define void @_Z7func_D12D1(%struct.D1* noalias sret align 8 %agg.result, %struct.D1* %x) +// X64: define dso_local x86_vectorcallcc void @"\01_Z7func_D12D1@@24"(%struct.D1* noalias sret align 8 %agg.result, %struct.D1* %x) D1 CC func_D1(D1 x) { return x; } // PPC: define [3 x double] @_Z7func_D22D2([3 x double] %x.coerce) @@ -50,9 +50,9 @@ D1 CC func_D1(D1 x) { return x; } // X64: define dso_local x86_vectorcallcc %struct.D2 @"\01_Z7func_D22D2@@24"(%struct.D2 inreg %x.coerce) D2 CC func_D2(D2 x) { return x; } -// PPC: define void @_Z7func_D32D3(%struct.D3* noalias sret %agg.result, [4 x i64] %x.coerce) -// ARM32: define arm_aapcs_vfpcc void @_Z7func_D32D3(%struct.D3* noalias sret %agg.result, [4 x i64] %x.coerce) -// ARM64: define void @_Z7func_D32D3(%struct.D3* noalias sret %agg.result, %struct.D3* %x) +// PPC: define void @_Z7func_D32D3(%struct.D3* noalias sret align 8 %agg.result, [4 x i64] %x.coerce) +// ARM32: define arm_aapcs_vfpcc void @_Z7func_D32D3(%struct.D3* noalias sret align 8 %agg.result, [4 x i64] %x.coerce) +// ARM64: define void @_Z7func_D32D3(%struct.D3* noalias sret align 8 %agg.result, %struct.D3* %x) D3 CC func_D3(D3 x) { return x; } // PPC: define [4 x double] @_Z7func_D42D4([4 x double] %x.coerce) diff --git a/clang/test/CodeGenCXX/lambda-expressions.cpp b/clang/test/CodeGenCXX/lambda-expressions.cpp index 566132ad64e30..c75f84f038715 100644 --- a/clang/test/CodeGenCXX/lambda-expressions.cpp +++ b/clang/test/CodeGenCXX/lambda-expressions.cpp @@ -194,8 +194,8 @@ namespace pr28595 { // CHECK-NEXT: call i32 @"_ZZ1fvENK3$_6clEii" // CHECK-NEXT: ret i32 -// CHECK-LABEL: define internal void @"_ZZ1hvEN4$_118__invokeEv"(%struct.A* noalias sret %agg.result) {{.*}} { -// CHECK: call void @"_ZZ1hvENK4$_11clEv"(%struct.A* sret %agg.result, +// CHECK-LABEL: define internal void @"_ZZ1hvEN4$_118__invokeEv"(%struct.A* noalias sret align 1 %agg.result) {{.*}} { +// CHECK: call void @"_ZZ1hvENK4$_11clEv"(%struct.A* sret align 1 %agg.result, // CHECK-NEXT: ret void struct A { ~A(); }; void h() { diff --git a/clang/test/CodeGenCXX/microsoft-abi-byval-sret.cpp b/clang/test/CodeGenCXX/microsoft-abi-byval-sret.cpp index 2c940d22010bd..a92049c3a7996 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-byval-sret.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-byval-sret.cpp @@ -49,7 +49,7 @@ A B::qux(A x) { } // CHECK-LABEL: define dso_local x86_fastcallcc void @"?qux@B@@QAI?AUA@@U2@@Z" -// CHECK: (%struct.B* inreg %this, %struct.A* inreg noalias sret %agg.result, <{ %struct.A }>* inalloca %0) +// CHECK: (%struct.B* inreg %this, %struct.A* inreg noalias sret align 4 %agg.result, <{ %struct.A }>* inalloca %0) // CHECK: ret void int main() { @@ -67,4 +67,4 @@ int main() { // CHECK: call x86_stdcallcc %struct.A* @"?baz@B@@QAG?AUA@@U2@@Z" // CHECK: (<{ %struct.B*, %struct.A*, %struct.A }>* inalloca %{{[^,]*}}) // CHECK: call x86_fastcallcc void @"?qux@B@@QAI?AUA@@U2@@Z" -// CHECK: (%struct.B* inreg %{{[^,]*}}, %struct.A* inreg sret %{{.*}}, <{ %struct.A }>* inalloca %{{[^,]*}}) +// CHECK: (%struct.B* inreg %{{[^,]*}}, %struct.A* inreg sret align 4 %{{.*}}, <{ %struct.A }>* inalloca %{{[^,]*}}) diff --git a/clang/test/CodeGenCXX/microsoft-abi-byval-thunks.cpp b/clang/test/CodeGenCXX/microsoft-abi-byval-thunks.cpp index ed4e1fbb36fdb..0ca68cccb7906 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-byval-thunks.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-byval-thunks.cpp @@ -86,10 +86,10 @@ C::C() {} // force emission // CHECK32-NEXT: ret %"struct.sret_thunk::Agg"* %[[rv]] // CHECK64-LABEL: define linkonce_odr dso_local void @"?foo@C@sret_thunk@@W7EAA?AUAgg@2@U32@@Z" -// CHECK64: (%"struct.sret_thunk::C"* %this, %"struct.sret_thunk::Agg"* noalias sret %agg.result, %"struct.sret_thunk::Agg"* %x) +// CHECK64: (%"struct.sret_thunk::C"* %this, %"struct.sret_thunk::Agg"* noalias sret align 4 %agg.result, %"struct.sret_thunk::Agg"* %x) // CHECK64: getelementptr i8, i8* %{{.*}}, i32 -8 // CHECK64: call void @"?foo@C@sret_thunk@@UEAA?AUAgg@2@U32@@Z" -// CHECK64: (%"struct.sret_thunk::C"* %{{.*}}, %"struct.sret_thunk::Agg"* sret %agg.result, %"struct.sret_thunk::Agg"* %x) +// CHECK64: (%"struct.sret_thunk::C"* %{{.*}}, %"struct.sret_thunk::Agg"* sret align 4 %agg.result, %"struct.sret_thunk::Agg"* %x) // CHECK64-NOT: call // CHECK64: ret void } diff --git a/clang/test/CodeGenCXX/microsoft-abi-cdecl-method-sret.cpp b/clang/test/CodeGenCXX/microsoft-abi-cdecl-method-sret.cpp index 5a8bdf78100f4..534aa7f804695 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-cdecl-method-sret.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-cdecl-method-sret.cpp @@ -19,9 +19,9 @@ S C::variadic_sret(const char *f, ...) { return S(); } S C::cdecl_sret() { return S(); } S C::byval_and_sret(S a) { return S(); } -// CHECK: define dso_local void @"?variadic_sret@C@@QAA?AUS@@PBDZZ"(%struct.C* %this, %struct.S* noalias sret %agg.result, i8* %f, ...) -// CHECK: define dso_local void @"?cdecl_sret@C@@QAA?AUS@@XZ"(%struct.C* %this, %struct.S* noalias sret %agg.result) -// CHECK: define dso_local void @"?byval_and_sret@C@@QAA?AUS@@U2@@Z"(%struct.C* %this, %struct.S* noalias sret %agg.result, %struct.S* byval(%struct.S) align 4 %a) +// CHECK: define dso_local void @"?variadic_sret@C@@QAA?AUS@@PBDZZ"(%struct.C* %this, %struct.S* noalias sret align 4 %agg.result, i8* %f, ...) +// CHECK: define dso_local void @"?cdecl_sret@C@@QAA?AUS@@XZ"(%struct.C* %this, %struct.S* noalias sret align 4 %agg.result) +// CHECK: define dso_local void @"?byval_and_sret@C@@QAA?AUS@@U2@@Z"(%struct.C* %this, %struct.S* noalias sret align 4 %agg.result, %struct.S* byval(%struct.S) align 4 %a) int main() { C c; @@ -41,4 +41,4 @@ struct A { S A::f(int x) { return S(); } -// CHECK-LABEL: define dso_local x86_fastcallcc void @"?f@A@@QAI?AUS@@H@Z"(%struct.A* inreg %this, %struct.S* inreg noalias sret %agg.result, i32 %x) +// CHECK-LABEL: define dso_local x86_fastcallcc void @"?f@A@@QAI?AUS@@H@Z"(%struct.A* inreg %this, %struct.S* inreg noalias sret align 4 %agg.result, i32 %x) diff --git a/clang/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp b/clang/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp index 7e8619b8b0ecf..60fa5c7991119 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-eh-cleanups.cpp @@ -18,9 +18,9 @@ void HasEHCleanup() { // WIN32-LABEL: define dso_local void @"?HasEHCleanup@@YAXXZ"() {{.*}} { // WIN32: %[[base:.*]] = call i8* @llvm.stacksave() // If this call throws, we have to restore the stack. -// WIN32: call void @"?getA@@YA?AUA@@XZ"(%struct.A* sret %{{.*}}) +// WIN32: call void @"?getA@@YA?AUA@@XZ"(%struct.A* sret align 4 %{{.*}}) // If this call throws, we have to cleanup the first temporary. -// WIN32: invoke void @"?getA@@YA?AUA@@XZ"(%struct.A* sret %{{.*}}) +// WIN32: invoke void @"?getA@@YA?AUA@@XZ"(%struct.A* sret align 4 %{{.*}}) // If this call throws, we have to cleanup the stacksave. // WIN32: call i32 @"?TakesTwo@@YAHUA@@0@Z" // WIN32: call void @llvm.stackrestore diff --git a/clang/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp b/clang/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp index 9fb9f39cb0832..8c8d4b7383d63 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-sret-and-byval.cpp @@ -84,45 +84,45 @@ void call_bools_and_chars() { // Returning structs that fit into a register. Small small_return() { return Small(); } -// LINUX-LABEL: define void @_Z12small_returnv(%struct.Small* noalias sret %agg.result) +// LINUX-LABEL: define void @_Z12small_returnv(%struct.Small* noalias sret align 4 %agg.result) // WIN32: define dso_local i32 @"?small_return@@YA?AUSmall@@XZ"() // WIN64: define dso_local i32 @"?small_return@@YA?AUSmall@@XZ"() Medium medium_return() { return Medium(); } -// LINUX-LABEL: define void @_Z13medium_returnv(%struct.Medium* noalias sret %agg.result) +// LINUX-LABEL: define void @_Z13medium_returnv(%struct.Medium* noalias sret align 4 %agg.result) // WIN32: define dso_local i64 @"?medium_return@@YA?AUMedium@@XZ"() // WIN64: define dso_local i64 @"?medium_return@@YA?AUMedium@@XZ"() // Returning structs that fit into a register but are not POD. SmallCpp11NotCpp03Pod small_non_pod_return() { return SmallCpp11NotCpp03Pod(); } -// LINUX-LABEL: define void @_Z20small_non_pod_returnv(%struct.SmallCpp11NotCpp03Pod* noalias sret %agg.result) -// WIN32: define dso_local void @"?small_non_pod_return@@YA?AUSmallCpp11NotCpp03Pod@@XZ"(%struct.SmallCpp11NotCpp03Pod* noalias sret %agg.result) -// WIN64: define dso_local void @"?small_non_pod_return@@YA?AUSmallCpp11NotCpp03Pod@@XZ"(%struct.SmallCpp11NotCpp03Pod* noalias sret %agg.result) +// LINUX-LABEL: define void @_Z20small_non_pod_returnv(%struct.SmallCpp11NotCpp03Pod* noalias sret align 4 %agg.result) +// WIN32: define dso_local void @"?small_non_pod_return@@YA?AUSmallCpp11NotCpp03Pod@@XZ"(%struct.SmallCpp11NotCpp03Pod* noalias sret align 4 %agg.result) +// WIN64: define dso_local void @"?small_non_pod_return@@YA?AUSmallCpp11NotCpp03Pod@@XZ"(%struct.SmallCpp11NotCpp03Pod* noalias sret align 4 %agg.result) SmallWithCtor small_with_ctor_return() { return SmallWithCtor(); } -// LINUX-LABEL: define void @_Z22small_with_ctor_returnv(%struct.SmallWithCtor* noalias sret %agg.result) -// WIN32: define dso_local void @"?small_with_ctor_return@@YA?AUSmallWithCtor@@XZ"(%struct.SmallWithCtor* noalias sret %agg.result) -// WIN64: define dso_local void @"?small_with_ctor_return@@YA?AUSmallWithCtor@@XZ"(%struct.SmallWithCtor* noalias sret %agg.result) +// LINUX-LABEL: define void @_Z22small_with_ctor_returnv(%struct.SmallWithCtor* noalias sret align 4 %agg.result) +// WIN32: define dso_local void @"?small_with_ctor_return@@YA?AUSmallWithCtor@@XZ"(%struct.SmallWithCtor* noalias sret align 4 %agg.result) +// WIN64: define dso_local void @"?small_with_ctor_return@@YA?AUSmallWithCtor@@XZ"(%struct.SmallWithCtor* noalias sret align 4 %agg.result) // FIXME: The 'sret' mark here doesn't seem to be enough to convince LLVM to // preserve the hidden sret pointer in R0 across the function. -// WOA: define dso_local arm_aapcs_vfpcc void @"?small_with_ctor_return@@YA?AUSmallWithCtor@@XZ"(%struct.SmallWithCtor* noalias sret %agg.result) +// WOA: define dso_local arm_aapcs_vfpcc void @"?small_with_ctor_return@@YA?AUSmallWithCtor@@XZ"(%struct.SmallWithCtor* noalias sret align 4 %agg.result) SmallWithVftable small_with_vftable_return() { return SmallWithVftable(); } -// LINUX-LABEL: define void @_Z25small_with_vftable_returnv(%struct.SmallWithVftable* noalias sret %agg.result) -// WIN32: define dso_local void @"?small_with_vftable_return@@YA?AUSmallWithVftable@@XZ"(%struct.SmallWithVftable* noalias sret %agg.result) -// WIN64: define dso_local void @"?small_with_vftable_return@@YA?AUSmallWithVftable@@XZ"(%struct.SmallWithVftable* noalias sret %agg.result) +// LINUX-LABEL: define void @_Z25small_with_vftable_returnv(%struct.SmallWithVftable* noalias sret align 4 %agg.result) +// WIN32: define dso_local void @"?small_with_vftable_return@@YA?AUSmallWithVftable@@XZ"(%struct.SmallWithVftable* noalias sret align 4 %agg.result) +// WIN64: define dso_local void @"?small_with_vftable_return@@YA?AUSmallWithVftable@@XZ"(%struct.SmallWithVftable* noalias sret align 8 %agg.result) MediumWithCopyCtor medium_with_copy_ctor_return() { return MediumWithCopyCtor(); } -// LINUX-LABEL: define void @_Z28medium_with_copy_ctor_returnv(%struct.MediumWithCopyCtor* noalias sret %agg.result) -// WIN32: define dso_local void @"?medium_with_copy_ctor_return@@YA?AUMediumWithCopyCtor@@XZ"(%struct.MediumWithCopyCtor* noalias sret %agg.result) -// WIN64: define dso_local void @"?medium_with_copy_ctor_return@@YA?AUMediumWithCopyCtor@@XZ"(%struct.MediumWithCopyCtor* noalias sret %agg.result) -// WOA: define dso_local arm_aapcs_vfpcc void @"?medium_with_copy_ctor_return@@YA?AUMediumWithCopyCtor@@XZ"(%struct.MediumWithCopyCtor* noalias sret %agg.result) +// LINUX-LABEL: define void @_Z28medium_with_copy_ctor_returnv(%struct.MediumWithCopyCtor* noalias sret align 4 %agg.result) +// WIN32: define dso_local void @"?medium_with_copy_ctor_return@@YA?AUMediumWithCopyCtor@@XZ"(%struct.MediumWithCopyCtor* noalias sret align 4 %agg.result) +// WIN64: define dso_local void @"?medium_with_copy_ctor_return@@YA?AUMediumWithCopyCtor@@XZ"(%struct.MediumWithCopyCtor* noalias sret align 4 %agg.result) +// WOA: define dso_local arm_aapcs_vfpcc void @"?medium_with_copy_ctor_return@@YA?AUMediumWithCopyCtor@@XZ"(%struct.MediumWithCopyCtor* noalias sret align 4 %agg.result) // Returning a large struct that doesn't fit into a register. Big big_return() { return Big(); } -// LINUX-LABEL: define void @_Z10big_returnv(%struct.Big* noalias sret %agg.result) -// WIN32: define dso_local void @"?big_return@@YA?AUBig@@XZ"(%struct.Big* noalias sret %agg.result) -// WIN64: define dso_local void @"?big_return@@YA?AUBig@@XZ"(%struct.Big* noalias sret %agg.result) +// LINUX-LABEL: define void @_Z10big_returnv(%struct.Big* noalias sret align 4 %agg.result) +// WIN32: define dso_local void @"?big_return@@YA?AUBig@@XZ"(%struct.Big* noalias sret align 4 %agg.result) +// WIN64: define dso_local void @"?big_return@@YA?AUBig@@XZ"(%struct.Big* noalias sret align 4 %agg.result) void small_arg(Small s) {} @@ -181,7 +181,7 @@ void small_arg_with_dtor(SmallWithDtor s) {} // Test that the eligible non-aggregate is passed directly, but returned // indirectly on ARM64 Windows. -// WOA64: define dso_local void @"?small_arg_with_private_member@@YA?AUSmallWithPrivate@@U1@@Z"(%struct.SmallWithPrivate* inreg noalias sret %agg.result, i64 %s.coerce) {{.*}} { +// WOA64: define dso_local void @"?small_arg_with_private_member@@YA?AUSmallWithPrivate@@U1@@Z"(%struct.SmallWithPrivate* inreg noalias sret align 4 %agg.result, i64 %s.coerce) {{.*}} { SmallWithPrivate small_arg_with_private_member(SmallWithPrivate s) { return s; } void call_small_arg_with_dtor() { @@ -281,24 +281,24 @@ void pass_ref_field() { class Class { public: Small thiscall_method_small() { return Small(); } - // LINUX: define {{.*}} void @_ZN5Class21thiscall_method_smallEv(%struct.Small* noalias sret %agg.result, %class.Class* %this) - // WIN32: define {{.*}} x86_thiscallcc void @"?thiscall_method_small@Class@@QAE?AUSmall@@XZ"(%class.Class* %this, %struct.Small* noalias sret %agg.result) - // WIN64: define linkonce_odr dso_local void @"?thiscall_method_small@Class@@QEAA?AUSmall@@XZ"(%class.Class* %this, %struct.Small* noalias sret %agg.result) + // LINUX: define {{.*}} void @_ZN5Class21thiscall_method_smallEv(%struct.Small* noalias sret align 4 %agg.result, %class.Class* %this) + // WIN32: define {{.*}} x86_thiscallcc void @"?thiscall_method_small@Class@@QAE?AUSmall@@XZ"(%class.Class* %this, %struct.Small* noalias sret align 4 %agg.result) + // WIN64: define linkonce_odr dso_local void @"?thiscall_method_small@Class@@QEAA?AUSmall@@XZ"(%class.Class* %this, %struct.Small* noalias sret align 4 %agg.result) SmallWithCtor thiscall_method_small_with_ctor() { return SmallWithCtor(); } - // LINUX: define {{.*}} void @_ZN5Class31thiscall_method_small_with_ctorEv(%struct.SmallWithCtor* noalias sret %agg.result, %class.Class* %this) - // WIN32: define {{.*}} x86_thiscallcc void @"?thiscall_method_small_with_ctor@Class@@QAE?AUSmallWithCtor@@XZ"(%class.Class* %this, %struct.SmallWithCtor* noalias sret %agg.result) - // WIN64: define linkonce_odr dso_local void @"?thiscall_method_small_with_ctor@Class@@QEAA?AUSmallWithCtor@@XZ"(%class.Class* %this, %struct.SmallWithCtor* noalias sret %agg.result) + // LINUX: define {{.*}} void @_ZN5Class31thiscall_method_small_with_ctorEv(%struct.SmallWithCtor* noalias sret align 4 %agg.result, %class.Class* %this) + // WIN32: define {{.*}} x86_thiscallcc void @"?thiscall_method_small_with_ctor@Class@@QAE?AUSmallWithCtor@@XZ"(%class.Class* %this, %struct.SmallWithCtor* noalias sret align 4 %agg.result) + // WIN64: define linkonce_odr dso_local void @"?thiscall_method_small_with_ctor@Class@@QEAA?AUSmallWithCtor@@XZ"(%class.Class* %this, %struct.SmallWithCtor* noalias sret align 4 %agg.result) Small __cdecl cdecl_method_small() { return Small(); } - // LINUX: define {{.*}} void @_ZN5Class18cdecl_method_smallEv(%struct.Small* noalias sret %agg.result, %class.Class* %this) - // WIN32: define {{.*}} void @"?cdecl_method_small@Class@@QAA?AUSmall@@XZ"(%class.Class* %this, %struct.Small* noalias sret %agg.result) - // WIN64: define linkonce_odr dso_local void @"?cdecl_method_small@Class@@QEAA?AUSmall@@XZ"(%class.Class* %this, %struct.Small* noalias sret %agg.result) + // LINUX: define {{.*}} void @_ZN5Class18cdecl_method_smallEv(%struct.Small* noalias sret align 4 %agg.result, %class.Class* %this) + // WIN32: define {{.*}} void @"?cdecl_method_small@Class@@QAA?AUSmall@@XZ"(%class.Class* %this, %struct.Small* noalias sret align 4 %agg.result) + // WIN64: define linkonce_odr dso_local void @"?cdecl_method_small@Class@@QEAA?AUSmall@@XZ"(%class.Class* %this, %struct.Small* noalias sret align 4 %agg.result) Big __cdecl cdecl_method_big() { return Big(); } - // LINUX: define {{.*}} void @_ZN5Class16cdecl_method_bigEv(%struct.Big* noalias sret %agg.result, %class.Class* %this) - // WIN32: define {{.*}} void @"?cdecl_method_big@Class@@QAA?AUBig@@XZ"(%class.Class* %this, %struct.Big* noalias sret %agg.result) - // WIN64: define linkonce_odr dso_local void @"?cdecl_method_big@Class@@QEAA?AUBig@@XZ"(%class.Class* %this, %struct.Big* noalias sret %agg.result) + // LINUX: define {{.*}} void @_ZN5Class16cdecl_method_bigEv(%struct.Big* noalias sret align 4 %agg.result, %class.Class* %this) + // WIN32: define {{.*}} void @"?cdecl_method_big@Class@@QAA?AUBig@@XZ"(%class.Class* %this, %struct.Big* noalias sret align 4 %agg.result) + // WIN64: define linkonce_odr dso_local void @"?cdecl_method_big@Class@@QEAA?AUBig@@XZ"(%class.Class* %this, %struct.Big* noalias sret align 4 %agg.result) void thiscall_method_arg(Empty s) {} // LINUX: define {{.*}} void @_ZN5Class19thiscall_method_argE5Empty(%class.Class* %this) diff --git a/clang/test/CodeGenCXX/microsoft-abi-vmemptr-conflicts.cpp b/clang/test/CodeGenCXX/microsoft-abi-vmemptr-conflicts.cpp index 607ec816aefb5..1ab60a5261287 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-vmemptr-conflicts.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-vmemptr-conflicts.cpp @@ -65,7 +65,7 @@ void f(C *c) { // CHECK-LABEL: define dso_local void @"?f@sret@@YAXPAUC@1@@Z"(%"struct.sret::C"* %c) // CHECK: call x86_thiscallcc i32 bitcast (void (%"struct.sret::C"*, ...)* @"??_9C@sret@@$BA@AE" to i32 (%"struct.sret::C"*)*)(%"struct.sret::C"* %{{.*}}) -// CHECK: call x86_thiscallcc void bitcast (void (%"struct.sret::C"*, ...)* @"??_9C@sret@@$BA@AE" to void (%"struct.sret::C"*, %"struct.sret::Big"*)*)(%"struct.sret::C"* %{{.*}}, %"struct.sret::Big"* sret %{{.*}}) +// CHECK: call x86_thiscallcc void bitcast (void (%"struct.sret::C"*, ...)* @"??_9C@sret@@$BA@AE" to void (%"struct.sret::C"*, %"struct.sret::Big"*)*)(%"struct.sret::C"* %{{.*}}, %"struct.sret::Big"* sret align 4 %{{.*}}) // CHECK-LABEL: define linkonce_odr x86_thiscallcc void @"??_9C@sret@@$BA@AE"(%"struct.sret::C"* %this, ...) {{.*}} comdat // CHECK: musttail call x86_thiscallcc void (%"struct.sret::C"*, ...) %{{.*}}(%"struct.sret::C"* %{{.*}}, ...) diff --git a/clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp b/clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp index 9e2c10d8a3337..d219e8f5a351e 100644 --- a/clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp +++ b/clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp @@ -168,8 +168,8 @@ typedef void (Derived0::*MethodTy1)(); // Check that the sret pointer passed to the caller is forwarded to the musttail // call. -// CHECK: define linkonce_odr hidden void @_ZN8Derived04sretEv_vfpthunk_(%[[STRUCT_A1]]* noalias sret %[[AGG_RESULT:.*]], %[[STRUCT_DERIVED0]]* %{{.*}}) -// CHECK: musttail call void %{{.*}}(%[[STRUCT_A1]]* sret %[[AGG_RESULT]], %[[STRUCT_DERIVED0]]* %{{.*}}) [ "ptrauth"(i32 0, i64 %{{.*}}) ] +// CHECK: define linkonce_odr hidden void @_ZN8Derived04sretEv_vfpthunk_(%[[STRUCT_A1]]* noalias sret align 4 %[[AGG_RESULT:.*]], %[[STRUCT_DERIVED0]]* %{{.*}}) +// CHECK: musttail call void %{{.*}}(%[[STRUCT_A1]]* sret align 4 %[[AGG_RESULT]], %[[STRUCT_DERIVED0]]* %{{.*}}) [ "ptrauth"(i32 0, i64 %{{.*}}) ] // CHECK-NEXT: ret void // Check that the thunk function doesn't destruct the trivial_abi argument. diff --git a/clang/test/CodeGenCXX/regcall.cpp b/clang/test/CodeGenCXX/regcall.cpp index bdf76964bf231..9eca868fc31d2 100644 --- a/clang/test/CodeGenCXX/regcall.cpp +++ b/clang/test/CodeGenCXX/regcall.cpp @@ -74,8 +74,8 @@ bool __regcall operator ==(const test_class&, const test_class&){ --x; return fa // CHECK-WIN32-DAG: define dso_local x86_regcallcc zeroext i1 @"??8@Yw_NABVtest_class@@0@Z" test_class __regcall operator""_test_class (unsigned long long) { ++x; return test_class{};} -// CHECK-LIN64-DAG: define x86_regcallcc void @_Zli11_test_classy(%class.test_class* noalias sret %agg.result, i64 %0) -// CHECK-LIN32-DAG: define x86_regcallcc void @_Zli11_test_classy(%class.test_class* inreg noalias sret %agg.result, i64 %0) +// CHECK-LIN64-DAG: define x86_regcallcc void @_Zli11_test_classy(%class.test_class* noalias sret align 4 %agg.result, i64 %0) +// CHECK-LIN32-DAG: define x86_regcallcc void @_Zli11_test_classy(%class.test_class* inreg noalias sret align 4 %agg.result, i64 %0) // CHECK-WIN64-DAG: ??__K_test_class@@Yw?AVtest_class@@_K@Z" // CHECK-WIN32-DAG: ??__K_test_class@@Yw?AVtest_class@@_K@Z" @@ -99,7 +99,7 @@ void force_gen() { long double _Complex __regcall foo(long double _Complex f) { return f; } -// CHECK-LIN64-DAG: define x86_regcallcc void @_Z15__regcall3__fooCe({ x86_fp80, x86_fp80 }* noalias sret %agg.result, { x86_fp80, x86_fp80 }* byval({ x86_fp80, x86_fp80 }) align 16 %f) -// CHECK-LIN32-DAG: define x86_regcallcc void @_Z15__regcall3__fooCe({ x86_fp80, x86_fp80 }* inreg noalias sret %agg.result, { x86_fp80, x86_fp80 }* byval({ x86_fp80, x86_fp80 }) align 4 %f) +// CHECK-LIN64-DAG: define x86_regcallcc void @_Z15__regcall3__fooCe({ x86_fp80, x86_fp80 }* noalias sret align 16 %agg.result, { x86_fp80, x86_fp80 }* byval({ x86_fp80, x86_fp80 }) align 16 %f) +// CHECK-LIN32-DAG: define x86_regcallcc void @_Z15__regcall3__fooCe({ x86_fp80, x86_fp80 }* inreg noalias sret align 4 %agg.result, { x86_fp80, x86_fp80 }* byval({ x86_fp80, x86_fp80 }) align 4 %f) // CHECK-WIN64-DAG: define dso_local x86_regcallcc { double, double } @"?foo@@YwU?$_Complex@O@__clang@@U12@@Z"(double %f.0, double %f.1) // CHECK-WIN32-DAG: define dso_local x86_regcallcc { double, double } @"?foo@@YwU?$_Complex@O@__clang@@U12@@Z"(double %f.0, double %f.1) diff --git a/clang/test/CodeGenCXX/stack-reuse-miscompile.cpp b/clang/test/CodeGenCXX/stack-reuse-miscompile.cpp index 4e824d94f510e..7d86ea8447b41 100644 --- a/clang/test/CodeGenCXX/stack-reuse-miscompile.cpp +++ b/clang/test/CodeGenCXX/stack-reuse-miscompile.cpp @@ -39,7 +39,7 @@ const char * f(S s) // CHECK: call void @llvm.lifetime.start.p0i8(i64 16, i8* [[T3i8]]) // CHECK: [[T5:%.*]] = call %class.T* @_ZN1TC1E1S(%class.T* [[T3]], [2 x i32] %{{.*}}) // -// CHECK: call void @_ZNK1T6concatERKS_(%class.T* sret [[T1]], %class.T* [[T2]], %class.T* dereferenceable(16) [[T3]]) +// CHECK: call void @_ZNK1T6concatERKS_(%class.T* sret align 4 [[T1]], %class.T* [[T2]], %class.T* dereferenceable(16) [[T3]]) // CHECK: [[T6:%.*]] = call i8* @_ZNK1T3strEv(%class.T* [[T1]]) // // CHECK: call void @llvm.lifetime.end.p0i8( diff --git a/clang/test/CodeGenCXX/stack-reuse.cpp b/clang/test/CodeGenCXX/stack-reuse.cpp index 35dcb5b349c3e..94e5e3d9b364b 100644 --- a/clang/test/CodeGenCXX/stack-reuse.cpp +++ b/clang/test/CodeGenCXX/stack-reuse.cpp @@ -135,7 +135,7 @@ int large_combiner_test(S_large s) { // CHECK: [[T2:%.*]] = alloca %struct.Combiner // CHECK: [[T1:%.*]] = alloca %struct.Combiner // CHECK: [[T3:%.*]] = call %struct.Combiner* @_ZN8CombinerC1E7S_large(%struct.Combiner* nonnull [[T1]], [9 x i32] %s.coerce) -// CHECK: call void @_ZN8Combiner1fEv(%struct.Combiner* nonnull sret [[T2]], %struct.Combiner* nonnull [[T1]]) +// CHECK: call void @_ZN8Combiner1fEv(%struct.Combiner* nonnull sret align 4 [[T2]], %struct.Combiner* nonnull [[T1]]) // CHECK: [[T4:%.*]] = getelementptr inbounds %struct.Combiner, %struct.Combiner* [[T2]], i32 0, i32 0, i32 0, i32 0 // CHECK: [[T5:%.*]] = load i32, i32* [[T4]] // CHECK: ret i32 [[T5]] diff --git a/clang/test/CodeGenCXX/temporaries.cpp b/clang/test/CodeGenCXX/temporaries.cpp index d15e0fa05bd86..175b475c8cd7f 100644 --- a/clang/test/CodeGenCXX/temporaries.cpp +++ b/clang/test/CodeGenCXX/temporaries.cpp @@ -403,13 +403,13 @@ namespace Elision { // CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[I]]) A i = (foo(), A()); - // CHECK-NEXT: call void @_ZN7Elision4fooAEv([[A]]* sret [[T0]]) + // CHECK-NEXT: call void @_ZN7Elision4fooAEv([[A]]* sret align 8 [[T0]]) // CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[J]]) // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[T0]]) A j = (fooA(), A()); // CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[T1]]) - // CHECK-NEXT: call void @_ZN7Elision4fooAEv([[A]]* sret [[K]]) + // CHECK-NEXT: call void @_ZN7Elision4fooAEv([[A]]* sret align 8 [[K]]) // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[T1]]) A k = (A(), fooA()); @@ -436,7 +436,7 @@ namespace Elision { // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[I]]) } - // CHECK: define void @_ZN7Elision5test2Ev([[A]]* noalias sret + // CHECK: define void @_ZN7Elision5test2Ev([[A]]* noalias sret align 8 A test2() { // CHECK: call void @_ZN7Elision3fooEv() // CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[RET:%.*]]) @@ -444,7 +444,7 @@ namespace Elision { return (foo(), A()); } - // CHECK: define void @_ZN7Elision5test3EiNS_1AE([[A]]* noalias sret + // CHECK: define void @_ZN7Elision5test3EiNS_1AE([[A]]* noalias sret align 8 A test3(int v, A x) { if (v < 5) // CHECK: call void @_ZN7Elision1AC1Ev([[A]]* [[RET:%.*]]) @@ -485,7 +485,7 @@ namespace Elision { } // rdar://problem/8433352 - // CHECK: define void @_ZN7Elision5test5Ev([[A]]* noalias sret + // CHECK: define void @_ZN7Elision5test5Ev([[A]]* noalias sret align 8 struct B { A a; B(); }; A test5() { // CHECK: [[AT0:%.*]] = alloca [[A]], align 8 @@ -523,7 +523,7 @@ namespace Elision { void test6(const C *x) { // CHECK: [[T0:%.*]] = alloca [[A]], align 8 // CHECK: [[X:%.*]] = load [[C]]*, [[C]]** {{%.*}}, align 8 - // CHECK-NEXT: call void @_ZNK7Elision1CcvNS_1AEEv([[A]]* sret [[T0]], [[C]]* [[X]]) + // CHECK-NEXT: call void @_ZNK7Elision1CcvNS_1AEEv([[A]]* sret align 8 [[T0]], [[C]]* [[X]]) // CHECK-NEXT: call void @_ZNK7Elision1A3fooEv([[A]]* [[T0]]) // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[T0]]) // CHECK-NEXT: ret void diff --git a/clang/test/CodeGenCXX/thiscall-struct-return.cpp b/clang/test/CodeGenCXX/thiscall-struct-return.cpp index a6be5aa494e1b..35d5cc479177a 100644 --- a/clang/test/CodeGenCXX/thiscall-struct-return.cpp +++ b/clang/test/CodeGenCXX/thiscall-struct-return.cpp @@ -34,8 +34,8 @@ void test( void ) { // CHECK: call void @_ZN1CC1Ev(%class.C* [[C:%.+]]) C c; -// CHECK: call x86_thiscallcc void @_ZNK1C5SmallEv(%struct.S* sret %{{.+}}, %class.C* [[C]]) +// CHECK: call x86_thiscallcc void @_ZNK1C5SmallEv(%struct.S* sret align 4 %{{.+}}, %class.C* [[C]]) (void)c.Small(); -// CHECK: call x86_thiscallcc void @_ZNK1C6MediumEv(%struct.M* sret %{{.+}}, %class.C* [[C]]) +// CHECK: call x86_thiscallcc void @_ZNK1C6MediumEv(%struct.M* sret align 4 %{{.+}}, %class.C* [[C]]) (void)c.Medium(); } diff --git a/clang/test/CodeGenCXX/thunk-returning-memptr.cpp b/clang/test/CodeGenCXX/thunk-returning-memptr.cpp index 0b7870c6d6582..63bb3d68472d7 100644 --- a/clang/test/CodeGenCXX/thunk-returning-memptr.cpp +++ b/clang/test/CodeGenCXX/thunk-returning-memptr.cpp @@ -23,5 +23,5 @@ C::C() {} // Because of the tail call, the return value cannot be copied into a local // alloca. (PR39901) -// CHECK-LABEL: define linkonce_odr void @_ZThn4_N1C1fEv({ i32, i32 }* noalias sret %agg.result, %struct.C* %this) -// CHECK: tail call void @_ZN1C1fEv({ i32, i32 }* sret %agg.result +// CHECK-LABEL: define linkonce_odr void @_ZThn4_N1C1fEv({ i32, i32 }* noalias sret align 4 %agg.result, %struct.C* %this) +// CHECK: tail call void @_ZN1C1fEv({ i32, i32 }* sret align 4 %agg.result diff --git a/clang/test/CodeGenCXX/thunks.cpp b/clang/test/CodeGenCXX/thunks.cpp index fe7d656eb7e52..b5c2852f87703 100644 --- a/clang/test/CodeGenCXX/thunks.cpp +++ b/clang/test/CodeGenCXX/thunks.cpp @@ -206,13 +206,13 @@ namespace Test6 { // CHECK-LABEL: define void @_ZThn16_N5Test66Thunks1fEv // CHECK-DBG-NOT: dbg.declare // CHECK-NOT: memcpy - // CHECK: {{call void @_ZN5Test66Thunks1fEv.*sret}} + // CHECK: {{call void @_ZN5Test66Thunks1fEv.*sret align 1}} // CHECK: ret void X Thunks::f() { return X(); } - // WIN64-LABEL: define linkonce_odr dso_local void @"?f@Thunks@Test6@@WBA@EAA?AUX@2@XZ"({{.*}} sret %{{.*}}) + // WIN64-LABEL: define linkonce_odr dso_local void @"?f@Thunks@Test6@@WBA@EAA?AUX@2@XZ"({{.*}} sret align 1 %{{.*}}) // WIN64-NOT: memcpy - // WIN64: tail call void @"?f@Thunks@Test6@@UEAA?AUX@2@XZ"({{.*}} sret %{{.*}}) + // WIN64: tail call void @"?f@Thunks@Test6@@UEAA?AUX@2@XZ"({{.*}} sret align 1 %{{.*}}) } namespace Test7 { diff --git a/clang/test/CodeGenCXX/trivial_abi.cpp b/clang/test/CodeGenCXX/trivial_abi.cpp index 2cf07b22581a2..23c589dacd7e2 100644 --- a/clang/test/CodeGenCXX/trivial_abi.cpp +++ b/clang/test/CodeGenCXX/trivial_abi.cpp @@ -126,7 +126,7 @@ void testIgnoredSmall() { void testParamLarge(Large a) noexcept { } -// CHECK: define void @_Z15testReturnLargev(%[[STRUCT_LARGE:.*]]* noalias sret %[[AGG_RESULT:.*]]) +// CHECK: define void @_Z15testReturnLargev(%[[STRUCT_LARGE:.*]]* noalias sret align 8 %[[AGG_RESULT:.*]]) // CHECK: %[[CALL:.*]] = call %[[STRUCT_LARGE]]* @_ZN5LargeC1Ev(%[[STRUCT_LARGE]]* %[[AGG_RESULT]]) // CHECK: ret void // CHECK: } @@ -153,7 +153,7 @@ void testCallLarge0() { // CHECK: define void @_Z14testCallLarge1v() // CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_LARGE:.*]], align 8 -// CHECK: call void @_Z15testReturnLargev(%[[STRUCT_LARGE]]* sret %[[AGG_TMP]]) +// CHECK: call void @_Z15testReturnLargev(%[[STRUCT_LARGE]]* sret align 8 %[[AGG_TMP]]) // CHECK: call void @_Z14testParamLarge5Large(%[[STRUCT_LARGE]]* %[[AGG_TMP]]) // CHECK: ret void // CHECK: } @@ -164,7 +164,7 @@ void testCallLarge1() { // CHECK: define void @_Z16testIgnoredLargev() // CHECK: %[[AGG_TMP_ENSURED:.*]] = alloca %[[STRUCT_LARGE:.*]], align 8 -// CHECK: call void @_Z15testReturnLargev(%[[STRUCT_LARGE]]* sret %[[AGG_TMP_ENSURED]]) +// CHECK: call void @_Z15testReturnLargev(%[[STRUCT_LARGE]]* sret align 8 %[[AGG_TMP_ENSURED]]) // CHECK: %[[CALL:.*]] = call %[[STRUCT_LARGE]]* @_ZN5LargeD1Ev(%[[STRUCT_LARGE]]* %[[AGG_TMP_ENSURED]]) // CHECK: ret void // CHECK: } @@ -186,7 +186,7 @@ Trivial testReturnHasTrivial() { return t; } -// CHECK: define void @_Z23testReturnHasNonTrivialv(%[[STRUCT_NONTRIVIAL:.*]]* noalias sret %[[AGG_RESULT:.*]]) +// CHECK: define void @_Z23testReturnHasNonTrivialv(%[[STRUCT_NONTRIVIAL:.*]]* noalias sret align 4 %[[AGG_RESULT:.*]]) // CHECK: %[[CALL:.*]] = call %[[STRUCT_NONTRIVIAL]]* @_ZN10NonTrivialC1Ev(%[[STRUCT_NONTRIVIAL]]* %[[AGG_RESULT]]) // CHECK: ret void // CHECK: } diff --git a/clang/test/CodeGenCXX/unknown-anytype.cpp b/clang/test/CodeGenCXX/unknown-anytype.cpp index 42ed472380b15..0a7ab53b7af6c 100644 --- a/clang/test/CodeGenCXX/unknown-anytype.cpp +++ b/clang/test/CodeGenCXX/unknown-anytype.cpp @@ -71,7 +71,7 @@ struct Test7 { }; extern "C" __unknown_anytype test7_any(int); Test7 test7() { - // COMMON: call void @test7_any({{%.*}}* sret {{%.*}}, i32 5) + // COMMON: call void @test7_any({{%.*}}* sret align 1 {{%.*}}, i32 5) return (Test7) test7_any(5); } diff --git a/clang/test/CodeGenCXX/wasm-args-returns.cpp b/clang/test/CodeGenCXX/wasm-args-returns.cpp index c547eb85390da..3c57961eb2fcc 100644 --- a/clang/test/CodeGenCXX/wasm-args-returns.cpp +++ b/clang/test/CodeGenCXX/wasm-args-returns.cpp @@ -30,52 +30,52 @@ struct two_fields { double d, e; }; test(two_fields); -// CHECK: define void @_Z7forward10two_fields(%struct.two_fields* noalias nocapture sret %{{.*}}, %struct.two_fields* nocapture readonly byval(%struct.two_fields) align 8 %{{.*}}) +// CHECK: define void @_Z7forward10two_fields(%struct.two_fields* noalias nocapture sret align 8 %{{.*}}, %struct.two_fields* nocapture readonly byval(%struct.two_fields) align 8 %{{.*}}) // // CHECK: define void @_Z15test_two_fieldsv() // CHECK: %[[tmp:.*]] = alloca %struct.two_fields, align 8 -// CHECK: call void @_Z14def_two_fieldsv(%struct.two_fields* nonnull sret %[[tmp]]) +// CHECK: call void @_Z14def_two_fieldsv(%struct.two_fields* nonnull sret align 8 %[[tmp]]) // CHECK: call void @_Z3use10two_fields(%struct.two_fields* nonnull byval(%struct.two_fields) align 8 %[[tmp]]) // CHECK: ret void // // CHECK: declare void @_Z3use10two_fields(%struct.two_fields* byval(%struct.two_fields) align 8) -// CHECK: declare void @_Z14def_two_fieldsv(%struct.two_fields* sret) +// CHECK: declare void @_Z14def_two_fieldsv(%struct.two_fields* sret align 8) struct copy_ctor { double d; copy_ctor(copy_ctor const &); }; test(copy_ctor); -// CHECK: define void @_Z7forward9copy_ctor(%struct.copy_ctor* noalias sret %{{.*}}, %struct.copy_ctor* nonnull %{{.*}}) +// CHECK: define void @_Z7forward9copy_ctor(%struct.copy_ctor* noalias sret align 8 %{{.*}}, %struct.copy_ctor* nonnull %{{.*}}) // // CHECK: declare %struct.copy_ctor* @_ZN9copy_ctorC1ERKS_(%struct.copy_ctor* returned, %struct.copy_ctor* dereferenceable(8)) // // CHECK: define void @_Z14test_copy_ctorv() // CHECK: %[[tmp:.*]] = alloca %struct.copy_ctor, align 8 -// CHECK: call void @_Z13def_copy_ctorv(%struct.copy_ctor* nonnull sret %[[tmp]]) +// CHECK: call void @_Z13def_copy_ctorv(%struct.copy_ctor* nonnull sret align 8 %[[tmp]]) // CHECK: call void @_Z3use9copy_ctor(%struct.copy_ctor* nonnull %[[tmp]]) // CHECK: ret void // // CHECK: declare void @_Z3use9copy_ctor(%struct.copy_ctor*) -// CHECK: declare void @_Z13def_copy_ctorv(%struct.copy_ctor* sret) +// CHECK: declare void @_Z13def_copy_ctorv(%struct.copy_ctor* sret align 8) struct __attribute__((aligned(16))) aligned_copy_ctor { double d, e; aligned_copy_ctor(aligned_copy_ctor const &); }; test(aligned_copy_ctor); -// CHECK: define void @_Z7forward17aligned_copy_ctor(%struct.aligned_copy_ctor* noalias sret %{{.*}}, %struct.aligned_copy_ctor* nonnull %{{.*}}) +// CHECK: define void @_Z7forward17aligned_copy_ctor(%struct.aligned_copy_ctor* noalias sret align 16 %{{.*}}, %struct.aligned_copy_ctor* nonnull %{{.*}}) // // CHECK: declare %struct.aligned_copy_ctor* @_ZN17aligned_copy_ctorC1ERKS_(%struct.aligned_copy_ctor* returned, %struct.aligned_copy_ctor* dereferenceable(16)) // // CHECK: define void @_Z22test_aligned_copy_ctorv() // CHECK: %[[tmp:.*]] = alloca %struct.aligned_copy_ctor, align 16 -// CHECK: call void @_Z21def_aligned_copy_ctorv(%struct.aligned_copy_ctor* nonnull sret %[[tmp]]) +// CHECK: call void @_Z21def_aligned_copy_ctorv(%struct.aligned_copy_ctor* nonnull sret align 16 %[[tmp]]) // CHECK: call void @_Z3use17aligned_copy_ctor(%struct.aligned_copy_ctor* nonnull %[[tmp]]) // CHECK: ret void // // CHECK: declare void @_Z3use17aligned_copy_ctor(%struct.aligned_copy_ctor*) -// CHECK: declare void @_Z21def_aligned_copy_ctorv(%struct.aligned_copy_ctor* sret) +// CHECK: declare void @_Z21def_aligned_copy_ctorv(%struct.aligned_copy_ctor* sret align 16) struct empty {}; test(empty); diff --git a/clang/test/CodeGenCXX/x86_32-arguments.cpp b/clang/test/CodeGenCXX/x86_32-arguments.cpp index 830168635b529..c7ff59e943d2e 100644 --- a/clang/test/CodeGenCXX/x86_32-arguments.cpp +++ b/clang/test/CodeGenCXX/x86_32-arguments.cpp @@ -6,7 +6,7 @@ struct S { short s; }; -// CHECK-LABEL: define void @_Z1fv(%struct.S* noalias sret % +// CHECK-LABEL: define void @_Z1fv(%struct.S* noalias sret align 2 % S f() { return S(); } // CHECK-LABEL: define void @_Z1f1S(%struct.S* %0) void f(S) { } @@ -18,7 +18,7 @@ class C { double c; }; -// CHECK-LABEL: define void @_Z1gv(%class.C* noalias sret % +// CHECK-LABEL: define void @_Z1gv(%class.C* noalias sret align 4 % C g() { return C(); } // CHECK-LABEL: define void @_Z1f1C(%class.C* %0) @@ -103,13 +103,13 @@ struct s7_1 { double x; }; struct s7 : s7_0, s7_1 { }; s7 f7() { return s7(); } -// CHECK-LABEL: define void @_Z2f8v(%struct.s8* noalias sret %agg.result) +// CHECK-LABEL: define void @_Z2f8v(%struct.s8* noalias sret align 4 %agg.result) struct s8_0 { }; struct s8_1 { double x; }; struct s8 { s8_0 a; s8_1 b; }; s8 f8() { return s8(); } -// CHECK-LABEL: define void @_Z2f9v(%struct.s9* noalias sret %agg.result) +// CHECK-LABEL: define void @_Z2f9v(%struct.s9* noalias sret align 4 %agg.result) struct s9_0 { unsigned : 0; }; struct s9_1 { double x; }; struct s9 { s9_0 a; s9_1 b; }; diff --git a/clang/test/CodeGenCXX/x86_64-arguments.cpp b/clang/test/CodeGenCXX/x86_64-arguments.cpp index e905907788950..f7a898b220af7 100644 --- a/clang/test/CodeGenCXX/x86_64-arguments.cpp +++ b/clang/test/CodeGenCXX/x86_64-arguments.cpp @@ -176,7 +176,7 @@ namespace test9 { // CHECK: define void @_ZN5test93fooEPNS_1SEPNS_1TE([[S:%.*]]* %0, [[T:%.*]]* %1) void foo(S*, T*) {} - // CHECK: define void @_ZN5test91aEiiiiNS_1TEPv([[S]]* noalias sret {{%.*}}, i32 %0, i32 %1, i32 %2, i32 %3, [[T]]* byval([[T]]) align 8 %4, i8* %5) + // CHECK: define void @_ZN5test91aEiiiiNS_1TEPv([[S]]* noalias sret align 8 {{%.*}}, i32 %0, i32 %1, i32 %2, i32 %3, [[T]]* byval([[T]]) align 8 %4, i8* %5) S a(int, int, int, int, T, void*) { return S(); } @@ -186,7 +186,7 @@ namespace test9 { return sret; } - // CHECK: define void @_ZN5test91cEiiiNS_1TEPv([[S]]* noalias sret {{%.*}}, i32 %0, i32 %1, i32 %2, i8* {{%.*}}, i8* {{%.*}}, i8* %3) + // CHECK: define void @_ZN5test91cEiiiNS_1TEPv([[S]]* noalias sret align 8 {{%.*}}, i32 %0, i32 %1, i32 %2, i8* {{%.*}}, i8* {{%.*}}, i8* %3) S c(int, int, int, T, void*) { return S(); } diff --git a/clang/test/CodeGenCoroutines/coro-await.cpp b/clang/test/CodeGenCoroutines/coro-await.cpp index 86bacc766db3f..99097f376aa57 100644 --- a/clang/test/CodeGenCoroutines/coro-await.cpp +++ b/clang/test/CodeGenCoroutines/coro-await.cpp @@ -130,7 +130,7 @@ extern "C" void f1(int) { // CHECK: %[[PROMISE:.+]] = alloca %"struct.std::experimental::coroutine_traits::promise_type" // CHECK: %[[FRAME:.+]] = call i8* @llvm.coro.begin( co_yield 42; - // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJviEE12promise_type11yield_valueEi(%struct.suspend_maybe* sret %[[AWAITER:.+]], %"struct.std::experimental::coroutine_traits::promise_type"* %[[PROMISE]], i32 42) + // CHECK: call void @_ZNSt12experimental16coroutine_traitsIJviEE12promise_type11yield_valueEi(%struct.suspend_maybe* sret align 4 %[[AWAITER:.+]], %"struct.std::experimental::coroutine_traits::promise_type"* %[[PROMISE]], i32 42) // See if we need to suspend: // -------------------------- @@ -197,20 +197,20 @@ extern "C" void UseAggr(Aggr&&); extern "C" void TestAggr() { UseAggr(co_await AggrAwaiter{}); Whatever(); - // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(%struct.Aggr* sret %[[AwaitResume:.+]], + // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(%struct.Aggr* sret align 4 %[[AwaitResume:.+]], // CHECK: call void @UseAggr(%struct.Aggr* dereferenceable(12) %[[AwaitResume]]) // CHECK: call void @_ZN4AggrD1Ev(%struct.Aggr* %[[AwaitResume]]) // CHECK: call void @Whatever() co_await AggrAwaiter{}; Whatever(); - // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(%struct.Aggr* sret %[[AwaitResume2:.+]], + // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(%struct.Aggr* sret align 4 %[[AwaitResume2:.+]], // CHECK: call void @_ZN4AggrD1Ev(%struct.Aggr* %[[AwaitResume2]]) // CHECK: call void @Whatever() Aggr Val = co_await AggrAwaiter{}; Whatever(); - // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(%struct.Aggr* sret %[[AwaitResume3:.+]], + // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(%struct.Aggr* sret align 4 %[[AwaitResume3:.+]], // CHECK: call void @Whatever() // CHECK: call void @_ZN4AggrD1Ev(%struct.Aggr* %[[AwaitResume3]]) } @@ -253,7 +253,7 @@ extern "C" void TestOpAwait() { co_await MyAgg{}; // CHECK: call void @_ZN5MyAggawEv(%struct.MyAgg* % - // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(%struct.Aggr* sret % + // CHECK: call void @_ZN11AggrAwaiter12await_resumeEv(%struct.Aggr* sret align 4 % } // CHECK-LABEL: EndlessLoop( diff --git a/clang/test/CodeGenCoroutines/coro-gro-nrvo.cpp b/clang/test/CodeGenCoroutines/coro-gro-nrvo.cpp index f4a71864ea0ec..890dc85991206 100644 --- a/clang/test/CodeGenCoroutines/coro-gro-nrvo.cpp +++ b/clang/test/CodeGenCoroutines/coro-gro-nrvo.cpp @@ -34,14 +34,14 @@ struct coro { }; // Verify that the NRVO is applied to the Gro object. -// CHECK-LABEL: define void @_Z1fi(%struct.coro* noalias sret %agg.result, i32 %0) +// CHECK-LABEL: define void @_Z1fi(%struct.coro* noalias sret align 8 %agg.result, i32 %0) coro f(int) { // CHECK: %call = call i8* @_Znwm( // CHECK-NEXT: br label %[[CoroInit:.*]] // CHECK: {{.*}}[[CoroInit]]: // CHECK: store i1 false, i1* %gro.active -// CHECK: call void @{{.*get_return_objectEv}}(%struct.coro* sret %agg.result +// CHECK: call void @{{.*get_return_objectEv}}(%struct.coro* sret align 8 %agg.result // CHECK-NEXT: store i1 true, i1* %gro.active co_return; } @@ -65,7 +65,7 @@ struct coro_two { }; // Verify that the NRVO is applied to the Gro object. -// CHECK-LABEL: define void @_Z1hi(%struct.coro_two* noalias sret %agg.result, i32 %0) +// CHECK-LABEL: define void @_Z1hi(%struct.coro_two* noalias sret align 8 %agg.result, i32 %0) coro_two h(int) { // CHECK: %call = call i8* @_ZnwmRKSt9nothrow_t @@ -73,12 +73,12 @@ struct coro_two { // CHECK-NEXT: br i1 %[[CheckNull]], label %[[InitOnSuccess:.*]], label %[[InitOnFailure:.*]] // CHECK: {{.*}}[[InitOnFailure]]: -// CHECK-NEXT: call void @{{.*get_return_object_on_allocation_failureEv}}(%struct.coro_two* sret %agg.result +// CHECK-NEXT: call void @{{.*get_return_object_on_allocation_failureEv}}(%struct.coro_two* sret align 8 %agg.result // CHECK-NEXT: br label %[[RetLabel:.*]] // CHECK: {{.*}}[[InitOnSuccess]]: // CHECK: store i1 false, i1* %gro.active -// CHECK: call void @{{.*get_return_objectEv}}(%struct.coro_two* sret %agg.result +// CHECK: call void @{{.*get_return_objectEv}}(%struct.coro_two* sret align 8 %agg.result // CHECK-NEXT: store i1 true, i1* %gro.active // CHECK: [[RetLabel]]: diff --git a/clang/test/CodeGenObjC/arc.m b/clang/test/CodeGenObjC/arc.m index 31ecb53713be8..45296fbd54ef6 100644 --- a/clang/test/CodeGenObjC/arc.m +++ b/clang/test/CodeGenObjC/arc.m @@ -1541,10 +1541,10 @@ void test71(void) { // // CHECK: %[[T:[^ ]+]] = bitcast %struct.AggDtor* %[[TMP1:[^ ]+]] to i8* // CHECK: call void @llvm.lifetime.start.p0i8({{[^,]+}}, i8* %[[T]]) - // CHECK: call void @getAggDtor(%struct.AggDtor* sret %[[TMP1]]) + // CHECK: call void @getAggDtor(%struct.AggDtor* sret align 8 %[[TMP1]]) // CHECK: %[[T:[^ ]+]] = bitcast %struct.AggDtor* %[[TMP2:[^ ]+]] to i8* // CHECK: call void @llvm.lifetime.start.p0i8({{[^,]+}}, i8* %[[T]]) - // CHECK: call void @getAggDtor(%struct.AggDtor* sret %[[TMP2]]) + // CHECK: call void @getAggDtor(%struct.AggDtor* sret align 8 %[[TMP2]]) // CHECK: %[[T:[^ ]+]] = bitcast %struct.AggDtor* %[[TMP2]] to i8** // CHECK: call void @__destructor_8_s40(i8** %[[T]]) // CHECK: %[[T:[^ ]+]] = bitcast %struct.AggDtor* %[[TMP2:[^ ]+]] to i8* diff --git a/clang/test/CodeGenObjC/direct-method.m b/clang/test/CodeGenObjC/direct-method.m index e53c99bc0f5e8..5bb84de1ddb58 100644 --- a/clang/test/CodeGenObjC/direct-method.m +++ b/clang/test/CodeGenObjC/direct-method.m @@ -120,7 +120,7 @@ + (struct my_complex_struct)classGetComplex __attribute__((objc_direct)) { // CHECK-LABEL: define hidden void @"\01-[Root getAggregate]"( - (struct my_aggregate_struct)getAggregate __attribute__((objc_direct)) { - // CHECK: %struct.my_aggregate_struct* noalias sret [[RETVAL:%[^,]*]], + // CHECK: %struct.my_aggregate_struct* noalias sret align 4 [[RETVAL:%[^,]*]], // loading parameters // CHECK-LABEL: entry: diff --git a/clang/test/CodeGenObjC/nontrivial-c-struct-exception.m b/clang/test/CodeGenObjC/nontrivial-c-struct-exception.m index 1733a019026c0..8d66485959a8c 100644 --- a/clang/test/CodeGenObjC/nontrivial-c-struct-exception.m +++ b/clang/test/CodeGenObjC/nontrivial-c-struct-exception.m @@ -41,8 +41,8 @@ void testStrongException(void) { // CHECK: define void @testWeakException() // CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_WEAK]], align 8 // CHECK: %[[AGG_TMP1:.*]] = alloca %[[STRUCT_WEAK]], align 8 -// CHECK: call void @genWeak(%[[STRUCT_WEAK]]* sret %[[AGG_TMP]]) -// CHECK: invoke void @genWeak(%[[STRUCT_WEAK]]* sret %[[AGG_TMP1]]) +// CHECK: call void @genWeak(%[[STRUCT_WEAK]]* sret align 8 %[[AGG_TMP]]) +// CHECK: invoke void @genWeak(%[[STRUCT_WEAK]]* sret align 8 %[[AGG_TMP1]]) // CHECK: call void @calleeWeak(%[[STRUCT_WEAK]]* %[[AGG_TMP]], %[[STRUCT_WEAK]]* %[[AGG_TMP1]]) // CHECK: ret void diff --git a/clang/test/CodeGenObjC/objc-non-trivial-struct-nrvo.m b/clang/test/CodeGenObjC/objc-non-trivial-struct-nrvo.m index 53ff433989e29..93f348185412a 100644 --- a/clang/test/CodeGenObjC/objc-non-trivial-struct-nrvo.m +++ b/clang/test/CodeGenObjC/objc-non-trivial-struct-nrvo.m @@ -37,7 +37,7 @@ Trivial testTrivial(void) { void func1(TrivialBig *); -// CHECK: define void @testTrivialBig(%[[STRUCT_TRIVIALBIG]]* noalias sret %[[AGG_RESULT:.*]]) +// CHECK: define void @testTrivialBig(%[[STRUCT_TRIVIALBIG]]* noalias sret align 4 %[[AGG_RESULT:.*]]) // CHECK: call void @func1(%[[STRUCT_TRIVIALBIG]]* %[[AGG_RESULT]]) // CHECK-NEXT: ret void @@ -69,7 +69,7 @@ Strong testStrong(void) { return a; } -// CHECK: define void @testWeak(%[[STRUCT_WEAK]]* noalias sret %[[AGG_RESULT:.*]]) +// CHECK: define void @testWeak(%[[STRUCT_WEAK]]* noalias sret align 8 %[[AGG_RESULT:.*]]) // CHECK: %[[NRVO:.*]] = alloca i1, align 1 // CHECK: %[[V0:.*]] = bitcast %[[STRUCT_WEAK]]* %[[AGG_RESULT]] to i8** // CHECK: call void @__default_constructor_8_w0(i8** %[[V0]]) @@ -105,7 +105,7 @@ Weak testWeak2(int c) { return b; } -// CHECK: define internal void @"\01-[C1 foo1]"(%[[STRUCT_WEAK]]* noalias sret %[[AGG_RESULT:.*]], %{{.*}}* %{{.*}}, i8* %{{.*}}) +// CHECK: define internal void @"\01-[C1 foo1]"(%[[STRUCT_WEAK]]* noalias sret align 8 %[[AGG_RESULT:.*]], %{{.*}}* %{{.*}}, i8* %{{.*}}) // CHECK: %[[NRVO:.*]] = alloca i1, align 1 // CHECK: %[[V0:.*]] = bitcast %[[STRUCT_WEAK]]* %[[AGG_RESULT]] to i8** // CHECK: call void @__default_constructor_8_w0(i8** %[[V0]]) diff --git a/clang/test/CodeGenObjC/stret-1.m b/clang/test/CodeGenObjC/stret-1.m index 1122c28a468bd..f25c40438e590 100644 --- a/clang/test/CodeGenObjC/stret-1.m +++ b/clang/test/CodeGenObjC/stret-1.m @@ -14,19 +14,19 @@ int main(int argc, const char **argv) { struct stret s; s = [(id)(argc&~255) method]; - // CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (%struct.stret*, i8*, i8*)*)(%struct.stret* sret [[T0:%[^,]+]] + // CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (%struct.stret*, i8*, i8*)*)(%struct.stret* sret align 4 [[T0:%[^,]+]] // CHECK: [[T0P:%.*]] = bitcast %struct.stret* [[T0]] to i8* // CHECK: call void @llvm.memset.p0i8.i64(i8* align 4 [[T0P]], i8 0, i64 400, i1 false) s = [Test method]; - // CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (%struct.stret*, i8*, i8*)*)(%struct.stret* sret [[T1:%[^,]+]] + // CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (%struct.stret*, i8*, i8*)*)(%struct.stret* sret align 4 [[T1:%[^,]+]] // CHECK-NOT: call void @llvm.memset.p0i8.i64( [(id)(argc&~255) method]; - // CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (%struct.stret*, i8*, i8*)*)(%struct.stret* sret [[T1:%[^,]+]] + // CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (%struct.stret*, i8*, i8*)*)(%struct.stret* sret align 4 [[T1:%[^,]+]] // CHECK-NOT: call void @llvm.memset.p0i8.i64( [Test method]; - // CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (%struct.stret*, i8*, i8*)*)(%struct.stret* sret [[T1:%[^,]+]] + // CHECK: call void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (%struct.stret*, i8*, i8*)*)(%struct.stret* sret align 4 [[T1:%[^,]+]] // CHECK-NOT: call void @llvm.memset.p0i8.i64( } diff --git a/clang/test/CodeGenObjC/weak-in-c-struct.m b/clang/test/CodeGenObjC/weak-in-c-struct.m index 001a7ed96dec8..90c799298253b 100644 --- a/clang/test/CodeGenObjC/weak-in-c-struct.m +++ b/clang/test/CodeGenObjC/weak-in-c-struct.m @@ -179,7 +179,7 @@ void test_argument_Weak(Weak *a) { calleeWeak(*a); } -// COMMON: define void @test_return_Weak(%[[STRUCT_WEAK]]* noalias sret %[[AGG_RESULT:.*]], %[[STRUCT_WEAK]]* %[[A:.*]]) +// COMMON: define void @test_return_Weak(%[[STRUCT_WEAK]]* noalias sret align {{.*}} %[[AGG_RESULT:.*]], %[[STRUCT_WEAK]]* %[[A:.*]]) // COMMON: %[[A_ADDR:.*]] = alloca %[[STRUCT_WEAK]]* // COMMON: store %[[STRUCT_WEAK]]* %[[A]], %[[STRUCT_WEAK]]** %[[A_ADDR]] // COMMON: %[[V0:.*]] = load %[[STRUCT_WEAK]]*, %[[STRUCT_WEAK]]** %[[A_ADDR]] diff --git a/clang/test/CodeGenObjCXX/objc-struct-cxx-abi.mm b/clang/test/CodeGenObjCXX/objc-struct-cxx-abi.mm index dd9b88b0234d0..8bb694705fef1 100644 --- a/clang/test/CodeGenObjCXX/objc-struct-cxx-abi.mm +++ b/clang/test/CodeGenObjCXX/objc-struct-cxx-abi.mm @@ -90,7 +90,7 @@ void testCallStrongWeak(StrongWeak *a) { testParamStrongWeak(*a); } -// CHECK: define void @_Z20testReturnStrongWeakP10StrongWeak(%[[STRUCT_STRONGWEAK:.*]]* noalias sret %[[AGG_RESULT:.*]], %[[STRUCT_STRONGWEAK]]* %[[A:.*]]) +// CHECK: define void @_Z20testReturnStrongWeakP10StrongWeak(%[[STRUCT_STRONGWEAK:.*]]* noalias sret align 8 %[[AGG_RESULT:.*]], %[[STRUCT_STRONGWEAK]]* %[[A:.*]]) // CHECK: %[[A_ADDR:.*]] = alloca %[[STRUCT_STRONGWEAK]]*, align 8 // CHECK: store %[[STRUCT_STRONGWEAK]]* %[[A]], %[[STRUCT_STRONGWEAK]]** %[[A_ADDR]], align 8 // CHECK: %[[V0:.*]] = load %[[STRUCT_STRONGWEAK]]*, %[[STRUCT_STRONGWEAK]]** %[[A_ADDR]], align 8 diff --git a/clang/test/CodeGenOpenCL/addr-space-struct-arg.cl b/clang/test/CodeGenOpenCL/addr-space-struct-arg.cl index cdbf28bbcad87..35cc54c50d6f2 100644 --- a/clang/test/CodeGenOpenCL/addr-space-struct-arg.cl +++ b/clang/test/CodeGenOpenCL/addr-space-struct-arg.cl @@ -43,7 +43,7 @@ struct LargeStructTwoMember { struct LargeStructOneMember g_s; #endif -// X86-LABEL: define void @foo(%struct.Mat4X4* noalias sret %agg.result, %struct.Mat3X3* byval(%struct.Mat3X3) align 4 %in) +// X86-LABEL: define void @foo(%struct.Mat4X4* noalias sret align 4 %agg.result, %struct.Mat3X3* byval(%struct.Mat3X3) align 4 %in) // AMDGCN-LABEL: define %struct.Mat4X4 @foo([9 x i32] %in.coerce) Mat4X4 __attribute__((noinline)) foo(Mat3X3 in) { Mat4X4 out; @@ -63,8 +63,8 @@ kernel void ker(global Mat3X3 *in, global Mat4X4 *out) { out[0] = foo(in[1]); } -// X86-LABEL: define void @foo_large(%struct.Mat64X64* noalias sret %agg.result, %struct.Mat32X32* byval(%struct.Mat32X32) align 4 %in) -// AMDGCN-LABEL: define void @foo_large(%struct.Mat64X64 addrspace(5)* noalias sret %agg.result, %struct.Mat32X32 addrspace(5)* byval(%struct.Mat32X32) align 4 %in) +// X86-LABEL: define void @foo_large(%struct.Mat64X64* noalias sret align 4 %agg.result, %struct.Mat32X32* byval(%struct.Mat32X32) align 4 %in) +// AMDGCN-LABEL: define void @foo_large(%struct.Mat64X64 addrspace(5)* noalias sret align 4 %agg.result, %struct.Mat32X32 addrspace(5)* byval(%struct.Mat32X32) align 4 %in) Mat64X64 __attribute__((noinline)) foo_large(Mat32X32 in) { Mat64X64 out; return out; diff --git a/clang/test/CodeGenOpenCL/amdgpu-abi-struct-coerce.cl b/clang/test/CodeGenOpenCL/amdgpu-abi-struct-coerce.cl index 0a7f289cb2f7c..fd46d3cce22e4 100644 --- a/clang/test/CodeGenOpenCL/amdgpu-abi-struct-coerce.cl +++ b/clang/test/CodeGenOpenCL/amdgpu-abi-struct-coerce.cl @@ -404,14 +404,14 @@ struct_arr16 func_ret_struct_arr16() return s; } -// CHECK: define void @func_ret_struct_arr32(%struct.struct_arr32 addrspace(5)* noalias nocapture sret %agg.result) +// CHECK: define void @func_ret_struct_arr32(%struct.struct_arr32 addrspace(5)* noalias nocapture sret align 4 %agg.result) struct_arr32 func_ret_struct_arr32() { struct_arr32 s = { 0 }; return s; } -// CHECK: define void @func_ret_struct_arr33(%struct.struct_arr33 addrspace(5)* noalias nocapture sret %agg.result) +// CHECK: define void @func_ret_struct_arr33(%struct.struct_arr33 addrspace(5)* noalias nocapture sret align 4 %agg.result) struct_arr33 func_ret_struct_arr33() { struct_arr33 s = { 0 }; @@ -440,7 +440,7 @@ different_size_type_pair func_different_size_type_pair_ret() return s; } -// CHECK: define void @func_flexible_array_ret(%struct.flexible_array addrspace(5)* noalias nocapture sret %agg.result) +// CHECK: define void @func_flexible_array_ret(%struct.flexible_array addrspace(5)* noalias nocapture sret align 4 %agg.result) flexible_array func_flexible_array_ret() { flexible_array s = { 0 }; diff --git a/clang/test/CodeGenOpenCLCXX/addrspace-of-this.cl b/clang/test/CodeGenOpenCLCXX/addrspace-of-this.cl index 07e3b0b7314ea..16495d38b9421 100644 --- a/clang/test/CodeGenOpenCLCXX/addrspace-of-this.cl +++ b/clang/test/CodeGenOpenCLCXX/addrspace-of-this.cl @@ -114,7 +114,7 @@ __kernel void test__global() { // Test the address space of 'this' when invoking the operator+ // COMMON: [[C1GEN:%[.a-z0-9]+]] = addrspacecast %class.C* %c1 to %class.C addrspace(4)* // COMMON: [[C2GEN:%[.a-z0-9]+]] = addrspacecast %class.C* %c2 to %class.C addrspace(4)* -// COMMON: call spir_func void @_ZNU3AS41CplERU3AS4KS_(%class.C* sret %c3, %class.C addrspace(4)* [[C1GEN]], %class.C addrspace(4)* dereferenceable(4) [[C2GEN]]) +// COMMON: call spir_func void @_ZNU3AS41CplERU3AS4KS_(%class.C* sret align 4 %c3, %class.C addrspace(4)* [[C1GEN]], %class.C addrspace(4)* dereferenceable(4) [[C2GEN]]) // Test the address space of 'this' when invoking the move constructor // COMMON: [[C4GEN:%[.a-z0-9]+]] = addrspacecast %class.C* %c4 to %class.C addrspace(4)* @@ -134,7 +134,7 @@ __kernel void test__global() { // Tests address space of inline members //COMMON: @_ZNU3AS41C3getEv(%class.C addrspace(4)* %this) -//COMMON: @_ZNU3AS41CplERU3AS4KS_(%class.C* noalias sret %agg.result, %class.C addrspace(4)* %this +//COMMON: @_ZNU3AS41CplERU3AS4KS_(%class.C* noalias sret align 4 %agg.result, %class.C addrspace(4)* %this #define TEST(AS) \ __kernel void test##AS() { \ AS C c; \ diff --git a/clang/test/Modules/templates.mm b/clang/test/Modules/templates.mm index 78206a980a8fb..9d4e4b9d16173 100644 --- a/clang/test/Modules/templates.mm +++ b/clang/test/Modules/templates.mm @@ -125,7 +125,7 @@ void testWithAttributes() { // Check that returnNonTrivial doesn't return Class0 directly in registers. -// CHECK: declare void @_Z16returnNonTrivialv(%struct.Class0* sret) +// CHECK: declare void @_Z16returnNonTrivialv(%struct.Class0* sret align 8) @import template_nontrivial0; @import template_nontrivial1; From 3b84a5f76052ccd8eeec3e34c1aa99b42508bae4 Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Tue, 10 Mar 2020 14:03:53 -0700 Subject: [PATCH 138/286] Make ThreadPlans use TID and Process, rather than Thread *. Differential Revision: https://reviews.llvm.org/D75711 --- lldb/include/lldb/Target/ThreadPlan.h | 24 +++--- lldb/include/lldb/Target/ThreadPlanPython.h | 2 + ...pleThreadPlanStepThroughObjCTrampoline.cpp | 17 ++-- lldb/source/Target/ThreadPlan.cpp | 48 ++++++----- lldb/source/Target/ThreadPlanBase.cpp | 26 +++--- lldb/source/Target/ThreadPlanCallFunction.cpp | 39 ++++----- .../Target/ThreadPlanCallFunctionUsingABI.cpp | 8 +- .../Target/ThreadPlanCallUserExpression.cpp | 3 +- lldb/source/Target/ThreadPlanPython.cpp | 29 ++----- lldb/source/Target/ThreadPlanRunToAddress.cpp | 19 ++--- lldb/source/Target/ThreadPlanStepInRange.cpp | 44 +++++----- .../Target/ThreadPlanStepInstruction.cpp | 42 +++++----- lldb/source/Target/ThreadPlanStepOut.cpp | 69 ++++++++-------- .../Target/ThreadPlanStepOverBreakpoint.cpp | 20 ++--- .../source/Target/ThreadPlanStepOverRange.cpp | 39 ++++----- lldb/source/Target/ThreadPlanStepRange.cpp | 60 +++++++------- lldb/source/Target/ThreadPlanStepThrough.cpp | 30 ++++--- lldb/source/Target/ThreadPlanStepUntil.cpp | 82 ++++++++----------- 18 files changed, 281 insertions(+), 320 deletions(-) diff --git a/lldb/include/lldb/Target/ThreadPlan.h b/lldb/include/lldb/Target/ThreadPlan.h index b25ee74766d43..0301de7d4159f 100644 --- a/lldb/include/lldb/Target/ThreadPlan.h +++ b/lldb/include/lldb/Target/ThreadPlan.h @@ -369,13 +369,11 @@ class ThreadPlan : public std::enable_shared_from_this, /// /// \return /// A pointer to the thread plan's owning thread. - Thread &GetThread() { return m_thread; } + Thread &GetThread(); - const Thread &GetThread() const { return m_thread; } + Target &GetTarget() { return m_process.GetTarget(); } - Target &GetTarget() { return m_thread.GetProcess()->GetTarget(); } - - const Target &GetTarget() const { return m_thread.GetProcess()->GetTarget(); } + const Target &GetTarget() const { return m_process.GetTarget(); } /// Print a description of this thread to the stream \a s. /// \a thread. @@ -464,7 +462,7 @@ class ThreadPlan : public std::enable_shared_from_this, // Also sets the plans to private and not master plans. A plan pushed by // another thread plan is never either of the above. void PushPlan(lldb::ThreadPlanSP &thread_plan_sp) { - m_thread.PushPlan(thread_plan_sp); + GetThread().PushPlan(thread_plan_sp); thread_plan_sp->SetPrivate(false); thread_plan_sp->SetIsMasterPlan(false); } @@ -497,7 +495,9 @@ class ThreadPlan : public std::enable_shared_from_this, // original stop reason so that stopping and calling a few functions won't // lose the history of the run. This call can be implemented to get you back // to the real stop info. - virtual lldb::StopInfoSP GetRealStopInfo() { return m_thread.GetStopInfo(); } + virtual lldb::StopInfoSP GetRealStopInfo() { + return GetThread().GetStopInfo(); + } // If the completion of the thread plan stepped out of a function, the return // value of the function might have been captured by the thread plan @@ -560,17 +560,17 @@ class ThreadPlan : public std::enable_shared_from_this, // This is mostly a formal requirement, it allows us to make the Thread's // GetPreviousPlan protected, but only friend ThreadPlan to thread. - ThreadPlan *GetPreviousPlan() { return m_thread.GetPreviousPlan(this); } + ThreadPlan *GetPreviousPlan() { return GetThread().GetPreviousPlan(this); } // This forwards the private Thread::GetPrivateStopInfo which is generally // what ThreadPlan's need to know. lldb::StopInfoSP GetPrivateStopInfo() { - return m_thread.GetPrivateStopInfo(); + return GetThread().GetPrivateStopInfo(); } void SetStopInfo(lldb::StopInfoSP stop_reason_sp) { - m_thread.SetStopInfo(stop_reason_sp); + GetThread().SetStopInfo(stop_reason_sp); } void CachePlanExplainsStop(bool does_explain) { @@ -586,7 +586,8 @@ class ThreadPlan : public std::enable_shared_from_this, bool IsUsuallyUnexplainedStopReason(lldb::StopReason); Status m_status; - Thread &m_thread; + Process &m_process; + lldb::tid_t m_tid; Vote m_stop_vote; Vote m_run_vote; bool m_takes_iteration_count; @@ -597,6 +598,7 @@ class ThreadPlan : public std::enable_shared_from_this, // For ThreadPlan only static lldb::user_id_t GetNextID(); + Thread *m_thread; ThreadPlanKind m_kind; std::string m_name; std::recursive_mutex m_plan_complete_mutex; diff --git a/lldb/include/lldb/Target/ThreadPlanPython.h b/lldb/include/lldb/Target/ThreadPlanPython.h index 0ee559b12960b..247a0e3c62187 100644 --- a/lldb/include/lldb/Target/ThreadPlanPython.h +++ b/lldb/include/lldb/Target/ThreadPlanPython.h @@ -55,6 +55,8 @@ class ThreadPlanPython : public ThreadPlan { bool DoPlanExplainsStop(Event *event_ptr) override; lldb::StateType GetPlanRunState() override; + + ScriptInterpreter *GetScriptInterpreter(); private: std::string m_class_name; diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp index ba9fb7f2e6ae8..0d99dc9e7bb4c 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp @@ -48,15 +48,14 @@ void AppleThreadPlanStepThroughObjCTrampoline::DidPush() { // Setting up the memory space for the called function text might require // allocations, i.e. a nested function call. This needs to be done as a // PreResumeAction. - m_thread.GetProcess()->AddPreResumeAction(PreResumeInitializeFunctionCaller, - (void *)this); + m_process.AddPreResumeAction(PreResumeInitializeFunctionCaller, (void *)this); } bool AppleThreadPlanStepThroughObjCTrampoline::InitializeFunctionCaller() { if (!m_func_sp) { DiagnosticManager diagnostics; m_args_addr = - m_trampoline_handler.SetupDispatchFunction(m_thread, m_input_values); + m_trampoline_handler.SetupDispatchFunction(GetThread(), m_input_values); if (m_args_addr == LLDB_INVALID_ADDRESS) { return false; @@ -68,7 +67,7 @@ bool AppleThreadPlanStepThroughObjCTrampoline::InitializeFunctionCaller() { options.SetUnwindOnError(true); options.SetIgnoreBreakpoints(true); options.SetStopOthers(m_stop_others); - m_thread.CalculateExecutionContext(exc_ctx); + GetThread().CalculateExecutionContext(exc_ctx); m_func_sp = m_impl_function->GetThreadPlanToCallFunction( exc_ctx, m_args_addr, options, diagnostics); m_func_sp->SetOkayToDiscard(true); @@ -132,7 +131,7 @@ bool AppleThreadPlanStepThroughObjCTrampoline::ShouldStop(Event *event_ptr) { if (!m_run_to_sp) { Value target_addr_value; ExecutionContext exc_ctx; - m_thread.CalculateExecutionContext(exc_ctx); + GetThread().CalculateExecutionContext(exc_ctx); m_impl_function->FetchFunctionResults(exc_ctx, m_args_addr, target_addr_value); m_impl_function->DeallocateFunctionResults(exc_ctx, m_args_addr); @@ -151,13 +150,13 @@ bool AppleThreadPlanStepThroughObjCTrampoline::ShouldStop(Event *event_ptr) { ", stopping.", target_addr); - SymbolContext sc = m_thread.GetStackFrameAtIndex(0)->GetSymbolContext( + SymbolContext sc = GetThread().GetStackFrameAtIndex(0)->GetSymbolContext( eSymbolContextEverything); Status status; const bool abort_other_plans = false; const bool first_insn = true; const uint32_t frame_idx = 0; - m_run_to_sp = m_thread.QueueThreadPlanForStepOutNoShouldStop( + m_run_to_sp = GetThread().QueueThreadPlanForStepOutNoShouldStop( abort_other_plans, &sc, first_insn, m_stop_others, eVoteNoOpinion, eVoteNoOpinion, frame_idx, status); if (m_run_to_sp && status.Success()) @@ -180,10 +179,10 @@ bool AppleThreadPlanStepThroughObjCTrampoline::ShouldStop(Event *event_ptr) { // Extract the target address from the value: m_run_to_sp = std::make_shared( - m_thread, target_so_addr, m_stop_others); + GetThread(), target_so_addr, m_stop_others); PushPlan(m_run_to_sp); return false; - } else if (m_thread.IsThreadPlanDone(m_run_to_sp.get())) { + } else if (GetThread().IsThreadPlanDone(m_run_to_sp.get())) { // Third stage, work the run to target plan. SetPlanComplete(); return true; diff --git a/lldb/source/Target/ThreadPlan.cpp b/lldb/source/Target/ThreadPlan.cpp index ba56f8d15d8a9..b946554576bdc 100644 --- a/lldb/source/Target/ThreadPlan.cpp +++ b/lldb/source/Target/ThreadPlan.cpp @@ -21,9 +21,10 @@ using namespace lldb_private; // ThreadPlan constructor ThreadPlan::ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread, Vote stop_vote, Vote run_vote) - : m_thread(thread), m_stop_vote(stop_vote), m_run_vote(run_vote), + : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()), + m_stop_vote(stop_vote), m_run_vote(run_vote), m_takes_iteration_count(false), m_could_not_resolve_hw_bp(false), - m_kind(kind), m_name(name), m_plan_complete_mutex(), + m_kind(kind), m_thread(&thread), m_name(name), m_plan_complete_mutex(), m_cached_plan_explains_stop(eLazyBoolCalculate), m_plan_complete(false), m_plan_private(false), m_okay_to_discard(true), m_is_master_plan(false), m_plan_succeeded(true) { @@ -33,6 +34,15 @@ ThreadPlan::ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread, // Destructor ThreadPlan::~ThreadPlan() = default; +Thread &ThreadPlan::GetThread() { + if (m_thread) + return *m_thread; + + ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(m_tid); + m_thread = thread_sp.get(); + return *m_thread; +} + bool ThreadPlan::PlanExplainsStop(Event *event_ptr) { if (m_cached_plan_explains_stop == eLazyBoolCalculate) { bool actual_value = DoPlanExplainsStop(event_ptr); @@ -103,7 +113,7 @@ bool ThreadPlan::WillResume(StateType resume_state, bool current_plan) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); if (log) { - RegisterContext *reg_ctx = m_thread.GetRegisterContext().get(); + RegisterContext *reg_ctx = GetThread().GetRegisterContext().get(); assert(reg_ctx); addr_t pc = reg_ctx->GetPC(); addr_t sp = reg_ctx->GetSP(); @@ -113,8 +123,8 @@ bool ThreadPlan::WillResume(StateType resume_state, bool current_plan) { "%s Thread #%u (0x%p): tid = 0x%4.4" PRIx64 ", pc = 0x%8.8" PRIx64 ", sp = 0x%8.8" PRIx64 ", fp = 0x%8.8" PRIx64 ", " "plan = '%s', state = %s, stop others = %d", - __FUNCTION__, m_thread.GetIndexID(), static_cast(&m_thread), - m_thread.GetID(), static_cast(pc), + __FUNCTION__, GetThread().GetIndexID(), + static_cast(&GetThread()), m_tid, static_cast(pc), static_cast(sp), static_cast(fp), m_name.c_str(), StateAsCString(resume_state), StopOthers()); } @@ -174,14 +184,13 @@ bool ThreadPlanNull::ValidatePlan(Stream *error) { fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); + LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); #else Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); if (log) log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, m_thread.GetID(), - m_thread.GetProtocolID()); + LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); #endif return true; } @@ -191,14 +200,13 @@ bool ThreadPlanNull::ShouldStop(Event *event_ptr) { fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); + LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); #else Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); if (log) log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, m_thread.GetID(), - m_thread.GetProtocolID()); + LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); #endif return true; } @@ -208,14 +216,13 @@ bool ThreadPlanNull::WillStop() { fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); + LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); #else Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); if (log) log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, m_thread.GetID(), - m_thread.GetProtocolID()); + LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); #endif return true; } @@ -231,8 +238,7 @@ bool ThreadPlanNull::DoPlanExplainsStop(Event *event_ptr) { if (log) log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, m_thread.GetID(), - m_thread.GetProtocolID()); + LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); #endif return true; } @@ -244,14 +250,13 @@ bool ThreadPlanNull::MischiefManaged() { fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); + LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); #else Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); if (log) log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, m_thread.GetID(), - m_thread.GetProtocolID()); + LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); #endif return false; } @@ -262,14 +267,13 @@ lldb::StateType ThreadPlanNull::GetPlanRunState() { fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); + LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); #else Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); if (log) log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, m_thread.GetID(), - m_thread.GetProtocolID()); + LLVM_PRETTY_FUNCTION, m_tid, GetThread().GetProtocolID()); #endif return eStateRunning; } diff --git a/lldb/source/Target/ThreadPlanBase.cpp b/lldb/source/Target/ThreadPlanBase.cpp index 821643d4bce51..40b002e7262c2 100644 --- a/lldb/source/Target/ThreadPlanBase.cpp +++ b/lldb/source/Target/ThreadPlanBase.cpp @@ -34,11 +34,11 @@ ThreadPlanBase::ThreadPlanBase(Thread &thread) #define THREAD_PLAN_USE_ASSEMBLY_TRACER 1 #ifdef THREAD_PLAN_USE_ASSEMBLY_TRACER - ThreadPlanTracerSP new_tracer_sp(new ThreadPlanAssemblyTracer(m_thread)); + ThreadPlanTracerSP new_tracer_sp(new ThreadPlanAssemblyTracer(thread)); #else ThreadPlanTracerSP new_tracer_sp(new ThreadPlanTracer(m_thread)); #endif - new_tracer_sp->EnableTracing(m_thread.GetTraceEnabledState()); + new_tracer_sp->EnableTracing(thread.GetTraceEnabledState()); SetThreadPlanTracer(new_tracer_sp); SetIsMasterPlan(true); } @@ -58,7 +58,7 @@ bool ThreadPlanBase::DoPlanExplainsStop(Event *event_ptr) { } Vote ThreadPlanBase::ShouldReportStop(Event *event_ptr) { - StopInfoSP stop_info_sp = m_thread.GetStopInfo(); + StopInfoSP stop_info_sp = GetThread().GetStopInfo(); if (stop_info_sp) { bool should_notify = stop_info_sp->ShouldNotify(event_ptr); if (should_notify) @@ -96,8 +96,8 @@ bool ThreadPlanBase::ShouldStop(Event *event_ptr) { log, "Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 " (breakpoint hit.)", - m_thread.GetID()); - m_thread.DiscardThreadPlans(false); + m_tid); + GetThread().DiscardThreadPlans(false); return true; } // If we aren't going to stop at this breakpoint, and it is internal, @@ -125,9 +125,9 @@ bool ThreadPlanBase::ShouldStop(Event *event_ptr) { LLDB_LOGF( log, "Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 - " (exception: %s)", - m_thread.GetID(), stop_info_sp->GetDescription()); - m_thread.DiscardThreadPlans(false); + " (exception: %s)", + m_tid, stop_info_sp->GetDescription()); + GetThread().DiscardThreadPlans(false); return true; case eStopReasonExec: @@ -138,8 +138,8 @@ bool ThreadPlanBase::ShouldStop(Event *event_ptr) { log, "Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 " (exec.)", - m_thread.GetID()); - m_thread.DiscardThreadPlans(false); + m_tid); + GetThread().DiscardThreadPlans(false); return true; case eStopReasonThreadExiting: @@ -148,9 +148,9 @@ bool ThreadPlanBase::ShouldStop(Event *event_ptr) { LLDB_LOGF( log, "Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 - " (signal: %s)", - m_thread.GetID(), stop_info_sp->GetDescription()); - m_thread.DiscardThreadPlans(false); + " (signal: %s)", + m_tid, stop_info_sp->GetDescription()); + GetThread().DiscardThreadPlans(false); return true; } else { // We're not going to stop, but while we are here, let's figure out diff --git a/lldb/source/Target/ThreadPlanCallFunction.cpp b/lldb/source/Target/ThreadPlanCallFunction.cpp index 23d114e309905..abbc8b4f48358 100644 --- a/lldb/source/Target/ThreadPlanCallFunction.cpp +++ b/lldb/source/Target/ThreadPlanCallFunction.cpp @@ -146,7 +146,7 @@ void ThreadPlanCallFunction::ReportRegisterState(const char *message) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); if (log && log->GetVerbose()) { StreamString strm; - RegisterContext *reg_ctx = m_thread.GetRegisterContext().get(); + RegisterContext *reg_ctx = GetThread().GetRegisterContext().get(); log->PutCString(message); @@ -178,19 +178,19 @@ void ThreadPlanCallFunction::DoTakedown(bool success) { } if (!m_takedown_done) { + Thread &thread = GetThread(); if (success) { SetReturnValue(); } LLDB_LOGF(log, "ThreadPlanCallFunction(%p): DoTakedown called for thread " "0x%4.4" PRIx64 ", m_valid: %d complete: %d.\n", - static_cast(this), m_thread.GetID(), m_valid, - IsPlanComplete()); + static_cast(this), m_tid, m_valid, IsPlanComplete()); m_takedown_done = true; m_stop_address = - m_thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC(); + thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC(); m_real_stop_info_sp = GetPrivateStopInfo(); - if (!m_thread.RestoreRegisterStateFromCheckpoint(m_stored_thread_state)) { + if (!thread.RestoreRegisterStateFromCheckpoint(m_stored_thread_state)) { LLDB_LOGF(log, "ThreadPlanCallFunction(%p): DoTakedown failed to restore " "register state", @@ -205,8 +205,7 @@ void ThreadPlanCallFunction::DoTakedown(bool success) { LLDB_LOGF(log, "ThreadPlanCallFunction(%p): DoTakedown called as no-op for " "thread 0x%4.4" PRIx64 ", m_valid: %d complete: %d.\n", - static_cast(this), m_thread.GetID(), m_valid, - IsPlanComplete()); + static_cast(this), m_tid, m_valid, IsPlanComplete()); } } @@ -216,9 +215,8 @@ void ThreadPlanCallFunction::GetDescription(Stream *s, DescriptionLevel level) { if (level == eDescriptionLevelBrief) { s->Printf("Function call thread plan"); } else { - TargetSP target_sp(m_thread.CalculateTarget()); s->Printf("Thread plan to call 0x%" PRIx64, - m_function_addr.GetLoadAddress(target_sp.get())); + m_function_addr.GetLoadAddress(&GetTarget())); } } @@ -283,11 +281,9 @@ bool ThreadPlanCallFunction::DoPlanExplainsStop(Event *event_ptr) { // m_ignore_breakpoints. if (stop_reason == eStopReasonBreakpoint) { - ProcessSP process_sp(m_thread.CalculateProcess()); uint64_t break_site_id = m_real_stop_info_sp->GetValue(); BreakpointSiteSP bp_site_sp; - if (process_sp) - bp_site_sp = process_sp->GetBreakpointSiteList().FindByID(break_site_id); + bp_site_sp = m_process.GetBreakpointSiteList().FindByID(break_site_id); if (bp_site_sp) { uint32_t num_owners = bp_site_sp->GetNumberOfOwners(); bool is_internal = true; @@ -374,10 +370,11 @@ void ThreadPlanCallFunction::DidPush() { GetThread().SetStopInfoToNothing(); #ifndef SINGLE_STEP_EXPRESSIONS - m_subplan_sp = std::make_shared( - m_thread, m_start_addr, m_stop_other_threads); + Thread &thread = GetThread(); + m_subplan_sp = std::make_shared(thread, m_start_addr, + m_stop_other_threads); - m_thread.QueueThreadPlan(m_subplan_sp, false); + thread.QueueThreadPlan(m_subplan_sp, false); m_subplan_sp->SetPrivate(true); #endif } @@ -399,11 +396,10 @@ bool ThreadPlanCallFunction::MischiefManaged() { } void ThreadPlanCallFunction::SetBreakpoints() { - ProcessSP process_sp(m_thread.CalculateProcess()); - if (m_trap_exceptions && process_sp) { + if (m_trap_exceptions) { m_cxx_language_runtime = - process_sp->GetLanguageRuntime(eLanguageTypeC_plus_plus); - m_objc_language_runtime = process_sp->GetLanguageRuntime(eLanguageTypeObjC); + m_process.GetLanguageRuntime(eLanguageTypeC_plus_plus); + m_objc_language_runtime = m_process.GetLanguageRuntime(eLanguageTypeObjC); if (m_cxx_language_runtime) { m_should_clear_cxx_exception_bp = @@ -463,11 +459,10 @@ bool ThreadPlanCallFunction::RestoreThreadState() { } void ThreadPlanCallFunction::SetReturnValue() { - ProcessSP process_sp(m_thread.GetProcess()); - const ABI *abi = process_sp ? process_sp->GetABI().get() : nullptr; + const ABI *abi = m_process.GetABI().get(); if (abi && m_return_type.IsValid()) { const bool persistent = false; m_return_valobj_sp = - abi->GetReturnValueObject(m_thread, m_return_type, persistent); + abi->GetReturnValueObject(GetThread(), m_return_type, persistent); } } diff --git a/lldb/source/Target/ThreadPlanCallFunctionUsingABI.cpp b/lldb/source/Target/ThreadPlanCallFunctionUsingABI.cpp index 3155e6f7965f9..1eb409a590c26 100644 --- a/lldb/source/Target/ThreadPlanCallFunctionUsingABI.cpp +++ b/lldb/source/Target/ThreadPlanCallFunctionUsingABI.cpp @@ -49,20 +49,18 @@ void ThreadPlanCallFunctionUsingABI::GetDescription(Stream *s, if (level == eDescriptionLevelBrief) { s->Printf("Function call thread plan using ABI instead of JIT"); } else { - TargetSP target_sp(m_thread.CalculateTarget()); s->Printf("Thread plan to call 0x%" PRIx64 " using ABI instead of JIT", - m_function_addr.GetLoadAddress(target_sp.get())); + m_function_addr.GetLoadAddress(&GetTarget())); } } void ThreadPlanCallFunctionUsingABI::SetReturnValue() { - ProcessSP process_sp(m_thread.GetProcess()); - const ABI *abi = process_sp ? process_sp->GetABI().get() : nullptr; + const ABI *abi = m_process.GetABI().get(); // Ask the abi for the return value if (abi) { const bool persistent = false; m_return_valobj_sp = - abi->GetReturnValueObject(m_thread, m_return_type, persistent); + abi->GetReturnValueObject(GetThread(), m_return_type, persistent); } } diff --git a/lldb/source/Target/ThreadPlanCallUserExpression.cpp b/lldb/source/Target/ThreadPlanCallUserExpression.cpp index 436938c8f207c..fdb329920483a 100644 --- a/lldb/source/Target/ThreadPlanCallUserExpression.cpp +++ b/lldb/source/Target/ThreadPlanCallUserExpression.cpp @@ -101,8 +101,7 @@ StopInfoSP ThreadPlanCallUserExpression::GetRealStopInfo() { if (stop_info_sp) { lldb::addr_t addr = GetStopAddress(); - DynamicCheckerFunctions *checkers = - m_thread.GetProcess()->GetDynamicCheckers(); + DynamicCheckerFunctions *checkers = m_process.GetDynamicCheckers(); StreamString s; if (checkers && checkers->DoCheckersExplainStop(addr, s)) diff --git a/lldb/source/Target/ThreadPlanPython.cpp b/lldb/source/Target/ThreadPlanPython.cpp index df432a0af3dae..a432511bc7a2c 100644 --- a/lldb/source/Target/ThreadPlanPython.cpp +++ b/lldb/source/Target/ThreadPlanPython.cpp @@ -55,15 +55,16 @@ bool ThreadPlanPython::ValidatePlan(Stream *error) { return true; } +ScriptInterpreter *ThreadPlanPython::GetScriptInterpreter() { + return m_process.GetTarget().GetDebugger().GetScriptInterpreter(); +} + void ThreadPlanPython::DidPush() { // We set up the script side in DidPush, so that it can push other plans in // the constructor, and doesn't have to care about the details of DidPush. m_did_push = true; if (!m_class_name.empty()) { - ScriptInterpreter *script_interp = m_thread.GetProcess() - ->GetTarget() - .GetDebugger() - .GetScriptInterpreter(); + ScriptInterpreter *script_interp = GetScriptInterpreter(); if (script_interp) { m_implementation_sp = script_interp->CreateScriptedThreadPlan( m_class_name.c_str(), m_args_data, m_error_str, @@ -79,10 +80,7 @@ bool ThreadPlanPython::ShouldStop(Event *event_ptr) { bool should_stop = true; if (m_implementation_sp) { - ScriptInterpreter *script_interp = m_thread.GetProcess() - ->GetTarget() - .GetDebugger() - .GetScriptInterpreter(); + ScriptInterpreter *script_interp = GetScriptInterpreter(); if (script_interp) { bool script_error; should_stop = script_interp->ScriptedThreadPlanShouldStop( @@ -101,10 +99,7 @@ bool ThreadPlanPython::IsPlanStale() { bool is_stale = true; if (m_implementation_sp) { - ScriptInterpreter *script_interp = m_thread.GetProcess() - ->GetTarget() - .GetDebugger() - .GetScriptInterpreter(); + ScriptInterpreter *script_interp = GetScriptInterpreter(); if (script_interp) { bool script_error; is_stale = script_interp->ScriptedThreadPlanIsStale(m_implementation_sp, @@ -123,10 +118,7 @@ bool ThreadPlanPython::DoPlanExplainsStop(Event *event_ptr) { bool explains_stop = true; if (m_implementation_sp) { - ScriptInterpreter *script_interp = m_thread.GetProcess() - ->GetTarget() - .GetDebugger() - .GetScriptInterpreter(); + ScriptInterpreter *script_interp = GetScriptInterpreter(); if (script_interp) { bool script_error; explains_stop = script_interp->ScriptedThreadPlanExplainsStop( @@ -159,10 +151,7 @@ lldb::StateType ThreadPlanPython::GetPlanRunState() { m_class_name.c_str()); lldb::StateType run_state = eStateRunning; if (m_implementation_sp) { - ScriptInterpreter *script_interp = m_thread.GetProcess() - ->GetTarget() - .GetDebugger() - .GetScriptInterpreter(); + ScriptInterpreter *script_interp = GetScriptInterpreter(); if (script_interp) { bool script_error; run_state = script_interp->ScriptedThreadPlanGetRunState( diff --git a/lldb/source/Target/ThreadPlanRunToAddress.cpp b/lldb/source/Target/ThreadPlanRunToAddress.cpp index 32ea2e6752707..f8a543ad21cf9 100644 --- a/lldb/source/Target/ThreadPlanRunToAddress.cpp +++ b/lldb/source/Target/ThreadPlanRunToAddress.cpp @@ -25,7 +25,7 @@ ThreadPlanRunToAddress::ThreadPlanRunToAddress(Thread &thread, Address &address, eVoteNoOpinion, eVoteNoOpinion), m_stop_others(stop_others), m_addresses(), m_break_ids() { m_addresses.push_back( - address.GetOpcodeLoadAddress(m_thread.CalculateTarget().get())); + address.GetOpcodeLoadAddress(thread.CalculateTarget().get())); SetInitialBreakpoints(); } @@ -36,7 +36,7 @@ ThreadPlanRunToAddress::ThreadPlanRunToAddress(Thread &thread, eVoteNoOpinion, eVoteNoOpinion), m_stop_others(stop_others), m_addresses(), m_break_ids() { m_addresses.push_back( - m_thread.CalculateTarget()->GetOpcodeLoadAddress(address)); + thread.CalculateTarget()->GetOpcodeLoadAddress(address)); SetInitialBreakpoints(); } @@ -62,14 +62,13 @@ void ThreadPlanRunToAddress::SetInitialBreakpoints() { for (size_t i = 0; i < num_addresses; i++) { Breakpoint *breakpoint; - breakpoint = m_thread.CalculateTarget() - ->CreateBreakpoint(m_addresses[i], true, false) - .get(); + breakpoint = + GetTarget().CreateBreakpoint(m_addresses[i], true, false).get(); if (breakpoint != nullptr) { if (breakpoint->IsHardware() && !breakpoint->HasResolvedLocations()) m_could_not_resolve_hw_bp = true; m_break_ids[i] = breakpoint->GetID(); - breakpoint->SetThreadID(m_thread.GetID()); + breakpoint->SetThreadID(m_tid); breakpoint->SetBreakpointKind("run-to-address"); } } @@ -78,7 +77,7 @@ void ThreadPlanRunToAddress::SetInitialBreakpoints() { ThreadPlanRunToAddress::~ThreadPlanRunToAddress() { size_t num_break_ids = m_break_ids.size(); for (size_t i = 0; i < num_break_ids; i++) { - m_thread.CalculateTarget()->RemoveBreakpointByID(m_break_ids[i]); + GetTarget().RemoveBreakpointByID(m_break_ids[i]); } m_could_not_resolve_hw_bp = false; } @@ -119,7 +118,7 @@ void ThreadPlanRunToAddress::GetDescription(Stream *s, DumpAddress(s->AsRawOstream(), m_addresses[i], sizeof(addr_t)); s->Printf(" using breakpoint: %d - ", m_break_ids[i]); Breakpoint *breakpoint = - m_thread.CalculateTarget()->GetBreakpointByID(m_break_ids[i]).get(); + GetTarget().GetBreakpointByID(m_break_ids[i]).get(); if (breakpoint) breakpoint->Dump(s); else @@ -178,7 +177,7 @@ bool ThreadPlanRunToAddress::MischiefManaged() { for (size_t i = 0; i < num_break_ids; i++) { if (m_break_ids[i] != LLDB_INVALID_BREAK_ID) { - m_thread.CalculateTarget()->RemoveBreakpointByID(m_break_ids[i]); + GetTarget().RemoveBreakpointByID(m_break_ids[i]); m_break_ids[i] = LLDB_INVALID_BREAK_ID; } } @@ -190,7 +189,7 @@ bool ThreadPlanRunToAddress::MischiefManaged() { } bool ThreadPlanRunToAddress::AtOurAddress() { - lldb::addr_t current_address = m_thread.GetRegisterContext()->GetPC(); + lldb::addr_t current_address = GetThread().GetRegisterContext()->GetPC(); bool found_it = false; size_t num_addresses = m_addresses.size(); for (size_t i = 0; i < num_addresses; i++) { diff --git a/lldb/source/Target/ThreadPlanStepInRange.cpp b/lldb/source/Target/ThreadPlanStepInRange.cpp index ab1f6a21a8623..a152f361c8f5b 100644 --- a/lldb/source/Target/ThreadPlanStepInRange.cpp +++ b/lldb/source/Target/ThreadPlanStepInRange.cpp @@ -69,7 +69,7 @@ void ThreadPlanStepInRange::SetupAvoidNoDebug( LazyBool step_in_avoids_code_without_debug_info, LazyBool step_out_avoids_code_without_debug_info) { bool avoid_nodebug = true; - + Thread &thread = GetThread(); switch (step_in_avoids_code_without_debug_info) { case eLazyBoolYes: avoid_nodebug = true; @@ -78,7 +78,7 @@ void ThreadPlanStepInRange::SetupAvoidNoDebug( avoid_nodebug = false; break; case eLazyBoolCalculate: - avoid_nodebug = m_thread.GetStepInAvoidsNoDebug(); + avoid_nodebug = thread.GetStepInAvoidsNoDebug(); break; } if (avoid_nodebug) @@ -94,7 +94,7 @@ void ThreadPlanStepInRange::SetupAvoidNoDebug( avoid_nodebug = false; break; case eLazyBoolCalculate: - avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug(); + avoid_nodebug = thread.GetStepOutAvoidsNoDebug(); break; } if (avoid_nodebug) @@ -145,9 +145,8 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) { if (log) { StreamString s; - DumpAddress( - s.AsRawOstream(), m_thread.GetRegisterContext()->GetPC(), - m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize()); + DumpAddress(s.AsRawOstream(), GetThread().GetRegisterContext()->GetPC(), + GetTarget().GetArchitecture().GetAddressByteSize()); LLDB_LOGF(log, "ThreadPlanStepInRange reached %s.", s.GetData()); } @@ -180,6 +179,7 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) { FrameComparison frame_order = CompareCurrentFrameToStartFrame(); + Thread &thread = GetThread(); if (frame_order == eFrameCompareOlder || frame_order == eFrameCompareSameParent) { // If we're in an older frame then we should stop. @@ -189,7 +189,7 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) { // I'm going to make the assumption that you wouldn't RETURN to a // trampoline. So if we are in a trampoline we think the frame is older // because the trampoline confused the backtracer. - m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough( + m_sub_plan_sp = thread.QueueThreadPlanForStepThrough( m_stack_id, false, stop_others, m_status); if (!m_sub_plan_sp) { // Otherwise check the ShouldStopHere for step out: @@ -233,7 +233,7 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) { // We may have set the plan up above in the FrameIsOlder section: if (!m_sub_plan_sp) - m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough( + m_sub_plan_sp = thread.QueueThreadPlanForStepThrough( m_stack_id, false, stop_others, m_status); if (log) { @@ -254,10 +254,10 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) { if (!m_sub_plan_sp && frame_order == eFrameCompareYounger && m_step_past_prologue) { - lldb::StackFrameSP curr_frame = m_thread.GetStackFrameAtIndex(0); + lldb::StackFrameSP curr_frame = thread.GetStackFrameAtIndex(0); if (curr_frame) { size_t bytes_to_skip = 0; - lldb::addr_t curr_addr = m_thread.GetRegisterContext()->GetPC(); + lldb::addr_t curr_addr = thread.GetRegisterContext()->GetPC(); Address func_start_address; SymbolContext sc = curr_frame->GetSymbolContext(eSymbolContextFunction | @@ -265,25 +265,20 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) { if (sc.function) { func_start_address = sc.function->GetAddressRange().GetBaseAddress(); - if (curr_addr == - func_start_address.GetLoadAddress( - m_thread.CalculateTarget().get())) + if (curr_addr == func_start_address.GetLoadAddress(&GetTarget())) bytes_to_skip = sc.function->GetPrologueByteSize(); } else if (sc.symbol) { func_start_address = sc.symbol->GetAddress(); - if (curr_addr == - func_start_address.GetLoadAddress( - m_thread.CalculateTarget().get())) + if (curr_addr == func_start_address.GetLoadAddress(&GetTarget())) bytes_to_skip = sc.symbol->GetPrologueByteSize(); } if (bytes_to_skip == 0 && sc.symbol) { - TargetSP target = m_thread.CalculateTarget(); - const Architecture *arch = target->GetArchitecturePlugin(); + const Architecture *arch = GetTarget().GetArchitecturePlugin(); if (arch) { Address curr_sec_addr; - target->GetSectionLoadList().ResolveLoadAddress(curr_addr, - curr_sec_addr); + GetTarget().GetSectionLoadList().ResolveLoadAddress(curr_addr, + curr_sec_addr); bytes_to_skip = arch->GetBytesToSkip(*sc.symbol, curr_sec_addr); } } @@ -293,7 +288,7 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) { log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP); LLDB_LOGF(log, "Pushing past prologue "); - m_sub_plan_sp = m_thread.QueueThreadPlanForRunToAddress( + m_sub_plan_sp = thread.QueueThreadPlanForRunToAddress( false, func_start_address, true, m_status); } } @@ -486,15 +481,16 @@ bool ThreadPlanStepInRange::DoWillResume(lldb::StateType resume_state, bool current_plan) { m_virtual_step = false; if (resume_state == eStateStepping && current_plan) { + Thread &thread = GetThread(); // See if we are about to step over a virtual inlined call. - bool step_without_resume = m_thread.DecrementCurrentInlinedDepth(); + bool step_without_resume = thread.DecrementCurrentInlinedDepth(); if (step_without_resume) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); LLDB_LOGF(log, "ThreadPlanStepInRange::DoWillResume: returning false, " "inline_depth: %d", - m_thread.GetCurrentInlinedDepth()); - SetStopInfo(StopInfo::CreateStopReasonToTrace(m_thread)); + thread.GetCurrentInlinedDepth()); + SetStopInfo(StopInfo::CreateStopReasonToTrace(thread)); // FIXME: Maybe it would be better to create a InlineStep stop reason, but // then diff --git a/lldb/source/Target/ThreadPlanStepInstruction.cpp b/lldb/source/Target/ThreadPlanStepInstruction.cpp index afcc9d608b27c..0507df99bca08 100644 --- a/lldb/source/Target/ThreadPlanStepInstruction.cpp +++ b/lldb/source/Target/ThreadPlanStepInstruction.cpp @@ -36,14 +36,15 @@ ThreadPlanStepInstruction::ThreadPlanStepInstruction(Thread &thread, ThreadPlanStepInstruction::~ThreadPlanStepInstruction() = default; void ThreadPlanStepInstruction::SetUpState() { - m_instruction_addr = m_thread.GetRegisterContext()->GetPC(0); - StackFrameSP start_frame_sp(m_thread.GetStackFrameAtIndex(0)); + Thread &thread = GetThread(); + m_instruction_addr = thread.GetRegisterContext()->GetPC(0); + StackFrameSP start_frame_sp(thread.GetStackFrameAtIndex(0)); m_stack_id = start_frame_sp->GetStackID(); m_start_has_symbol = start_frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol != nullptr; - StackFrameSP parent_frame_sp = m_thread.GetStackFrameAtIndex(1); + StackFrameSP parent_frame_sp = thread.GetStackFrameAtIndex(1); if (parent_frame_sp) m_parent_frame_id = parent_frame_sp->GetStackID(); } @@ -95,18 +96,19 @@ bool ThreadPlanStepInstruction::DoPlanExplainsStop(Event *event_ptr) { bool ThreadPlanStepInstruction::IsPlanStale() { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); - StackID cur_frame_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); + Thread &thread = GetThread(); + StackID cur_frame_id = thread.GetStackFrameAtIndex(0)->GetStackID(); if (cur_frame_id == m_stack_id) { // Set plan Complete when we reach next instruction - uint64_t pc = m_thread.GetRegisterContext()->GetPC(0); - uint32_t max_opcode_size = m_thread.CalculateTarget() - ->GetArchitecture().GetMaximumOpcodeByteSize(); + uint64_t pc = thread.GetRegisterContext()->GetPC(0); + uint32_t max_opcode_size = + GetTarget().GetArchitecture().GetMaximumOpcodeByteSize(); bool next_instruction_reached = (pc > m_instruction_addr) && (pc <= m_instruction_addr + max_opcode_size); if (next_instruction_reached) { SetPlanComplete(); } - return (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr); + return (thread.GetRegisterContext()->GetPC(0) != m_instruction_addr); } else if (cur_frame_id < m_stack_id) { // If the current frame is younger than the start frame and we are stepping // over, then we need to continue, but if we are doing just one step, we're @@ -123,10 +125,10 @@ bool ThreadPlanStepInstruction::IsPlanStale() { } bool ThreadPlanStepInstruction::ShouldStop(Event *event_ptr) { + Thread &thread = GetThread(); if (m_step_over) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); - - StackFrameSP cur_frame_sp = m_thread.GetStackFrameAtIndex(0); + StackFrameSP cur_frame_sp = thread.GetStackFrameAtIndex(0); if (!cur_frame_sp) { LLDB_LOGF( log, @@ -138,7 +140,7 @@ bool ThreadPlanStepInstruction::ShouldStop(Event *event_ptr) { StackID cur_frame_zero_id = cur_frame_sp->GetStackID(); if (cur_frame_zero_id == m_stack_id || m_stack_id < cur_frame_zero_id) { - if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr) { + if (thread.GetRegisterContext()->GetPC(0) != m_instruction_addr) { if (--m_iteration_count <= 0) { SetPlanComplete(); return true; @@ -152,7 +154,7 @@ bool ThreadPlanStepInstruction::ShouldStop(Event *event_ptr) { return false; } else { // We've stepped in, step back out again: - StackFrame *return_frame = m_thread.GetStackFrameAtIndex(1).get(); + StackFrame *return_frame = thread.GetStackFrameAtIndex(1).get(); if (return_frame) { if (return_frame->GetStackID() != m_parent_frame_id || m_start_has_symbol) { @@ -162,7 +164,7 @@ bool ThreadPlanStepInstruction::ShouldStop(Event *event_ptr) { if (cur_frame_sp->IsInlined()) { StackFrameSP parent_frame_sp = - m_thread.GetFrameWithStackID(m_stack_id); + thread.GetFrameWithStackID(m_stack_id); if (parent_frame_sp && parent_frame_sp->GetConcreteFrameIndex() == @@ -181,24 +183,20 @@ bool ThreadPlanStepInstruction::ShouldStop(Event *event_ptr) { StreamString s; s.PutCString("Stepped in to: "); addr_t stop_addr = - m_thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC(); + thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC(); DumpAddress(s.AsRawOstream(), stop_addr, - m_thread.CalculateTarget() - ->GetArchitecture() - .GetAddressByteSize()); + GetTarget().GetArchitecture().GetAddressByteSize()); s.PutCString(" stepping out to: "); addr_t return_addr = return_frame->GetRegisterContext()->GetPC(); DumpAddress(s.AsRawOstream(), return_addr, - m_thread.CalculateTarget() - ->GetArchitecture() - .GetAddressByteSize()); + GetTarget().GetArchitecture().GetAddressByteSize()); LLDB_LOGF(log, "%s.", s.GetData()); } // StepInstruction should probably have the tri-state RunMode, but // for now it is safer to run others. const bool stop_others = false; - m_thread.QueueThreadPlanForStepOutNoShouldStop( + thread.QueueThreadPlanForStepOutNoShouldStop( false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0, m_status); return false; @@ -219,7 +217,7 @@ bool ThreadPlanStepInstruction::ShouldStop(Event *event_ptr) { } } } else { - lldb::addr_t pc_addr = m_thread.GetRegisterContext()->GetPC(0); + lldb::addr_t pc_addr = thread.GetRegisterContext()->GetPC(0); if (pc_addr != m_instruction_addr) { if (--m_iteration_count <= 0) { SetPlanComplete(); diff --git a/lldb/source/Target/ThreadPlanStepOut.cpp b/lldb/source/Target/ThreadPlanStepOut.cpp index f15a343aaa385..c7a0bf667e0c3 100644 --- a/lldb/source/Target/ThreadPlanStepOut.cpp +++ b/lldb/source/Target/ThreadPlanStepOut.cpp @@ -47,13 +47,11 @@ ThreadPlanStepOut::ThreadPlanStepOut( SetFlagsToDefault(); SetupAvoidNoDebug(step_out_avoids_code_without_debug_info); - m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0); + m_step_from_insn = thread.GetRegisterContext()->GetPC(0); uint32_t return_frame_index = frame_idx + 1; - StackFrameSP return_frame_sp( - m_thread.GetStackFrameAtIndex(return_frame_index)); - StackFrameSP immediate_return_from_sp( - m_thread.GetStackFrameAtIndex(frame_idx)); + StackFrameSP return_frame_sp(thread.GetStackFrameAtIndex(return_frame_index)); + StackFrameSP immediate_return_from_sp(thread.GetStackFrameAtIndex(frame_idx)); if (!return_frame_sp || !immediate_return_from_sp) return; // we can't do anything here. ValidatePlan() will return false. @@ -63,7 +61,7 @@ ThreadPlanStepOut::ThreadPlanStepOut( m_stepped_past_frames.push_back(return_frame_sp); ++return_frame_index; - return_frame_sp = m_thread.GetStackFrameAtIndex(return_frame_index); + return_frame_sp = thread.GetStackFrameAtIndex(return_frame_index); // We never expect to see an artificial frame without a regular ancestor. // If this happens, log the issue and defensively refuse to step out. @@ -85,7 +83,7 @@ ThreadPlanStepOut::ThreadPlanStepOut( // First queue a plan that gets us to this inlined frame, and when we get // there we'll queue a second plan that walks us out of this frame. m_step_out_to_inline_plan_sp = std::make_shared( - m_thread, nullptr, false, stop_others, eVoteNoOpinion, eVoteNoOpinion, + thread, nullptr, false, stop_others, eVoteNoOpinion, eVoteNoOpinion, frame_idx - 1, eLazyBoolNo, continue_to_next_branch); static_cast(m_step_out_to_inline_plan_sp.get()) ->SetShouldStopHereCallbacks(nullptr, nullptr); @@ -114,22 +112,20 @@ ThreadPlanStepOut::ThreadPlanStepOut( range = return_address_sc.line_entry.GetSameLineContiguousAddressRange( include_inlined_functions); if (range.GetByteSize() > 0) { - return_address = - m_thread.GetProcess()->AdvanceAddressToNextBranchInstruction( - return_address, range); + return_address = m_process.AdvanceAddressToNextBranchInstruction( + return_address, range); } } } - m_return_addr = - return_address.GetLoadAddress(&m_thread.GetProcess()->GetTarget()); + m_return_addr = return_address.GetLoadAddress(&m_process.GetTarget()); if (m_return_addr == LLDB_INVALID_ADDRESS) return; // Perform some additional validation on the return address. uint32_t permissions = 0; - if (!m_thread.GetProcess()->GetLoadAddressPermissions(m_return_addr, - permissions)) { + if (!m_process->GetLoadAddressPermissions(m_return_addr, + permissions)) { m_constructor_errors.Printf("Return address (0x%" PRIx64 ") permissions not found.", m_return_addr); @@ -145,14 +141,13 @@ ThreadPlanStepOut::ThreadPlanStepOut( return; } - Breakpoint *return_bp = m_thread.CalculateTarget() - ->CreateBreakpoint(m_return_addr, true, false) - .get(); + Breakpoint *return_bp = + GetTarget().CreateBreakpoint(m_return_addr, true, false).get(); if (return_bp != nullptr) { if (return_bp->IsHardware() && !return_bp->HasResolvedLocations()) m_could_not_resolve_hw_bp = true; - return_bp->SetThreadID(m_thread.GetID()); + return_bp->SetThreadID(m_tid); m_return_bp_id = return_bp->GetID(); return_bp->SetBreakpointKind("step-out"); } @@ -178,7 +173,7 @@ void ThreadPlanStepOut::SetupAvoidNoDebug( avoid_nodebug = false; break; case eLazyBoolCalculate: - avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug(); + avoid_nodebug = GetThread().GetStepOutAvoidsNoDebug(); break; } if (avoid_nodebug) @@ -188,15 +183,16 @@ void ThreadPlanStepOut::SetupAvoidNoDebug( } void ThreadPlanStepOut::DidPush() { + Thread &thread = GetThread(); if (m_step_out_to_inline_plan_sp) - m_thread.QueueThreadPlan(m_step_out_to_inline_plan_sp, false); + thread.QueueThreadPlan(m_step_out_to_inline_plan_sp, false); else if (m_step_through_inline_plan_sp) - m_thread.QueueThreadPlan(m_step_through_inline_plan_sp, false); + thread.QueueThreadPlan(m_step_through_inline_plan_sp, false); } ThreadPlanStepOut::~ThreadPlanStepOut() { if (m_return_bp_id != LLDB_INVALID_BREAK_ID) - m_thread.CalculateTarget()->RemoveBreakpointByID(m_return_bp_id); + GetThread().CalculateTarget()->RemoveBreakpointByID(m_return_bp_id); } void ThreadPlanStepOut::GetDescription(Stream *s, @@ -296,12 +292,12 @@ bool ThreadPlanStepOut::DoPlanExplainsStop(Event *event_ptr) { // If this is OUR breakpoint, we're fine, otherwise we don't know why // this happened... BreakpointSiteSP site_sp( - m_thread.GetProcess()->GetBreakpointSiteList().FindByID( - stop_info_sp->GetValue())); + m_process.GetBreakpointSiteList().FindByID(stop_info_sp->GetValue())); if (site_sp && site_sp->IsBreakpointAtThisSite(m_return_bp_id)) { bool done; - StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); + StackID frame_zero_id = + GetThread().GetStackFrameAtIndex(0)->GetStackID(); if (m_step_out_to_id == frame_zero_id) done = true; @@ -368,7 +364,7 @@ bool ThreadPlanStepOut::ShouldStop(Event *event_ptr) { } if (!done) { - StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); + StackID frame_zero_id = GetThread().GetStackFrameAtIndex(0)->GetStackID(); done = !(frame_zero_id < m_step_out_to_id); } @@ -402,8 +398,7 @@ bool ThreadPlanStepOut::DoWillResume(StateType resume_state, return false; if (current_plan) { - Breakpoint *return_bp = - m_thread.CalculateTarget()->GetBreakpointByID(m_return_bp_id).get(); + Breakpoint *return_bp = GetTarget().GetBreakpointByID(m_return_bp_id).get(); if (return_bp != nullptr) return_bp->SetEnabled(true); } @@ -412,8 +407,7 @@ bool ThreadPlanStepOut::DoWillResume(StateType resume_state, bool ThreadPlanStepOut::WillStop() { if (m_return_bp_id != LLDB_INVALID_BREAK_ID) { - Breakpoint *return_bp = - m_thread.CalculateTarget()->GetBreakpointByID(m_return_bp_id).get(); + Breakpoint *return_bp = GetTarget().GetBreakpointByID(m_return_bp_id).get(); if (return_bp != nullptr) return_bp->SetEnabled(false); } @@ -434,7 +428,7 @@ bool ThreadPlanStepOut::MischiefManaged() { if (log) LLDB_LOGF(log, "Completed step out plan."); if (m_return_bp_id != LLDB_INVALID_BREAK_ID) { - m_thread.CalculateTarget()->RemoveBreakpointByID(m_return_bp_id); + GetTarget().RemoveBreakpointByID(m_return_bp_id); m_return_bp_id = LLDB_INVALID_BREAK_ID; } @@ -449,7 +443,8 @@ bool ThreadPlanStepOut::QueueInlinedStepPlan(bool queue_now) { // Now figure out the range of this inlined block, and set up a "step through // range" plan for that. If we've been provided with a context, then use the // block in that context. - StackFrameSP immediate_return_from_sp(m_thread.GetStackFrameAtIndex(0)); + Thread &thread = GetThread(); + StackFrameSP immediate_return_from_sp(thread.GetStackFrameAtIndex(0)); if (!immediate_return_from_sp) return false; @@ -476,7 +471,7 @@ bool ThreadPlanStepOut::QueueInlinedStepPlan(bool queue_now) { m_step_through_inline_plan_sp = std::make_shared( - m_thread, inline_range, inlined_sc, run_mode, avoid_no_debug); + thread, inline_range, inlined_sc, run_mode, avoid_no_debug); ThreadPlanStepOverRange *step_through_inline_plan_ptr = static_cast( m_step_through_inline_plan_sp.get()); @@ -496,7 +491,7 @@ bool ThreadPlanStepOut::QueueInlinedStepPlan(bool queue_now) { } if (queue_now) - m_thread.QueueThreadPlan(m_step_through_inline_plan_sp, false); + thread.QueueThreadPlan(m_step_through_inline_plan_sp, false); return true; } } @@ -517,10 +512,10 @@ void ThreadPlanStepOut::CalculateReturnValue() { m_immediate_step_from_function->GetCompilerType() .GetFunctionReturnType(); if (return_compiler_type) { - lldb::ABISP abi_sp = m_thread.GetProcess()->GetABI(); + lldb::ABISP abi_sp = m_process.GetABI(); if (abi_sp) m_return_valobj_sp = - abi_sp->GetReturnValueObject(m_thread, return_compiler_type); + abi_sp->GetReturnValueObject(GetThread(), return_compiler_type); } } } @@ -529,6 +524,6 @@ bool ThreadPlanStepOut::IsPlanStale() { // If we are still lower on the stack than the frame we are returning to, // then there's something for us to do. Otherwise, we're stale. - StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); + StackID frame_zero_id = GetThread().GetStackFrameAtIndex(0)->GetStackID(); return !(frame_zero_id < m_step_out_to_id); } diff --git a/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp b/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp index 725669b1e9a8b..22498fd65f6f9 100644 --- a/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp +++ b/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp @@ -30,9 +30,9 @@ ThreadPlanStepOverBreakpoint::ThreadPlanStepOverBreakpoint(Thread &thread) m_auto_continue(false), m_reenabled_breakpoint_site(false) { - m_breakpoint_addr = m_thread.GetRegisterContext()->GetPC(); + m_breakpoint_addr = thread.GetRegisterContext()->GetPC(); m_breakpoint_site_id = - m_thread.GetProcess()->GetBreakpointSiteList().FindIDByAddress( + thread.GetProcess()->GetBreakpointSiteList().FindIDByAddress( m_breakpoint_addr); } @@ -86,7 +86,7 @@ bool ThreadPlanStepOverBreakpoint::DoPlanExplainsStop(Event *event_ptr) { // Be careful, however, as we may have "seen a breakpoint under the PC // because we stopped without changing the PC, in which case we do want // to re-claim this stop so we'll try again. - lldb::addr_t pc_addr = m_thread.GetRegisterContext()->GetPC(); + lldb::addr_t pc_addr = GetThread().GetRegisterContext()->GetPC(); if (pc_addr == m_breakpoint_addr) { LLDB_LOGF(log, @@ -120,10 +120,9 @@ bool ThreadPlanStepOverBreakpoint::DoWillResume(StateType resume_state, bool current_plan) { if (current_plan) { BreakpointSiteSP bp_site_sp( - m_thread.GetProcess()->GetBreakpointSiteList().FindByAddress( - m_breakpoint_addr)); + m_process.GetBreakpointSiteList().FindByAddress(m_breakpoint_addr)); if (bp_site_sp && bp_site_sp->IsEnabled()) { - m_thread.GetProcess()->DisableBreakpointSite(bp_site_sp.get()); + m_process.DisableBreakpointSite(bp_site_sp.get()); m_reenabled_breakpoint_site = false; } } @@ -140,7 +139,7 @@ void ThreadPlanStepOverBreakpoint::WillPop() { } bool ThreadPlanStepOverBreakpoint::MischiefManaged() { - lldb::addr_t pc_addr = m_thread.GetRegisterContext()->GetPC(); + lldb::addr_t pc_addr = GetThread().GetRegisterContext()->GetPC(); if (pc_addr == m_breakpoint_addr) { // If we are still at the PC of our breakpoint, then for some reason we @@ -161,10 +160,9 @@ void ThreadPlanStepOverBreakpoint::ReenableBreakpointSite() { if (!m_reenabled_breakpoint_site) { m_reenabled_breakpoint_site = true; BreakpointSiteSP bp_site_sp( - m_thread.GetProcess()->GetBreakpointSiteList().FindByAddress( - m_breakpoint_addr)); + m_process.GetBreakpointSiteList().FindByAddress(m_breakpoint_addr)); if (bp_site_sp) { - m_thread.GetProcess()->EnableBreakpointSite(bp_site_sp.get()); + m_process.EnableBreakpointSite(bp_site_sp.get()); } } } @@ -181,5 +179,5 @@ bool ThreadPlanStepOverBreakpoint::ShouldAutoContinue(Event *event_ptr) { } bool ThreadPlanStepOverBreakpoint::IsPlanStale() { - return m_thread.GetRegisterContext()->GetPC() != m_breakpoint_addr; + return GetThread().GetRegisterContext()->GetPC() != m_breakpoint_addr; } diff --git a/lldb/source/Target/ThreadPlanStepOverRange.cpp b/lldb/source/Target/ThreadPlanStepOverRange.cpp index 3dc1967e6d4e5..ab49a37bc8d55 100644 --- a/lldb/source/Target/ThreadPlanStepOverRange.cpp +++ b/lldb/source/Target/ThreadPlanStepOverRange.cpp @@ -85,7 +85,7 @@ void ThreadPlanStepOverRange::SetupAvoidNoDebug( avoid_nodebug = false; break; case eLazyBoolCalculate: - avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug(); + avoid_nodebug = GetThread().GetStepOutAvoidsNoDebug(); break; } if (avoid_nodebug) @@ -125,12 +125,12 @@ bool ThreadPlanStepOverRange::IsEquivalentContext( bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + Thread &thread = GetThread(); if (log) { StreamString s; - DumpAddress( - s.AsRawOstream(), m_thread.GetRegisterContext()->GetPC(), - m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize()); + DumpAddress(s.AsRawOstream(), thread.GetRegisterContext()->GetPC(), + GetTarget().GetArchitecture().GetAddressByteSize()); LLDB_LOGF(log, "ThreadPlanStepOverRange reached %s.", s.GetData()); } @@ -151,8 +151,8 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) { // because the trampoline confused the backtracer. As below, we step // through first, and then try to figure out how to get back out again. - new_plan_sp = m_thread.QueueThreadPlanForStepThrough(m_stack_id, false, - stop_others, m_status); + new_plan_sp = thread.QueueThreadPlanForStepThrough(m_stack_id, false, + stop_others, m_status); if (new_plan_sp && log) LLDB_LOGF(log, @@ -161,7 +161,7 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) { // Make sure we really are in a new frame. Do that by unwinding and seeing // if the start function really is our start function... for (uint32_t i = 1;; ++i) { - StackFrameSP older_frame_sp = m_thread.GetStackFrameAtIndex(i); + StackFrameSP older_frame_sp = thread.GetStackFrameAtIndex(i); if (!older_frame_sp) { // We can't unwind the next frame we should just get out of here & // stop... @@ -171,12 +171,12 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) { const SymbolContext &older_context = older_frame_sp->GetSymbolContext(eSymbolContextEverything); if (IsEquivalentContext(older_context)) { - new_plan_sp = m_thread.QueueThreadPlanForStepOutNoShouldStop( + new_plan_sp = thread.QueueThreadPlanForStepOutNoShouldStop( false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0, m_status, true); break; } else { - new_plan_sp = m_thread.QueueThreadPlanForStepThrough( + new_plan_sp = thread.QueueThreadPlanForStepThrough( m_stack_id, false, stop_others, m_status); // If we found a way through, then we should stop recursing. if (new_plan_sp) @@ -196,8 +196,8 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) { // we are in a stub then it's likely going to be hard to get out from // here. It is probably easiest to step into the stub, and then it will // be straight-forward to step out. - new_plan_sp = m_thread.QueueThreadPlanForStepThrough( - m_stack_id, false, stop_others, m_status); + new_plan_sp = thread.QueueThreadPlanForStepThrough(m_stack_id, false, + stop_others, m_status); } else { // The current clang (at least through 424) doesn't always get the // address range for the DW_TAG_inlined_subroutines right, so that when @@ -212,7 +212,7 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) { if (m_addr_context.line_entry.IsValid()) { SymbolContext sc; - StackFrameSP frame_sp = m_thread.GetStackFrameAtIndex(0); + StackFrameSP frame_sp = thread.GetStackFrameAtIndex(0); sc = frame_sp->GetSymbolContext(eSymbolContextEverything); if (sc.line_entry.IsValid()) { if (sc.line_entry.original_file != @@ -278,7 +278,7 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) { m_addr_context.line_entry.original_file) { const bool abort_other_plans = false; const RunMode stop_other_threads = RunMode::eAllThreads; - lldb::addr_t cur_pc = m_thread.GetStackFrameAtIndex(0) + lldb::addr_t cur_pc = thread.GetStackFrameAtIndex(0) ->GetRegisterContext() ->GetPC(); AddressRange step_range( @@ -286,7 +286,7 @@ bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) { next_line_address.GetLoadAddress(&GetTarget()) - cur_pc); - new_plan_sp = m_thread.QueueThreadPlanForStepOverRange( + new_plan_sp = thread.QueueThreadPlanForStepOverRange( abort_other_plans, step_range, sc, stop_other_threads, m_status); break; @@ -365,23 +365,24 @@ bool ThreadPlanStepOverRange::DoWillResume(lldb::StateType resume_state, if (resume_state != eStateSuspended && m_first_resume) { m_first_resume = false; if (resume_state == eStateStepping && current_plan) { + Thread &thread = GetThread(); // See if we are about to step over an inlined call in the middle of the // inlined stack, if so figure out its extents and reset our range to // step over that. - bool in_inlined_stack = m_thread.DecrementCurrentInlinedDepth(); + bool in_inlined_stack = thread.DecrementCurrentInlinedDepth(); if (in_inlined_stack) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); LLDB_LOGF(log, "ThreadPlanStepInRange::DoWillResume: adjusting range to " "the frame at inlined depth %d.", - m_thread.GetCurrentInlinedDepth()); - StackFrameSP stack_sp = m_thread.GetStackFrameAtIndex(0); + thread.GetCurrentInlinedDepth()); + StackFrameSP stack_sp = thread.GetStackFrameAtIndex(0); if (stack_sp) { Block *frame_block = stack_sp->GetFrameBlock(); - lldb::addr_t curr_pc = m_thread.GetRegisterContext()->GetPC(); + lldb::addr_t curr_pc = thread.GetRegisterContext()->GetPC(); AddressRange my_range; if (frame_block->GetRangeContainingLoadAddress( - curr_pc, m_thread.GetProcess()->GetTarget(), my_range)) { + curr_pc, m_process.GetTarget(), my_range)) { m_address_ranges.clear(); m_address_ranges.push_back(my_range); if (log) { diff --git a/lldb/source/Target/ThreadPlanStepRange.cpp b/lldb/source/Target/ThreadPlanStepRange.cpp index d1c56165da500..90cdac5b98099 100644 --- a/lldb/source/Target/ThreadPlanStepRange.cpp +++ b/lldb/source/Target/ThreadPlanStepRange.cpp @@ -41,8 +41,8 @@ ThreadPlanStepRange::ThreadPlanStepRange(ThreadPlanKind kind, const char *name, m_given_ranges_only(given_ranges_only) { m_use_fast_step = GetTarget().GetUseFastStepping(); AddRange(range); - m_stack_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); - StackFrameSP parent_stack = m_thread.GetStackFrameAtIndex(1); + m_stack_id = thread.GetStackFrameAtIndex(0)->GetStackID(); + StackFrameSP parent_stack = thread.GetStackFrameAtIndex(1); if (parent_stack) m_parent_stack_id = parent_stack->GetStackID(); } @@ -86,15 +86,14 @@ void ThreadPlanStepRange::AddRange(const AddressRange &new_range) { } void ThreadPlanStepRange::DumpRanges(Stream *s) { + Thread &thread = GetThread(); size_t num_ranges = m_address_ranges.size(); if (num_ranges == 1) { - m_address_ranges[0].Dump(s, m_thread.CalculateTarget().get(), - Address::DumpStyleLoadAddress); + m_address_ranges[0].Dump(s, &GetTarget(), Address::DumpStyleLoadAddress); } else { for (size_t i = 0; i < num_ranges; i++) { s->Printf(" %" PRIu64 ": ", uint64_t(i)); - m_address_ranges[i].Dump(s, m_thread.CalculateTarget().get(), - Address::DumpStyleLoadAddress); + m_address_ranges[i].Dump(s, &GetTarget(), Address::DumpStyleLoadAddress); } } } @@ -102,20 +101,20 @@ void ThreadPlanStepRange::DumpRanges(Stream *s) { bool ThreadPlanStepRange::InRange() { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); bool ret_value = false; - - lldb::addr_t pc_load_addr = m_thread.GetRegisterContext()->GetPC(); + Thread &thread = GetThread(); + lldb::addr_t pc_load_addr = thread.GetRegisterContext()->GetPC(); size_t num_ranges = m_address_ranges.size(); for (size_t i = 0; i < num_ranges; i++) { - ret_value = m_address_ranges[i].ContainsLoadAddress( - pc_load_addr, m_thread.CalculateTarget().get()); + ret_value = + m_address_ranges[i].ContainsLoadAddress(pc_load_addr, &GetTarget()); if (ret_value) break; } if (!ret_value && !m_given_ranges_only) { // See if we've just stepped to another part of the same line number... - StackFrame *frame = m_thread.GetStackFrameAtIndex(0).get(); + StackFrame *frame = thread.GetStackFrameAtIndex(0).get(); SymbolContext new_context( frame->GetSymbolContext(eSymbolContextEverything)); @@ -132,8 +131,8 @@ bool ThreadPlanStepRange::InRange() { ret_value = true; if (log) { StreamString s; - m_addr_context.line_entry.Dump(&s, m_thread.CalculateTarget().get(), - true, Address::DumpStyleLoadAddress, + m_addr_context.line_entry.Dump(&s, &GetTarget(), true, + Address::DumpStyleLoadAddress, Address::DumpStyleLoadAddress, true); LLDB_LOGF( @@ -151,8 +150,8 @@ bool ThreadPlanStepRange::InRange() { ret_value = true; if (log) { StreamString s; - m_addr_context.line_entry.Dump(&s, m_thread.CalculateTarget().get(), - true, Address::DumpStyleLoadAddress, + m_addr_context.line_entry.Dump(&s, &GetTarget(), true, + Address::DumpStyleLoadAddress, Address::DumpStyleLoadAddress, true); LLDB_LOGF(log, @@ -161,7 +160,7 @@ bool ThreadPlanStepRange::InRange() { s.GetData()); } } else if (new_context.line_entry.range.GetBaseAddress().GetLoadAddress( - m_thread.CalculateTarget().get()) != pc_load_addr) { + &GetTarget()) != pc_load_addr) { // Another thing that sometimes happens here is that we step out of // one line into the MIDDLE of another line. So far I mostly see // this due to bugs in the debug information. But we probably don't @@ -174,8 +173,8 @@ bool ThreadPlanStepRange::InRange() { ret_value = true; if (log) { StreamString s; - m_addr_context.line_entry.Dump(&s, m_thread.CalculateTarget().get(), - true, Address::DumpStyleLoadAddress, + m_addr_context.line_entry.Dump(&s, &GetTarget(), true, + Address::DumpStyleLoadAddress, Address::DumpStyleLoadAddress, true); LLDB_LOGF(log, @@ -195,14 +194,14 @@ bool ThreadPlanStepRange::InRange() { } bool ThreadPlanStepRange::InSymbol() { - lldb::addr_t cur_pc = m_thread.GetRegisterContext()->GetPC(); + lldb::addr_t cur_pc = GetThread().GetRegisterContext()->GetPC(); if (m_addr_context.function != nullptr) { return m_addr_context.function->GetAddressRange().ContainsLoadAddress( - cur_pc, m_thread.CalculateTarget().get()); + cur_pc, &GetTarget()); } else if (m_addr_context.symbol && m_addr_context.symbol->ValueIsAddress()) { AddressRange range(m_addr_context.symbol->GetAddressRef(), m_addr_context.symbol->GetByteSize()); - return range.ContainsLoadAddress(cur_pc, m_thread.CalculateTarget().get()); + return range.ContainsLoadAddress(cur_pc, &GetTarget()); } return false; } @@ -216,15 +215,15 @@ bool ThreadPlanStepRange::InSymbol() { lldb::FrameComparison ThreadPlanStepRange::CompareCurrentFrameToStartFrame() { FrameComparison frame_order; - - StackID cur_frame_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); + Thread &thread = GetThread(); + StackID cur_frame_id = thread.GetStackFrameAtIndex(0)->GetStackID(); if (cur_frame_id == m_stack_id) { frame_order = eFrameCompareEqual; } else if (cur_frame_id < m_stack_id) { frame_order = eFrameCompareYounger; } else { - StackFrameSP cur_parent_frame = m_thread.GetStackFrameAtIndex(1); + StackFrameSP cur_parent_frame = thread.GetStackFrameAtIndex(1); StackID cur_parent_id; if (cur_parent_frame) cur_parent_id = cur_parent_frame->GetStackID(); @@ -378,11 +377,10 @@ bool ThreadPlanStepRange::SetNextBranchBreakpoint() { "ThreadPlanStepRange::SetNextBranchBreakpoint - Setting " "breakpoint %d (site %d) to run to address 0x%" PRIx64, m_next_branch_bp_sp->GetID(), bp_site_id, - run_to_address.GetLoadAddress( - &m_thread.GetProcess()->GetTarget())); + run_to_address.GetLoadAddress(&m_process.GetTarget())); } - m_next_branch_bp_sp->SetThreadID(m_thread.GetID()); + m_next_branch_bp_sp->SetThreadID(m_tid); m_next_branch_bp_sp->SetBreakpointKind("next-branch-location"); return true; @@ -401,7 +399,7 @@ bool ThreadPlanStepRange::NextRangeBreakpointExplainsStop( break_id_t bp_site_id = stop_info_sp->GetValue(); BreakpointSiteSP bp_site_sp = - m_thread.GetProcess()->GetBreakpointSiteList().FindByID(bp_site_id); + m_process.GetBreakpointSiteList().FindByID(bp_site_id); if (!bp_site_sp) return false; else if (!bp_site_sp->IsBreakpointAtThisSite(m_next_branch_bp_sp->GetID())) @@ -488,11 +486,11 @@ bool ThreadPlanStepRange::IsPlanStale() { // check that we are in the same symbol. if (!InRange()) { // Set plan Complete when we reach next instruction just after the range - lldb::addr_t addr = m_thread.GetRegisterContext()->GetPC() - 1; + lldb::addr_t addr = GetThread().GetRegisterContext()->GetPC() - 1; size_t num_ranges = m_address_ranges.size(); for (size_t i = 0; i < num_ranges; i++) { - bool in_range = m_address_ranges[i].ContainsLoadAddress( - addr, m_thread.CalculateTarget().get()); + bool in_range = + m_address_ranges[i].ContainsLoadAddress(addr, &GetTarget()); if (in_range) { SetPlanComplete(); } diff --git a/lldb/source/Target/ThreadPlanStepThrough.cpp b/lldb/source/Target/ThreadPlanStepThrough.cpp index 8c7b180fce2d3..8d5939741323a 100644 --- a/lldb/source/Target/ThreadPlanStepThrough.cpp +++ b/lldb/source/Target/ThreadPlanStepThrough.cpp @@ -44,21 +44,20 @@ ThreadPlanStepThrough::ThreadPlanStepThrough(Thread &thread, // some inlined code that we're in the middle of by doing this, but it's // easier than trying to figure out where the inlined code might return to. - StackFrameSP return_frame_sp = m_thread.GetFrameWithStackID(m_stack_id); + StackFrameSP return_frame_sp = thread.GetFrameWithStackID(m_stack_id); if (return_frame_sp) { m_backstop_addr = return_frame_sp->GetFrameCodeAddress().GetLoadAddress( - m_thread.CalculateTarget().get()); + thread.CalculateTarget().get()); Breakpoint *return_bp = - m_thread.GetProcess() - ->GetTarget() + m_process.GetTarget() .CreateBreakpoint(m_backstop_addr, true, false) .get(); if (return_bp != nullptr) { if (return_bp->IsHardware() && !return_bp->HasResolvedLocations()) m_could_not_resolve_hw_bp = true; - return_bp->SetThreadID(m_thread.GetID()); + return_bp->SetThreadID(m_tid); m_backstop_bkpt_id = return_bp->GetID(); return_bp->SetBreakpointKind("step-through-backstop"); } @@ -79,18 +78,17 @@ void ThreadPlanStepThrough::DidPush() { } void ThreadPlanStepThrough::LookForPlanToStepThroughFromCurrentPC() { - DynamicLoader *loader = m_thread.GetProcess()->GetDynamicLoader(); + Thread &thread = GetThread(); + DynamicLoader *loader = thread.GetProcess()->GetDynamicLoader(); if (loader) - m_sub_plan_sp = - loader->GetStepThroughTrampolinePlan(m_thread, m_stop_others); + m_sub_plan_sp = loader->GetStepThroughTrampolinePlan(thread, m_stop_others); // If the DynamicLoader was unable to provide us with a ThreadPlan, then we // try the LanguageRuntimes. if (!m_sub_plan_sp) { - for (LanguageRuntime *runtime : - m_thread.GetProcess()->GetLanguageRuntimes()) { + for (LanguageRuntime *runtime : m_process.GetLanguageRuntimes()) { m_sub_plan_sp = - runtime->GetStepThroughTrampolinePlan(m_thread, m_stop_others); + runtime->GetStepThroughTrampolinePlan(thread, m_stop_others); if (m_sub_plan_sp) break; @@ -223,7 +221,7 @@ bool ThreadPlanStepThrough::WillStop() { return true; } void ThreadPlanStepThrough::ClearBackstopBreakpoint() { if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID) { - m_thread.GetProcess()->GetTarget().RemoveBreakpointByID(m_backstop_bkpt_id); + m_process.GetTarget().RemoveBreakpointByID(m_backstop_bkpt_id); m_backstop_bkpt_id = LLDB_INVALID_BREAK_ID; m_could_not_resolve_hw_bp = false; } @@ -244,15 +242,15 @@ bool ThreadPlanStepThrough::MischiefManaged() { } bool ThreadPlanStepThrough::HitOurBackstopBreakpoint() { - StopInfoSP stop_info_sp(m_thread.GetStopInfo()); + Thread &thread = GetThread(); + StopInfoSP stop_info_sp(thread.GetStopInfo()); if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonBreakpoint) { break_id_t stop_value = (break_id_t)stop_info_sp->GetValue(); BreakpointSiteSP cur_site_sp = - m_thread.GetProcess()->GetBreakpointSiteList().FindByID(stop_value); + m_process.GetBreakpointSiteList().FindByID(stop_value); if (cur_site_sp && cur_site_sp->IsBreakpointAtThisSite(m_backstop_bkpt_id)) { - StackID cur_frame_zero_id = - m_thread.GetStackFrameAtIndex(0)->GetStackID(); + StackID cur_frame_zero_id = thread.GetStackFrameAtIndex(0)->GetStackID(); if (cur_frame_zero_id == m_return_stack_id) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); diff --git a/lldb/source/Target/ThreadPlanStepUntil.cpp b/lldb/source/Target/ThreadPlanStepUntil.cpp index 54d276337488d..8de7505d86e2b 100644 --- a/lldb/source/Target/ThreadPlanStepUntil.cpp +++ b/lldb/source/Target/ThreadPlanStepUntil.cpp @@ -34,17 +34,16 @@ ThreadPlanStepUntil::ThreadPlanStepUntil(Thread &thread, m_should_stop(false), m_ran_analyze(false), m_explains_stop(false), m_until_points(), m_stop_others(stop_others) { // Stash away our "until" addresses: - TargetSP target_sp(m_thread.CalculateTarget()); + TargetSP target_sp(thread.CalculateTarget()); - StackFrameSP frame_sp(m_thread.GetStackFrameAtIndex(frame_idx)); + StackFrameSP frame_sp(thread.GetStackFrameAtIndex(frame_idx)); if (frame_sp) { m_step_from_insn = frame_sp->GetStackID().GetPC(); - lldb::user_id_t thread_id = m_thread.GetID(); // Find the return address and set a breakpoint there: // FIXME - can we do this more securely if we know first_insn? - StackFrameSP return_frame_sp(m_thread.GetStackFrameAtIndex(frame_idx + 1)); + StackFrameSP return_frame_sp(thread.GetStackFrameAtIndex(frame_idx + 1)); if (return_frame_sp) { // TODO: add inline functionality m_return_addr = return_frame_sp->GetStackID().GetPC(); @@ -54,7 +53,7 @@ ThreadPlanStepUntil::ThreadPlanStepUntil(Thread &thread, if (return_bp != nullptr) { if (return_bp->IsHardware() && !return_bp->HasResolvedLocations()) m_could_not_resolve_hw_bp = true; - return_bp->SetThreadID(thread_id); + return_bp->SetThreadID(m_tid); m_return_bp_id = return_bp->GetID(); return_bp->SetBreakpointKind("until-return-backstop"); } @@ -67,7 +66,7 @@ ThreadPlanStepUntil::ThreadPlanStepUntil(Thread &thread, Breakpoint *until_bp = target_sp->CreateBreakpoint(address_list[i], true, false).get(); if (until_bp != nullptr) { - until_bp->SetThreadID(thread_id); + until_bp->SetThreadID(m_tid); m_until_points[address_list[i]] = until_bp->GetID(); until_bp->SetBreakpointKind("until-target"); } else { @@ -80,17 +79,15 @@ ThreadPlanStepUntil::ThreadPlanStepUntil(Thread &thread, ThreadPlanStepUntil::~ThreadPlanStepUntil() { Clear(); } void ThreadPlanStepUntil::Clear() { - TargetSP target_sp(m_thread.CalculateTarget()); - if (target_sp) { - if (m_return_bp_id != LLDB_INVALID_BREAK_ID) { - target_sp->RemoveBreakpointByID(m_return_bp_id); - m_return_bp_id = LLDB_INVALID_BREAK_ID; - } + Target &target = GetTarget(); + if (m_return_bp_id != LLDB_INVALID_BREAK_ID) { + target.RemoveBreakpointByID(m_return_bp_id); + m_return_bp_id = LLDB_INVALID_BREAK_ID; + } - until_collection::iterator pos, end = m_until_points.end(); - for (pos = m_until_points.begin(); pos != end; pos++) { - target_sp->RemoveBreakpointByID((*pos).second); - } + until_collection::iterator pos, end = m_until_points.end(); + for (pos = m_until_points.begin(); pos != end; pos++) { + target.RemoveBreakpointByID((*pos).second); } m_until_points.clear(); m_could_not_resolve_hw_bp = false; @@ -158,8 +155,7 @@ void ThreadPlanStepUntil::AnalyzeStop() { // If this is OUR breakpoint, we're fine, otherwise we don't know why // this happened... BreakpointSiteSP this_site = - m_thread.GetProcess()->GetBreakpointSiteList().FindByID( - stop_info_sp->GetValue()); + m_process.GetBreakpointSiteList().FindByID(stop_info_sp->GetValue()); if (!this_site) { m_explains_stop = false; return; @@ -196,17 +192,17 @@ void ThreadPlanStepUntil::AnalyzeStop() { for (pos = m_until_points.begin(); pos != end; pos++) { if (this_site->IsBreakpointAtThisSite((*pos).second)) { // If we're at the right stack depth, then we're done. - + Thread &thread = GetThread(); bool done; StackID frame_zero_id = - m_thread.GetStackFrameAtIndex(0)->GetStackID(); + thread.GetStackFrameAtIndex(0)->GetStackID(); if (frame_zero_id == m_stack_id) done = true; else if (frame_zero_id < m_stack_id) done = false; else { - StackFrameSP older_frame_sp = m_thread.GetStackFrameAtIndex(1); + StackFrameSP older_frame_sp = thread.GetStackFrameAtIndex(1); // But if we can't even unwind one frame we should just get out // of here & stop... @@ -280,20 +276,16 @@ StateType ThreadPlanStepUntil::GetPlanRunState() { return eStateRunning; } bool ThreadPlanStepUntil::DoWillResume(StateType resume_state, bool current_plan) { if (current_plan) { - TargetSP target_sp(m_thread.CalculateTarget()); - if (target_sp) { - Breakpoint *return_bp = - target_sp->GetBreakpointByID(m_return_bp_id).get(); - if (return_bp != nullptr) - return_bp->SetEnabled(true); + Target &target = GetTarget(); + Breakpoint *return_bp = target.GetBreakpointByID(m_return_bp_id).get(); + if (return_bp != nullptr) + return_bp->SetEnabled(true); - until_collection::iterator pos, end = m_until_points.end(); - for (pos = m_until_points.begin(); pos != end; pos++) { - Breakpoint *until_bp = - target_sp->GetBreakpointByID((*pos).second).get(); - if (until_bp != nullptr) - until_bp->SetEnabled(true); - } + until_collection::iterator pos, end = m_until_points.end(); + for (pos = m_until_points.begin(); pos != end; pos++) { + Breakpoint *until_bp = target.GetBreakpointByID((*pos).second).get(); + if (until_bp != nullptr) + until_bp->SetEnabled(true); } } @@ -304,18 +296,16 @@ bool ThreadPlanStepUntil::DoWillResume(StateType resume_state, } bool ThreadPlanStepUntil::WillStop() { - TargetSP target_sp(m_thread.CalculateTarget()); - if (target_sp) { - Breakpoint *return_bp = target_sp->GetBreakpointByID(m_return_bp_id).get(); - if (return_bp != nullptr) - return_bp->SetEnabled(false); - - until_collection::iterator pos, end = m_until_points.end(); - for (pos = m_until_points.begin(); pos != end; pos++) { - Breakpoint *until_bp = target_sp->GetBreakpointByID((*pos).second).get(); - if (until_bp != nullptr) - until_bp->SetEnabled(false); - } + Target &target = GetTarget(); + Breakpoint *return_bp = target.GetBreakpointByID(m_return_bp_id).get(); + if (return_bp != nullptr) + return_bp->SetEnabled(false); + + until_collection::iterator pos, end = m_until_points.end(); + for (pos = m_until_points.begin(); pos != end; pos++) { + Breakpoint *until_bp = target.GetBreakpointByID((*pos).second).get(); + if (until_bp != nullptr) + until_bp->SetEnabled(false); } return true; } From f9e807282756016b3c6022197a17705fbfe6b950 Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Tue, 10 Mar 2020 14:04:42 -0700 Subject: [PATCH 139/286] Make ThreadPlanTracers use TID & Process rather than Thread *. Differential Revision: https://reviews.llvm.org/D75720 --- lldb/include/lldb/Target/ThreadPlanTracer.h | 6 ++- lldb/source/Target/ThreadPlanTracer.cpp | 52 +++++++++++---------- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/lldb/include/lldb/Target/ThreadPlanTracer.h b/lldb/include/lldb/Target/ThreadPlanTracer.h index 80b08078e975e..a7db53debfe01 100644 --- a/lldb/include/lldb/Target/ThreadPlanTracer.h +++ b/lldb/include/lldb/Target/ThreadPlanTracer.h @@ -57,9 +57,12 @@ class ThreadPlanTracer { } bool SingleStepEnabled() { return m_single_step; } + + Thread &GetThread(); protected: - Thread &m_thread; + Process &m_process; + lldb::tid_t m_tid; Stream *GetLogStream(); @@ -71,6 +74,7 @@ class ThreadPlanTracer { bool m_single_step; bool m_enabled; lldb::StreamSP m_stream_sp; + Thread *m_thread; }; class ThreadPlanAssemblyTracer : public ThreadPlanTracer { diff --git a/lldb/source/Target/ThreadPlanTracer.cpp b/lldb/source/Target/ThreadPlanTracer.cpp index b50c1636b7ff7..fb31eb9829d21 100644 --- a/lldb/source/Target/ThreadPlanTracer.cpp +++ b/lldb/source/Target/ThreadPlanTracer.cpp @@ -34,23 +34,32 @@ using namespace lldb_private; #pragma mark ThreadPlanTracer ThreadPlanTracer::ThreadPlanTracer(Thread &thread, lldb::StreamSP &stream_sp) - : m_thread(thread), m_single_step(true), m_enabled(false), - m_stream_sp(stream_sp) {} + : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()), + m_single_step(true), m_enabled(false), m_stream_sp(stream_sp) {} ThreadPlanTracer::ThreadPlanTracer(Thread &thread) - : m_thread(thread), m_single_step(true), m_enabled(false), m_stream_sp() {} + : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()), + m_single_step(true), m_enabled(false), m_stream_sp() {} Stream *ThreadPlanTracer::GetLogStream() { if (m_stream_sp) return m_stream_sp.get(); else { - TargetSP target_sp(m_thread.CalculateTarget()); + TargetSP target_sp(GetThread().CalculateTarget()); if (target_sp) return &(target_sp->GetDebugger().GetOutputStream()); } return nullptr; } +Thread &ThreadPlanTracer::GetThread() { + if (m_thread) + return *m_thread; + + ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(m_tid); + m_thread = thread_sp.get(); + return *m_thread; +} void ThreadPlanTracer::Log() { SymbolContext sc; bool show_frame_index = false; @@ -58,8 +67,8 @@ void ThreadPlanTracer::Log() { Stream *stream = GetLogStream(); if (stream) { - m_thread.GetStackFrameAtIndex(0)->Dump(stream, show_frame_index, - show_fullpaths); + GetThread().GetStackFrameAtIndex(0)->Dump(stream, show_frame_index, + show_fullpaths); stream->Printf("\n"); stream->Flush(); } @@ -67,7 +76,7 @@ void ThreadPlanTracer::Log() { bool ThreadPlanTracer::TracerExplainsStop() { if (m_enabled && m_single_step) { - lldb::StopInfoSP stop_info = m_thread.GetStopInfo(); + lldb::StopInfoSP stop_info = GetThread().GetStopInfo(); return (stop_info->GetStopReason() == eStopReasonTrace); } else return false; @@ -87,13 +96,13 @@ ThreadPlanAssemblyTracer::ThreadPlanAssemblyTracer(Thread &thread) Disassembler *ThreadPlanAssemblyTracer::GetDisassembler() { if (!m_disassembler_sp) m_disassembler_sp = Disassembler::FindPlugin( - m_thread.GetProcess()->GetTarget().GetArchitecture(), nullptr, nullptr); + m_process.GetTarget().GetArchitecture(), nullptr, nullptr); return m_disassembler_sp.get(); } TypeFromUser ThreadPlanAssemblyTracer::GetIntPointerType() { if (!m_intptr_type.IsValid()) { - if (auto target_sp = m_thread.CalculateTarget()) { + if (auto target_sp = m_process.CalculateTarget()) { auto type_system_or_err = target_sp->GetScratchTypeSystemForLanguage(eLanguageTypeC); if (auto err = type_system_or_err.takeError()) { @@ -125,29 +134,27 @@ void ThreadPlanAssemblyTracer::Log() { if (!stream) return; - RegisterContext *reg_ctx = m_thread.GetRegisterContext().get(); + RegisterContext *reg_ctx = GetThread().GetRegisterContext().get(); lldb::addr_t pc = reg_ctx->GetPC(); - ProcessSP process_sp(m_thread.GetProcess()); Address pc_addr; bool addr_valid = false; uint8_t buffer[16] = {0}; // Must be big enough for any single instruction - addr_valid = process_sp->GetTarget().GetSectionLoadList().ResolveLoadAddress( + addr_valid = m_process.GetTarget().GetSectionLoadList().ResolveLoadAddress( pc, pc_addr); - pc_addr.Dump(stream, &m_thread, Address::DumpStyleResolvedDescription, + pc_addr.Dump(stream, &GetThread(), Address::DumpStyleResolvedDescription, Address::DumpStyleModuleWithFileAddress); stream->PutCString(" "); Disassembler *disassembler = GetDisassembler(); if (disassembler) { Status err; - process_sp->ReadMemory(pc, buffer, sizeof(buffer), err); + m_process.ReadMemory(pc, buffer, sizeof(buffer), err); if (err.Success()) { - DataExtractor extractor(buffer, sizeof(buffer), - process_sp->GetByteOrder(), - process_sp->GetAddressByteSize()); + DataExtractor extractor(buffer, sizeof(buffer), m_process.GetByteOrder(), + m_process.GetAddressByteSize()); bool data_from_file = false; if (addr_valid) @@ -167,10 +174,7 @@ void ThreadPlanAssemblyTracer::Log() { Instruction *instruction = instruction_list.GetInstructionAtIndex(0).get(); const FormatEntity::Entry *disassemble_format = - m_thread.GetProcess() - ->GetTarget() - .GetDebugger() - .GetDisassemblyFormat(); + m_process.GetTarget().GetDebugger().GetDisassemblyFormat(); instruction->Dump(stream, max_opcode_byte_size, show_address, show_bytes, nullptr, nullptr, nullptr, disassemble_format, 0); @@ -178,7 +182,7 @@ void ThreadPlanAssemblyTracer::Log() { } } - const ABI *abi = process_sp->GetABI().get(); + const ABI *abi = m_process.GetABI().get(); TypeFromUser intptr_type = GetIntPointerType(); if (abi && intptr_type.IsValid()) { @@ -192,7 +196,7 @@ void ThreadPlanAssemblyTracer::Log() { value_list.PushValue(value); } - if (abi->GetArgumentValues(m_thread, value_list)) { + if (abi->GetArgumentValues(GetThread(), value_list)) { for (int arg_index = 0; arg_index < num_args; ++arg_index) { stream->Printf( "\n\targ[%d]=%llx", arg_index, @@ -205,7 +209,7 @@ void ThreadPlanAssemblyTracer::Log() { } if (m_register_values.empty()) { - RegisterContext *reg_ctx = m_thread.GetRegisterContext().get(); + RegisterContext *reg_ctx = GetThread().GetRegisterContext().get(); m_register_values.resize(reg_ctx->GetRegisterCount()); } From 96399ae5799119e322112752ea516e5ef302a0b4 Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Tue, 10 Mar 2020 16:18:11 -0700 Subject: [PATCH 140/286] Move thread plan stacks into the Process, indexed by TID. Differential Revision: https://reviews.llvm.org/D75880 --- lldb/include/lldb/Target/Process.h | 20 +- lldb/include/lldb/Target/Thread.h | 36 +- lldb/include/lldb/Target/ThreadPlan.h | 4 +- lldb/include/lldb/Target/ThreadPlanStack.h | 153 ++++++++ lldb/source/Target/CMakeLists.txt | 1 + lldb/source/Target/Process.cpp | 20 ++ lldb/source/Target/Thread.cpp | 396 +++++---------------- lldb/source/Target/ThreadList.cpp | 4 +- lldb/source/Target/ThreadPlan.cpp | 4 + lldb/source/Target/ThreadPlanStack.cpp | 370 +++++++++++++++++++ 10 files changed, 668 insertions(+), 340 deletions(-) create mode 100644 lldb/include/lldb/Target/ThreadPlanStack.h create mode 100644 lldb/source/Target/ThreadPlanStack.cpp diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index cc35a3167a505..6d5dcb0698436 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -37,6 +37,7 @@ #include "lldb/Target/Memory.h" #include "lldb/Target/QueueList.h" #include "lldb/Target/ThreadList.h" +#include "lldb/Target/ThreadPlanStack.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/Broadcaster.h" #include "lldb/Utility/Event.h" @@ -2198,6 +2199,19 @@ class Process : public std::enable_shared_from_this, } void SetDynamicCheckers(DynamicCheckerFunctions *dynamic_checkers); + + /// Find the thread plan stack associated with thread with \a tid. + /// + /// \param[in] tid + /// The tid whose Plan Stack we are seeking.. + /// + /// \return + /// Returns a ThreadPlan if the TID is found or nullptr if not. + ThreadPlanStack *FindThreadPlans(lldb::tid_t tid); + + void AddThreadPlansForThread(Thread &thread); + + void RemoveThreadPlansForTID(lldb::tid_t tid); /// Call this to set the lldb in the mode where it breaks on new thread /// creations, and then auto-restarts. This is useful when you are trying @@ -2534,7 +2548,7 @@ class Process : public std::enable_shared_from_this, virtual EventActionResult HandleBeingInterrupted() = 0; virtual const char *GetExitString() = 0; void RequestResume() { m_process->m_resume_requested = true; } - + protected: Process *m_process; }; @@ -2668,6 +2682,10 @@ class Process : public std::enable_shared_from_this, ///see them. This is usually the same as ///< m_thread_list_real, but might be different if there is an OS plug-in ///creating memory threads + ThreadPlanStackMap m_thread_plans; ///< This is the list of thread plans for + /// threads in m_thread_list, as well as + /// threads we knew existed, but haven't + /// determined that they have died yet. ThreadList m_extended_thread_list; ///< Owner for extended threads that may be ///generated, cleared on natural stops uint32_t m_extended_thread_stop_id; ///< The natural stop id when diff --git a/lldb/include/lldb/Target/Thread.h b/lldb/include/lldb/Target/Thread.h index e68ef08dd7d51..4de7cb09a51cb 100644 --- a/lldb/include/lldb/Target/Thread.h +++ b/lldb/include/lldb/Target/Thread.h @@ -28,6 +28,8 @@ namespace lldb_private { +class ThreadPlanStack; + class ThreadProperties : public Properties { public: ThreadProperties(bool is_global); @@ -119,7 +121,7 @@ class Thread : public std::enable_shared_from_this, // bit of data. lldb::StopInfoSP stop_info_sp; // You have to restore the stop info or you // might continue with the wrong signals. - std::vector m_completed_plan_stack; + size_t m_completed_plan_checkpoint; lldb::RegisterCheckpointSP register_backup_sp; // You need to restore the registers, of course... uint32_t current_inlined_depth; @@ -914,7 +916,7 @@ class Thread : public std::enable_shared_from_this, /// /// \return /// A pointer to the next executed plan. - ThreadPlan *GetCurrentPlan(); + ThreadPlan *GetCurrentPlan() const; /// Unwinds the thread stack for the innermost expression plan currently /// on the thread plan stack. @@ -929,14 +931,14 @@ class Thread : public std::enable_shared_from_this, /// /// \return /// A pointer to the last completed plan. - lldb::ThreadPlanSP GetCompletedPlan(); + lldb::ThreadPlanSP GetCompletedPlan() const; /// Gets the outer-most return value from the completed plans /// /// \return /// A ValueObjectSP, either empty if there is no return value, /// or containing the return value. - lldb::ValueObjectSP GetReturnValueObject(); + lldb::ValueObjectSP GetReturnValueObject() const; /// Gets the outer-most expression variable from the completed plans /// @@ -944,7 +946,7 @@ class Thread : public std::enable_shared_from_this, /// A ExpressionVariableSP, either empty if there is no /// plan completed an expression during the current stop /// or the expression variable that was made for the completed expression. - lldb::ExpressionVariableSP GetExpressionVariable(); + lldb::ExpressionVariableSP GetExpressionVariable() const; /// Checks whether the given plan is in the completed plans for this /// stop. @@ -955,7 +957,7 @@ class Thread : public std::enable_shared_from_this, /// \return /// Returns true if the input plan is in the completed plan stack, /// false otherwise. - bool IsThreadPlanDone(ThreadPlan *plan); + bool IsThreadPlanDone(ThreadPlan *plan) const; /// Checks whether the given plan is in the discarded plans for this /// stop. @@ -966,14 +968,14 @@ class Thread : public std::enable_shared_from_this, /// \return /// Returns true if the input plan is in the discarded plan stack, /// false otherwise. - bool WasThreadPlanDiscarded(ThreadPlan *plan); + bool WasThreadPlanDiscarded(ThreadPlan *plan) const; /// Check if we have completed plan to override breakpoint stop reason /// /// \return /// Returns true if completed plan stack is not empty /// false otherwise. - bool CompletedPlanOverridesBreakpoint(); + bool CompletedPlanOverridesBreakpoint() const; /// Queues a generic thread plan. /// @@ -1186,16 +1188,16 @@ class Thread : public std::enable_shared_from_this, // thread is still in good shape to call virtual thread methods. This must // be called by classes that derive from Thread in their destructor. virtual void DestroyThread(); + + ThreadPlanStack &GetPlans() const; - void PushPlan(lldb::ThreadPlanSP &plan_sp); + void PushPlan(lldb::ThreadPlanSP plan_sp); void PopPlan(); void DiscardPlan(); - ThreadPlan *GetPreviousPlan(ThreadPlan *plan); - - typedef std::vector plan_stack; + ThreadPlan *GetPreviousPlan(ThreadPlan *plan) const; virtual lldb_private::Unwind *GetUnwinder(); @@ -1240,13 +1242,6 @@ class Thread : public std::enable_shared_from_this, lldb::StateType m_state; ///< The state of our process. mutable std::recursive_mutex m_state_mutex; ///< Multithreaded protection for m_state. - plan_stack m_plan_stack; ///< The stack of plans this thread is executing. - plan_stack m_completed_plan_stack; ///< Plans that have been completed by this - ///stop. They get deleted when the thread - ///resumes. - plan_stack m_discarded_plan_stack; ///< Plans that have been discarded by this - ///stop. They get deleted when the thread - ///resumes. mutable std::recursive_mutex m_frame_mutex; ///< Multithreaded protection for m_state. lldb::StackFrameListSP m_curr_frames_sp; ///< The stack frames that get lazily @@ -1274,8 +1269,7 @@ class Thread : public std::enable_shared_from_this, StructuredData::ObjectSP m_extended_info; // The extended info for this thread private: - bool PlanIsBasePlan(ThreadPlan *plan_ptr); - + void BroadcastSelectedFrameChange(StackID &new_frame_id); DISALLOW_COPY_AND_ASSIGN(Thread); diff --git a/lldb/include/lldb/Target/ThreadPlan.h b/lldb/include/lldb/Target/ThreadPlan.h index 0301de7d4159f..2935ecb4effe0 100644 --- a/lldb/include/lldb/Target/ThreadPlan.h +++ b/lldb/include/lldb/Target/ThreadPlan.h @@ -371,9 +371,9 @@ class ThreadPlan : public std::enable_shared_from_this, /// A pointer to the thread plan's owning thread. Thread &GetThread(); - Target &GetTarget() { return m_process.GetTarget(); } + Target &GetTarget(); - const Target &GetTarget() const { return m_process.GetTarget(); } + const Target &GetTarget() const; /// Print a description of this thread to the stream \a s. /// \a thread. diff --git a/lldb/include/lldb/Target/ThreadPlanStack.h b/lldb/include/lldb/Target/ThreadPlanStack.h new file mode 100644 index 0000000000000..be7791abef81e --- /dev/null +++ b/lldb/include/lldb/Target/ThreadPlanStack.h @@ -0,0 +1,153 @@ +//===-- ThreadPlanStack.h ---------------------------------------*- 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 LLDB_TARGET_THREADPLANSTACK_H +#define LLDB_TARGET_THREADPLANSTACK_H + +#include +#include +#include +#include + +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/lldb-private-forward.h" +#include "lldb/lldb-private.h" + +namespace lldb_private { + +// The ThreadPlans have a thread for use when they are asked all the ThreadPlan +// state machine questions, but they should never cache any pointers from their +// owning lldb_private::Thread. That's because we want to be able to detach +// them from an owning thread, then reattach them by TID. +// The ThreadPlanStack holds the ThreadPlans for a given TID. All its methods +// are private, and it should only be accessed through the owning thread. When +// it is detached from a thread, all you can do is reattach it or delete it. +class ThreadPlanStack { + friend class lldb_private::Thread; + +public: + ThreadPlanStack(Thread &thread) {} + ~ThreadPlanStack() {} + + enum StackKind { ePlans, eCompletedPlans, eDiscardedPlans }; + + using PlanStack = std::vector; + + void DumpThreadPlans(Stream *s, lldb::DescriptionLevel desc_level, + bool include_internal) const; + + size_t CheckpointCompletedPlans(); + + void RestoreCompletedPlanCheckpoint(size_t checkpoint); + + void DiscardCompletedPlanCheckpoint(size_t checkpoint); + + void ThreadDestroyed(Thread *thread); + + void EnableTracer(bool value, bool single_stepping); + + void SetTracer(lldb::ThreadPlanTracerSP &tracer_sp); + + void PushPlan(lldb::ThreadPlanSP new_plan_sp); + + lldb::ThreadPlanSP PopPlan(); + + lldb::ThreadPlanSP DiscardPlan(); + + // If the input plan is nullptr, discard all plans. Otherwise make sure this + // plan is in the stack, and if so discard up to and including it. + void DiscardPlansUpToPlan(ThreadPlan *up_to_plan_ptr); + + void DiscardAllPlans(); + + void DiscardConsultingMasterPlans(); + + lldb::ThreadPlanSP GetCurrentPlan() const; + + lldb::ThreadPlanSP GetCompletedPlan(bool skip_private = true) const; + + lldb::ThreadPlanSP GetPlanByIndex(uint32_t plan_idx, + bool skip_private = true) const; + + lldb::ValueObjectSP GetReturnValueObject() const; + + lldb::ExpressionVariableSP GetExpressionVariable() const; + + bool AnyPlans() const; + + bool AnyCompletedPlans() const; + + bool AnyDiscardedPlans() const; + + bool IsPlanDone(ThreadPlan *plan) const; + + bool WasPlanDiscarded(ThreadPlan *plan) const; + + ThreadPlan *GetPreviousPlan(ThreadPlan *current_plan) const; + + ThreadPlan *GetInnermostExpression() const; + + void WillResume(); + +private: + const PlanStack &GetStackOfKind(ThreadPlanStack::StackKind kind) const; + + PlanStack m_plans; ///< The stack of plans this thread is executing. + PlanStack m_completed_plans; ///< Plans that have been completed by this + /// stop. They get deleted when the thread + /// resumes. + PlanStack m_discarded_plans; ///< Plans that have been discarded by this + /// stop. They get deleted when the thread + /// resumes. + size_t m_completed_plan_checkpoint = 0; // Monotonically increasing token for + // completed plan checkpoints. + std::unordered_map m_completed_plan_store; +}; + +class ThreadPlanStackMap { +public: + ThreadPlanStackMap() {} + ~ThreadPlanStackMap() {} + + void AddThread(Thread &thread) { + lldb::tid_t tid = thread.GetID(); + auto result = m_plans_list.emplace(tid, thread); + } + + bool RemoveTID(lldb::tid_t tid) { + auto result = m_plans_list.find(tid); + if (result == m_plans_list.end()) + return false; + result->second.ThreadDestroyed(nullptr); + m_plans_list.erase(result); + return true; + } + + ThreadPlanStack *Find(lldb::tid_t tid) { + auto result = m_plans_list.find(tid); + if (result == m_plans_list.end()) + return nullptr; + else + return &result->second; + } + + void Clear() { + for (auto plan : m_plans_list) + plan.second.ThreadDestroyed(nullptr); + m_plans_list.clear(); + } + +private: + using PlansList = std::unordered_map; + PlansList m_plans_list; +}; + +} // namespace lldb_private + +#endif // LLDB_TARGET_THREADPLANSTACK_H diff --git a/lldb/source/Target/CMakeLists.txt b/lldb/source/Target/CMakeLists.txt index 3c6246e29ee39..7e80458889146 100644 --- a/lldb/source/Target/CMakeLists.txt +++ b/lldb/source/Target/CMakeLists.txt @@ -62,6 +62,7 @@ add_lldb_library(lldbTarget ThreadPlanStepThrough.cpp ThreadPlanStepUntil.cpp ThreadPlanTracer.cpp + ThreadPlanStack.cpp ThreadSpec.cpp UnixSignals.cpp UnwindAssembly.cpp diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index a874322234645..07b1ac78eaca8 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -60,6 +60,7 @@ #include "lldb/Target/ThreadPlan.h" #include "lldb/Target/ThreadPlanBase.h" #include "lldb/Target/ThreadPlanCallFunction.h" +#include "lldb/Target/ThreadPlanStack.h" #include "lldb/Target/UnixSignals.h" #include "lldb/Utility/Event.h" #include "lldb/Utility/Log.h" @@ -607,6 +608,7 @@ void Process::Finalize() { m_system_runtime_up.reset(); m_dyld_up.reset(); m_jit_loaders_up.reset(); + m_thread_plans.Clear(); m_thread_list_real.Destroy(); m_thread_list.Destroy(); m_extended_thread_list.Destroy(); @@ -1262,6 +1264,20 @@ void Process::UpdateThreadListIfNeeded() { } } +ThreadPlanStack *Process::FindThreadPlans(lldb::tid_t tid) { + return m_thread_plans.Find(tid); +} + +void Process::AddThreadPlansForThread(Thread &thread) { + if (m_thread_plans.Find(thread.GetID())) + return; + m_thread_plans.AddThread(thread); +} + +void Process::RemoveThreadPlansForTID(lldb::tid_t tid) { + m_thread_plans.RemoveTID(tid); +} + void Process::UpdateQueueListIfNeeded() { if (m_system_runtime_up) { if (m_queue_list.GetSize() == 0 || @@ -3241,6 +3257,10 @@ Status Process::Detach(bool keep_stopped) { } Status Process::Destroy(bool force_kill) { + // If we've already called Process::Finalize then there's nothing useful to + // be done here. Finalize has actually called Destroy already. + if (m_finalize_called) + return {}; // Tell ourselves we are in the process of destroying the process, so that we // don't do any unnecessary work that might hinder the destruction. Remember diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp index ad196425b00e0..2464c15885462 100644 --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -35,6 +35,7 @@ #include "lldb/Target/ThreadPlanCallFunction.h" #include "lldb/Target/ThreadPlanPython.h" #include "lldb/Target/ThreadPlanRunToAddress.h" +#include "lldb/Target/ThreadPlanStack.h" #include "lldb/Target/ThreadPlanStepInRange.h" #include "lldb/Target/ThreadPlanStepInstruction.h" #include "lldb/Target/ThreadPlanStepOut.h" @@ -230,8 +231,7 @@ Thread::Thread(Process &process, lldb::tid_t tid, bool use_invalid_index_id) m_index_id(use_invalid_index_id ? LLDB_INVALID_INDEX32 : process.GetNextThreadIndexID(tid)), m_reg_context_sp(), m_state(eStateUnloaded), m_state_mutex(), - m_plan_stack(), m_completed_plan_stack(), m_frame_mutex(), - m_curr_frames_sp(), m_prev_frames_sp(), + m_frame_mutex(), m_curr_frames_sp(), m_prev_frames_sp(), m_resume_signal(LLDB_INVALID_SIGNAL_NUMBER), m_resume_state(eStateRunning), m_temporary_resume_state(eStateRunning), m_unwinder_up(), m_destroy_called(false), @@ -242,7 +242,9 @@ Thread::Thread(Process &process, lldb::tid_t tid, bool use_invalid_index_id) static_cast(this), GetID()); CheckInWithManager(); - + + process.AddThreadPlansForThread(*this); + QueueFundamentalPlan(true); } @@ -256,30 +258,7 @@ Thread::~Thread() { } void Thread::DestroyThread() { - // Tell any plans on the plan stacks that the thread is being destroyed since - // any plans that have a thread go away in the middle of might need to do - // cleanup, or in some cases NOT do cleanup... - for (auto plan : m_plan_stack) - plan->ThreadDestroyed(); - - for (auto plan : m_discarded_plan_stack) - plan->ThreadDestroyed(); - - for (auto plan : m_completed_plan_stack) - plan->ThreadDestroyed(); - m_destroy_called = true; - m_plan_stack.clear(); - m_discarded_plan_stack.clear(); - m_completed_plan_stack.clear(); - - // Push a ThreadPlanNull on the plan stack. That way we can continue - // assuming that the plan stack is never empty, but if somebody errantly asks - // questions of a destroyed thread without checking first whether it is - // destroyed, they won't crash. - ThreadPlanSP null_plan_sp(new ThreadPlanNull(*this)); - m_plan_stack.push_back(null_plan_sp); - m_stop_info_sp.reset(); m_reg_context_sp.reset(); m_unwinder_up.reset(); @@ -524,7 +503,8 @@ bool Thread::CheckpointThreadState(ThreadStateCheckpoint &saved_state) { if (process_sp) saved_state.orig_stop_id = process_sp->GetStopID(); saved_state.current_inlined_depth = GetCurrentInlinedDepth(); - saved_state.m_completed_plan_stack = m_completed_plan_stack; + saved_state.m_completed_plan_checkpoint = + GetPlans().CheckpointCompletedPlans(); return true; } @@ -558,7 +538,8 @@ bool Thread::RestoreThreadStateFromCheckpoint( SetStopInfo(saved_state.stop_info_sp); GetStackFrameList()->SetCurrentInlinedDepth( saved_state.current_inlined_depth); - m_completed_plan_stack = saved_state.m_completed_plan_stack; + GetPlans().RestoreCompletedPlanCheckpoint( + saved_state.m_completed_plan_checkpoint); return true; } @@ -687,8 +668,7 @@ void Thread::SetupForResume() { bool Thread::ShouldResume(StateType resume_state) { // At this point clear the completed plan stack. - m_completed_plan_stack.clear(); - m_discarded_plan_stack.clear(); + GetPlans().WillResume(); m_override_should_notify = eLazyBoolCalculate; StateType prev_resume_state = GetTemporaryResumeState(); @@ -882,7 +862,7 @@ bool Thread::ShouldStop(Event *event_ptr) { current_plan->GetName(), over_ride_stop); // We're starting from the base plan, so just let it decide; - if (PlanIsBasePlan(current_plan)) { + if (current_plan->IsBasePlan()) { should_stop = current_plan->ShouldStop(event_ptr); LLDB_LOGF(log, "Base plan says should stop: %i.", should_stop); } else { @@ -890,7 +870,7 @@ bool Thread::ShouldStop(Event *event_ptr) { // to do, since presumably if there were other plans they would know what // to do... while (true) { - if (PlanIsBasePlan(current_plan)) + if (current_plan->IsBasePlan()) break; should_stop = current_plan->ShouldStop(event_ptr); @@ -936,7 +916,7 @@ bool Thread::ShouldStop(Event *event_ptr) { // Discard the stale plans and all plans below them in the stack, plus move // the completed plans to the completed plan stack - while (!PlanIsBasePlan(plan_ptr)) { + while (!plan_ptr->IsBasePlan()) { bool stale = plan_ptr->IsPlanStale(); ThreadPlan *examined_plan = plan_ptr; plan_ptr = GetPreviousPlan(examined_plan); @@ -1002,13 +982,14 @@ Vote Thread::ShouldReportStop(Event *event_ptr) { return eVoteNoOpinion; } - if (m_completed_plan_stack.size() > 0) { - // Don't use GetCompletedPlan here, since that suppresses private plans. + if (GetPlans().AnyCompletedPlans()) { + // Pass skip_private = false to GetCompletedPlan, since we want to ask + // the last plan, regardless of whether it is private or not. LLDB_LOGF(log, "Thread::ShouldReportStop() tid = 0x%4.4" PRIx64 ": returning vote for complete stack's back plan", GetID()); - return m_completed_plan_stack.back()->ShouldReportStop(event_ptr); + return GetPlans().GetCompletedPlan(false)->ShouldReportStop(event_ptr); } else { Vote thread_vote = eVoteNoOpinion; ThreadPlan *plan_ptr = GetCurrentPlan(); @@ -1017,7 +998,7 @@ Vote Thread::ShouldReportStop(Event *event_ptr) { thread_vote = plan_ptr->ShouldReportStop(event_ptr); break; } - if (PlanIsBasePlan(plan_ptr)) + if (plan_ptr->IsBasePlan()) break; else plan_ptr = GetPreviousPlan(plan_ptr); @@ -1039,16 +1020,17 @@ Vote Thread::ShouldReportRun(Event *event_ptr) { } Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); - if (m_completed_plan_stack.size() > 0) { - // Don't use GetCompletedPlan here, since that suppresses private plans. + if (GetPlans().AnyCompletedPlans()) { + // Pass skip_private = false to GetCompletedPlan, since we want to ask + // the last plan, regardless of whether it is private or not. LLDB_LOGF(log, "Current Plan for thread %d(%p) (0x%4.4" PRIx64 ", %s): %s being asked whether we should report run.", GetIndexID(), static_cast(this), GetID(), StateAsCString(GetTemporaryResumeState()), - m_completed_plan_stack.back()->GetName()); + GetCompletedPlan()->GetName()); - return m_completed_plan_stack.back()->ShouldReportRun(event_ptr); + return GetPlans().GetCompletedPlan(false)->ShouldReportRun(event_ptr); } else { LLDB_LOGF(log, "Current Plan for thread %d(%p) (0x%4.4" PRIx64 @@ -1065,148 +1047,75 @@ bool Thread::MatchesSpec(const ThreadSpec *spec) { return (spec == nullptr) ? true : spec->ThreadPassesBasicTests(*this); } -void Thread::PushPlan(ThreadPlanSP &thread_plan_sp) { - if (thread_plan_sp) { - // If the thread plan doesn't already have a tracer, give it its parent's - // tracer: - if (!thread_plan_sp->GetThreadPlanTracer()) { - assert(!m_plan_stack.empty()); - thread_plan_sp->SetThreadPlanTracer( - m_plan_stack.back()->GetThreadPlanTracer()); - } - m_plan_stack.push_back(thread_plan_sp); +ThreadPlanStack &Thread::GetPlans() const { + ThreadPlanStack *plans = GetProcess()->FindThreadPlans(GetID()); + assert(plans && "Can't have a thread with no plans"); + return *plans; +} - thread_plan_sp->DidPush(); +void Thread::PushPlan(ThreadPlanSP thread_plan_sp) { + assert(thread_plan_sp && "Don't push an empty thread plan."); - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); - if (log) { - StreamString s; - thread_plan_sp->GetDescription(&s, lldb::eDescriptionLevelFull); - LLDB_LOGF(log, "Thread::PushPlan(0x%p): \"%s\", tid = 0x%4.4" PRIx64 ".", - static_cast(this), s.GetData(), - thread_plan_sp->GetThread().GetID()); - } + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (log) { + StreamString s; + thread_plan_sp->GetDescription(&s, lldb::eDescriptionLevelFull); + LLDB_LOGF(log, "Thread::PushPlan(0x%p): \"%s\", tid = 0x%4.4" PRIx64 ".", + static_cast(this), s.GetData(), + thread_plan_sp->GetThread().GetID()); } + + GetPlans().PushPlan(std::move(thread_plan_sp)); } void Thread::PopPlan() { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); - - if (m_plan_stack.size() <= 1) - return; - else { - ThreadPlanSP &plan = m_plan_stack.back(); - if (log) { - LLDB_LOGF(log, "Popping plan: \"%s\", tid = 0x%4.4" PRIx64 ".", - plan->GetName(), plan->GetThread().GetID()); - } - m_completed_plan_stack.push_back(plan); - plan->WillPop(); - m_plan_stack.pop_back(); + ThreadPlanSP popped_plan_sp = GetPlans().PopPlan(); + if (log) { + LLDB_LOGF(log, "Popping plan: \"%s\", tid = 0x%4.4" PRIx64 ".", + popped_plan_sp->GetName(), popped_plan_sp->GetThread().GetID()); } } void Thread::DiscardPlan() { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); - if (m_plan_stack.size() > 1) { - ThreadPlanSP &plan = m_plan_stack.back(); - LLDB_LOGF(log, "Discarding plan: \"%s\", tid = 0x%4.4" PRIx64 ".", - plan->GetName(), plan->GetThread().GetID()); - - m_discarded_plan_stack.push_back(plan); - plan->WillPop(); - m_plan_stack.pop_back(); - } -} + ThreadPlanSP discarded_plan_sp = GetPlans().PopPlan(); -ThreadPlan *Thread::GetCurrentPlan() { - // There will always be at least the base plan. If somebody is mucking with - // a thread with an empty plan stack, we should assert right away. - return m_plan_stack.empty() ? nullptr : m_plan_stack.back().get(); + LLDB_LOGF(log, "Discarding plan: \"%s\", tid = 0x%4.4" PRIx64 ".", + discarded_plan_sp->GetName(), + discarded_plan_sp->GetThread().GetID()); } -ThreadPlanSP Thread::GetCompletedPlan() { - ThreadPlanSP empty_plan_sp; - if (!m_completed_plan_stack.empty()) { - for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--) { - ThreadPlanSP completed_plan_sp; - completed_plan_sp = m_completed_plan_stack[i]; - if (!completed_plan_sp->GetPrivate()) - return completed_plan_sp; - } - } - return empty_plan_sp; +ThreadPlan *Thread::GetCurrentPlan() const { + return GetPlans().GetCurrentPlan().get(); } -ValueObjectSP Thread::GetReturnValueObject() { - if (!m_completed_plan_stack.empty()) { - for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--) { - ValueObjectSP return_valobj_sp; - return_valobj_sp = m_completed_plan_stack[i]->GetReturnValueObject(); - if (return_valobj_sp) - return return_valobj_sp; - } - } - return ValueObjectSP(); +ThreadPlanSP Thread::GetCompletedPlan() const { + return GetPlans().GetCompletedPlan(); } -ExpressionVariableSP Thread::GetExpressionVariable() { - if (!m_completed_plan_stack.empty()) { - for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--) { - ExpressionVariableSP expression_variable_sp; - expression_variable_sp = - m_completed_plan_stack[i]->GetExpressionVariable(); - if (expression_variable_sp) - return expression_variable_sp; - } - } - return ExpressionVariableSP(); +ValueObjectSP Thread::GetReturnValueObject() const { + return GetPlans().GetReturnValueObject(); } -bool Thread::IsThreadPlanDone(ThreadPlan *plan) { - if (!m_completed_plan_stack.empty()) { - for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--) { - if (m_completed_plan_stack[i].get() == plan) - return true; - } - } - return false; +ExpressionVariableSP Thread::GetExpressionVariable() const { + return GetPlans().GetExpressionVariable(); } -bool Thread::WasThreadPlanDiscarded(ThreadPlan *plan) { - if (!m_discarded_plan_stack.empty()) { - for (int i = m_discarded_plan_stack.size() - 1; i >= 0; i--) { - if (m_discarded_plan_stack[i].get() == plan) - return true; - } - } - return false; +bool Thread::IsThreadPlanDone(ThreadPlan *plan) const { + return GetPlans().IsPlanDone(plan); } -bool Thread::CompletedPlanOverridesBreakpoint() { - return (!m_completed_plan_stack.empty()) ; +bool Thread::WasThreadPlanDiscarded(ThreadPlan *plan) const { + return GetPlans().WasPlanDiscarded(plan); } -ThreadPlan *Thread::GetPreviousPlan(ThreadPlan *current_plan) { - if (current_plan == nullptr) - return nullptr; - - int stack_size = m_completed_plan_stack.size(); - for (int i = stack_size - 1; i > 0; i--) { - if (current_plan == m_completed_plan_stack[i].get()) - return m_completed_plan_stack[i - 1].get(); - } - - if (stack_size > 0 && m_completed_plan_stack[0].get() == current_plan) { - return GetCurrentPlan(); - } +bool Thread::CompletedPlanOverridesBreakpoint() const { + return GetPlans().AnyCompletedPlans(); +} - stack_size = m_plan_stack.size(); - for (int i = stack_size - 1; i > 0; i--) { - if (current_plan == m_plan_stack[i].get()) - return m_plan_stack[i - 1].get(); - } - return nullptr; +ThreadPlan *Thread::GetPreviousPlan(ThreadPlan *current_plan) const{ + return GetPlans().GetPreviousPlan(current_plan); } Status Thread::QueueThreadPlan(ThreadPlanSP &thread_plan_sp, @@ -1240,38 +1149,18 @@ Status Thread::QueueThreadPlan(ThreadPlanSP &thread_plan_sp, } void Thread::EnableTracer(bool value, bool single_stepping) { - int stack_size = m_plan_stack.size(); - for (int i = 0; i < stack_size; i++) { - if (m_plan_stack[i]->GetThreadPlanTracer()) { - m_plan_stack[i]->GetThreadPlanTracer()->EnableTracing(value); - m_plan_stack[i]->GetThreadPlanTracer()->EnableSingleStep(single_stepping); - } - } + GetPlans().EnableTracer(value, single_stepping); } void Thread::SetTracer(lldb::ThreadPlanTracerSP &tracer_sp) { - int stack_size = m_plan_stack.size(); - for (int i = 0; i < stack_size; i++) - m_plan_stack[i]->SetThreadPlanTracer(tracer_sp); + GetPlans().SetTracer(tracer_sp); } -bool Thread::DiscardUserThreadPlansUpToIndex(uint32_t thread_index) { +bool Thread::DiscardUserThreadPlansUpToIndex(uint32_t plan_index) { // Count the user thread plans from the back end to get the number of the one // we want to discard: - uint32_t idx = 0; - ThreadPlan *up_to_plan_ptr = nullptr; - - for (ThreadPlanSP plan_sp : m_plan_stack) { - if (plan_sp->GetPrivate()) - continue; - if (idx == thread_index) { - up_to_plan_ptr = plan_sp.get(); - break; - } else - idx++; - } - + ThreadPlan *up_to_plan_ptr = GetPlans().GetPlanByIndex(plan_index).get(); if (up_to_plan_ptr == nullptr) return false; @@ -1289,30 +1178,7 @@ void Thread::DiscardThreadPlansUpToPlan(ThreadPlan *up_to_plan_ptr) { "Discarding thread plans for thread tid = 0x%4.4" PRIx64 ", up to %p", GetID(), static_cast(up_to_plan_ptr)); - - int stack_size = m_plan_stack.size(); - - // If the input plan is nullptr, discard all plans. Otherwise make sure this - // plan is in the stack, and if so discard up to and including it. - - if (up_to_plan_ptr == nullptr) { - for (int i = stack_size - 1; i > 0; i--) - DiscardPlan(); - } else { - bool found_it = false; - for (int i = stack_size - 1; i > 0; i--) { - if (m_plan_stack[i].get() == up_to_plan_ptr) - found_it = true; - } - if (found_it) { - bool last_one = false; - for (int i = stack_size - 1; i > 0 && !last_one; i--) { - if (GetCurrentPlan() == up_to_plan_ptr) - last_one = true; - DiscardPlan(); - } - } - } + GetPlans().DiscardPlansUpToPlan(up_to_plan_ptr); } void Thread::DiscardThreadPlans(bool force) { @@ -1325,73 +1191,20 @@ void Thread::DiscardThreadPlans(bool force) { } if (force) { - int stack_size = m_plan_stack.size(); - for (int i = stack_size - 1; i > 0; i--) { - DiscardPlan(); - } + GetPlans().DiscardAllPlans(); return; } - - while (true) { - int master_plan_idx; - bool discard = true; - - // Find the first master plan, see if it wants discarding, and if yes - // discard up to it. - for (master_plan_idx = m_plan_stack.size() - 1; master_plan_idx >= 0; - master_plan_idx--) { - if (m_plan_stack[master_plan_idx]->IsMasterPlan()) { - discard = m_plan_stack[master_plan_idx]->OkayToDiscard(); - break; - } - } - - if (discard) { - // First pop all the dependent plans: - for (int i = m_plan_stack.size() - 1; i > master_plan_idx; i--) { - // FIXME: Do we need a finalize here, or is the rule that - // "PrepareForStop" - // for the plan leaves it in a state that it is safe to pop the plan - // with no more notice? - DiscardPlan(); - } - - // Now discard the master plan itself. - // The bottom-most plan never gets discarded. "OkayToDiscard" for it - // means discard it's dependent plans, but not it... - if (master_plan_idx > 0) { - DiscardPlan(); - } - } else { - // If the master plan doesn't want to get discarded, then we're done. - break; - } - } -} - -bool Thread::PlanIsBasePlan(ThreadPlan *plan_ptr) { - if (plan_ptr->IsBasePlan()) - return true; - else if (m_plan_stack.size() == 0) - return false; - else - return m_plan_stack[0].get() == plan_ptr; + GetPlans().DiscardConsultingMasterPlans(); } Status Thread::UnwindInnermostExpression() { Status error; - int stack_size = m_plan_stack.size(); - - // If the input plan is nullptr, discard all plans. Otherwise make sure this - // plan is in the stack, and if so discard up to and including it. - - for (int i = stack_size - 1; i > 0; i--) { - if (m_plan_stack[i]->GetKind() == ThreadPlan::eKindCallFunction) { - DiscardThreadPlansUpToPlan(m_plan_stack[i].get()); - return error; - } - } - error.SetErrorString("No expressions currently active on this thread"); + ThreadPlan *innermost_expr_plan = GetPlans().GetInnermostExpression(); + if (!innermost_expr_plan) { + error.SetErrorString("No expressions currently active on this thread"); + return error; + } + DiscardThreadPlansUpToPlan(innermost_expr_plan); return error; } @@ -1557,40 +1370,12 @@ lldb::ThreadPlanSP Thread::QueueThreadPlanForStepScripted( uint32_t Thread::GetIndexID() const { return m_index_id; } -static void PrintPlanElement(Stream *s, const ThreadPlanSP &plan, - lldb::DescriptionLevel desc_level, - int32_t elem_idx) { - s->IndentMore(); - s->Indent(); - s->Printf("Element %d: ", elem_idx); - plan->GetDescription(s, desc_level); - s->EOL(); - s->IndentLess(); -} - -static void PrintPlanStack(Stream *s, - const std::vector &plan_stack, - lldb::DescriptionLevel desc_level, - bool include_internal) { - int32_t print_idx = 0; - for (ThreadPlanSP plan_sp : plan_stack) { - if (include_internal || !plan_sp->GetPrivate()) { - PrintPlanElement(s, plan_sp, desc_level, print_idx++); - } - } -} - void Thread::DumpThreadPlans(Stream *s, lldb::DescriptionLevel desc_level, bool include_internal, bool ignore_boring_threads) const { - uint32_t stack_size; - if (ignore_boring_threads) { - uint32_t stack_size = m_plan_stack.size(); - uint32_t completed_stack_size = m_completed_plan_stack.size(); - uint32_t discarded_stack_size = m_discarded_plan_stack.size(); - if (stack_size == 1 && completed_stack_size == 0 && - discarded_stack_size == 0) { + if (!GetPlans().AnyPlans() && !GetPlans().AnyCompletedPlans() + && !GetPlans().AnyDiscardedPlans()) { s->Printf("thread #%u: tid = 0x%4.4" PRIx64 "\n", GetIndexID(), GetID()); s->IndentMore(); s->Indent(); @@ -1599,29 +1384,10 @@ void Thread::DumpThreadPlans(Stream *s, lldb::DescriptionLevel desc_level, return; } } - + s->Indent(); s->Printf("thread #%u: tid = 0x%4.4" PRIx64 ":\n", GetIndexID(), GetID()); - s->IndentMore(); - s->Indent(); - s->Printf("Active plan stack:\n"); - PrintPlanStack(s, m_plan_stack, desc_level, include_internal); - - stack_size = m_completed_plan_stack.size(); - if (stack_size > 0) { - s->Indent(); - s->Printf("Completed Plan Stack:\n"); - PrintPlanStack(s, m_completed_plan_stack, desc_level, include_internal); - } - - stack_size = m_discarded_plan_stack.size(); - if (stack_size > 0) { - s->Indent(); - s->Printf("Discarded Plan Stack:\n"); - PrintPlanStack(s, m_discarded_plan_stack, desc_level, include_internal); - } - - s->IndentLess(); + GetPlans().DumpThreadPlans(s, desc_level, include_internal); } TargetSP Thread::CalculateTarget() { diff --git a/lldb/source/Target/ThreadList.cpp b/lldb/source/Target/ThreadList.cpp index 183b39c2cfa9b..bcbbe76071d4d 100644 --- a/lldb/source/Target/ThreadList.cpp +++ b/lldb/source/Target/ThreadList.cpp @@ -726,8 +726,10 @@ void ThreadList::Update(ThreadList &rhs) { break; } } - if (!thread_is_alive) + if (!thread_is_alive) { (*rhs_pos)->DestroyThread(); + m_process->RemoveThreadPlansForTID((*rhs_pos)->GetID()); + } } } } diff --git a/lldb/source/Target/ThreadPlan.cpp b/lldb/source/Target/ThreadPlan.cpp index b946554576bdc..ef5aa3b5390ea 100644 --- a/lldb/source/Target/ThreadPlan.cpp +++ b/lldb/source/Target/ThreadPlan.cpp @@ -34,6 +34,10 @@ ThreadPlan::ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread, // Destructor ThreadPlan::~ThreadPlan() = default; +Target &ThreadPlan::GetTarget() { return m_process.GetTarget(); } + +const Target &ThreadPlan::GetTarget() const { return m_process.GetTarget(); } + Thread &ThreadPlan::GetThread() { if (m_thread) return *m_thread; diff --git a/lldb/source/Target/ThreadPlanStack.cpp b/lldb/source/Target/ThreadPlanStack.cpp new file mode 100644 index 0000000000000..bd11718f01d93 --- /dev/null +++ b/lldb/source/Target/ThreadPlanStack.cpp @@ -0,0 +1,370 @@ +//===-- ThreadPlanStack.cpp -------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "lldb/Target/ThreadPlanStack.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/ThreadPlan.h" +#include "lldb/Utility/Log.h" + +using namespace lldb; +using namespace lldb_private; + +static void PrintPlanElement(Stream *s, const ThreadPlanSP &plan, + lldb::DescriptionLevel desc_level, + int32_t elem_idx) { + s->IndentMore(); + s->Indent(); + s->Printf("Element %d: ", elem_idx); + plan->GetDescription(s, desc_level); + s->EOL(); + s->IndentLess(); +} + +void ThreadPlanStack::DumpThreadPlans(Stream *s, + lldb::DescriptionLevel desc_level, + bool include_internal) const { + + uint32_t stack_size; + + s->IndentMore(); + s->Indent(); + s->Printf("Active plan stack:\n"); + int32_t print_idx = 0; + for (auto plan : m_plans) { + PrintPlanElement(s, plan, desc_level, print_idx++); + } + + if (AnyCompletedPlans()) { + print_idx = 0; + s->Indent(); + s->Printf("Completed Plan Stack:\n"); + for (auto plan : m_completed_plans) + PrintPlanElement(s, plan, desc_level, print_idx++); + } + + if (AnyDiscardedPlans()) { + print_idx = 0; + s->Indent(); + s->Printf("Discarded Plan Stack:\n"); + for (auto plan : m_discarded_plans) + PrintPlanElement(s, plan, desc_level, print_idx++); + } + + s->IndentLess(); +} + +size_t ThreadPlanStack::CheckpointCompletedPlans() { + m_completed_plan_checkpoint++; + m_completed_plan_store.insert( + std::make_pair(m_completed_plan_checkpoint, m_completed_plans)); + return m_completed_plan_checkpoint; +} + +void ThreadPlanStack::RestoreCompletedPlanCheckpoint(size_t checkpoint) { + auto result = m_completed_plan_store.find(checkpoint); + assert(result != m_completed_plan_store.end() && + "Asked for a checkpoint that didn't exist"); + m_completed_plans.swap((*result).second); + m_completed_plan_store.erase(result); +} + +void ThreadPlanStack::DiscardCompletedPlanCheckpoint(size_t checkpoint) { + m_completed_plan_store.erase(checkpoint); +} + +void ThreadPlanStack::ThreadDestroyed(Thread *thread) { + // Tell the plan stacks that this thread is going away: + for (ThreadPlanSP plan : m_plans) + plan->ThreadDestroyed(); + + for (ThreadPlanSP plan : m_discarded_plans) + plan->ThreadDestroyed(); + + for (ThreadPlanSP plan : m_completed_plans) + plan->ThreadDestroyed(); + + // Now clear the current plan stacks: + m_plans.clear(); + m_discarded_plans.clear(); + m_completed_plans.clear(); + + // Push a ThreadPlanNull on the plan stack. That way we can continue + // assuming that the plan stack is never empty, but if somebody errantly asks + // questions of a destroyed thread without checking first whether it is + // destroyed, they won't crash. + if (thread != nullptr) { + lldb::ThreadPlanSP null_plan_sp(new ThreadPlanNull(*thread)); + m_plans.push_back(null_plan_sp); + } +} + +void ThreadPlanStack::EnableTracer(bool value, bool single_stepping) { + for (ThreadPlanSP plan : m_plans) { + if (plan->GetThreadPlanTracer()) { + plan->GetThreadPlanTracer()->EnableTracing(value); + plan->GetThreadPlanTracer()->EnableSingleStep(single_stepping); + } + } +} + +void ThreadPlanStack::SetTracer(lldb::ThreadPlanTracerSP &tracer_sp) { + for (ThreadPlanSP plan : m_plans) + plan->SetThreadPlanTracer(tracer_sp); +} + +void ThreadPlanStack::PushPlan(lldb::ThreadPlanSP new_plan_sp) { + // If the thread plan doesn't already have a tracer, give it its parent's + // tracer: + // The first plan has to be a base plan: + assert(m_plans.size() > 0 || + new_plan_sp->IsBasePlan() && "Zeroth plan must be a base plan"); + + if (!new_plan_sp->GetThreadPlanTracer()) { + assert(!m_plans.empty()); + new_plan_sp->SetThreadPlanTracer(m_plans.back()->GetThreadPlanTracer()); + } + m_plans.push_back(new_plan_sp); + new_plan_sp->DidPush(); +} + +lldb::ThreadPlanSP ThreadPlanStack::PopPlan() { + assert(m_plans.size() > 1 && "Can't pop the base thread plan"); + + lldb::ThreadPlanSP &plan_sp = m_plans.back(); + m_completed_plans.push_back(plan_sp); + plan_sp->WillPop(); + m_plans.pop_back(); + return plan_sp; +} + +lldb::ThreadPlanSP ThreadPlanStack::DiscardPlan() { + assert(m_plans.size() > 1 && "Can't discard the base thread plan"); + + lldb::ThreadPlanSP &plan_sp = m_plans.back(); + m_discarded_plans.push_back(plan_sp); + plan_sp->WillPop(); + m_plans.pop_back(); + return plan_sp; +} + +// If the input plan is nullptr, discard all plans. Otherwise make sure this +// plan is in the stack, and if so discard up to and including it. +void ThreadPlanStack::DiscardPlansUpToPlan(ThreadPlan *up_to_plan_ptr) { + int stack_size = m_plans.size(); + + if (up_to_plan_ptr == nullptr) { + for (int i = stack_size - 1; i > 0; i--) + DiscardPlan(); + return; + } + + bool found_it = false; + for (int i = stack_size - 1; i > 0; i--) { + if (m_plans[i].get() == up_to_plan_ptr) { + found_it = true; + break; + } + } + + if (found_it) { + bool last_one = false; + for (int i = stack_size - 1; i > 0 && !last_one; i--) { + if (GetCurrentPlan().get() == up_to_plan_ptr) + last_one = true; + DiscardPlan(); + } + } +} + +void ThreadPlanStack::DiscardAllPlans() { + int stack_size = m_plans.size(); + for (int i = stack_size - 1; i > 0; i--) { + DiscardPlan(); + } + return; +} + +void ThreadPlanStack::DiscardConsultingMasterPlans() { + while (true) { + int master_plan_idx; + bool discard = true; + + // Find the first master plan, see if it wants discarding, and if yes + // discard up to it. + for (master_plan_idx = m_plans.size() - 1; master_plan_idx >= 0; + master_plan_idx--) { + if (m_plans[master_plan_idx]->IsMasterPlan()) { + discard = m_plans[master_plan_idx]->OkayToDiscard(); + break; + } + } + + // If the master plan doesn't want to get discarded, then we're done. + if (!discard) + return; + + // First pop all the dependent plans: + for (int i = m_plans.size() - 1; i > master_plan_idx; i--) { + DiscardPlan(); + } + + // Now discard the master plan itself. + // The bottom-most plan never gets discarded. "OkayToDiscard" for it + // means discard it's dependent plans, but not it... + if (master_plan_idx > 0) { + DiscardPlan(); + } + } +} + +lldb::ThreadPlanSP ThreadPlanStack::GetCurrentPlan() const { + assert(m_plans.size() != 0 && "There will always be a base plan."); + return m_plans.back(); +} + +lldb::ThreadPlanSP ThreadPlanStack::GetCompletedPlan(bool skip_private) const { + if (m_completed_plans.empty()) + return {}; + + if (!skip_private) + return m_completed_plans.back(); + + for (int i = m_completed_plans.size() - 1; i >= 0; i--) { + lldb::ThreadPlanSP completed_plan_sp; + completed_plan_sp = m_completed_plans[i]; + if (!completed_plan_sp->GetPrivate()) + return completed_plan_sp; + } + return {}; +} + +lldb::ThreadPlanSP ThreadPlanStack::GetPlanByIndex(uint32_t plan_idx, + bool skip_private) const { + uint32_t idx = 0; + ThreadPlan *up_to_plan_ptr = nullptr; + + for (lldb::ThreadPlanSP plan_sp : m_plans) { + if (skip_private && plan_sp->GetPrivate()) + continue; + if (idx == plan_idx) + return plan_sp; + idx++; + } + return {}; +} + +lldb::ValueObjectSP ThreadPlanStack::GetReturnValueObject() const { + if (m_completed_plans.empty()) + return {}; + + for (int i = m_completed_plans.size() - 1; i >= 0; i--) { + lldb::ValueObjectSP return_valobj_sp; + return_valobj_sp = m_completed_plans[i]->GetReturnValueObject(); + if (return_valobj_sp) + return return_valobj_sp; + } + return {}; +} + +lldb::ExpressionVariableSP ThreadPlanStack::GetExpressionVariable() const { + if (m_completed_plans.empty()) + return {}; + + for (int i = m_completed_plans.size() - 1; i >= 0; i--) { + lldb::ExpressionVariableSP expression_variable_sp; + expression_variable_sp = m_completed_plans[i]->GetExpressionVariable(); + if (expression_variable_sp) + return expression_variable_sp; + } + return {}; +} +bool ThreadPlanStack::AnyPlans() const { + // There is always a base plan... + return m_plans.size() > 1; +} + +bool ThreadPlanStack::AnyCompletedPlans() const { + return !m_completed_plans.empty(); +} + +bool ThreadPlanStack::AnyDiscardedPlans() const { + return !m_discarded_plans.empty(); +} + +bool ThreadPlanStack::IsPlanDone(ThreadPlan *in_plan) const { + for (auto plan : m_completed_plans) { + if (plan.get() == in_plan) + return true; + } + return false; +} + +bool ThreadPlanStack::WasPlanDiscarded(ThreadPlan *in_plan) const { + for (auto plan : m_discarded_plans) { + if (plan.get() == in_plan) + return true; + } + return false; +} + +ThreadPlan *ThreadPlanStack::GetPreviousPlan(ThreadPlan *current_plan) const { + if (current_plan == nullptr) + return nullptr; + + // Look first in the completed plans, if the plan is here and there is + // a completed plan above it, return that. + int stack_size = m_completed_plans.size(); + for (int i = stack_size - 1; i > 0; i--) { + if (current_plan == m_completed_plans[i].get()) + return m_completed_plans[i - 1].get(); + } + + // If this is the first completed plan, the previous one is the + // bottom of the regular plan stack. + if (stack_size > 0 && m_completed_plans[0].get() == current_plan) { + return GetCurrentPlan().get(); + } + + // Otherwise look for it in the regular plans. + stack_size = m_plans.size(); + for (int i = stack_size - 1; i > 0; i--) { + if (current_plan == m_plans[i].get()) + return m_plans[i - 1].get(); + } + return nullptr; +} + +ThreadPlan *ThreadPlanStack::GetInnermostExpression() const { + int stack_size = m_plans.size(); + + for (int i = stack_size - 1; i > 0; i--) { + if (m_plans[i]->GetKind() == ThreadPlan::eKindCallFunction) + return m_plans[i].get(); + } + return nullptr; +} + +void ThreadPlanStack::WillResume() { + m_completed_plans.clear(); + m_discarded_plans.clear(); +} + +const ThreadPlanStack::PlanStack & +ThreadPlanStack::GetStackOfKind(ThreadPlanStack::StackKind kind) const { + switch (kind) { + case ePlans: + return m_plans; + case eCompletedPlans: + return m_completed_plans; + case eDiscardedPlans: + return m_discarded_plans; + } + llvm_unreachable("Invalid StackKind value"); +} From 0349f1ec31d2bd66f1ac173285f95002d0c34337 Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Wed, 18 Mar 2020 12:05:08 -0700 Subject: [PATCH 141/286] Allow the ThreadPlanStackMap to hold the thread plans for threads that were not reported by the OS plugin. To facilitate this, move adding/updating the ThreadPlans for a Thread to the ThreadPlanStackMap. Also move dumping thread plans there as well. Added some tests for "thread plan list" and "thread plan discard" since I didn't seem to have written any originally. Differential Revision: https://reviews.llvm.org/D76814 --- lldb/include/lldb/Target/Process.h | 70 ++++++- lldb/include/lldb/Target/Target.h | 5 + lldb/include/lldb/Target/Thread.h | 14 +- lldb/include/lldb/Target/ThreadPlan.h | 8 +- lldb/include/lldb/Target/ThreadPlanStack.h | 26 ++- lldb/source/Commands/CommandObjectThread.cpp | 143 +++++++++++-- lldb/source/Commands/Options.td | 5 + lldb/source/Target/Process.cpp | 41 +++- lldb/source/Target/Target.cpp | 28 +++ lldb/source/Target/TargetProperties.td | 4 + lldb/source/Target/Thread.cpp | 46 ++-- lldb/source/Target/ThreadList.cpp | 6 +- lldb/source/Target/ThreadPlan.cpp | 12 +- lldb/source/Target/ThreadPlanStack.cpp | 198 +++++++++++++++--- lldb/source/Target/ThreadPlanStepOut.cpp | 9 +- .../stepping_plugin_threads/Makefile | 4 + .../TestOSPluginStepping.py | 113 ++++++++++ .../stepping_plugin_threads/main.cpp | 55 +++++ .../operating_system.py | 62 ++++++ .../API/functionalities/thread_plan/Makefile | 4 + .../thread_plan/TestThreadPlanCommands.py | 164 +++++++++++++++ .../API/functionalities/thread_plan/main.c | 16 ++ 22 files changed, 925 insertions(+), 108 deletions(-) create mode 100644 lldb/test/API/functionalities/plugins/python_os_plugin/stepping_plugin_threads/Makefile create mode 100644 lldb/test/API/functionalities/plugins/python_os_plugin/stepping_plugin_threads/TestOSPluginStepping.py create mode 100644 lldb/test/API/functionalities/plugins/python_os_plugin/stepping_plugin_threads/main.cpp create mode 100644 lldb/test/API/functionalities/plugins/python_os_plugin/stepping_plugin_threads/operating_system.py create mode 100644 lldb/test/API/functionalities/thread_plan/Makefile create mode 100644 lldb/test/API/functionalities/thread_plan/TestThreadPlanCommands.py create mode 100644 lldb/test/API/functionalities/thread_plan/main.c diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index 6d5dcb0698436..d385be20430a3 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -2199,19 +2199,75 @@ class Process : public std::enable_shared_from_this, } void SetDynamicCheckers(DynamicCheckerFunctions *dynamic_checkers); - + +/// Prune ThreadPlanStacks for unreported threads. +/// +/// \param[in] tid +/// The tid whose Plan Stack we are seeking to prune. +/// +/// \return +/// \b true if the TID is found or \b false if not. +bool PruneThreadPlansForTID(lldb::tid_t tid); + +/// Prune ThreadPlanStacks for all unreported threads. +void PruneThreadPlans(); + /// Find the thread plan stack associated with thread with \a tid. /// /// \param[in] tid - /// The tid whose Plan Stack we are seeking.. + /// The tid whose Plan Stack we are seeking. /// /// \return /// Returns a ThreadPlan if the TID is found or nullptr if not. ThreadPlanStack *FindThreadPlans(lldb::tid_t tid); - - void AddThreadPlansForThread(Thread &thread); - - void RemoveThreadPlansForTID(lldb::tid_t tid); + + /// Dump the thread plans associated with thread with \a tid. + /// + /// \param[in/out] strm + /// The stream to which to dump the output + /// + /// \param[in] tid + /// The tid whose Plan Stack we are dumping + /// + /// \param[in] desc_level + /// How much detail to dump + /// + /// \param[in] internal + /// If \b true dump all plans, if false only user initiated plans + /// + /// \param[in] condense_trivial + /// If true, only dump a header if the plan stack is just the base plan. + /// + /// \param[in] skip_unreported_plans + /// If true, only dump a plan if it is currently backed by an + /// lldb_private::Thread *. + /// + /// \return + /// Returns \b true if TID was found, \b false otherwise + bool DumpThreadPlansForTID(Stream &strm, lldb::tid_t tid, + lldb::DescriptionLevel desc_level, bool internal, + bool condense_trivial, bool skip_unreported_plans); + + /// Dump all the thread plans for this process. + /// + /// \param[in/out] strm + /// The stream to which to dump the output + /// + /// \param[in] desc_level + /// How much detail to dump + /// + /// \param[in] internal + /// If \b true dump all plans, if false only user initiated plans + /// + /// \param[in] condense_trivial + /// If true, only dump a header if the plan stack is just the base plan. + /// + /// \param[in] skip_unreported_plans + /// If true, skip printing all thread plan stacks that don't currently + /// have a backing lldb_private::Thread *. + void DumpThreadPlans(Stream &strm, lldb::DescriptionLevel desc_level, + bool internal, bool condense_trivial, + bool skip_unreported_plans); /// Call this to set the lldb in the mode where it breaks on new thread /// creations, and then auto-restarts. This is useful when you are trying @@ -2548,7 +2604,7 @@ class Process : public std::enable_shared_from_this, virtual EventActionResult HandleBeingInterrupted() = 0; virtual const char *GetExitString() = 0; void RequestResume() { m_process->m_resume_requested = true; } - + protected: Process *m_process; }; diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index 4dd340e483742..be09f926cbc9d 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -202,6 +202,10 @@ class TargetProperties : public Properties { bool GetInjectLocalVariables(ExecutionContext *exe_ctx) const; void SetInjectLocalVariables(ExecutionContext *exe_ctx, bool b); + + bool GetOSPluginReportsAllThreads() const; + + void SetOSPluginReportsAllThreads(bool does_report); void SetRequireHardwareBreakpoints(bool b); @@ -209,6 +213,7 @@ class TargetProperties : public Properties { void UpdateLaunchInfoFromProperties(); + private: // Callbacks for m_launch_info. static void Arg0ValueChangedCallback(void *target_property_ptr, diff --git a/lldb/include/lldb/Target/Thread.h b/lldb/include/lldb/Target/Thread.h index 4de7cb09a51cb..e79cc6652ade6 100644 --- a/lldb/include/lldb/Target/Thread.h +++ b/lldb/include/lldb/Target/Thread.h @@ -1021,16 +1021,6 @@ class Thread : public std::enable_shared_from_this, /// otherwise. bool DiscardUserThreadPlansUpToIndex(uint32_t thread_index); - /// Prints the current plan stack. - /// - /// \param[in] s - /// The stream to which to dump the plan stack info. - /// - void DumpThreadPlans( - Stream *s, - lldb::DescriptionLevel desc_level = lldb::eDescriptionLevelVerbose, - bool include_internal = true, bool ignore_boring = false) const; - virtual bool CheckpointThreadState(ThreadStateCheckpoint &saved_state); virtual bool @@ -1188,7 +1178,7 @@ class Thread : public std::enable_shared_from_this, // thread is still in good shape to call virtual thread methods. This must // be called by classes that derive from Thread in their destructor. virtual void DestroyThread(); - + ThreadPlanStack &GetPlans() const; void PushPlan(lldb::ThreadPlanSP plan_sp); @@ -1262,6 +1252,7 @@ class Thread : public std::enable_shared_from_this, bool m_destroy_called; // This is used internally to make sure derived Thread // classes call DestroyThread. LazyBool m_override_should_notify; + mutable std::unique_ptr m_null_plan_stack_up; private: bool m_extended_info_fetched; // Have we tried to retrieve the m_extended_info @@ -1269,7 +1260,6 @@ class Thread : public std::enable_shared_from_this, StructuredData::ObjectSP m_extended_info; // The extended info for this thread private: - void BroadcastSelectedFrameChange(StackID &new_frame_id); DISALLOW_COPY_AND_ASSIGN(Thread); diff --git a/lldb/include/lldb/Target/ThreadPlan.h b/lldb/include/lldb/Target/ThreadPlan.h index 2935ecb4effe0..b578cee62b3a3 100644 --- a/lldb/include/lldb/Target/ThreadPlan.h +++ b/lldb/include/lldb/Target/ThreadPlan.h @@ -376,7 +376,9 @@ class ThreadPlan : public std::enable_shared_from_this, const Target &GetTarget() const; /// Print a description of this thread to the stream \a s. - /// \a thread. + /// \a thread. Don't expect that the result of GetThread is valid in + /// the description method. This might get called when the underlying + /// Thread has not been reported, so we only know the TID and not the thread. /// /// \param[in] s /// The stream to which to print the description. @@ -598,7 +600,9 @@ class ThreadPlan : public std::enable_shared_from_this, // For ThreadPlan only static lldb::user_id_t GetNextID(); - Thread *m_thread; + Thread *m_thread; // Stores a cached value of the thread, which is set to + // nullptr when the thread resumes. Don't use this anywhere + // but ThreadPlan::GetThread(). ThreadPlanKind m_kind; std::string m_name; std::recursive_mutex m_plan_complete_mutex; diff --git a/lldb/include/lldb/Target/ThreadPlanStack.h b/lldb/include/lldb/Target/ThreadPlanStack.h index be7791abef81e..de52ee3ee198a 100644 --- a/lldb/include/lldb/Target/ThreadPlanStack.h +++ b/lldb/include/lldb/Target/ThreadPlanStack.h @@ -32,14 +32,14 @@ class ThreadPlanStack { friend class lldb_private::Thread; public: - ThreadPlanStack(Thread &thread) {} + ThreadPlanStack(const Thread &thread, bool make_empty = false); ~ThreadPlanStack() {} enum StackKind { ePlans, eCompletedPlans, eDiscardedPlans }; using PlanStack = std::vector; - void DumpThreadPlans(Stream *s, lldb::DescriptionLevel desc_level, + void DumpThreadPlans(Stream &s, lldb::DescriptionLevel desc_level, bool include_internal) const; size_t CheckpointCompletedPlans(); @@ -98,6 +98,10 @@ class ThreadPlanStack { private: const PlanStack &GetStackOfKind(ThreadPlanStack::StackKind kind) const; + void PrintOneStack(Stream &s, llvm::StringRef stack_name, + const PlanStack &stack, lldb::DescriptionLevel desc_level, + bool include_internal) const; + PlanStack m_plans; ///< The stack of plans this thread is executing. PlanStack m_completed_plans; ///< Plans that have been completed by this /// stop. They get deleted when the thread @@ -112,9 +116,13 @@ class ThreadPlanStack { class ThreadPlanStackMap { public: - ThreadPlanStackMap() {} + ThreadPlanStackMap(Process &process) : m_process(process) {} ~ThreadPlanStackMap() {} + // Prune the map using the current_threads list. + void Update(ThreadList ¤t_threads, bool delete_missing, + bool check_for_new = true); + void AddThread(Thread &thread) { lldb::tid_t tid = thread.GetID(); auto result = m_plans_list.emplace(tid, thread); @@ -143,7 +151,19 @@ class ThreadPlanStackMap { m_plans_list.clear(); } + // Implements Process::DumpThreadPlans + void DumpPlans(Stream &strm, lldb::DescriptionLevel desc_level, bool internal, + bool ignore_boring, bool skip_unreported); + + // Implements Process::DumpThreadPlansForTID + bool DumpPlansForTID(Stream &strm, lldb::tid_t tid, + lldb::DescriptionLevel desc_level, bool internal, + bool ignore_boring, bool skip_unreported); + + bool PrunePlansForTID(lldb::tid_t tid); + private: + Process &m_process; using PlansList = std::unordered_map; PlansList m_plans_list; }; diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp index 83c7cb50d142f..0f64219a1dbef 100644 --- a/lldb/source/Commands/CommandObjectThread.cpp +++ b/lldb/source/Commands/CommandObjectThread.cpp @@ -1833,25 +1833,36 @@ class CommandObjectThreadPlanList : public CommandObjectIterateOverThreads { Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, ExecutionContext *execution_context) override { - Status error; const int short_option = m_getopt_table[option_idx].val; switch (short_option) { case 'i': m_internal = true; break; + case 't': + lldb::tid_t tid; + if (option_arg.getAsInteger(0, tid)) + return Status("invalid tid: '%s'.", option_arg.str().c_str()); + m_tids.push_back(tid); + break; + case 'u': + m_unreported = false; + break; case 'v': m_verbose = true; break; default: llvm_unreachable("Unimplemented option"); } - return error; + return {}; } void OptionParsingStarting(ExecutionContext *execution_context) override { m_verbose = false; m_internal = false; + m_unreported = true; // The variable is "skip unreported" and we want to + // skip unreported by default. + m_tids.clear(); } llvm::ArrayRef GetDefinitions() override { @@ -1861,6 +1872,8 @@ class CommandObjectThreadPlanList : public CommandObjectIterateOverThreads { // Instance variables to hold the values for command options. bool m_verbose; bool m_internal; + bool m_unreported; + std::vector m_tids; }; CommandObjectThreadPlanList(CommandInterpreter &interpreter) @@ -1879,25 +1892,59 @@ class CommandObjectThreadPlanList : public CommandObjectIterateOverThreads { Options *GetOptions() override { return &m_options; } + bool DoExecute(Args &command, CommandReturnObject &result) override { + // If we are reporting all threads, dispatch to the Process to do that: + if (command.GetArgumentCount() == 0 && m_options.m_tids.empty()) { + Stream &strm = result.GetOutputStream(); + DescriptionLevel desc_level = m_options.m_verbose + ? eDescriptionLevelVerbose + : eDescriptionLevelFull; + m_exe_ctx.GetProcessPtr()->DumpThreadPlans( + strm, desc_level, m_options.m_internal, true, m_options.m_unreported); + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } else { + // Do any TID's that the user may have specified as TID, then do any + // Thread Indexes... + if (!m_options.m_tids.empty()) { + Process *process = m_exe_ctx.GetProcessPtr(); + StreamString tmp_strm; + for (lldb::tid_t tid : m_options.m_tids) { + bool success = process->DumpThreadPlansForTID( + tmp_strm, tid, eDescriptionLevelFull, m_options.m_internal, + true /* condense_trivial */, m_options.m_unreported); + // If we didn't find a TID, stop here and return an error. + if (!success) { + result.SetError("Error dumping plans:"); + result.AppendError(tmp_strm.GetString()); + result.SetStatus(eReturnStatusFailed); + return false; + } + // Otherwise, add our data to the output: + result.GetOutputStream() << tmp_strm.GetString(); + } + } + return CommandObjectIterateOverThreads::DoExecute(command, result); + } + } + protected: bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override { - ThreadSP thread_sp = - m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid); - if (!thread_sp) { - result.AppendErrorWithFormat("thread no longer exists: 0x%" PRIx64 "\n", - tid); - result.SetStatus(eReturnStatusFailed); - return false; - } + // If we have already handled this from a -t option, skip it here. + if (std::find(m_options.m_tids.begin(), m_options.m_tids.end(), tid) != + m_options.m_tids.end()) + return true; - Thread *thread = thread_sp.get(); + Process *process = m_exe_ctx.GetProcessPtr(); Stream &strm = result.GetOutputStream(); DescriptionLevel desc_level = eDescriptionLevelFull; if (m_options.m_verbose) desc_level = eDescriptionLevelVerbose; - thread->DumpThreadPlans(&strm, desc_level, m_options.m_internal, true); + process->DumpThreadPlansForTID(strm, tid, desc_level, m_options.m_internal, + true /* condense_trivial */, + m_options.m_unreported); return true; } @@ -1974,6 +2021,75 @@ class CommandObjectThreadPlanDiscard : public CommandObjectParsed { } }; +class CommandObjectThreadPlanPrune : public CommandObjectParsed { +public: + CommandObjectThreadPlanPrune(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "thread plan prune", + "Removes any thread plans associated with " + "currently unreported threads. " + "Specify one or more TID's to remove, or if no " + "TID's are provides, remove threads for all " + "unreported threads", + nullptr, + eCommandRequiresProcess | + eCommandTryTargetAPILock | + eCommandProcessMustBeLaunched | + eCommandProcessMustBePaused) { + CommandArgumentEntry arg; + CommandArgumentData tid_arg; + + // Define the first (and only) variant of this arg. + tid_arg.arg_type = eArgTypeThreadID; + tid_arg.arg_repetition = eArgRepeatStar; + + // There is only one variant this argument could be; put it into the + // argument entry. + arg.push_back(tid_arg); + + // Push the data for the first argument into the m_arguments vector. + m_arguments.push_back(arg); + } + + ~CommandObjectThreadPlanPrune() override = default; + + bool DoExecute(Args &args, CommandReturnObject &result) override { + Process *process = m_exe_ctx.GetProcessPtr(); + + if (args.GetArgumentCount() == 0) { + process->PruneThreadPlans(); + result.SetStatus(eReturnStatusSuccessFinishNoResult); + return true; + } + + bool success; + const size_t num_args = args.GetArgumentCount(); + + std::lock_guard guard( + process->GetThreadList().GetMutex()); + + for (size_t i = 0; i < num_args; i++) { + bool success; + + lldb::tid_t tid = StringConvert::ToUInt64( + args.GetArgumentAtIndex(i), 0, 0, &success); + if (!success) { + result.AppendErrorWithFormat("invalid thread specification: \"%s\"\n", + args.GetArgumentAtIndex(i)); + result.SetStatus(eReturnStatusFailed); + return false; + } + if (!process->PruneThreadPlansForTID(tid)) { + result.AppendErrorWithFormat("Could not find unreported tid: \"%s\"\n", + args.GetArgumentAtIndex(i)); + result.SetStatus(eReturnStatusFailed); + return false; + } + } + result.SetStatus(eReturnStatusSuccessFinishNoResult); + return true; + } +}; + // CommandObjectMultiwordThreadPlan class CommandObjectMultiwordThreadPlan : public CommandObjectMultiword { @@ -1988,6 +2104,9 @@ class CommandObjectMultiwordThreadPlan : public CommandObjectMultiword { LoadSubCommand( "discard", CommandObjectSP(new CommandObjectThreadPlanDiscard(interpreter))); + LoadSubCommand( + "prune", + CommandObjectSP(new CommandObjectThreadPlanPrune(interpreter))); } ~CommandObjectMultiwordThreadPlan() override = default; diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td index 5953ed4452234..658368a35073f 100644 --- a/lldb/source/Commands/Options.td +++ b/lldb/source/Commands/Options.td @@ -964,6 +964,11 @@ let Command = "thread plan list" in { Desc<"Display more information about the thread plans">; def thread_plan_list_internal : Option<"internal", "i">, Group<1>, Desc<"Display internal as well as user thread plans">; + def thread_plan_list_thread_id : Option<"thread-id", "t">, Group<1>, + Arg<"ThreadID">, Desc<"List the thread plans for this TID, can be " + "specified more than once.">; + def thread_plan_list_unreported : Option<"unreported", "u">, Group<1>, + Desc<"Display thread plans for unreported threads">; } let Command = "type summary add" in { diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index 07b1ac78eaca8..b07bb7e1b189a 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -485,7 +485,7 @@ Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp, m_mod_id(), m_process_unique_id(0), m_thread_index_id(0), m_thread_id_to_index_id_map(), m_exit_status(-1), m_exit_string(), m_exit_status_mutex(), m_thread_mutex(), m_thread_list_real(this), - m_thread_list(this), m_extended_thread_list(this), + m_thread_list(this), m_thread_plans(*this), m_extended_thread_list(this), m_extended_thread_stop_id(0), m_queue_list(this), m_queue_list_stop_id(0), m_notifications(), m_image_tokens(), m_listener_sp(listener_sp), m_breakpoint_site_list(), m_dynamic_checkers_up(), @@ -1194,9 +1194,12 @@ void Process::UpdateThreadListIfNeeded() { const uint32_t stop_id = GetStopID(); if (m_thread_list.GetSize(false) == 0 || stop_id != m_thread_list.GetStopID()) { + bool clear_unused_threads = true; const StateType state = GetPrivateState(); if (StateIsStoppedState(state, true)) { std::lock_guard guard(m_thread_list.GetMutex()); + m_thread_list.SetStopID(stop_id); + // m_thread_list does have its own mutex, but we need to hold onto the // mutex between the call to UpdateThreadList(...) and the // os->UpdateThreadList(...) so it doesn't change on us @@ -1217,6 +1220,10 @@ void Process::UpdateThreadListIfNeeded() { size_t num_old_threads = old_thread_list.GetSize(false); for (size_t i = 0; i < num_old_threads; ++i) old_thread_list.GetThreadAtIndex(i, false)->ClearBackingThread(); + // See if the OS plugin reports all threads. If it does, then + // it is safe to clear unseen thread's plans here. Otherwise we + // should preserve them in case they show up again: + clear_unused_threads = GetTarget().GetOSPluginReportsAllThreads(); // Turn off dynamic types to ensure we don't run any expressions. // Objective-C can run an expression to determine if a SBValue is a @@ -1243,7 +1250,7 @@ void Process::UpdateThreadListIfNeeded() { target.SetPreferDynamicValue(saved_prefer_dynamic); } else { // No OS plug-in, the new thread list is the same as the real thread - // list + // list. new_thread_list = real_thread_list; } @@ -1260,6 +1267,12 @@ void Process::UpdateThreadListIfNeeded() { m_queue_list_stop_id = GetLastNaturalStopID(); } } + // Now update the plan stack map. + // If we do have an OS plugin, any absent real threads in the + // m_thread_list have already been removed from the ThreadPlanStackMap. + // So any remaining threads are OS Plugin threads, and those we want to + // preserve in case they show up again. + m_thread_plans.Update(m_thread_list, clear_unused_threads); } } } @@ -1268,14 +1281,26 @@ ThreadPlanStack *Process::FindThreadPlans(lldb::tid_t tid) { return m_thread_plans.Find(tid); } -void Process::AddThreadPlansForThread(Thread &thread) { - if (m_thread_plans.Find(thread.GetID())) - return; - m_thread_plans.AddThread(thread); +bool Process::PruneThreadPlansForTID(lldb::tid_t tid) { + return m_thread_plans.PrunePlansForTID(tid); } -void Process::RemoveThreadPlansForTID(lldb::tid_t tid) { - m_thread_plans.RemoveTID(tid); +void Process::PruneThreadPlans() { + m_thread_plans.Update(GetThreadList(), true, false); +} + +bool Process::DumpThreadPlansForTID(Stream &strm, lldb::tid_t tid, + lldb::DescriptionLevel desc_level, + bool internal, bool condense_trivial, + bool skip_unreported_plans) { + return m_thread_plans.DumpPlansForTID( + strm, tid, desc_level, internal, condense_trivial, skip_unreported_plans); +} +void Process::DumpThreadPlans(Stream &strm, lldb::DescriptionLevel desc_level, + bool internal, bool condense_trivial, + bool skip_unreported_plans) { + m_thread_plans.DumpPlans(strm, desc_level, internal, condense_trivial, + skip_unreported_plans); } void Process::UpdateQueueListIfNeeded() { diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index 3b2a5bbc6d906..dbd050e878271 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -3507,6 +3507,34 @@ void TargetProperties::SetInjectLocalVariables(ExecutionContext *exe_ctx, true); } +bool TargetProperties::GetOSPluginReportsAllThreads() const { + const bool fail_value = true; + const Property *exp_property = + m_collection_sp->GetPropertyAtIndex(nullptr, true, ePropertyExperimental); + OptionValueProperties *exp_values = + exp_property->GetValue()->GetAsProperties(); + if (!exp_values) + return fail_value; + + return + exp_values->GetPropertyAtIndexAsBoolean(nullptr, + ePropertyOSPluginReportsAllThreads, + fail_value); +} + +void TargetProperties::SetOSPluginReportsAllThreads(bool does_report) { + const Property *exp_property = + m_collection_sp->GetPropertyAtIndex(nullptr, true, ePropertyExperimental); + OptionValueProperties *exp_values = + exp_property->GetValue()->GetAsProperties(); + if (exp_values) + exp_values->SetPropertyAtIndexAsBoolean(nullptr, + ePropertyOSPluginReportsAllThreads, + does_report); +} + + + ArchSpec TargetProperties::GetDefaultArchitecture() const { OptionValueArch *value = m_collection_sp->GetPropertyAtIndexAsOptionValueArch( nullptr, ePropertyDefaultArch); diff --git a/lldb/source/Target/TargetProperties.td b/lldb/source/Target/TargetProperties.td index 009d96ccbf919..88d812fa8d69a 100644 --- a/lldb/source/Target/TargetProperties.td +++ b/lldb/source/Target/TargetProperties.td @@ -4,6 +4,10 @@ let Definition = "experimental" in { def InjectLocalVars : Property<"inject-local-vars", "Boolean">, Global, DefaultTrue, Desc<"If true, inject local variables explicitly into the expression text. This will fix symbol resolution when there are name collisions between ivars and local variables. But it can make expressions run much more slowly.">; + def OSPluginReportsAllThreads: Property<"os-plugin-reports-all-threads", "Boolean">, + Global, + DefaultTrue, + Desc<"Set to False if your OS Plugins doesn't report all threads on each stop.">; } let Definition = "target" in { diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp index 2464c15885462..ecb14db0ac988 100644 --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -242,10 +242,6 @@ Thread::Thread(Process &process, lldb::tid_t tid, bool use_invalid_index_id) static_cast(this), GetID()); CheckInWithManager(); - - process.AddThreadPlansForThread(*this); - - QueueFundamentalPlan(true); } Thread::~Thread() { @@ -779,7 +775,9 @@ bool Thread::ShouldStop(Event *event_ptr) { LLDB_LOGF(log, "^^^^^^^^ Thread::ShouldStop Begin ^^^^^^^^"); StreamString s; s.IndentMore(); - DumpThreadPlans(&s); + GetProcess()->DumpThreadPlansForTID( + s, GetID(), eDescriptionLevelVerbose, true /* internal */, + false /* condense_trivial */, true /* skip_unreported */); LLDB_LOGF(log, "Plan stack initial state:\n%s", s.GetData()); } @@ -943,7 +941,9 @@ bool Thread::ShouldStop(Event *event_ptr) { if (log) { StreamString s; s.IndentMore(); - DumpThreadPlans(&s); + GetProcess()->DumpThreadPlansForTID( + s, GetID(), eDescriptionLevelVerbose, true /* internal */, + false /* condense_trivial */, true /* skip_unreported */); LLDB_LOGF(log, "Plan stack final state:\n%s", s.GetData()); LLDB_LOGF(log, "vvvvvvvv Thread::ShouldStop End (returning %i) vvvvvvvv", should_stop); @@ -1049,8 +1049,18 @@ bool Thread::MatchesSpec(const ThreadSpec *spec) { ThreadPlanStack &Thread::GetPlans() const { ThreadPlanStack *plans = GetProcess()->FindThreadPlans(GetID()); - assert(plans && "Can't have a thread with no plans"); - return *plans; + if (plans) + return *plans; + + // History threads don't have a thread plan, but they do ask get asked to + // describe themselves, which usually involves pulling out the stop reason. + // That in turn will check for a completed plan on the ThreadPlanStack. + // Instead of special-casing at that point, we return a Stack with a + // ThreadPlanNull as its base plan. That will give the right answers to the + // queries GetDescription makes, and only assert if you try to run the thread. + if (!m_null_plan_stack_up) + m_null_plan_stack_up.reset(new ThreadPlanStack(*this, true)); + return *(m_null_plan_stack_up.get()); } void Thread::PushPlan(ThreadPlanSP thread_plan_sp) { @@ -1370,26 +1380,6 @@ lldb::ThreadPlanSP Thread::QueueThreadPlanForStepScripted( uint32_t Thread::GetIndexID() const { return m_index_id; } -void Thread::DumpThreadPlans(Stream *s, lldb::DescriptionLevel desc_level, - bool include_internal, - bool ignore_boring_threads) const { - if (ignore_boring_threads) { - if (!GetPlans().AnyPlans() && !GetPlans().AnyCompletedPlans() - && !GetPlans().AnyDiscardedPlans()) { - s->Printf("thread #%u: tid = 0x%4.4" PRIx64 "\n", GetIndexID(), GetID()); - s->IndentMore(); - s->Indent(); - s->Printf("No active thread plans\n"); - s->IndentLess(); - return; - } - } - - s->Indent(); - s->Printf("thread #%u: tid = 0x%4.4" PRIx64 ":\n", GetIndexID(), GetID()); - GetPlans().DumpThreadPlans(s, desc_level, include_internal); -} - TargetSP Thread::CalculateTarget() { TargetSP target_sp; ProcessSP process_sp(GetProcess()); diff --git a/lldb/source/Target/ThreadList.cpp b/lldb/source/Target/ThreadList.cpp index bcbbe76071d4d..efdea45f81444 100644 --- a/lldb/source/Target/ThreadList.cpp +++ b/lldb/source/Target/ThreadList.cpp @@ -715,6 +715,11 @@ void ThreadList::Update(ThreadList &rhs) { // to work around the issue collection::iterator rhs_pos, rhs_end = rhs.m_threads.end(); for (rhs_pos = rhs.m_threads.begin(); rhs_pos != rhs_end; ++rhs_pos) { + // If this thread has already been destroyed, we don't need to look for + // it to destroy it again. + if (!(*rhs_pos)->IsValid()) + continue; + const lldb::tid_t tid = (*rhs_pos)->GetID(); bool thread_is_alive = false; const uint32_t num_threads = m_threads.size(); @@ -728,7 +733,6 @@ void ThreadList::Update(ThreadList &rhs) { } if (!thread_is_alive) { (*rhs_pos)->DestroyThread(); - m_process->RemoveThreadPlansForTID((*rhs_pos)->GetID()); } } } diff --git a/lldb/source/Target/ThreadPlan.cpp b/lldb/source/Target/ThreadPlan.cpp index ef5aa3b5390ea..9d393ff4fd843 100644 --- a/lldb/source/Target/ThreadPlan.cpp +++ b/lldb/source/Target/ThreadPlan.cpp @@ -21,7 +21,7 @@ using namespace lldb_private; // ThreadPlan constructor ThreadPlan::ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread, Vote stop_vote, Vote run_vote) - : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()), + : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()), m_stop_vote(stop_vote), m_run_vote(run_vote), m_takes_iteration_count(false), m_could_not_resolve_hw_bp(false), m_kind(kind), m_thread(&thread), m_name(name), m_plan_complete_mutex(), @@ -41,7 +41,7 @@ const Target &ThreadPlan::GetTarget() const { return m_process.GetTarget(); } Thread &ThreadPlan::GetThread() { if (m_thread) return *m_thread; - + ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(m_tid); m_thread = thread_sp.get(); return *m_thread; @@ -127,13 +127,17 @@ bool ThreadPlan::WillResume(StateType resume_state, bool current_plan) { "%s Thread #%u (0x%p): tid = 0x%4.4" PRIx64 ", pc = 0x%8.8" PRIx64 ", sp = 0x%8.8" PRIx64 ", fp = 0x%8.8" PRIx64 ", " "plan = '%s', state = %s, stop others = %d", - __FUNCTION__, GetThread().GetIndexID(), + __FUNCTION__, GetThread().GetIndexID(), static_cast(&GetThread()), m_tid, static_cast(pc), static_cast(sp), static_cast(fp), m_name.c_str(), StateAsCString(resume_state), StopOthers()); } } - return DoWillResume(resume_state, current_plan); + bool success = DoWillResume(resume_state, current_plan); + m_thread = nullptr; // We don't cache the thread pointer over resumes. This + // Thread might go away, and another Thread represent + // the same underlying object on a later stop. + return success; } lldb::user_id_t ThreadPlan::GetNextID() { diff --git a/lldb/source/Target/ThreadPlanStack.cpp b/lldb/source/Target/ThreadPlanStack.cpp index bd11718f01d93..6120d0ccefcbc 100644 --- a/lldb/source/Target/ThreadPlanStack.cpp +++ b/lldb/source/Target/ThreadPlanStack.cpp @@ -16,48 +16,70 @@ using namespace lldb; using namespace lldb_private; -static void PrintPlanElement(Stream *s, const ThreadPlanSP &plan, +static void PrintPlanElement(Stream &s, const ThreadPlanSP &plan, lldb::DescriptionLevel desc_level, int32_t elem_idx) { - s->IndentMore(); - s->Indent(); - s->Printf("Element %d: ", elem_idx); - plan->GetDescription(s, desc_level); - s->EOL(); - s->IndentLess(); + s.IndentMore(); + s.Indent(); + s.Printf("Element %d: ", elem_idx); + plan->GetDescription(&s, desc_level); + s.EOL(); + s.IndentLess(); } -void ThreadPlanStack::DumpThreadPlans(Stream *s, +ThreadPlanStack::ThreadPlanStack(const Thread &thread, bool make_null) { + if (make_null) { + // The ThreadPlanNull doesn't do anything to the Thread, so this is actually + // still a const operation. + m_plans.push_back( + ThreadPlanSP(new ThreadPlanNull(const_cast(thread)))); + } +} + +void ThreadPlanStack::DumpThreadPlans(Stream &s, lldb::DescriptionLevel desc_level, bool include_internal) const { uint32_t stack_size; - s->IndentMore(); - s->Indent(); - s->Printf("Active plan stack:\n"); - int32_t print_idx = 0; - for (auto plan : m_plans) { - PrintPlanElement(s, plan, desc_level, print_idx++); - } + s.IndentMore(); + PrintOneStack(s, "Active plan stack", m_plans, desc_level, include_internal); + PrintOneStack(s, "Completed plan stack", m_completed_plans, desc_level, + include_internal); + PrintOneStack(s, "Discarded plan stack", m_discarded_plans, desc_level, + include_internal); + s.IndentLess(); +} - if (AnyCompletedPlans()) { - print_idx = 0; - s->Indent(); - s->Printf("Completed Plan Stack:\n"); - for (auto plan : m_completed_plans) - PrintPlanElement(s, plan, desc_level, print_idx++); +void ThreadPlanStack::PrintOneStack(Stream &s, llvm::StringRef stack_name, + const PlanStack &stack, + lldb::DescriptionLevel desc_level, + bool include_internal) const { + // If the stack is empty, just exit: + if (stack.empty()) + return; + + // Make sure there are public completed plans: + bool any_public = false; + if (!include_internal) { + for (auto plan : stack) { + if (!plan->GetPrivate()) { + any_public = true; + break; + } + } } - if (AnyDiscardedPlans()) { - print_idx = 0; - s->Indent(); - s->Printf("Discarded Plan Stack:\n"); - for (auto plan : m_discarded_plans) + if (include_internal || any_public) { + int print_idx = 0; + s.Indent(); + s.Printf("%s:\n", stack_name); + for (auto plan : stack) { + if (!include_internal && plan->GetPrivate()) + continue; PrintPlanElement(s, plan, desc_level, print_idx++); + } } - - s->IndentLess(); } size_t ThreadPlanStack::CheckpointCompletedPlans() { @@ -368,3 +390,123 @@ ThreadPlanStack::GetStackOfKind(ThreadPlanStack::StackKind kind) const { } llvm_unreachable("Invalid StackKind value"); } + +void ThreadPlanStackMap::Update(ThreadList ¤t_threads, + bool delete_missing, + bool check_for_new) { + + // Now find all the new threads and add them to the map: + if (check_for_new) { + for (auto thread : current_threads.Threads()) { + lldb::tid_t cur_tid = thread->GetID(); + if (!Find(cur_tid)) { + AddThread(*thread.get()); + thread->QueueFundamentalPlan(true); + } + } + } + + // If we aren't reaping missing threads at this point, + // we are done. + if (!delete_missing) + return; + // Otherwise scan for absent TID's. + std::vector missing_threads; + // If we are going to delete plans from the plan stack, + // then scan for absent TID's: + for (auto thread_plans : m_plans_list) { + lldb::tid_t cur_tid = thread_plans.first; + ThreadSP thread_sp = current_threads.FindThreadByID(cur_tid); + if (!thread_sp) + missing_threads.push_back(cur_tid); + } + for (lldb::tid_t tid : missing_threads) { + RemoveTID(tid); + } +} + +void ThreadPlanStackMap::DumpPlans(Stream &strm, + lldb::DescriptionLevel desc_level, + bool internal, bool condense_if_trivial, + bool skip_unreported) { + for (auto elem : m_plans_list) { + lldb::tid_t tid = elem.first; + uint32_t index_id = 0; + ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid); + + if (skip_unreported) { + if (!thread_sp) + continue; + } + if (thread_sp) + index_id = thread_sp->GetIndexID(); + + if (condense_if_trivial) { + if (!elem.second.AnyPlans() && !elem.second.AnyCompletedPlans() && + !elem.second.AnyDiscardedPlans()) { + strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 "\n", index_id, tid); + strm.IndentMore(); + strm.Indent(); + strm.Printf("No active thread plans\n"); + strm.IndentLess(); + return; + } + } + + strm.Indent(); + strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 ":\n", index_id, tid); + + elem.second.DumpThreadPlans(strm, desc_level, internal); + } +} + +bool ThreadPlanStackMap::DumpPlansForTID(Stream &strm, lldb::tid_t tid, + lldb::DescriptionLevel desc_level, + bool internal, + bool condense_if_trivial, + bool skip_unreported) { + uint32_t index_id = 0; + ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid); + + if (skip_unreported) { + if (!thread_sp) { + strm.Format("Unknown TID: {0}", tid); + return false; + } + } + + if (thread_sp) + index_id = thread_sp->GetIndexID(); + ThreadPlanStack *stack = Find(tid); + if (!stack) { + strm.Format("Unknown TID: {0}\n", tid); + return false; + } + + if (condense_if_trivial) { + if (!stack->AnyPlans() && !stack->AnyCompletedPlans() && + !stack->AnyDiscardedPlans()) { + strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 "\n", index_id, tid); + strm.IndentMore(); + strm.Indent(); + strm.Printf("No active thread plans\n"); + strm.IndentLess(); + return true; + } + } + + strm.Indent(); + strm.Printf("thread #%u: tid = 0x%4.4" PRIx64 ":\n", index_id, tid); + + stack->DumpThreadPlans(strm, desc_level, internal); + return true; +} + +bool ThreadPlanStackMap::PrunePlansForTID(lldb::tid_t tid) { + // We only remove the plans for unreported TID's. + ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid); + if (thread_sp) + return false; + + return RemoveTID(tid); +} diff --git a/lldb/source/Target/ThreadPlanStepOut.cpp b/lldb/source/Target/ThreadPlanStepOut.cpp index c7a0bf667e0c3..db3c84af48ed1 100644 --- a/lldb/source/Target/ThreadPlanStepOut.cpp +++ b/lldb/source/Target/ThreadPlanStepOut.cpp @@ -192,7 +192,7 @@ void ThreadPlanStepOut::DidPush() { ThreadPlanStepOut::~ThreadPlanStepOut() { if (m_return_bp_id != LLDB_INVALID_BREAK_ID) - GetThread().CalculateTarget()->RemoveBreakpointByID(m_return_bp_id); + GetTarget().RemoveBreakpointByID(m_return_bp_id); } void ThreadPlanStepOut::GetDescription(Stream *s, @@ -208,7 +208,7 @@ void ThreadPlanStepOut::GetDescription(Stream *s, s->Printf("Stepping out from "); Address tmp_address; if (tmp_address.SetLoadAddress(m_step_from_insn, &GetTarget())) { - tmp_address.Dump(s, &GetThread(), Address::DumpStyleResolvedDescription, + tmp_address.Dump(s, &m_process, Address::DumpStyleResolvedDescription, Address::DumpStyleLoadAddress); } else { s->Printf("address 0x%" PRIx64 "", (uint64_t)m_step_from_insn); @@ -220,7 +220,7 @@ void ThreadPlanStepOut::GetDescription(Stream *s, s->Printf(" returning to frame at "); if (tmp_address.SetLoadAddress(m_return_addr, &GetTarget())) { - tmp_address.Dump(s, &GetThread(), Address::DumpStyleResolvedDescription, + tmp_address.Dump(s, &m_process, Address::DumpStyleResolvedDescription, Address::DumpStyleLoadAddress); } else { s->Printf("address 0x%" PRIx64 "", (uint64_t)m_return_addr); @@ -231,6 +231,9 @@ void ThreadPlanStepOut::GetDescription(Stream *s, } } + if (m_stepped_past_frames.empty()) + return; + s->Printf("\n"); for (StackFrameSP frame_sp : m_stepped_past_frames) { s->Printf("Stepped out past: "); diff --git a/lldb/test/API/functionalities/plugins/python_os_plugin/stepping_plugin_threads/Makefile b/lldb/test/API/functionalities/plugins/python_os_plugin/stepping_plugin_threads/Makefile new file mode 100644 index 0000000000000..c46619c662348 --- /dev/null +++ b/lldb/test/API/functionalities/plugins/python_os_plugin/stepping_plugin_threads/Makefile @@ -0,0 +1,4 @@ +CXX_SOURCES := main.cpp +ENABLE_THREADS := YES + +include Makefile.rules diff --git a/lldb/test/API/functionalities/plugins/python_os_plugin/stepping_plugin_threads/TestOSPluginStepping.py b/lldb/test/API/functionalities/plugins/python_os_plugin/stepping_plugin_threads/TestOSPluginStepping.py new file mode 100644 index 0000000000000..5bba483647310 --- /dev/null +++ b/lldb/test/API/functionalities/plugins/python_os_plugin/stepping_plugin_threads/TestOSPluginStepping.py @@ -0,0 +1,113 @@ +""" +Test that stepping works even when the OS Plugin doesn't report +all threads at every stop. +""" + +from __future__ import print_function + + +import os +import lldb +from lldbsuite.test.lldbtest import * +import lldbsuite.test.lldbutil as lldbutil + + +class TestOSPluginStepping(TestBase): + + mydir = TestBase.compute_mydir(__file__) + NO_DEBUG_INFO_TESTCASE = True + + def test_python_os_plugin(self): + """Test that stepping works when the OS Plugin doesn't report all + threads at every stop""" + self.build() + self.main_file = lldb.SBFileSpec('main.cpp') + self.run_python_os_step_missing_thread(False) + + def test_python_os_plugin_prune(self): + """Test that pruning the unreported PlanStacks works""" + self.build() + self.main_file = lldb.SBFileSpec('main.cpp') + self.run_python_os_step_missing_thread(True) + + def get_os_thread(self): + return self.process.GetThreadByID(0x111111111) + + def is_os_thread(self, thread): + id = thread.GetID() + return id == 0x111111111 + + def run_python_os_step_missing_thread(self, do_prune): + """Test that the Python operating system plugin works correctly""" + + # Our OS plugin does NOT report all threads: + result = self.dbg.HandleCommand("settings set target.experimental.os-plugin-reports-all-threads false") + + python_os_plugin_path = os.path.join(self.getSourceDir(), + "operating_system.py") + (target, self.process, thread, thread_bkpt) = lldbutil.run_to_source_breakpoint( + self, "first stop in thread - do a step out", self.main_file) + + main_bkpt = target.BreakpointCreateBySourceRegex('Stop here and do not make a memory thread for thread_1', + self.main_file) + self.assertEqual(main_bkpt.GetNumLocations(), 1, "Main breakpoint has one location") + + # There should not be an os thread before we load the plugin: + self.assertFalse(self.get_os_thread().IsValid(), "No OS thread before loading plugin") + + # Now load the python OS plug-in which should update the thread list and we should have + # an OS plug-in thread overlaying thread_1 with id 0x111111111 + command = "settings set target.process.python-os-plugin-path '%s'" % python_os_plugin_path + self.dbg.HandleCommand(command) + + # Verify our OS plug-in threads showed up + os_thread = self.get_os_thread() + self.assertTrue( + os_thread.IsValid(), + "Make sure we added the thread 0x111111111 after we load the python OS plug-in") + + # Now we are going to step-out. This should get interrupted by main_bkpt. We've + # set up the OS plugin so at this stop, we have lost the OS thread 0x111111111. + # Make sure both of these are true: + os_thread.StepOut() + + stopped_threads = lldbutil.get_threads_stopped_at_breakpoint(self.process, main_bkpt) + self.assertEqual(len(stopped_threads), 1, "Stopped at main_bkpt") + thread = self.process.GetThreadByID(0x111111111) + self.assertFalse(thread.IsValid(), "No thread 0x111111111 on second stop.") + + # Make sure we still have the thread plans for this thread: + # First, don't show unreported threads, that should fail: + command = "thread plan list -t 0x111111111" + result = lldb.SBCommandReturnObject() + interp = self.dbg.GetCommandInterpreter() + interp.HandleCommand(command, result) + self.assertFalse(result.Succeeded(), "We found no plans for the unreported thread.") + # Now do it again but with the -u flag: + command = "thread plan list -u -t 0x111111111" + result = lldb.SBCommandReturnObject() + interp.HandleCommand(command, result) + self.assertTrue(result.Succeeded(), "We found plans for the unreported thread.") + + if do_prune: + # Prune the thread plan and continue, and we will run to exit. + interp.HandleCommand("thread plan prune 0x111111111", result) + self.assertTrue(result.Succeeded(), "Found the plan for 0x111111111 and pruned it") + + # List again, make sure it doesn't work: + command = "thread plan list -u -t 0x111111111" + interp.HandleCommand(command, result) + self.assertFalse(result.Succeeded(), "We still found plans for the unreported thread.") + + self.process.Continue() + self.assertEqual(self.process.GetState(), lldb.eStateExited, "We exited.") + else: + # Now we are going to continue, and when we hit the step-out breakpoint, we will + # put the OS plugin thread back, lldb will recover its ThreadPlanStack, and + # we will stop with a "step-out" reason. + self.process.Continue() + os_thread = self.get_os_thread() + self.assertTrue(os_thread.IsValid(), "The OS thread is back after continue") + self.assertTrue("step out" in os_thread.GetStopDescription(100), "Completed step out plan") + + diff --git a/lldb/test/API/functionalities/plugins/python_os_plugin/stepping_plugin_threads/main.cpp b/lldb/test/API/functionalities/plugins/python_os_plugin/stepping_plugin_threads/main.cpp new file mode 100644 index 0000000000000..6fd6b1c4332cf --- /dev/null +++ b/lldb/test/API/functionalities/plugins/python_os_plugin/stepping_plugin_threads/main.cpp @@ -0,0 +1,55 @@ +// This test will present lldb with two threads one of which the test will +// overlay with an OSPlugin thread. Then we'll do a step out on the thread_1, +// but arrange to hit a breakpoint in main before the step out completes. At +// that point we will not report an OS plugin thread for thread_1. Then we'll +// run again and hit the step out breakpoint. Make sure we haven't deleted +// that, and recognize it. + +#include +#include +#include +#include + +static int g_value = 0; // I don't have access to the real threads in the + // OS Plugin, and I don't want to have to count + // StopID's. So I'm using this value to tell me which + // stop point the program has reached. +std::mutex g_mutex; +std::condition_variable g_cv; +static int g_condition = 0; // Using this as the variable backing g_cv + // to prevent spurious wakeups. + +void step_out_of_here() { + std::unique_lock func_lock(g_mutex); + // Set a breakpoint:first stop in thread - do a step out. + g_condition = 1; + g_cv.notify_one(); + g_cv.wait(func_lock, [&] { return g_condition == 2; }); +} + +void *thread_func() { + // Do something + step_out_of_here(); + + // Return + return NULL; +} + +int main() { + // Lock the mutex so we can block the thread: + std::unique_lock main_lock(g_mutex); + // Create the thread + std::thread thread_1(thread_func); + g_cv.wait(main_lock, [&] { return g_condition == 1; }); + g_value = 1; + g_condition = 2; + // Stop here and do not make a memory thread for thread_1. + g_cv.notify_one(); + g_value = 2; + main_lock.unlock(); + + // Wait for the threads to finish + thread_1.join(); + + return 0; +} diff --git a/lldb/test/API/functionalities/plugins/python_os_plugin/stepping_plugin_threads/operating_system.py b/lldb/test/API/functionalities/plugins/python_os_plugin/stepping_plugin_threads/operating_system.py new file mode 100644 index 0000000000000..ff9a57367a2aa --- /dev/null +++ b/lldb/test/API/functionalities/plugins/python_os_plugin/stepping_plugin_threads/operating_system.py @@ -0,0 +1,62 @@ +#!/usr/bin/python + +import lldb +import struct + + +class OperatingSystemPlugIn(object): + """Class that provides a OS plugin that along with the particular code in main.cpp + emulates the following scenario: + a) We stop in an OS Plugin created thread - which should be thread index 1 + b) We step-out from that thread + c) We hit a breakpoint in another thread, and DON'T produce the OS Plugin thread. + d) We continue, and when we hit the step out breakpoint, we again produce the same + OS Plugin thread. + main.cpp sets values into the global variable g_value, which we use to tell the OS + plugin whether to produce the OS plugin thread or not. + Since we are always producing an OS plugin thread with a backing thread, we don't + need to implement get_register_info or get_register_data. + """ + + def __init__(self, process): + '''Initialization needs a valid.SBProcess object. + + This plug-in will get created after a live process is valid and has stopped for the + first time.''' + print("Plugin initialized.") + self.process = None + self.start_stop_id = 0 + self.g_value = lldb.SBValue() + + if isinstance(process, lldb.SBProcess) and process.IsValid(): + self.process = process + self.g_value = process.GetTarget().FindFirstGlobalVariable("g_value") + if not self.g_value.IsValid(): + print("Could not find g_value") + + def create_thread(self, tid, context): + print("Called create thread with tid: ", tid) + return None + + def get_thread_info(self): + g_value = self.g_value.GetValueAsUnsigned() + print("Called get_thread_info: g_value: %d"%(g_value)) + if g_value == 0 or g_value == 2: + return [{'tid': 0x111111111, + 'name': 'one', + 'queue': 'queue1', + 'state': 'stopped', + 'stop_reason': 'breakpoint', + 'core' : 1 }] + else: + return [] + + def get_register_info(self): + print ("called get_register_info") + return None + + + def get_register_data(self, tid): + print("Get register data called for tid: %d"%(tid)) + return None + diff --git a/lldb/test/API/functionalities/thread_plan/Makefile b/lldb/test/API/functionalities/thread_plan/Makefile new file mode 100644 index 0000000000000..695335e068c0c --- /dev/null +++ b/lldb/test/API/functionalities/thread_plan/Makefile @@ -0,0 +1,4 @@ +C_SOURCES := main.c +CFLAGS_EXTRAS := -std=c99 + +include Makefile.rules diff --git a/lldb/test/API/functionalities/thread_plan/TestThreadPlanCommands.py b/lldb/test/API/functionalities/thread_plan/TestThreadPlanCommands.py new file mode 100644 index 0000000000000..30fdb218fc2eb --- /dev/null +++ b/lldb/test/API/functionalities/thread_plan/TestThreadPlanCommands.py @@ -0,0 +1,164 @@ +""" +Test that thread plan listing, and deleting works. +""" + + + +import lldb +import lldbsuite.test.lldbutil as lldbutil +from lldbsuite.test.lldbtest import * + + +class TestThreadPlanCommands(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + NO_DEBUG_INFO_TESTCASE = True + + def test_thread_plan_actions(self): + self.build() + self.main_source_file = lldb.SBFileSpec("main.c") + self.thread_plan_test() + + def check_list_output(self, command, active_plans = [], completed_plans = [], discarded_plans = []): + # Check the "thread plan list" output against a list of active & completed and discarded plans. + # If all three check arrays are empty, that means the command is expected to fail. + + interp = self.dbg.GetCommandInterpreter() + result = lldb.SBCommandReturnObject() + + num_active = len(active_plans) + num_completed = len(completed_plans) + num_discarded = len(discarded_plans) + + interp.HandleCommand(command, result) + if self.TraceOn(): + print("Command: %s"%(command)) + print(result.GetOutput()) + + if num_active == 0 and num_completed == 0 and num_discarded == 0: + self.assertFalse(result.Succeeded(), "command: '%s' succeeded when it should have failed: '%s'"% + (command, result.GetError())) + return + + self.assertTrue(result.Succeeded(), "command: '%s' failed: '%s'"%(command, result.GetError())) + result_arr = result.GetOutput().splitlines() + num_results = len(result_arr) + + # Match the expected number of elements. + # Adjust the count for the number of header lines we aren't matching: + fudge = 0 + + if num_completed == 0 and num_discarded == 0: + # The fudge is 3: Thread header, Active Plan header and base plan + fudge = 3 + elif num_completed == 0 or num_discarded == 0: + # The fudge is 4: The above plus either the Completed or Discarded Plan header: + fudge = 4 + else: + # The fudge is 5 since we have both headers: + fudge = 5 + + self.assertEqual(num_results, num_active + num_completed + num_discarded + fudge, + "Too many elements in match arrays") + + # Now iterate through the results array and pick out the results. + result_idx = 0 + self.assertIn("thread #", result_arr[result_idx], "Found thread header") ; result_idx += 1 + self.assertIn("Active plan stack", result_arr[result_idx], "Found active header") ; result_idx += 1 + self.assertIn("Element 0: Base thread plan", result_arr[result_idx], "Found base plan") ; result_idx += 1 + + for text in active_plans: + self.assertFalse("Completed plan stack" in result_arr[result_idx], "Found Completed header too early.") + self.assertIn(text, result_arr[result_idx], "Didn't find active plan: %s"%(text)) ; result_idx += 1 + + if len(completed_plans) > 0: + self.assertIn("Completed plan stack:", result_arr[result_idx], "Found completed plan stack header") ; result_idx += 1 + for text in completed_plans: + self.assertIn(text, result_arr[result_idx], "Didn't find completed plan: %s"%(text)) ; result_idx += 1 + + if len(discarded_plans) > 0: + self.assertIn("Discarded plan stack:", result_arr[result_idx], "Found discarded plan stack header") ; result_idx += 1 + for text in discarded_plans: + self.assertIn(text, result_arr[result_idx], "Didn't find completed plan: %s"%(text)) ; result_idx += 1 + + + def thread_plan_test(self): + (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self, + "Set a breakpoint here", self.main_source_file) + + # Now set a breakpoint in call_me and step over. We should have + # two public thread plans + call_me_bkpt = target.BreakpointCreateBySourceRegex("Set another here", self.main_source_file) + self.assertTrue(call_me_bkpt.GetNumLocations() > 0, "Set the breakpoint successfully") + thread.StepOver() + threads = lldbutil.get_threads_stopped_at_breakpoint(process, call_me_bkpt) + self.assertEqual(len(threads), 1, "Hit my breakpoint while stepping over") + + current_id = threads[0].GetIndexID() + current_tid = threads[0].GetThreadID() + # Run thread plan list without the -i flag: + command = "thread plan list %d"%(current_id) + self.check_list_output (command, ["Stepping over line main.c"], []) + + # Run thread plan list with the -i flag: + command = "thread plan list -i %d"%(current_id) + self.check_list_output(command, ["Stepping over line main.c", "Stepping out from"]) + + # Run thread plan list providing TID, output should be the same: + command = "thread plan list -t %d"%(current_tid) + self.check_list_output(command, ["Stepping over line main.c"]) + + # Provide both index & tid, and make sure we only print once: + command = "thread plan list -t %d %d"%(current_tid, current_id) + self.check_list_output(command, ["Stepping over line main.c"]) + + # Try a fake TID, and make sure that fails: + fake_tid = 0 + for i in range(100, 10000, 100): + fake_tid = current_tid + i + thread = process.GetThreadByID(fake_tid) + if not thread: + break + + command = "thread plan list -t %d"%(fake_tid) + self.check_list_output(command) + + # Now continue, and make sure we printed the completed plan: + process.Continue() + threads = lldbutil.get_stopped_threads(process, lldb.eStopReasonPlanComplete) + self.assertEqual(len(threads), 1, "One thread completed a step") + + # Run thread plan list - there aren't any private plans at this point: + command = "thread plan list %d"%(current_id) + self.check_list_output(command, [], ["Stepping over line main.c"]) + + # Set another breakpoint that we can run to, to try deleting thread plans. + second_step_bkpt = target.BreakpointCreateBySourceRegex("Run here to step over again", + self.main_source_file) + self.assertTrue(second_step_bkpt.GetNumLocations() > 0, "Set the breakpoint successfully") + final_bkpt = target.BreakpointCreateBySourceRegex("Make sure we get here on last continue", + self.main_source_file) + self.assertTrue(final_bkpt.GetNumLocations() > 0, "Set the breakpoint successfully") + + threads = lldbutil.continue_to_breakpoint(process, second_step_bkpt) + self.assertEqual(len(threads), 1, "Hit the second step breakpoint") + + threads[0].StepOver() + threads = lldbutil.get_threads_stopped_at_breakpoint(process, call_me_bkpt) + + result = lldb.SBCommandReturnObject() + interp = self.dbg.GetCommandInterpreter() + interp.HandleCommand("thread plan discard 1", result) + self.assertTrue(result.Succeeded(), "Deleted the step over plan: %s"%(result.GetOutput())) + + # Make sure the plan gets listed in the discarded plans: + command = "thread plan list %d"%(current_id) + self.check_list_output(command, [], [], ["Stepping over line main.c:"]) + + process.Continue() + threads = lldbutil.get_threads_stopped_at_breakpoint(process, final_bkpt) + self.assertEqual(len(threads), 1, "Ran to final breakpoint") + threads = lldbutil.get_stopped_threads(process, lldb.eStopReasonPlanComplete) + self.assertEqual(len(threads), 0, "Did NOT complete the step over plan") + diff --git a/lldb/test/API/functionalities/thread_plan/main.c b/lldb/test/API/functionalities/thread_plan/main.c new file mode 100644 index 0000000000000..74654cb976a88 --- /dev/null +++ b/lldb/test/API/functionalities/thread_plan/main.c @@ -0,0 +1,16 @@ +#include + +void +call_me(int value) { + printf("called with %d\n", value); // Set another here. +} + +int +main(int argc, char **argv) +{ + call_me(argc); // Set a breakpoint here. + printf("This just spaces the two calls\n"); + call_me(argc); // Run here to step over again. + printf("More spacing\n"); + return 0; // Make sure we get here on last continue +} From 684a9d17ba95d4030ca90d7b279f562e66da3327 Mon Sep 17 00:00:00 2001 From: Francis Visoiu Mistrih Date: Fri, 3 Apr 2020 12:29:54 -0700 Subject: [PATCH 142/286] [Driver] Handle all optimization-record options for Darwin LTO clang with -flto does not handle -foptimization-record-path= This dulicates the code from ToolChains/Clang.cpp with modifications to support everything in the same fashion. (cherry picked from commit ba8b3052b59ebee4311d10bee5209dac8747acea) rdar://61243768 --- clang/lib/Driver/ToolChains/Darwin.cpp | 121 ++++++++++++++--------- clang/test/Driver/darwin-ld.c | 26 ----- clang/test/Driver/darwin-opt-record-ld.c | 42 ++++++++ 3 files changed, 114 insertions(+), 75 deletions(-) create mode 100644 clang/test/Driver/darwin-opt-record-ld.c diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp index 8a0d6e34b2458..c9e56f88f009a 100644 --- a/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/clang/lib/Driver/ToolChains/Darwin.cpp @@ -434,6 +434,75 @@ static bool isObjCRuntimeLinked(const ArgList &Args) { return Args.hasArg(options::OPT_fobjc_link_runtime); } +static bool checkRemarksOptions(const Driver &D, const ArgList &Args, + const llvm::Triple &Triple) { + // When enabling remarks, we need to error if: + // * The remark file is specified but we're targeting multiple architectures, + // which means more than one remark file is being generated. + bool hasMultipleInvocations = + Args.getAllArgValues(options::OPT_arch).size() > 1; + bool hasExplicitOutputFile = + Args.getLastArg(options::OPT_foptimization_record_file_EQ); + if (hasMultipleInvocations && hasExplicitOutputFile) { + D.Diag(diag::err_drv_invalid_output_with_multiple_archs) + << "-foptimization-record-file"; + return false; + } + return true; +} + +static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs, + const llvm::Triple &Triple, + const InputInfo &Output, const JobAction &JA) { + StringRef Format = "yaml"; + if (const Arg *A = Args.getLastArg(options::OPT_fsave_optimization_record_EQ)) + Format = A->getValue(); + + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-lto-pass-remarks-output"); + CmdArgs.push_back("-mllvm"); + + const Arg *A = Args.getLastArg(options::OPT_foptimization_record_file_EQ); + if (A) { + CmdArgs.push_back(A->getValue()); + } else { + assert(Output.isFilename() && "Unexpected ld output."); + SmallString<128> F; + F = Output.getFilename(); + F += ".opt."; + F += Format; + + CmdArgs.push_back(Args.MakeArgString(F)); + } + + if (const Arg *A = + Args.getLastArg(options::OPT_foptimization_record_passes_EQ)) { + CmdArgs.push_back("-mllvm"); + std::string Passes = + std::string("-lto-pass-remarks-filter=") + A->getValue(); + CmdArgs.push_back(Args.MakeArgString(Passes)); + } + + if (!Format.empty()) { + CmdArgs.push_back("-mllvm"); + Twine FormatArg = Twine("-lto-pass-remarks-format=") + Format; + CmdArgs.push_back(Args.MakeArgString(FormatArg)); + } + + if (getLastProfileUseArg(Args)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-lto-pass-remarks-with-hotness"); + + if (const Arg *A = + Args.getLastArg(options::OPT_fdiagnostics_hotness_threshold_EQ)) { + CmdArgs.push_back("-mllvm"); + std::string Opt = + std::string("-lto-pass-remarks-hotness-threshold=") + A->getValue(); + CmdArgs.push_back(Args.MakeArgString(Opt)); + } + } +} + void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -472,55 +541,9 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, // we follow suite for ease of comparison. AddLinkArgs(C, Args, CmdArgs, Inputs); - // For LTO, pass the name of the optimization record file and other - // opt-remarks flags. - if (Args.hasFlag(options::OPT_fsave_optimization_record, - options::OPT_fsave_optimization_record_EQ, - options::OPT_fno_save_optimization_record, false)) { - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back("-lto-pass-remarks-output"); - CmdArgs.push_back("-mllvm"); - - SmallString<128> F; - F = Output.getFilename(); - F += ".opt."; - if (const Arg *A = - Args.getLastArg(options::OPT_fsave_optimization_record_EQ)) - F += A->getValue(); - else - F += "yaml"; - - CmdArgs.push_back(Args.MakeArgString(F)); - - if (getLastProfileUseArg(Args)) { - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back("-lto-pass-remarks-with-hotness"); - - if (const Arg *A = - Args.getLastArg(options::OPT_fdiagnostics_hotness_threshold_EQ)) { - CmdArgs.push_back("-mllvm"); - std::string Opt = - std::string("-lto-pass-remarks-hotness-threshold=") + A->getValue(); - CmdArgs.push_back(Args.MakeArgString(Opt)); - } - } - - if (const Arg *A = - Args.getLastArg(options::OPT_foptimization_record_passes_EQ)) { - CmdArgs.push_back("-mllvm"); - std::string Passes = - std::string("-lto-pass-remarks-filter=") + A->getValue(); - CmdArgs.push_back(Args.MakeArgString(Passes)); - } - - if (const Arg *A = - Args.getLastArg(options::OPT_fsave_optimization_record_EQ)) { - CmdArgs.push_back("-mllvm"); - std::string Format = - std::string("-lto-pass-remarks-format=") + A->getValue(); - CmdArgs.push_back(Args.MakeArgString(Format)); - } - } + if (checkRemarksOptions(getToolChain().getDriver(), Args, + getToolChain().getTriple())) + renderRemarksOptions(Args, CmdArgs, getToolChain().getTriple(), Output, JA); // Propagate the -moutline flag to the linker in LTO. if (Arg *A = diff --git a/clang/test/Driver/darwin-ld.c b/clang/test/Driver/darwin-ld.c index dee3df0337e92..63764c4a97755 100644 --- a/clang/test/Driver/darwin-ld.c +++ b/clang/test/Driver/darwin-ld.c @@ -321,32 +321,6 @@ // LINK_VERSION_DIGITS: invalid version number in '-mlinker-version=133.3.0.1.a' // LINK_VERSION_DIGITS: invalid version number in '-mlinker-version=133.3.0.1a' -// Check that we're passing -lto-pass-remarks-output for LTO -// RUN: %clang -target x86_64-apple-darwin12 %t.o -fsave-optimization-record -### -o foo/bar.out 2> %t.log -// RUN: FileCheck -check-prefix=PASS_REMARKS_OUTPUT %s < %t.log -// PASS_REMARKS_OUTPUT: "-mllvm" "-lto-pass-remarks-output" "-mllvm" "foo/bar.out.opt.yaml" -// PASS_REMARKS_OUTPUT-NOT: -lto-pass-remarks-with-hotness - -// RUN: %clang -target x86_64-apple-darwin12 %t.o -fsave-optimization-record -### 2> %t.log -// RUN: FileCheck -check-prefix=PASS_REMARKS_OUTPUT_NO_O %s < %t.log -// PASS_REMARKS_OUTPUT_NO_O: "-mllvm" "-lto-pass-remarks-output" "-mllvm" "a.out.opt.yaml" - -// RUN: %clang -target x86_64-apple-darwin12 %t.o -fsave-optimization-record -fprofile-instr-use=blah -### -o foo/bar.out 2> %t.log -// RUN: FileCheck -check-prefix=PASS_REMARKS_WITH_HOTNESS %s < %t.log -// PASS_REMARKS_WITH_HOTNESS: "-mllvm" "-lto-pass-remarks-output" "-mllvm" "foo/bar.out.opt.yaml" "-mllvm" "-lto-pass-remarks-with-hotness" - -// RUN: %clang -target x86_64-apple-darwin12 %t.o -fsave-optimization-record -fprofile-instr-use=blah -fdiagnostics-hotness-threshold=100 -### -o foo/bar.out 2> %t.log -// RUN: FileCheck -check-prefix=PASS_REMARKS_WITH_HOTNESS_THRESHOLD %s < %t.log -// PASS_REMARKS_WITH_HOTNESS_THRESHOLD: "-mllvm" "-lto-pass-remarks-output" "-mllvm" "foo/bar.out.opt.yaml" "-mllvm" "-lto-pass-remarks-with-hotness" "-mllvm" "-lto-pass-remarks-hotness-threshold=100" - -// RUN: %clang -target x86_64-apple-darwin12 %t.o -fsave-optimization-record -foptimization-record-passes=inline -### -o foo/bar.out 2> %t.log -// RUN: FileCheck -check-prefix=PASS_REMARKS_WITH_PASSES %s < %t.log -// PASS_REMARKS_WITH_PASSES: "-mllvm" "-lto-pass-remarks-output" "-mllvm" "foo/bar.out.opt.yaml" "-mllvm" "-lto-pass-remarks-filter=inline" -// -// RUN: %clang -target x86_64-apple-darwin12 %t.o -fsave-optimization-record=some-format -### -o foo/bar.out 2> %t.log -// RUN: FileCheck -check-prefix=PASS_REMARKS_WITH_FORMAT %s < %t.log -// PASS_REMARKS_WITH_FORMAT: "-mllvm" "-lto-pass-remarks-output" "-mllvm" "foo/bar.out.opt.some-format" "-mllvm" "-lto-pass-remarks-format=some-format" - // RUN: %clang -target x86_64-apple-ios6.0 -miphoneos-version-min=6.0 -fprofile-instr-generate -### %t.o 2> %t.log // RUN: FileCheck -check-prefix=LINK_PROFILE_FIRST %s < %t.log // RUN: %clang -target x86_64-apple-darwin12 -fprofile-instr-generate -### %t.o 2> %t.log diff --git a/clang/test/Driver/darwin-opt-record-ld.c b/clang/test/Driver/darwin-opt-record-ld.c new file mode 100644 index 0000000000000..0e1e312c493d4 --- /dev/null +++ b/clang/test/Driver/darwin-opt-record-ld.c @@ -0,0 +1,42 @@ +// REQUIRES: system-darwin + +// RUN: touch %t.o +// +// Check that we're passing -lto-pass-remarks-output for LTO +// RUN: %clang -target x86_64-apple-darwin12 %t.o -fsave-optimization-record -### -o foo/bar.out 2> %t.log +// RUN: FileCheck -check-prefix=PASS_REMARKS_OUTPUT %s < %t.log +// PASS_REMARKS_OUTPUT: "-mllvm" "-lto-pass-remarks-output" "-mllvm" "foo/bar.out.opt.yaml" "-mllvm" "-lto-pass-remarks-format=yaml" +// PASS_REMARKS_OUTPUT-NOT: -lto-pass-remarks-with-hotness + +// RUN: %clang -target x86_64-apple-darwin12 %t.o -fsave-optimization-record -### 2> %t.log +// RUN: FileCheck -check-prefix=PASS_REMARKS_OUTPUT_NO_O %s < %t.log +// PASS_REMARKS_OUTPUT_NO_O: "-mllvm" "-lto-pass-remarks-output" "-mllvm" "a.out.opt.yaml" + +// RUN: %clang -target x86_64-apple-darwin12 %t.o -fsave-optimization-record -fprofile-instr-use=blah -### -o foo/bar.out 2> %t.log +// RUN: FileCheck -check-prefix=PASS_REMARKS_WITH_HOTNESS %s < %t.log +// PASS_REMARKS_WITH_HOTNESS: "-mllvm" "-lto-pass-remarks-output" "-mllvm" "foo/bar.out.opt.yaml" "-mllvm" "-lto-pass-remarks-format=yaml" "-mllvm" "-lto-pass-remarks-with-hotness" + +// RUN: %clang -target x86_64-apple-darwin12 %t.o -fsave-optimization-record -fprofile-instr-use=blah -fdiagnostics-hotness-threshold=100 -### -o foo/bar.out 2> %t.log +// RUN: FileCheck -check-prefix=PASS_REMARKS_WITH_HOTNESS_THRESHOLD %s < %t.log +// PASS_REMARKS_WITH_HOTNESS_THRESHOLD: "-mllvm" "-lto-pass-remarks-output" "-mllvm" "foo/bar.out.opt.yaml" "-mllvm" "-lto-pass-remarks-format=yaml" "-mllvm" "-lto-pass-remarks-with-hotness" "-mllvm" "-lto-pass-remarks-hotness-threshold=100" + +// RUN: %clang -target x86_64-apple-darwin12 %t.o -fsave-optimization-record -foptimization-record-passes=inline -### -o foo/bar.out 2> %t.log +// RUN: FileCheck -check-prefix=PASS_REMARKS_WITH_PASSES %s < %t.log +// PASS_REMARKS_WITH_PASSES: "-mllvm" "-lto-pass-remarks-output" "-mllvm" "foo/bar.out.opt.yaml" "-mllvm" "-lto-pass-remarks-filter=inline" +// +// RUN: %clang -target x86_64-apple-darwin12 %t.o -fsave-optimization-record=some-format -### -o foo/bar.out 2> %t.log +// RUN: FileCheck -check-prefix=PASS_REMARKS_WITH_FORMAT %s < %t.log +// PASS_REMARKS_WITH_FORMAT: "-mllvm" "-lto-pass-remarks-output" "-mllvm" "foo/bar.out.opt.some-format" "-mllvm" "-lto-pass-remarks-format=some-format" + +// RUN: %clang -target x86_64-apple-darwin12 %t.o -foptimization-record-file=remarks-custom.opt.yaml -### -o foo/bar.out 2> %t.log +// RUN: FileCheck -check-prefix=PASS_REMARKS_WITH_FILE %s < %t.log +// PASS_REMARKS_WITH_FILE: "-mllvm" "-lto-pass-remarks-output" "-mllvm" "remarks-custom.opt.yaml" + +// RUN: %clang -target x86_64-apple-darwin12 -arch x86_64 -arch x86_64h %t.o -fsave-optimization-record -### -o foo/bar.out 2> %t.log +// RUN: FileCheck -check-prefix=PASS_REMARKS_WITH_FAT %s < %t.log +// PASS_REMARKS_WITH_FAT: "-arch" "x86_64"{{.*}}"-mllvm" "-lto-pass-remarks-output" +// PASS_REMARKS_WITH_FAT-NEXT: "-arch" "x86_64h"{{.*}}"-mllvm" "-lto-pass-remarks-output" +// +// RUN: %clang -target x86_64-apple-darwin12 -arch x86_64 -arch x86_64h %t.o -foptimization-record-file=custom.opt.yaml -### -o foo/bar.out 2> %t.log +// RUN: FileCheck -check-prefix=PASS_REMARKS_WITH_FILE_FAT %s < %t.log +// PASS_REMARKS_WITH_FILE_FAT: error: cannot use '-foptimization-record-file' output with multiple -arch options From 8a81c148b24b515f9514e6a047937825a707d776 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Fri, 3 Apr 2020 17:35:22 -0700 Subject: [PATCH 143/286] Windows: add very basic support for `DoLoadImage` Add some very basic support for `DoLoadImage` and `UnloadImage` for Windows. This was previously not implemented and would result in a failure at runtime that is hard to detect. This implementation is extremely limited but serves as a starting point for proper support for loading a library. Ideally, the user input would be converted from UTF-8 to UTF-16. This requires additional heap allocations and conversion logic. Error recovery there requires additional allocations both from the local heap and the global heap. This support enables the use of LLDB's Swift REPL on Windows. --- .../Platform/Windows/PlatformWindows.cpp | 108 ++++++++++++++++++ .../Platform/Windows/PlatformWindows.h | 13 +++ .../Shell/Process/Windows/process_load.cpp | 12 ++ 3 files changed, 133 insertions(+) create mode 100644 lldb/test/Shell/Process/Windows/process_load.cpp diff --git a/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp b/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp index c18939faa8f77..3981e96989b95 100644 --- a/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp +++ b/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp @@ -20,7 +20,10 @@ #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" +#include "lldb/Core/ValueObject.h" +#include "lldb/Expression/UserExpression.h" #include "lldb/Host/HostInfo.h" +#include "lldb/Target/DynamicLoader.h" #include "lldb/Target/Process.h" #include "lldb/Utility/Status.h" @@ -306,6 +309,111 @@ Status PlatformWindows::DisconnectRemote() { return error; } +Status PlatformWindows::EvaluateLoaderExpression(Process *process, + const char *expression, + ValueObjectSP &value) { + // FIXME(compnerd) `-fdeclspec` is not passed to the clang instance? + static const char kLoaderDecls[] = + R"( + // libloaderapi.h + + // WINBASEAPI BOOL WINAPI FreeModule(HMODULE); + extern "C" /* __declspec(dllimport) */ BOOL __stdcall FreeModule(void *hLibModule); + + // WINBASEAPI HMODULE WINAPI LoadLibraryA(LPCSTR); + extern "C" /* __declspec(dllimport) */ void * __stdcall LoadLibraryA(const char *); + )"; + + if (DynamicLoader *loader = process->GetDynamicLoader()) { + Status result = loader->CanLoadImage(); + if (result.Fail()) + return result; + } + + ThreadSP thread = process->GetThreadList().GetExpressionExecutionThread(); + if (!thread) + return Status("selected thread is invalid"); + + StackFrameSP frame = thread->GetStackFrameAtIndex(0); + if (!frame) + return Status("frame 0 is invalid"); + + ExecutionContext context; + frame->CalculateExecutionContext(context); + + EvaluateExpressionOptions options; + options.SetUnwindOnError(true); + options.SetIgnoreBreakpoints(true); + options.SetExecutionPolicy(eExecutionPolicyAlways); + options.SetLanguage(eLanguageTypeC_plus_plus); + // LoadLibrary{A,W}/FreeLibrary cannot raise exceptions which we can handle. + // They may potentially throw SEH exceptions which we do not know how to + // handle currently. + options.SetTrapExceptions(false); + options.SetTimeout(process->GetUtilityExpressionTimeout()); + + Status error; + ExpressionResults result = UserExpression::Evaluate( + context, options, expression, kLoaderDecls, value, error); + if (result != eExpressionCompleted) + return error; + + if (value->GetError().Fail()) + return value->GetError(); + + return Status(); +} + +uint32_t PlatformWindows::DoLoadImage(Process *process, + const FileSpec &remote_file, + const std::vector *paths, + Status &error, FileSpec *loaded_path) { + if (loaded_path) + loaded_path->Clear(); + + StreamString expression; + expression.Printf("LoadLibraryA(\"%s\")", remote_file.GetPath().c_str()); + + ValueObjectSP value; + Status result = + EvaluateLoaderExpression(process, expression.GetData(), value); + if (result.Fail()) + return LLDB_INVALID_IMAGE_TOKEN; + + Scalar scalar; + if (value->ResolveValue(scalar)) { + lldb::addr_t address = scalar.ULongLong(); + if (address == 0) + return LLDB_INVALID_IMAGE_TOKEN; + return process->AddImageToken(address); + } + return LLDB_INVALID_IMAGE_TOKEN; +} + +Status PlatformWindows::UnloadImage(Process *process, uint32_t image_token) { + const addr_t address = process->GetImagePtrFromToken(image_token); + if (address == LLDB_INVALID_ADDRESS) + return Status("invalid image token"); + + StreamString expression; + expression.Printf("FreeLibrary((HMODULE)0x%" PRIx64 ")", address); + + ValueObjectSP value; + Status result = + EvaluateLoaderExpression(process, expression.GetData(), value); + if (result.Fail()) + return result; + + Scalar scalar; + if (value->ResolveValue(scalar)) { + if (scalar.UInt(1)) + return Status("expression failed: \"%s\"", expression.GetData()); + process->ResetImageToken(image_token); + } + + return Status(); +} + ProcessSP PlatformWindows::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, Target *target, Status &error) { diff --git a/lldb/source/Plugins/Platform/Windows/PlatformWindows.h b/lldb/source/Plugins/Platform/Windows/PlatformWindows.h index 5740001f0e036..1ca747aa14ec4 100644 --- a/lldb/source/Plugins/Platform/Windows/PlatformWindows.h +++ b/lldb/source/Plugins/Platform/Windows/PlatformWindows.h @@ -49,6 +49,15 @@ class PlatformWindows : public RemoteAwarePlatform { lldb_private::Status DisconnectRemote() override; + uint32_t DoLoadImage(lldb_private::Process *process, + const lldb_private::FileSpec &remote_file, + const std::vector *paths, + lldb_private::Status &error, + lldb_private::FileSpec *loaded_path) override; + + lldb_private::Status UnloadImage(lldb_private::Process *process, + uint32_t image_token) override; + lldb::ProcessSP DebugProcess(lldb_private::ProcessLaunchInfo &launch_info, lldb_private::Debugger &debugger, lldb_private::Target *target, @@ -73,6 +82,10 @@ class PlatformWindows : public RemoteAwarePlatform { private: DISALLOW_COPY_AND_ASSIGN(PlatformWindows); + + lldb_private::Status EvaluateLoaderExpression(lldb_private::Process *process, + const char *expression, + lldb::ValueObjectSP &value); }; } // namespace lldb_private diff --git a/lldb/test/Shell/Process/Windows/process_load.cpp b/lldb/test/Shell/Process/Windows/process_load.cpp new file mode 100644 index 0000000000000..43bf45865f9ba --- /dev/null +++ b/lldb/test/Shell/Process/Windows/process_load.cpp @@ -0,0 +1,12 @@ +// clang-format off + +// REQUIRES: system-windows +// RUN: %build --compiler=clang-cl -o %t.exe -- %s +// RUN: env LLDB_USE_NATIVE_PDB_READER=1 %lldb -f %t.exe -o "b main" -o "process launch" -o "process load kernel32.dll" | FileCheck %s + +int main(int argc, char *argv[]) { + return 0; +} + +// CHECK: "Loading "kernel32.dll"...ok{{.*}} +// CHECK: Image 0 loaded. From be34806589999eb233c2a6e05cd7b23a7997087a Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Fri, 13 Mar 2020 09:49:00 -0700 Subject: [PATCH 144/286] [lldb/Test] Convert stdout to str by calling decode('utf-8') on it. Make sure both arguments to assertIn are of type str. This should fix the following error: TypeError: a bytes-like object is required, not 'str'. (cherry picked from commit 17bdb7a17912bb4d961cf292c035b08c9d0c13ba) --- .../reproducers/attach/TestReproducerAttach.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lldb/test/API/functionalities/reproducers/attach/TestReproducerAttach.py b/lldb/test/API/functionalities/reproducers/attach/TestReproducerAttach.py index 96c031f62286a..968268d6838bd 100644 --- a/lldb/test/API/functionalities/reproducers/attach/TestReproducerAttach.py +++ b/lldb/test/API/functionalities/reproducers/attach/TestReproducerAttach.py @@ -53,7 +53,8 @@ def test_reproducer_attach(self): stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - outs, errs = capture.communicate() + outs, _ = capture.communicate() + outs = outs.decode('utf-8') self.assertIn('Process {} stopped'.format(pid), outs) self.assertIn('Reproducer written', outs) @@ -63,7 +64,8 @@ def test_reproducer_attach(self): stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - outs, errs = replay.communicate() + outs, _ = replay.communicate() + outs = outs.decode('utf-8') self.assertIn('Process {} stopped'.format(pid), outs) # We can dump the reproducer in the current context. From 945c05ff471f8d2a0fc5d483fe31eca31e55ac7c Mon Sep 17 00:00:00 2001 From: OCHyams Date: Thu, 2 Apr 2020 08:41:25 +0100 Subject: [PATCH 145/286] [NFC] Fix performance issue in LiveDebugVariables When compiling AMDGPUDisassembler.cpp in a stage 1 trunk build with CMAKE_BUILD_TYPE=RelWithDebInfo LLVM_USE_SANITIZER=Address LiveDebugVariables accounts for 21.5% wall clock time. This fix reduces that to 1.2% by switching out a linked list lookup with a map lookup. Note that the linked list is still used to group UserValues by vreg. The vreg lookups don't cause any problems in this pathological case. This is the same idea as D68816, which was reverted, except that it is a less intrusive fix. Reviewed By: vsk Differential Revision: https://reviews.llvm.org/D77226 (cherry picked from commit 550ab58bc106335f8dcbc1767548a55c7151f87a) --- llvm/lib/CodeGen/LiveDebugVariables.cpp | 47 +++++++------------------ 1 file changed, 12 insertions(+), 35 deletions(-) diff --git a/llvm/lib/CodeGen/LiveDebugVariables.cpp b/llvm/lib/CodeGen/LiveDebugVariables.cpp index 2b3e98f933284..a686d12c45a9b 100644 --- a/llvm/lib/CodeGen/LiveDebugVariables.cpp +++ b/llvm/lib/CodeGen/LiveDebugVariables.cpp @@ -154,9 +154,8 @@ class LDVImpl; /// holds part of a user variable. The part is identified by a byte offset. /// /// UserValues are grouped into equivalence classes for easier searching. Two -/// user values are related if they refer to the same variable, or if they are -/// held by the same virtual register. The equivalence class is the transitive -/// closure of that relation. +/// user values are related if they are held by the same virtual register. The +/// equivalence class is the transitive closure of that relation. class UserValue { const DILocalVariable *Variable; ///< The debug info variable we are part of. /// The part of the variable we describe. @@ -207,24 +206,6 @@ class UserValue { /// Return the next UserValue in the equivalence class. UserValue *getNext() const { return next; } - /// Does this UserValue match the parameters? - bool matches(const DILocalVariable *Var, - Optional OtherFragment, - const DILocation *IA) const { - // FIXME: Handle partially overlapping fragments. - // A DBG_VALUE with a fragment which overlaps a previous DBG_VALUE fragment - // for the same variable terminates the interval opened by the first. - // getUserValue() uses matches() to filter DBG_VALUEs into interval maps to - // represent these intervals. - // Given two _partially_ overlapping fragments matches() will always return - // false. The DBG_VALUEs will be filtered into separate interval maps and - // therefore we do not faithfully represent the original intervals. - // See D70121#1849741 for a more detailed explanation and further - // discussion. - return Var == Variable && OtherFragment == Fragment && - dl->getInlinedAt() == IA; - } - /// Merge equivalence classes. static UserValue *merge(UserValue *L1, UserValue *L2) { L2 = L2->getLeader(); @@ -429,8 +410,8 @@ class LDVImpl { using VRMap = DenseMap; VRMap virtRegToEqClass; - /// Map user variable to eq class leader. - using UVMap = DenseMap; + /// Map to find existing UserValue instances. + using UVMap = DenseMap; UVMap userVarMap; /// Find or create a UserValue. @@ -600,19 +581,15 @@ void UserValue::mapVirtRegs(LDVImpl *LDV) { UserValue *LDVImpl::getUserValue(const DILocalVariable *Var, Optional Fragment, const DebugLoc &DL) { - UserValue *&Leader = userVarMap[Var]; - if (Leader) { - UserValue *UV = Leader->getLeader(); - Leader = UV; - for (; UV; UV = UV->getNext()) - if (UV->matches(Var, Fragment, DL->getInlinedAt())) - return UV; + // FIXME: Handle partially overlapping fragments. See + // https://reviews.llvm.org/D70121#1849741. + DebugVariable ID(Var, Fragment, DL->getInlinedAt()); + UserValue *&UV = userVarMap[ID]; + if (!UV) { + userValues.push_back( + std::make_unique(Var, Fragment, DL, allocator)); + UV = userValues.back().get(); } - - userValues.push_back( - std::make_unique(Var, Fragment, DL, allocator)); - UserValue *UV = userValues.back().get(); - Leader = UserValue::merge(Leader, UV); return UV; } From fcc7b6da8f6d8a345608530a4af83efe6e9faffe Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Tue, 31 Mar 2020 15:27:06 -0700 Subject: [PATCH 146/286] [AddressSanitizer] Fix for wrong argument values appearing in backtraces Summary: In some cases, ASan may insert instrumentation before function arguments have been stored into their allocas. This causes two issues: 1) The argument value must be spilled until it can be stored into the reserved alloca, wasting a stack slot. 2) Until the store occurs in a later basic block, the debug location will point to the wrong frame offset, and backtraces will show an uninitialized value. The proposed solution is to move instructions which initialize allocas for arguments up into the entry block, before the position where ASan starts inserting its instrumentation. For the motivating test case, before the patch we see: ``` | 0033: movq %rdi, 0x68(%rbx) | | DW_TAG_formal_parameter | | ... | | DW_AT_name ("a") | | 00d1: movq 0x68(%rbx), %rsi | | DW_AT_location (RBX+0x90) | | 00d5: movq %rsi, 0x90(%rbx) | | ^ not correct ... | ``` and after the patch we see: ``` | 002f: movq %rdi, 0x70(%rbx) | | DW_TAG_formal_parameter | | | | DW_AT_name ("a") | | | | DW_AT_location (RBX+0x70) | ``` rdar://61122691 Reviewers: aprantl, eugenis Subscribers: hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D77182 (cherry picked from commit 5f185a89991e85eed10c630028fc9d2569514491) --- .../Instrumentation/AddressSanitizer.cpp | 62 +++++++ .../hoist-argument-init-insts.ll | 173 ++++++++++++++++++ 2 files changed, 235 insertions(+) create mode 100644 llvm/test/Instrumentation/AddressSanitizer/hoist-argument-init-insts.ll diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp index 0688ef628e90c..d77fbd73af1ff 100644 --- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -2984,6 +2984,59 @@ void FunctionStackPoisoner::processDynamicAllocas() { unpoisonDynamicAllocas(); } +/// Collect instructions in the entry block after \p InsBefore which initialize +/// permanent storage for a function argument. These instructions must remain in +/// the entry block so that uninitialized values do not appear in backtraces. An +/// added benefit is that this conserves spill slots. This does not move stores +/// before instrumented / "interesting" allocas. +static void findStoresToUninstrumentedArgAllocas( + AddressSanitizer &ASan, Instruction &InsBefore, + SmallVectorImpl &InitInsts) { + Instruction *Start = InsBefore.getNextNonDebugInstruction(); + for (Instruction *It = Start; It; It = It->getNextNonDebugInstruction()) { + // Argument initialization looks like: + // 1) store , OR + // 2) = cast to ... + // store to + // Do not consider any other kind of instruction. + // + // Note: This covers all known cases, but may not be exhaustive. An + // alternative to pattern-matching stores is to DFS over all Argument uses: + // this might be more general, but is probably much more complicated. + if (isa(It) || isa(It)) + continue; + if (auto *Store = dyn_cast(It)) { + // The store destination must be an alloca that isn't interesting for + // ASan to instrument. These are moved up before InsBefore, and they're + // not interesting because allocas for arguments can be mem2reg'd. + auto *Alloca = dyn_cast(Store->getPointerOperand()); + if (!Alloca || ASan.isInterestingAlloca(*Alloca)) + continue; + + Value *Val = Store->getValueOperand(); + bool IsDirectArgInit = isa(Val); + bool IsArgInitViaCast = + isa(Val) && + isa(cast(Val)->getOperand(0)) && + // Check that the cast appears directly before the store. Otherwise + // moving the cast before InsBefore may break the IR. + Val == It->getPrevNonDebugInstruction(); + bool IsArgInit = IsDirectArgInit || IsArgInitViaCast; + if (!IsArgInit) + continue; + + if (IsArgInitViaCast) + InitInsts.push_back(cast(Val)); + InitInsts.push_back(Store); + continue; + } + + // Do not reorder past unknown instructions: argument initialization should + // only involve casts and stores. + return; + } +} + void FunctionStackPoisoner::processStaticAllocas() { if (AllocaVec.empty()) { assert(StaticAllocaPoisonCallVec.empty()); @@ -3007,6 +3060,15 @@ void FunctionStackPoisoner::processStaticAllocas() { if (AI->getParent() == InsBeforeB) AI->moveBefore(InsBefore); + // Move stores of arguments into entry-block allocas as well. This prevents + // extra stack slots from being generated (to house the argument values until + // they can be stored into the allocas). This also prevents uninitialized + // values from being shown in backtraces. + SmallVector ArgInitInsts; + findStoresToUninstrumentedArgAllocas(ASan, *InsBefore, ArgInitInsts); + for (Instruction *ArgInitInst : ArgInitInsts) + ArgInitInst->moveBefore(InsBefore); + // If we have a call to llvm.localescape, keep it in the entry block. if (LocalEscapeCall) LocalEscapeCall->moveBefore(InsBefore); diff --git a/llvm/test/Instrumentation/AddressSanitizer/hoist-argument-init-insts.ll b/llvm/test/Instrumentation/AddressSanitizer/hoist-argument-init-insts.ll new file mode 100644 index 0000000000000..1414b2122d983 --- /dev/null +++ b/llvm/test/Instrumentation/AddressSanitizer/hoist-argument-init-insts.ll @@ -0,0 +1,173 @@ +; RUN: opt < %s -asan -asan-module -asan-use-after-return -S | FileCheck %s + +; Source (-O0 -fsanitize=address -fsanitize-address-use-after-scope): +;; struct S { int x, y; }; +;; void swap(S *a, S *b, bool doit) { +;; if (!doit) +;; return; +;; auto tmp = *a; +;; *a = *b; +;; *b = tmp; +;; } + +target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.14.0" + +%struct.S = type { i32, i32 } + +; CHECK-LABEL: define {{.*}} @_Z4swapP1SS0_b( + +; First come the argument allocas. +; CHECK: [[argA:%.*]] = alloca %struct.S*, +; CHECK-NEXT: [[argB:%.*]] = alloca %struct.S*, +; CHECK-NEXT: [[argDoit:%.*]] = alloca i8, + +; Next, the stores into the argument allocas. +; CHECK-NEXT: store %struct.S* {{.*}}, %struct.S** [[argA]] +; CHECK-NEXT: store %struct.S* {{.*}}, %struct.S** [[argB]] +; CHECK-NEXT: [[frombool:%.*]] = zext i1 {{.*}} to i8 +; CHECK-NEXT: store i8 [[frombool]], i8* [[argDoit]] + +define void @_Z4swapP1SS0_b(%struct.S* %a, %struct.S* %b, i1 zeroext %doit) sanitize_address { +entry: + %a.addr = alloca %struct.S*, align 8 + %b.addr = alloca %struct.S*, align 8 + %doit.addr = alloca i8, align 1 + %tmp = alloca %struct.S, align 4 + store %struct.S* %a, %struct.S** %a.addr, align 8 + store %struct.S* %b, %struct.S** %b.addr, align 8 + %frombool = zext i1 %doit to i8 + store i8 %frombool, i8* %doit.addr, align 1 + %0 = load i8, i8* %doit.addr, align 1 + %tobool = trunc i8 %0 to i1 + br i1 %tobool, label %if.end, label %if.then + +if.then: ; preds = %entry + br label %return + +if.end: ; preds = %entry + %1 = load %struct.S*, %struct.S** %a.addr, align 8 + %2 = bitcast %struct.S* %tmp to i8* + %3 = bitcast %struct.S* %1 to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %2, i8* align 4 %3, i64 8, i1 false) + %4 = load %struct.S*, %struct.S** %b.addr, align 8 + %5 = load %struct.S*, %struct.S** %a.addr, align 8 + %6 = bitcast %struct.S* %5 to i8* + %7 = bitcast %struct.S* %4 to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %6, i8* align 4 %7, i64 8, i1 false) + %8 = load %struct.S*, %struct.S** %b.addr, align 8 + %9 = bitcast %struct.S* %8 to i8* + %10 = bitcast %struct.S* %tmp to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %9, i8* align 4 %10, i64 8, i1 false) + br label %return + +return: ; preds = %if.end, %if.then + ret void +} + +; Synthetic test case, meant to check that we do not reorder instructions past +; a load when attempting to hoist argument init insts. +; CHECK-LABEL: define {{.*}} @func_with_load_in_arginit_sequence +; CHECK: [[argA:%.*]] = alloca %struct.S*, +; CHECK-NEXT: [[argB:%.*]] = alloca %struct.S*, +; CHECK-NEXT: [[argDoit:%.*]] = alloca i8, +; CHECK-NEXT: store %struct.S* {{.*}}, %struct.S** [[argA]] +; CHECK-NEXT: store %struct.S* {{.*}}, %struct.S** [[argB]] +; CHECK-NEXT: [[stack_base:%.*]] = alloca i64 +define void @func_with_load_in_arginit_sequence(%struct.S* %a, %struct.S* %b, i1 zeroext %doit) sanitize_address { +entry: + %a.addr = alloca %struct.S*, align 8 + %b.addr = alloca %struct.S*, align 8 + %doit.addr = alloca i8, align 1 + %tmp = alloca %struct.S, align 4 + store %struct.S* %a, %struct.S** %a.addr, align 8 + store %struct.S* %b, %struct.S** %b.addr, align 8 + + ; This load prevents the next argument init sequence from being moved. + %0 = load i8, i8* %doit.addr, align 1 + + %frombool = zext i1 %doit to i8 + store i8 %frombool, i8* %doit.addr, align 1 + %tobool = trunc i8 %0 to i1 + br i1 %tobool, label %if.end, label %if.then + +if.then: ; preds = %entry + br label %return + +if.end: ; preds = %entry + %1 = load %struct.S*, %struct.S** %a.addr, align 8 + %2 = bitcast %struct.S* %tmp to i8* + %3 = bitcast %struct.S* %1 to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %2, i8* align 4 %3, i64 8, i1 false) + %4 = load %struct.S*, %struct.S** %b.addr, align 8 + %5 = load %struct.S*, %struct.S** %a.addr, align 8 + %6 = bitcast %struct.S* %5 to i8* + %7 = bitcast %struct.S* %4 to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %6, i8* align 4 %7, i64 8, i1 false) + %8 = load %struct.S*, %struct.S** %b.addr, align 8 + %9 = bitcast %struct.S* %8 to i8* + %10 = bitcast %struct.S* %tmp to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %9, i8* align 4 %10, i64 8, i1 false) + br label %return + +return: ; preds = %if.end, %if.then + ret void +} + +; Synthetic test case, meant to check that we can handle functions with more +; than one interesting alloca. +; CHECK-LABEL: define {{.*}} @func_with_multiple_interesting_allocas +; CHECK: [[argA:%.*]] = alloca %struct.S*, +; CHECK-NEXT: [[argB:%.*]] = alloca %struct.S*, +; CHECK-NEXT: [[argDoit:%.*]] = alloca i8, +; CHECK-NEXT: store %struct.S* {{.*}}, %struct.S** [[argA]] +; CHECK-NEXT: store %struct.S* {{.*}}, %struct.S** [[argB]] +; CHECK-NEXT: [[frombool:%.*]] = zext i1 {{.*}} to i8 +; CHECK-NEXT: store i8 [[frombool]], i8* [[argDoit]] +define void @func_with_multiple_interesting_allocas(%struct.S* %a, %struct.S* %b, i1 zeroext %doit) sanitize_address { +entry: + %a.addr = alloca %struct.S*, align 8 + %b.addr = alloca %struct.S*, align 8 + %doit.addr = alloca i8, align 1 + %tmp = alloca %struct.S, align 4 + %tmp2 = alloca %struct.S, align 4 + store %struct.S* %a, %struct.S** %a.addr, align 8 + store %struct.S* %b, %struct.S** %b.addr, align 8 + %frombool = zext i1 %doit to i8 + store i8 %frombool, i8* %doit.addr, align 1 + %0 = load i8, i8* %doit.addr, align 1 + %tobool = trunc i8 %0 to i1 + br i1 %tobool, label %if.end, label %if.then + +if.then: ; preds = %entry + br label %return + +if.end: ; preds = %entry + %1 = load %struct.S*, %struct.S** %a.addr, align 8 + %2 = bitcast %struct.S* %tmp to i8* + %3 = bitcast %struct.S* %1 to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %2, i8* align 4 %3, i64 8, i1 false) + %4 = load %struct.S*, %struct.S** %b.addr, align 8 + %5 = bitcast %struct.S* %tmp2 to i8* + %6 = bitcast %struct.S* %4 to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %5, i8* align 4 %6, i64 8, i1 false) + %7 = load %struct.S*, %struct.S** %b.addr, align 8 + %8 = load %struct.S*, %struct.S** %a.addr, align 8 + %9 = bitcast %struct.S* %8 to i8* + %10 = bitcast %struct.S* %7 to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %9, i8* align 4 %10, i64 8, i1 false) + %11 = load %struct.S*, %struct.S** %b.addr, align 8 + %12 = bitcast %struct.S* %11 to i8* + %13 = bitcast %struct.S* %tmp to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %12, i8* align 4 %13, i64 8, i1 false) + %14 = load %struct.S*, %struct.S** %a.addr, align 8 + %15 = bitcast %struct.S* %14 to i8* + %16 = bitcast %struct.S* %tmp2 to i8* + call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %15, i8* align 4 %16, i64 8, i1 false) + br label %return + +return: ; preds = %if.end, %if.then + ret void +} + +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) From 4140df11413559a93b5661dc980cb663fb4b221b Mon Sep 17 00:00:00 2001 From: OCHyams Date: Wed, 1 Apr 2020 16:45:33 +0100 Subject: [PATCH 147/286] [DebugInfo] Salvage debug info when sinking loop invariant instructions Reviewed By: vsk, aprantl, djtodoro Differential Revision: https://reviews.llvm.org/D77318 (cherry picked from commit 9b56cc9361a471a3ce57da4c98f60e377cc43026) --- llvm/lib/Transforms/Scalar/LICM.cpp | 1 + .../DebugInfo/X86/licm-undef-dbg-value.ll | 86 +++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 llvm/test/DebugInfo/X86/licm-undef-dbg-value.ll diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp index 8c33045c23802..a0d3cf5b44cab 100644 --- a/llvm/lib/Transforms/Scalar/LICM.cpp +++ b/llvm/lib/Transforms/Scalar/LICM.cpp @@ -549,6 +549,7 @@ bool llvm::sinkRegion(DomTreeNode *N, AliasAnalysis *AA, LoopInfo *LI, if (sink(I, LI, DT, CurLoop, SafetyInfo, MSSAU, ORE)) { if (!FreeInLoop) { ++II; + salvageDebugInfoOrMarkUndef(I); eraseInstruction(I, *SafetyInfo, CurAST, MSSAU); } Changed = true; diff --git a/llvm/test/DebugInfo/X86/licm-undef-dbg-value.ll b/llvm/test/DebugInfo/X86/licm-undef-dbg-value.ll new file mode 100644 index 0000000000000..09a18f937b3bb --- /dev/null +++ b/llvm/test/DebugInfo/X86/licm-undef-dbg-value.ll @@ -0,0 +1,86 @@ +; RUN: opt -licm %s -S | FileCheck %s + +; CHECK: for.body: +; CHECK-NEXT: llvm.dbg.value(metadata i8 undef + +; The load is loop invariant. Check that we leave an undef dbg.value behind +; when licm sinks the instruction. + +; clang reduce.cpp -g -O2 -Xclang -disable-llvm-passes -emit-llvm -o reduce.ll +; opt -simplifycfg -sroa -loop-rotate -o - -S reduce.ll +; cat reduce.cpp +; extern char a; +; extern char b; +; void use(char); +; void fun() { +; char local = 0; +; for (;b;) +; local = a; +; use(local); +; } + +@b = external dso_local global i8, align 1 +@a = external dso_local global i8, align 1 + +define dso_local void @_Z3funv() !dbg !12 { +entry: + call void @llvm.dbg.value(metadata i8 0, metadata !16, metadata !DIExpression()), !dbg !17 + %0 = load i8, i8* @b, align 1, !dbg !18 + %tobool1 = icmp ne i8 %0, 0, !dbg !18 + br i1 %tobool1, label %for.body.lr.ph, label %for.end, !dbg !24 + +for.body.lr.ph: ; preds = %entry + br label %for.body, !dbg !24 + +for.body: ; preds = %for.body.lr.ph, %for.body + %1 = load i8, i8* @a, align 1, !dbg !25 + call void @llvm.dbg.value(metadata i8 %1, metadata !16, metadata !DIExpression()), !dbg !17 + %2 = load i8, i8* @b, align 1, !dbg !18 + %tobool = icmp ne i8 %2, 0, !dbg !18 + br i1 %tobool, label %for.body, label %for.cond.for.end_crit_edge, !dbg !24, !llvm.loop !26 + +for.cond.for.end_crit_edge: ; preds = %for.body + %split = phi i8 [ %1, %for.body ] + br label %for.end, !dbg !24 + +for.end: ; preds = %for.cond.for.end_crit_edge, %entry + %local.0.lcssa = phi i8 [ %split, %for.cond.for.end_crit_edge ], [ 0, %entry ], !dbg !17 + call void @llvm.dbg.value(metadata i8 %local.0.lcssa, metadata !16, metadata !DIExpression()), !dbg !17 + call void @_Z3usec(i8 signext %local.0.lcssa), !dbg !28 + ret void, !dbg !29 +} + +declare !dbg !4 dso_local void @_Z3usec(i8 signext) +declare void @llvm.dbg.value(metadata, metadata, metadata) + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!8, !9, !10} +!llvm.ident = !{!11} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang version 11.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "reduce.cpp", directory: "/") +!2 = !{} +!3 = !{!4} +!4 = !DISubprogram(name: "use", linkageName: "_Z3usec", scope: !1, file: !1, line: 3, type: !5, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2) +!5 = !DISubroutineType(types: !6) +!6 = !{null, !7} +!7 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!8 = !{i32 7, !"Dwarf Version", i32 4} +!9 = !{i32 2, !"Debug Info Version", i32 3} +!10 = !{i32 1, !"wchar_size", i32 4} +!11 = !{!"clang version 11.0.0"} +!12 = distinct !DISubprogram(name: "fun", linkageName: "_Z3funv", scope: !1, file: !1, line: 4, type: !13, scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !15) +!13 = !DISubroutineType(types: !14) +!14 = !{null} +!15 = !{!16} +!16 = !DILocalVariable(name: "local", scope: !12, file: !1, line: 5, type: !7) +!17 = !DILocation(line: 0, scope: !12) +!18 = !DILocation(line: 6, column: 9, scope: !19) +!19 = distinct !DILexicalBlock(scope: !20, file: !1, line: 6, column: 3) +!20 = distinct !DILexicalBlock(scope: !12, file: !1, line: 6, column: 3) +!24 = !DILocation(line: 6, column: 3, scope: !20) +!25 = !DILocation(line: 7, column: 13, scope: !19) +!26 = distinct !{!26, !24, !27} +!27 = !DILocation(line: 7, column: 13, scope: !20) +!28 = !DILocation(line: 8, column: 3, scope: !12) +!29 = !DILocation(line: 9, column: 1, scope: !12) From 450af79aae24068dfee689c348759ce0798aa1f7 Mon Sep 17 00:00:00 2001 From: Raphael Isemann Date: Tue, 25 Feb 2020 08:20:41 +0100 Subject: [PATCH 148/286] [lldb] Fix that a crashing test is marked as unsupported when it prints UNSUPPORTED before crashing Summary: I added an `abort()` call to some code and noticed that the test suite was still passing and it just marked my test as "UNSUPPORTED". It seems the reason for that is that we expect failing tests to print "FAIL:" which doesn't happen when we crash. If we then also have an unsupported because we skipped some debug information in the output, we just mark the test passing because it is unsupported on the current platform. This patch marks any test that has a non-zero exit code as failing even if it doesn't print "FAIL:" (e.g., because it crashed). Reviewers: labath, JDevlieghere Reviewed By: labath, JDevlieghere Subscribers: aprantl, lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D75031 --- lldb/test/API/lldbtest.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lldb/test/API/lldbtest.py b/lldb/test/API/lldbtest.py index 65aafab5c617d..94c0588fd9e63 100644 --- a/lldb/test/API/lldbtest.py +++ b/lldb/test/API/lldbtest.py @@ -114,14 +114,12 @@ def execute(self, test, litConfig): return lit.Test.TIMEOUT, output if exitCode: - # Match FAIL but not XFAIL. - for line in out.splitlines() + err.splitlines(): - if line.startswith('FAIL:'): - return lit.Test.FAIL, output - if 'XPASS:' in out or 'XPASS:' in err: return lit.Test.XPASS, output + # Otherwise this is just a failure. + return lit.Test.FAIL, output + has_unsupported_tests = 'UNSUPPORTED:' in out or 'UNSUPPORTED:' in err has_passing_tests = 'PASS:' in out or 'PASS:' in err if has_unsupported_tests and not has_passing_tests: From 1eeb3ddb2250fe549d89743ca9168c89a9dabd10 Mon Sep 17 00:00:00 2001 From: Erik Pilkington Date: Mon, 6 Apr 2020 10:17:30 -0400 Subject: [PATCH 149/286] [CodeGenObjC] Fix a crash when attempting to copy a zero-sized bit-field in a non-trivial C struct Zero sized bit-fields aren't included in the CGRecordLayout, so we shouldn't be calling EmitLValueForField for them. rdar://60695105 Differential revision: https://reviews.llvm.org/D76782 Conflicts: clang/test/CodeGenObjC/strong-in-c-struct.m --- clang/include/clang/AST/NonTrivialTypeVisitor.h | 2 +- clang/lib/CodeGen/CGNonTrivialStruct.cpp | 8 ++++++++ clang/test/CodeGenObjC/strong-in-c-struct.m | 12 ++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/AST/NonTrivialTypeVisitor.h b/clang/include/clang/AST/NonTrivialTypeVisitor.h index ce389178b7b22..e9403763ab78b 100644 --- a/clang/include/clang/AST/NonTrivialTypeVisitor.h +++ b/clang/include/clang/AST/NonTrivialTypeVisitor.h @@ -1,4 +1,4 @@ -//===-- NonTrivialTypeVisitor.h - Visitor for non-trivial Types *- C++ --*-===// +//===-- NonTrivialTypeVisitor.h - Visitor for non-trivial Types -*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/clang/lib/CodeGen/CGNonTrivialStruct.cpp b/clang/lib/CodeGen/CGNonTrivialStruct.cpp index 4d0992410478a..61b8cad76d3ae 100644 --- a/clang/lib/CodeGen/CGNonTrivialStruct.cpp +++ b/clang/lib/CodeGen/CGNonTrivialStruct.cpp @@ -254,6 +254,10 @@ struct GenBinaryFuncName : CopyStructVisitor, IsMove>, void visitVolatileTrivial(QualType FT, const FieldDecl *FD, CharUnits CurStructOffset) { + // Zero-length bit-fields don't need to be copied/assigned. + if (FD && FD->isZeroLengthBitField(this->Ctx)) + return; + // Because volatile fields can be bit-fields and are individually copied, // their offset and width are in bits. uint64_t OffsetInBits = @@ -553,6 +557,10 @@ struct GenBinaryFunc : CopyStructVisitor, std::array Addrs) { LValue DstLV, SrcLV; if (FD) { + // No need to copy zero-length bit-fields. + if (FD->isZeroLengthBitField(this->CGF->getContext())) + return; + QualType RT = QualType(FD->getParent()->getTypeForDecl(), 0); llvm::PointerType *PtrTy = this->CGF->ConvertType(RT)->getPointerTo(); Address DstAddr = this->getAddrWithOffset(Addrs[DstIdx], Offset); diff --git a/clang/test/CodeGenObjC/strong-in-c-struct.m b/clang/test/CodeGenObjC/strong-in-c-struct.m index eae5013dd3fcb..01887c5fb9b32 100644 --- a/clang/test/CodeGenObjC/strong-in-c-struct.m +++ b/clang/test/CodeGenObjC/strong-in-c-struct.m @@ -709,4 +709,16 @@ void test_copy_constructor_VolatileArray(VolatileArray *a) { VolatileArray t = *a; } +struct ZeroBitfield { + int : 0; + id strong; +}; + + +// CHECK: define linkonce_odr hidden void @__default_constructor_8_sv0 +// CHECK: define linkonce_odr hidden void @__copy_assignment_8_8_sv0 +void test_zero_bitfield() { + struct ZeroBitfield volatile a, b; + a = b; +} #endif /* USESTRUCT */ From 2eed9575e5a5b72c35b371ccfbbf972e83f718f2 Mon Sep 17 00:00:00 2001 From: Raphael Isemann Date: Tue, 7 Apr 2020 16:11:16 +0200 Subject: [PATCH 150/286] [lldb][NFC] Fix typo in 'watchpoint delete' error message --- lldb/source/Commands/CommandObjectWatchpoint.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/source/Commands/CommandObjectWatchpoint.cpp b/lldb/source/Commands/CommandObjectWatchpoint.cpp index c965d354f7346..78fee94621f2d 100644 --- a/lldb/source/Commands/CommandObjectWatchpoint.cpp +++ b/lldb/source/Commands/CommandObjectWatchpoint.cpp @@ -41,7 +41,7 @@ static bool CheckTargetForWatchpointOperations(Target *target, bool process_is_valid = target->GetProcessSP() && target->GetProcessSP()->IsAlive(); if (!process_is_valid) { - result.AppendError("Thre's no process or it is not alive."); + result.AppendError("There's no process or it is not alive."); result.SetStatus(eReturnStatusFailed); return false; } From f82bfee9a7e58066b2398925d3cdcdd136f574af Mon Sep 17 00:00:00 2001 From: Alex Langford Date: Wed, 29 Jan 2020 11:59:28 -0800 Subject: [PATCH 151/286] [lldb] Move clang-based files out of Symbol Summary: This change represents the move of ClangASTImporter, ClangASTMetadata, ClangExternalASTSourceCallbacks, ClangUtil, CxxModuleHandler, and TypeSystemClang from lldbSource to lldbPluginExpressionParserClang.h This explicitly removes knowledge of clang internals from lldbSymbol, moving towards a more generic core implementation of lldb. Reviewers: JDevlieghere, davide, aprantl, teemperor, clayborg, labath, jingham, shafik Subscribers: emaste, mgorny, arphaman, jfb, usaxena95, lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D73661 --- lldb/source/API/SystemInitializerFull.cpp | 2 +- lldb/source/Core/ValueObject.cpp | 2 +- .../Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp | 2 +- .../Plugins/ABI/SysV-ppc64/CMakeLists.txt | 1 + lldb/source/Plugins/CMakeLists.txt | 1 + .../DynamicLoader/MacOSX-DYLD/CMakeLists.txt | 1 + .../MacOSX-DYLD/DynamicLoaderDarwin.cpp | 2 +- .../MacOSX-DYLD/DynamicLoaderMacOS.cpp | 3 ++- .../MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp | 2 +- .../Clang/ASTResultSynthesizer.cpp | 4 ++-- .../ExpressionParser/Clang/CMakeLists.txt | 7 +++++++ .../Clang}/ClangASTImporter.cpp | 9 +++++---- .../Clang}/ClangASTImporter.h | 3 ++- .../Clang}/ClangASTMetadata.cpp | 2 +- .../Clang}/ClangASTMetadata.h | 0 .../ExpressionParser/Clang/ClangASTSource.cpp | 4 ++-- .../ExpressionParser/Clang/ClangASTSource.h | 2 +- .../Clang/ClangDeclVendor.cpp | 3 ++- .../Clang/ClangExpressionDeclMap.cpp | 4 ++-- .../Clang/ClangExpressionParser.cpp | 2 +- .../ClangExternalASTSourceCallbacks.cpp | 4 ++-- .../Clang}/ClangExternalASTSourceCallbacks.h | 2 +- .../Clang/ClangFunctionCaller.cpp | 2 +- .../Clang/ClangModulesDeclVendor.cpp | 2 +- .../Clang/ClangPersistentVariables.cpp | 3 ++- .../Clang/ClangUserExpression.cpp | 4 ++-- .../ExpressionParser/Clang}/ClangUtil.cpp | 4 ++-- .../ExpressionParser/Clang}/ClangUtil.h | 0 .../Clang}/CxxModuleHandler.cpp | 4 ++-- .../Clang}/CxxModuleHandler.h | 0 .../ExpressionParser/Clang/IRForTarget.cpp | 4 ++-- .../Language/CPlusPlus/BlockPointer.cpp | 5 +++-- .../Plugins/Language/CPlusPlus/CMakeLists.txt | 1 + .../Language/CPlusPlus/CxxStringTypes.cpp | 2 +- .../Plugins/Language/CPlusPlus/LibCxx.cpp | 2 +- .../Language/CPlusPlus/LibCxxBitset.cpp | 2 +- .../Plugins/Language/CPlusPlus/LibCxxList.cpp | 2 +- .../Plugins/Language/CPlusPlus/LibCxxMap.cpp | 2 +- .../Language/CPlusPlus/LibCxxUnorderedMap.cpp | 2 +- .../Plugins/Language/CPlusPlus/LibStdcpp.cpp | 2 +- lldb/source/Plugins/Language/ObjC/CF.cpp | 2 +- .../Plugins/Language/ObjC/CMakeLists.txt | 1 + lldb/source/Plugins/Language/ObjC/Cocoa.cpp | 2 +- lldb/source/Plugins/Language/ObjC/NSArray.cpp | 2 +- .../Plugins/Language/ObjC/NSDictionary.cpp | 2 +- lldb/source/Plugins/Language/ObjC/NSError.cpp | 2 +- .../Plugins/Language/ObjC/NSException.cpp | 2 +- .../Plugins/Language/ObjC/NSIndexPath.cpp | 2 +- lldb/source/Plugins/Language/ObjC/NSSet.cpp | 2 +- .../source/Plugins/Language/ObjC/NSString.cpp | 2 +- .../Plugins/Language/ObjC/ObjCLanguage.cpp | 4 ++-- .../LanguageRuntime/CPlusPlus/CMakeLists.txt | 1 + .../CPlusPlus/CPPLanguageRuntime.cpp | 2 +- .../CPlusPlus/ItaniumABI/CMakeLists.txt | 1 + .../ItaniumABI/ItaniumABILanguageRuntime.cpp | 2 +- .../AppleObjCRuntime/AppleObjCDeclVendor.cpp | 4 ++-- .../AppleObjCRuntime/AppleObjCDeclVendor.h | 2 +- .../AppleObjCRuntime/AppleObjCRuntime.cpp | 3 ++- .../AppleObjCRuntime/AppleObjCRuntimeV1.cpp | 2 +- .../AppleObjCRuntime/AppleObjCRuntimeV2.cpp | 2 +- .../AppleObjCTrampolineHandler.cpp | 2 +- .../AppleObjCTypeEncodingParser.cpp | 4 ++-- .../ObjC/AppleObjCRuntime/CMakeLists.txt | 1 + .../ObjC/ObjCLanguageRuntime.cpp | 2 +- .../Plugins/Platform/POSIX/CMakeLists.txt | 1 + .../Plugins/Platform/POSIX/PlatformPOSIX.cpp | 2 +- .../Plugins/SymbolFile/DWARF/CMakeLists.txt | 1 + .../SymbolFile/DWARF/DWARFASTParserClang.cpp | 6 +++--- .../SymbolFile/DWARF/DWARFASTParserClang.h | 5 +++-- .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 4 ++-- .../SymbolFile/NativePDB/CMakeLists.txt | 1 + .../SymbolFile/NativePDB/PdbAstBuilder.cpp | 6 +++--- .../SymbolFile/NativePDB/PdbAstBuilder.h | 2 +- .../NativePDB/SymbolFileNativePDB.cpp | 4 ++-- .../NativePDB/UdtRecordCompleter.cpp | 4 ++-- .../SymbolFile/NativePDB/UdtRecordCompleter.h | 2 +- .../Plugins/SymbolFile/PDB/CMakeLists.txt | 1 + .../Plugins/SymbolFile/PDB/PDBASTParser.cpp | 6 +++--- .../Plugins/SymbolFile/PDB/PDBASTParser.h | 2 +- .../Plugins/SymbolFile/PDB/SymbolFilePDB.cpp | 2 +- .../MacOSX/AppleGetItemInfoHandler.cpp | 3 +-- .../MacOSX/AppleGetPendingItemsHandler.cpp | 3 +-- .../MacOSX/AppleGetQueuesHandler.cpp | 2 +- .../MacOSX/AppleGetThreadItemInfoHandler.cpp | 3 +-- .../SystemRuntime/MacOSX/CMakeLists.txt | 1 + .../MacOSX/SystemRuntimeMacOSX.cpp | 2 +- lldb/source/Plugins/TypeSystem/CMakeLists.txt | 1 + .../Plugins/TypeSystem/Clang/CMakeLists.txt | 20 +++++++++++++++++++ .../TypeSystem/Clang}/TypeSystemClang.cpp | 10 +++++----- .../TypeSystem/Clang}/TypeSystemClang.h | 0 lldb/source/Symbol/CMakeLists.txt | 15 -------------- lldb/source/Target/Target.cpp | 4 ++-- .../tools/lldb-test/SystemInitializerTest.cpp | 2 +- lldb/tools/lldb-test/lldb-test.cpp | 2 +- lldb/unittests/Expression/CMakeLists.txt | 1 + .../Expression/ClangExpressionDeclMapTest.cpp | 4 ++-- lldb/unittests/Symbol/CMakeLists.txt | 1 + .../unittests/Symbol/TestClangASTImporter.cpp | 8 ++++---- lldb/unittests/Symbol/TestLineEntry.cpp | 2 +- lldb/unittests/Symbol/TestTypeSystemClang.cpp | 4 ++-- .../unittests/SymbolFile/DWARF/CMakeLists.txt | 1 + .../SymbolFile/DWARF/SymbolFileDWARFTests.cpp | 4 +--- lldb/unittests/SymbolFile/PDB/CMakeLists.txt | 1 + .../SymbolFile/PDB/SymbolFilePDBTests.cpp | 2 +- .../TestingSupport/Symbol/ClangTestUtils.h | 4 ++-- 105 files changed, 169 insertions(+), 136 deletions(-) rename lldb/source/{Symbol => Plugins/ExpressionParser/Clang}/ClangASTImporter.cpp (99%) rename lldb/{include/lldb/Symbol => source/Plugins/ExpressionParser/Clang}/ClangASTImporter.h (99%) rename lldb/source/{Symbol => Plugins/ExpressionParser/Clang}/ClangASTMetadata.cpp (93%) rename lldb/{include/lldb/Symbol => source/Plugins/ExpressionParser/Clang}/ClangASTMetadata.h (100%) rename lldb/source/{Symbol => Plugins/ExpressionParser/Clang}/ClangExternalASTSourceCallbacks.cpp (92%) rename lldb/{include/lldb/Symbol => source/Plugins/ExpressionParser/Clang}/ClangExternalASTSourceCallbacks.h (96%) rename lldb/source/{Symbol => Plugins/ExpressionParser/Clang}/ClangUtil.cpp (95%) rename lldb/{include/lldb/Symbol => source/Plugins/ExpressionParser/Clang}/ClangUtil.h (100%) rename lldb/source/{Symbol => Plugins/ExpressionParser/Clang}/CxxModuleHandler.cpp (98%) rename lldb/{include/lldb/Symbol => source/Plugins/ExpressionParser/Clang}/CxxModuleHandler.h (100%) create mode 100644 lldb/source/Plugins/TypeSystem/CMakeLists.txt create mode 100644 lldb/source/Plugins/TypeSystem/Clang/CMakeLists.txt rename lldb/source/{Symbol => Plugins/TypeSystem/Clang}/TypeSystemClang.cpp (99%) rename lldb/{include/lldb/Symbol => source/Plugins/TypeSystem/Clang}/TypeSystemClang.h (100%) diff --git a/lldb/source/API/SystemInitializerFull.cpp b/lldb/source/API/SystemInitializerFull.cpp index 25d191aa4f70f..dae919d6d8687 100644 --- a/lldb/source/API/SystemInitializerFull.cpp +++ b/lldb/source/API/SystemInitializerFull.cpp @@ -22,7 +22,6 @@ #include "lldb/Host/Host.h" #include "lldb/Initialization/SystemInitializerCommon.h" #include "lldb/Interpreter/CommandInterpreter.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Utility/Timer.h" #include "Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h" @@ -95,6 +94,7 @@ #include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h" #include "Plugins/SymbolVendor/ELF/SymbolVendorELF.h" #include "Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h" #include "Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h" diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index ee312d8d562dd..1bbf601d6d65e 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -25,7 +25,6 @@ #include "lldb/DataFormatters/ValueObjectPrinter.h" #include "lldb/Expression/ExpressionVariable.h" #include "lldb/Host/Config.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Symbol/Declaration.h" @@ -50,6 +49,7 @@ #include "lldb/Utility/Stream.h" #include "lldb/Utility/StreamString.h" #include "lldb/lldb-private-types.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "llvm/Support/Compiler.h" diff --git a/lldb/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp b/lldb/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp index 91720a7094456..eb51cf26ced37 100644 --- a/lldb/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp +++ b/lldb/source/Plugins/ABI/SysV-ppc64/ABISysV_ppc64.cpp @@ -11,6 +11,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "Utility/PPC64LE_DWARF_Registers.h" #include "Utility/PPC64_DWARF_Registers.h" #include "lldb/Core/Module.h" @@ -19,7 +20,6 @@ #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Core/ValueObjectMemory.h" #include "lldb/Core/ValueObjectRegister.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/UnwindPlan.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" diff --git a/lldb/source/Plugins/ABI/SysV-ppc64/CMakeLists.txt b/lldb/source/Plugins/ABI/SysV-ppc64/CMakeLists.txt index b31182dd0f78e..0a0bb7b8623d9 100644 --- a/lldb/source/Plugins/ABI/SysV-ppc64/CMakeLists.txt +++ b/lldb/source/Plugins/ABI/SysV-ppc64/CMakeLists.txt @@ -5,6 +5,7 @@ add_lldb_library(lldbPluginABISysV_ppc64 PLUGIN lldbCore lldbSymbol lldbTarget + lldbPluginTypeSystemClang LINK_COMPONENTS Support ) diff --git a/lldb/source/Plugins/CMakeLists.txt b/lldb/source/Plugins/CMakeLists.txt index 5092b210a12cf..08817baec14ca 100644 --- a/lldb/source/Plugins/CMakeLists.txt +++ b/lldb/source/Plugins/CMakeLists.txt @@ -19,4 +19,5 @@ add_subdirectory(StructuredData) add_subdirectory(SymbolFile) add_subdirectory(SystemRuntime) add_subdirectory(SymbolVendor) +add_subdirectory(TypeSystem) add_subdirectory(UnwindAssembly) diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/CMakeLists.txt b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/CMakeLists.txt index 515c82dcaca97..c470bc6e8339f 100644 --- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/CMakeLists.txt +++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/CMakeLists.txt @@ -11,6 +11,7 @@ add_lldb_library(lldbPluginDynamicLoaderMacOSXDYLD PLUGIN lldbSymbol lldbTarget lldbUtility + lldbPluginTypeSystemClang LINK_COMPONENTS Support ) diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp index 73347241a7391..1a5d9e21bed34 100644 --- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp +++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp @@ -16,7 +16,6 @@ #include "lldb/Core/Section.h" #include "lldb/Expression/DiagnosticManager.h" #include "lldb/Host/FileSystem.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/ABI.h" @@ -32,6 +31,7 @@ #include "lldb/Utility/State.h" #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" //#define ENABLE_DEBUG_PRINTF // COMMENT THIS LINE OUT PRIOR TO CHECKIN #ifdef ENABLE_DEBUG_PRINTF diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp index e57f5cee64232..b9ace1b666175 100644 --- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp +++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp @@ -11,7 +11,6 @@ #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolVendor.h" #include "lldb/Target/ABI.h" @@ -24,6 +23,8 @@ #include "DynamicLoaderDarwin.h" #include "DynamicLoaderMacOS.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" + using namespace lldb; using namespace lldb_private; diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp index 0bc732a75896d..f3e052846443d 100644 --- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp @@ -12,7 +12,6 @@ #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/ABI.h" @@ -30,6 +29,7 @@ #include "DynamicLoaderMacOSXDYLD.h" #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" //#define ENABLE_DEBUG_PRINTF // COMMENT THIS LINE OUT PRIOR TO CHECKIN #ifdef ENABLE_DEBUG_PRINTF diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp index e21bc738992e7..b3252cf0cc87c 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp @@ -8,10 +8,10 @@ #include "ASTResultSynthesizer.h" +#include "ClangASTImporter.h" #include "ClangPersistentVariables.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangASTImporter.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Target/Target.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" diff --git a/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt b/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt index e92d089cab108..3bb120a48e90b 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt +++ b/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt @@ -6,19 +6,24 @@ add_lldb_library(lldbPluginExpressionParserClang PLUGIN ASTResultSynthesizer.cpp ASTStructExtractor.cpp ASTUtils.cpp + ClangASTImporter.cpp + ClangASTMetadata.cpp ClangASTSource.cpp ClangDeclVendor.cpp ClangExpressionDeclMap.cpp ClangExpressionParser.cpp ClangExpressionSourceCode.cpp ClangExpressionVariable.cpp + ClangExternalASTSourceCallbacks.cpp ClangFunctionCaller.cpp ClangHost.cpp ClangModulesDeclVendor.cpp ClangPersistentVariables.cpp ClangUserExpression.cpp + ClangUtil.cpp ClangUtilityFunction.cpp CppModuleConfiguration.cpp + CxxModuleHandler.cpp IRForTarget.cpp IRDynamicChecks.cpp @@ -35,6 +40,8 @@ add_lldb_library(lldbPluginExpressionParserClang PLUGIN lldbUtility lldbPluginCPlusPlusLanguage lldbPluginCPPRuntime + lldbPluginObjCRuntime + lldbPluginTypeSystemClang CLANG_LIBS clangAST clangCodeGen diff --git a/lldb/source/Symbol/ClangASTImporter.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp similarity index 99% rename from lldb/source/Symbol/ClangASTImporter.cpp rename to lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp index d36d06c633798..61fe5e24492b7 100644 --- a/lldb/source/Symbol/ClangASTImporter.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp @@ -6,11 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "lldb/Symbol/ClangASTImporter.h" #include "lldb/Core/Module.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangASTMetadata.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" #include "clang/AST/Decl.h" @@ -20,6 +16,11 @@ #include "clang/Sema/Sema.h" #include "llvm/Support/raw_ostream.h" +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" + #include using namespace lldb_private; diff --git a/lldb/include/lldb/Symbol/ClangASTImporter.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h similarity index 99% rename from lldb/include/lldb/Symbol/ClangASTImporter.h rename to lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h index a4e042425dc62..2bc0cd6f7ecb8 100644 --- a/lldb/include/lldb/Symbol/ClangASTImporter.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h @@ -23,9 +23,10 @@ #include "lldb/Host/FileSystem.h" #include "lldb/Symbol/CompilerDeclContext.h" -#include "lldb/Symbol/CxxModuleHandler.h" #include "lldb/lldb-types.h" +#include "Plugins/ExpressionParser/Clang/CxxModuleHandler.h" + #include "llvm/ADT/DenseMap.h" namespace lldb_private { diff --git a/lldb/source/Symbol/ClangASTMetadata.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.cpp similarity index 93% rename from lldb/source/Symbol/ClangASTMetadata.cpp rename to lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.cpp index 31b012f553fab..6a24e4551797d 100644 --- a/lldb/source/Symbol/ClangASTMetadata.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "lldb/Symbol/ClangASTMetadata.h" +#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h" #include "lldb/Utility/Stream.h" using namespace lldb_private; diff --git a/lldb/include/lldb/Symbol/ClangASTMetadata.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.h similarity index 100% rename from lldb/include/lldb/Symbol/ClangASTMetadata.h rename to lldb/source/Plugins/ExpressionParser/Clang/ClangASTMetadata.h diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp index 925c640134d5e..f84ce63dc3532 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp @@ -13,8 +13,6 @@ #include "lldb/Core/Module.h" #include "lldb/Core/ModuleList.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompilerDeclContext.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/SymbolFile.h" @@ -24,7 +22,9 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/RecordLayout.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include #include diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h index 52fb0d1f4eae3..4f0c9ac386369 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h @@ -11,7 +11,7 @@ #include -#include "lldb/Symbol/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Target/Target.h" #include "clang/AST/ExternalASTSource.h" diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.cpp index 4bdd37d513c78..4dd932adab328 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.cpp @@ -7,8 +7,9 @@ //===----------------------------------------------------------------------===// #include "Plugins/ExpressionParser/Clang/ClangDeclVendor.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Utility/ConstString.h" using namespace lldb_private; diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp index 2604b80c1edb2..0a829f89f1942 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp @@ -11,15 +11,15 @@ #include "ClangASTSource.h" #include "ClangModulesDeclVendor.h" #include "ClangPersistentVariables.h" +#include "ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Address.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Core/ValueObjectVariable.h" #include "lldb/Expression/Materializer.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/CompilerDecl.h" #include "lldb/Symbol/CompilerDeclContext.h" diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp index b26493c87fecb..95975e4230acd 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -67,6 +67,7 @@ #include "IRForTarget.h" #include "ModuleDependencyCollector.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Disassembler.h" #include "lldb/Core/Module.h" @@ -75,7 +76,6 @@ #include "lldb/Expression/IRInterpreter.h" #include "lldb/Host/File.h" #include "lldb/Host/HostInfo.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/SymbolVendor.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Language.h" diff --git a/lldb/source/Symbol/ClangExternalASTSourceCallbacks.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp similarity index 92% rename from lldb/source/Symbol/ClangExternalASTSourceCallbacks.cpp rename to lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp index a830194975d65..db9d265ba9a2c 100644 --- a/lldb/source/Symbol/ClangExternalASTSourceCallbacks.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#include "lldb/Symbol/ClangExternalASTSourceCallbacks.h" -#include "lldb/Symbol/TypeSystemClang.h" +#include "Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "clang/AST/Decl.h" diff --git a/lldb/include/lldb/Symbol/ClangExternalASTSourceCallbacks.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h similarity index 96% rename from lldb/include/lldb/Symbol/ClangExternalASTSourceCallbacks.h rename to lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h index 49bc30c633c30..98e9f5adbdbf1 100644 --- a/lldb/include/lldb/Symbol/ClangExternalASTSourceCallbacks.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h @@ -9,7 +9,7 @@ #ifndef liblldb_ClangExternalASTSourceCallbacks_h_ #define liblldb_ClangExternalASTSourceCallbacks_h_ -#include "lldb/Symbol/TypeSystemClang.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "clang/AST/ExternalASTSource.h" namespace lldb_private { diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp index 364ee582f5382..4c986a55e7496 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp @@ -21,12 +21,12 @@ #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/IR/Module.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Module.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectList.h" #include "lldb/Expression/IRExecutionUnit.h" #include "lldb/Interpreter/CommandReturnObject.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/Type.h" #include "lldb/Target/ExecutionContext.h" diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp index 0490888fea70d..4fd4b84cb39e7 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp @@ -24,10 +24,10 @@ #include "ClangModulesDeclVendor.h" #include "ModuleDependencyCollector.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ModuleList.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/SourceModule.h" #include "lldb/Target/Target.h" diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp index 7106f7d553fbe..0edcfef36dd73 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp @@ -7,9 +7,10 @@ //===----------------------------------------------------------------------===// #include "ClangPersistentVariables.h" +#include "ClangASTImporter.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Value.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Log.h" diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp index c5296009c6da8..0132ccf1c2b28 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp @@ -20,6 +20,7 @@ #include "ClangUserExpression.h" #include "ASTResultSynthesizer.h" +#include "ClangASTMetadata.h" #include "ClangDiagnostic.h" #include "ClangExpressionDeclMap.h" #include "ClangExpressionParser.h" @@ -27,6 +28,7 @@ #include "ClangPersistentVariables.h" #include "CppModuleConfiguration.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" #include "lldb/Core/StreamFile.h" @@ -37,8 +39,6 @@ #include "lldb/Expression/Materializer.h" #include "lldb/Host/HostInfo.h" #include "lldb/Symbol/Block.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangASTMetadata.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" diff --git a/lldb/source/Symbol/ClangUtil.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp similarity index 95% rename from lldb/source/Symbol/ClangUtil.cpp rename to lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp index e351a16d87279..4e27d3d9adc2d 100644 --- a/lldb/source/Symbol/ClangUtil.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.cpp @@ -8,8 +8,8 @@ // types and decls. //===----------------------------------------------------------------------===// -#include "lldb/Symbol/ClangUtil.h" -#include "lldb/Symbol/TypeSystemClang.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" using namespace clang; using namespace lldb_private; diff --git a/lldb/include/lldb/Symbol/ClangUtil.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.h similarity index 100% rename from lldb/include/lldb/Symbol/ClangUtil.h rename to lldb/source/Plugins/ExpressionParser/Clang/ClangUtil.h diff --git a/lldb/source/Symbol/CxxModuleHandler.cpp b/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp similarity index 98% rename from lldb/source/Symbol/CxxModuleHandler.cpp rename to lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp index 6930f71d1eb57..4b74e9a0d13c2 100644 --- a/lldb/source/Symbol/CxxModuleHandler.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp @@ -6,9 +6,9 @@ // //===----------------------------------------------------------------------===// -#include "lldb/Symbol/CxxModuleHandler.h" +#include "Plugins/ExpressionParser/Clang/CxxModuleHandler.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Utility/Log.h" #include "clang/Sema/Lookup.h" #include "llvm/Support/Error.h" diff --git a/lldb/include/lldb/Symbol/CxxModuleHandler.h b/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.h similarity index 100% rename from lldb/include/lldb/Symbol/CxxModuleHandler.h rename to lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.h diff --git a/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp b/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp index d5860ec4fd5a5..63dc6c8859f90 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp @@ -9,7 +9,9 @@ #include "IRForTarget.h" #include "ClangExpressionDeclMap.h" +#include "ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/InstrTypes.h" @@ -27,8 +29,6 @@ #include "lldb/Core/dwarf.h" #include "lldb/Expression/IRExecutionUnit.h" #include "lldb/Expression/IRInterpreter.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/DataBufferHeap.h" diff --git a/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp b/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp index c4cd025da0175..decbdbce7ea52 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp @@ -8,10 +8,11 @@ #include "BlockPointer.h" +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangASTImporter.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Symbol/TypeSystem.h" #include "lldb/Target/Target.h" diff --git a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt index ea36c7ec80dbe..2a541a9e528cd 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt +++ b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt @@ -29,6 +29,7 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN lldbUtility lldbPluginClangCommon lldbPluginCPPRuntime + lldbPluginTypeSystemClang LINK_COMPONENTS Support diff --git a/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp b/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp index eab42ec285261..c4f3446e1c78e 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CxxStringTypes.cpp @@ -10,13 +10,13 @@ #include "llvm/Support/ConvertUTF.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" #include "lldb/DataFormatters/StringPrinter.h" #include "lldb/DataFormatters/TypeSummary.h" #include "lldb/Host/Time.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/ProcessStructReader.h" #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp index 07e9a0e83fab4..3cb4a28eefee3 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp @@ -16,7 +16,6 @@ #include "lldb/DataFormatters/StringPrinter.h" #include "lldb/DataFormatters/TypeSummary.h" #include "lldb/DataFormatters/VectorIterator.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/ProcessStructReader.h" #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" @@ -26,6 +25,7 @@ #include "lldb/Utility/Stream.h" #include "Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" using namespace lldb; using namespace lldb_private; diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxBitset.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxBitset.cpp index 6f18e3501ad97..381a13584fac6 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxBitset.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxBitset.cpp @@ -7,8 +7,8 @@ //===----------------------------------------------------------------------===// #include "LibCxx.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/Target.h" using namespace lldb; diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp index ea4cc41440c66..746f842f5e417 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp @@ -8,10 +8,10 @@ #include "LibCxx.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/Endian.h" diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp index 9cfc70ebbcae0..ab3a9752ecee5 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp @@ -8,10 +8,10 @@ #include "LibCxx.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/Endian.h" diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp index 63214de7b5578..aa38591daf996 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxUnorderedMap.cpp @@ -8,10 +8,10 @@ #include "LibCxx.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/Endian.h" diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp index 61ac6a796beec..0900a7b7032e3 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.cpp @@ -8,11 +8,11 @@ #include "LibStdcpp.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/StringPrinter.h" #include "lldb/DataFormatters/VectorIterator.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/Endian.h" diff --git a/lldb/source/Plugins/Language/ObjC/CF.cpp b/lldb/source/Plugins/Language/ObjC/CF.cpp index bfda06e376e2e..68ae0ece58f84 100644 --- a/lldb/source/Plugins/Language/ObjC/CF.cpp +++ b/lldb/source/Plugins/Language/ObjC/CF.cpp @@ -9,10 +9,10 @@ #include "CF.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/Language.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" diff --git a/lldb/source/Plugins/Language/ObjC/CMakeLists.txt b/lldb/source/Plugins/Language/ObjC/CMakeLists.txt index ebb96c299087d..7b220e4c0c21d 100644 --- a/lldb/source/Plugins/Language/ObjC/CMakeLists.txt +++ b/lldb/source/Plugins/Language/ObjC/CMakeLists.txt @@ -31,6 +31,7 @@ add_lldb_library(lldbPluginObjCLanguage PLUGIN lldbUtility lldbPluginAppleObjCRuntime lldbPluginClangCommon + lldbPluginTypeSystemClang CLANG_LIBS clangAST diff --git a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp index 3b53372f2b883..00df3303e45af 100644 --- a/lldb/source/Plugins/Language/ObjC/Cocoa.cpp +++ b/lldb/source/Plugins/Language/ObjC/Cocoa.cpp @@ -8,6 +8,7 @@ #include "Cocoa.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Mangled.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" @@ -15,7 +16,6 @@ #include "lldb/DataFormatters/StringPrinter.h" #include "lldb/DataFormatters/TypeSummary.h" #include "lldb/Host/Time.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/Language.h" #include "lldb/Target/Process.h" #include "lldb/Target/ProcessStructReader.h" diff --git a/lldb/source/Plugins/Language/ObjC/NSArray.cpp b/lldb/source/Plugins/Language/ObjC/NSArray.cpp index 1897a7678184d..8aba804a4263a 100644 --- a/lldb/source/Plugins/Language/ObjC/NSArray.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSArray.cpp @@ -11,12 +11,12 @@ #include "Cocoa.h" #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" #include "lldb/Expression/FunctionCaller.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/Language.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataBufferHeap.h" diff --git a/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp b/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp index 7b1013a74e07e..d2cb3d19516ca 100644 --- a/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp @@ -13,11 +13,11 @@ #include "NSDictionary.h" #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/Language.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" diff --git a/lldb/source/Plugins/Language/ObjC/NSError.cpp b/lldb/source/Plugins/Language/ObjC/NSError.cpp index 3cd784afcdc63..ad2f9bd80a2e3 100644 --- a/lldb/source/Plugins/Language/ObjC/NSError.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSError.cpp @@ -10,10 +10,10 @@ #include "Cocoa.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/ProcessStructReader.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataBufferHeap.h" diff --git a/lldb/source/Plugins/Language/ObjC/NSException.cpp b/lldb/source/Plugins/Language/ObjC/NSException.cpp index 31a17ddd10d98..a001ab8673339 100644 --- a/lldb/source/Plugins/Language/ObjC/NSException.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSException.cpp @@ -13,7 +13,6 @@ #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/ProcessStructReader.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataBufferHeap.h" @@ -23,6 +22,7 @@ #include "Plugins/Language/ObjC/NSString.h" #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" using namespace lldb; using namespace lldb_private; diff --git a/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp b/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp index 81cfb9b0ddfd8..50d539fa2952e 100644 --- a/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp @@ -8,11 +8,11 @@ #include "Cocoa.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" #include "lldb/DataFormatters/TypeSynthetic.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" diff --git a/lldb/source/Plugins/Language/ObjC/NSSet.cpp b/lldb/source/Plugins/Language/ObjC/NSSet.cpp index 3ccf8eb30e6c9..8dfc7ea50b2cc 100644 --- a/lldb/source/Plugins/Language/ObjC/NSSet.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSSet.cpp @@ -9,10 +9,10 @@ #include "NSSet.h" #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/Language.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataBufferHeap.h" diff --git a/lldb/source/Plugins/Language/ObjC/NSString.cpp b/lldb/source/Plugins/Language/ObjC/NSString.cpp index 92e31db517e22..04088747a3afd 100644 --- a/lldb/source/Plugins/Language/ObjC/NSString.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSString.cpp @@ -9,11 +9,11 @@ #include "NSString.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/FormattersHelpers.h" #include "lldb/DataFormatters/StringPrinter.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/Language.h" #include "lldb/Target/ProcessStructReader.h" #include "lldb/Target/Target.h" diff --git a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp index 2de5014111785..813af7d69fcca 100644 --- a/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp +++ b/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp @@ -10,12 +10,12 @@ #include "ObjCLanguage.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/ValueObject.h" #include "lldb/DataFormatters/DataVisualization.h" #include "lldb/DataFormatters/FormattersHelpers.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Target/Target.h" #include "lldb/Utility/ConstString.h" diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt index 508a361aa6ddf..0260212266fbd 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt @@ -5,6 +5,7 @@ add_lldb_library(lldbPluginCPPRuntime PLUGIN lldbCore lldbSymbol lldbTarget + lldbPluginTypeSystemClang ) add_subdirectory(ItaniumABI) diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp index 1bd993313ea37..43c51e75e6a88 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp @@ -18,9 +18,9 @@ #include "lldb/Symbol/Variable.h" #include "lldb/Symbol/VariableList.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/UniqueCStringMap.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Target/ABI.h" #include "lldb/Target/ExecutionContext.h" diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/CMakeLists.txt b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/CMakeLists.txt index 52c297d944b9f..5ab494414ac5b 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/CMakeLists.txt +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/CMakeLists.txt @@ -8,4 +8,5 @@ add_lldb_library(lldbPluginCXXItaniumABI PLUGIN lldbSymbol lldbTarget lldbPluginCPPRuntime + lldbPluginTypeSystemClang ) diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp index 836989868b626..a9127d4bdfd82 100644 --- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp @@ -9,6 +9,7 @@ #include "ItaniumABILanguageRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/Mangled.h" #include "lldb/Core/Module.h" @@ -21,7 +22,6 @@ #include "lldb/Interpreter/CommandObject.h" #include "lldb/Interpreter/CommandObjectMultiword.h" #include "lldb/Interpreter/CommandReturnObject.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/TypeList.h" diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp index d33af7943761a..7219f61a9834d 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp @@ -8,10 +8,10 @@ #include "AppleObjCDeclVendor.h" +#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" #include "lldb/Core/Module.h" -#include "lldb/Symbol/ClangASTMetadata.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Utility/Log.h" diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.h index eee802766117c..0d66cc781320f 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.h +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.h @@ -9,11 +9,11 @@ #ifndef liblldb_AppleObjCDeclVendor_h_ #define liblldb_AppleObjCDeclVendor_h_ -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/lldb-private.h" #include "Plugins/ExpressionParser/Clang/ClangDeclVendor.h" #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" namespace lldb_private { diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp index d620bc567296d..d84a7341e5a34 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp @@ -22,7 +22,6 @@ #include "lldb/DataFormatters/FormattersHelpers.h" #include "lldb/Expression/DiagnosticManager.h" #include "lldb/Expression/FunctionCaller.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" @@ -40,6 +39,8 @@ #include "Plugins/Language/ObjC/NSString.h" #include "Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" + #include using namespace lldb; diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp index 69673443ce570..f7c1409682627 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp @@ -13,12 +13,12 @@ #include "clang/AST/Type.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" #include "lldb/Expression/FunctionCaller.h" #include "lldb/Expression/UtilityFunction.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp index 85b551539b506..a52013fcf7669 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp @@ -20,6 +20,7 @@ #include "lldb/Symbol/CompilerType.h" #include "lldb/lldb-enumerations.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/ClangForward.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" @@ -35,7 +36,6 @@ #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/OptionArgParser.h" #include "lldb/Interpreter/OptionValueBoolean.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Symbol/TypeList.h" diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp index 5b5e416b20d89..79c7ab1c5c733 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp @@ -10,6 +10,7 @@ #include "AppleObjCTrampolineHandler.h" #include "AppleThreadPlanStepThroughObjCTrampoline.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" @@ -19,7 +20,6 @@ #include "lldb/Expression/FunctionCaller.h" #include "lldb/Expression/UserExpression.h" #include "lldb/Expression/UtilityFunction.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/ABI.h" #include "lldb/Target/ExecutionContext.h" diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp index 55655bf69c863..2bc6cfd9a7fc9 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp @@ -8,8 +8,8 @@ #include "AppleObjCTypeEncodingParser.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangUtil.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/CMakeLists.txt b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/CMakeLists.txt index bcf324023c221..3789f56325980 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/CMakeLists.txt +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/CMakeLists.txt @@ -19,6 +19,7 @@ add_lldb_library(lldbPluginAppleObjCRuntime PLUGIN lldbUtility lldbPluginExpressionParserClang lldbPluginCPPRuntime + lldbPluginTypeSystemClang CLANG_LIBS clangAST LINK_COMPONENTS diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp index 9447597d9263c..1b2286ae19d1c 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp @@ -9,11 +9,11 @@ #include "ObjCLanguageRuntime.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/MappedHash.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/ValueObject.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/Type.h" diff --git a/lldb/source/Plugins/Platform/POSIX/CMakeLists.txt b/lldb/source/Plugins/Platform/POSIX/CMakeLists.txt index 749407d63d5c9..c4c62e46add3d 100644 --- a/lldb/source/Plugins/Platform/POSIX/CMakeLists.txt +++ b/lldb/source/Plugins/Platform/POSIX/CMakeLists.txt @@ -7,4 +7,5 @@ add_lldb_library(lldbPluginPlatformPOSIX PLUGIN lldbHost lldbInterpreter lldbTarget + lldbPluginTypeSystemClang ) diff --git a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp index 71da7cccbce31..e719cdb2fb38d 100644 --- a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp +++ b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp @@ -8,6 +8,7 @@ #include "PlatformPOSIX.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" @@ -22,7 +23,6 @@ #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/ProcessLaunchInfo.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Target/DynamicLoader.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" diff --git a/lldb/source/Plugins/SymbolFile/DWARF/CMakeLists.txt b/lldb/source/Plugins/SymbolFile/DWARF/CMakeLists.txt index 4a3bc81afa7d4..49de7df9c74ec 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/CMakeLists.txt +++ b/lldb/source/Plugins/SymbolFile/DWARF/CMakeLists.txt @@ -53,6 +53,7 @@ add_lldb_library(lldbPluginSymbolFileDWARF PLUGIN lldbPluginObjCLanguage lldbPluginCPlusPlusLanguage lldbPluginExpressionParserClang + lldbPluginTypeSystemClang CLANG_LIBS clangAST clangBasic diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index a8d177696427e..59604a25fad6f 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -17,13 +17,13 @@ #include "SymbolFileDWARFDebugMap.h" #include "UniqueDWARFASTType.h" +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" #include "Plugins/Language/ObjC/ObjCLanguage.h" #include "lldb/Core/Module.h" #include "lldb/Core/Value.h" #include "lldb/Host/Host.h" -#include "lldb/Symbol/ClangASTImporter.h" -#include "lldb/Symbol/ClangASTMetadata.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h index 6cd2dc8bf5580..9282131301f5d 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h @@ -21,8 +21,9 @@ #include "LogChannelDWARF.h" #include "lldb/Core/ClangForward.h" #include "lldb/Core/PluginInterface.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangASTImporter.h" + +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index a4646fd9336ee..49dd49c26a206 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -34,9 +34,9 @@ #include "lldb/Interpreter/OptionValueFileSpecList.h" #include "lldb/Interpreter/OptionValueProperties.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Symbol/Block.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/CompilerDecl.h" #include "lldb/Symbol/CompilerDeclContext.h" diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt b/lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt index aaecec4765f57..4f19231c346ca 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt +++ b/lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt @@ -14,6 +14,7 @@ add_lldb_library(lldbPluginSymbolFileNativePDB PLUGIN lldbCore lldbSymbol lldbUtility + lldbPluginTypeSystemClang CLANG_LIBS clangAST clangLex diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp index f80d45b8d3402..03cd8ffc53921 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp @@ -14,11 +14,11 @@ #include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/Demangle/MicrosoftDemangle.h" +#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" #include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Module.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangASTMetadata.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/LLDBAssert.h" diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h index 78f19b85c359c..f31eeb57cc5c0 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.h @@ -12,7 +12,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringRef.h" -#include "lldb/Symbol/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" #include "PdbIndex.h" #include "PdbSymUid.h" diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp index f6982b3925a54..2f9a605f607e2 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp @@ -14,13 +14,13 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/Type.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" #include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/StreamBuffer.h" #include "lldb/Core/StreamFile.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/LineTable.h" #include "lldb/Symbol/ObjectFile.h" diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp index 9ecd4e2e14402..308ba9e3dec0b 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.cpp @@ -5,8 +5,8 @@ #include "PdbSymUid.h" #include "PdbUtil.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Symbol/Type.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/lldb-enumerations.h" diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h index 55397582209b8..1b082785764e2 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h +++ b/lldb/source/Plugins/SymbolFile/NativePDB/UdtRecordCompleter.h @@ -9,7 +9,7 @@ #ifndef LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_UDTRECORDCOMPLETER_H #define LLDB_PLUGINS_SYMBOLFILE_NATIVEPDB_UDTRECORDCOMPLETER_H -#include "lldb/Symbol/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" #include "llvm/DebugInfo/CodeView/CVRecord.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h" diff --git a/lldb/source/Plugins/SymbolFile/PDB/CMakeLists.txt b/lldb/source/Plugins/SymbolFile/PDB/CMakeLists.txt index 79bdce4277c75..ceeb173a99e1d 100644 --- a/lldb/source/Plugins/SymbolFile/PDB/CMakeLists.txt +++ b/lldb/source/Plugins/SymbolFile/PDB/CMakeLists.txt @@ -8,6 +8,7 @@ add_lldb_library(lldbPluginSymbolFilePDB PLUGIN lldbPluginSymbolFileNativePDB lldbSymbol lldbUtility + lldbPluginTypeSystemClang CLANG_LIBS clangAST clangLex diff --git a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp index eb382387df37c..8f1a40a82150e 100644 --- a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp +++ b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp @@ -14,10 +14,10 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" +#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Module.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangASTMetadata.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/Declaration.h" #include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/TypeMap.h" diff --git a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.h b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.h index 6ded624fa435f..06ae32c664c5e 100644 --- a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.h +++ b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.h @@ -11,7 +11,7 @@ #include "lldb/lldb-forward.h" -#include "lldb/Symbol/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" class SymbolFilePDB; diff --git a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp index b7e54682b86fa..b55fa1fef1e85 100644 --- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp +++ b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp @@ -13,9 +13,9 @@ #include "clang/Lex/Lexer.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/LineTable.h" #include "lldb/Symbol/ObjectFile.h" diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp index fb271a988cb8f..d822698e26e09 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp @@ -9,13 +9,12 @@ #include "AppleGetItemInfoHandler.h" - +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Module.h" #include "lldb/Core/Value.h" #include "lldb/Expression/DiagnosticManager.h" #include "lldb/Expression/FunctionCaller.h" #include "lldb/Expression/UtilityFunction.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp index 3d7c31bd01164..99b403ffdc163 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp @@ -9,13 +9,12 @@ #include "AppleGetPendingItemsHandler.h" - +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Module.h" #include "lldb/Core/Value.h" #include "lldb/Expression/DiagnosticManager.h" #include "lldb/Expression/FunctionCaller.h" #include "lldb/Expression/UtilityFunction.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp index 20fa540a1e3f0..5a69578462e04 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp @@ -8,12 +8,12 @@ #include "AppleGetQueuesHandler.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Module.h" #include "lldb/Core/Value.h" #include "lldb/Expression/DiagnosticManager.h" #include "lldb/Expression/FunctionCaller.h" #include "lldb/Expression/UtilityFunction.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp index d3ee8a852f40d..4b99b56eef8f3 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp @@ -9,14 +9,13 @@ #include "AppleGetThreadItemInfoHandler.h" - +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Module.h" #include "lldb/Core/Value.h" #include "lldb/Expression/DiagnosticManager.h" #include "lldb/Expression/Expression.h" #include "lldb/Expression/FunctionCaller.h" #include "lldb/Expression/UtilityFunction.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/CMakeLists.txt b/lldb/source/Plugins/SystemRuntime/MacOSX/CMakeLists.txt index ac5781b98b09c..04d30652ba4b4 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/CMakeLists.txt +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/CMakeLists.txt @@ -14,4 +14,5 @@ add_lldb_library(lldbPluginSystemRuntimeMacOSX PLUGIN lldbTarget lldbUtility lldbPluginProcessUtility + lldbPluginTypeSystemClang ) diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp index a42671331c8e6..41a7a525385b7 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp @@ -7,12 +7,12 @@ //===----------------------------------------------------------------------===// #include "Plugins/Process/Utility/HistoryThread.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Target/Process.h" diff --git a/lldb/source/Plugins/TypeSystem/CMakeLists.txt b/lldb/source/Plugins/TypeSystem/CMakeLists.txt new file mode 100644 index 0000000000000..17c40aee44cc2 --- /dev/null +++ b/lldb/source/Plugins/TypeSystem/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(Clang) diff --git a/lldb/source/Plugins/TypeSystem/Clang/CMakeLists.txt b/lldb/source/Plugins/TypeSystem/Clang/CMakeLists.txt new file mode 100644 index 0000000000000..37a3142da7274 --- /dev/null +++ b/lldb/source/Plugins/TypeSystem/Clang/CMakeLists.txt @@ -0,0 +1,20 @@ +add_lldb_library(lldbPluginTypeSystemClang PLUGIN + TypeSystemClang.cpp + + LINK_LIBS + lldbCore + lldbSymbol + lldbTarget + lldbUtility + lldbPluginExpressionParserClang + lldbPluginSymbolFileDWARF + lldbPluginSymbolFilePDB + lldbPluginObjCRuntime + CLANG_LIBS + clangAST + clangBasic + clangFrontend + clangSema + LINK_COMPONENTS + Support +) diff --git a/lldb/source/Symbol/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp similarity index 99% rename from lldb/source/Symbol/TypeSystemClang.cpp rename to lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index b21e9715f0afc..ba4a30f373009 100644 --- a/lldb/source/Symbol/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include "lldb/Symbol/TypeSystemClang.h" +#include "TypeSystemClang.h" #include "llvm/Support/FormatAdapters.h" #include "llvm/Support/FormatVariadic.h" @@ -39,9 +39,13 @@ #include "llvm/Support/Signals.h" #include "llvm/Support/Threading.h" +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h" +#include "Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h" #include "Plugins/ExpressionParser/Clang/ClangFunctionCaller.h" #include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h" #include "Plugins/ExpressionParser/Clang/ClangUserExpression.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" #include "Plugins/ExpressionParser/Clang/ClangUtilityFunction.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/Flags.h" @@ -52,10 +56,6 @@ #include "lldb/Core/StreamFile.h" #include "lldb/Core/ThreadSafeDenseMap.h" #include "lldb/Core/UniqueCStringMap.h" -#include "lldb/Symbol/ClangASTImporter.h" -#include "lldb/Symbol/ClangASTMetadata.h" -#include "lldb/Symbol/ClangExternalASTSourceCallbacks.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolFile.h" #include "lldb/Target/ExecutionContext.h" diff --git a/lldb/include/lldb/Symbol/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h similarity index 100% rename from lldb/include/lldb/Symbol/TypeSystemClang.h rename to lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h diff --git a/lldb/source/Symbol/CMakeLists.txt b/lldb/source/Symbol/CMakeLists.txt index 46fb9a892c3e9..95bf156ff538b 100644 --- a/lldb/source/Symbol/CMakeLists.txt +++ b/lldb/source/Symbol/CMakeLists.txt @@ -7,17 +7,11 @@ endif() add_lldb_library(lldbSymbol ArmUnwindInfo.cpp Block.cpp - TypeSystemClang.cpp - ClangASTImporter.cpp - ClangASTMetadata.cpp - ClangExternalASTSourceCallbacks.cpp - ClangUtil.cpp CompactUnwindInfo.cpp CompileUnit.cpp CompilerDecl.cpp CompilerDeclContext.cpp CompilerType.cpp - CxxModuleHandler.cpp DWARFCallFrameInfo.cpp DebugMacros.cpp Declaration.cpp @@ -51,16 +45,7 @@ add_lldb_library(lldbSymbol lldbHost lldbTarget lldbUtility - lldbPluginExpressionParserClang - lldbPluginSymbolFileDWARF - lldbPluginSymbolFilePDB lldbPluginObjCLanguage - lldbPluginObjCRuntime - - CLANG_LIBS - clangAST - clangBasic - clangFrontend LINK_COMPONENTS Support diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index 3b2a5bbc6d906..88f965b782557 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -36,8 +36,8 @@ #include "lldb/Interpreter/OptionGroupWatchpoint.h" #include "lldb/Interpreter/OptionValues.h" #include "lldb/Interpreter/Property.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangASTImporter.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/Symbol.h" diff --git a/lldb/tools/lldb-test/SystemInitializerTest.cpp b/lldb/tools/lldb-test/SystemInitializerTest.cpp index 0d637f8dfd06a..8385653bc4197 100644 --- a/lldb/tools/lldb-test/SystemInitializerTest.cpp +++ b/lldb/tools/lldb-test/SystemInitializerTest.cpp @@ -12,7 +12,6 @@ #include "lldb/Host/Host.h" #include "lldb/Initialization/SystemInitializerCommon.h" #include "lldb/Interpreter/CommandInterpreter.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Utility/Timer.h" #include "Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h" @@ -76,6 +75,7 @@ #include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h" #include "Plugins/SymbolVendor/ELF/SymbolVendorELF.h" #include "Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h" #include "Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h" diff --git a/lldb/tools/lldb-test/lldb-test.cpp b/lldb/tools/lldb-test/lldb-test.cpp index 696f64cdeff9e..0bd532fa2945a 100644 --- a/lldb/tools/lldb-test/lldb-test.cpp +++ b/lldb/tools/lldb-test/lldb-test.cpp @@ -10,6 +10,7 @@ #include "SystemInitializerTest.h" #include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" @@ -18,7 +19,6 @@ #include "lldb/Initialization/SystemLifetimeManager.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/LineTable.h" #include "lldb/Symbol/SymbolFile.h" diff --git a/lldb/unittests/Expression/CMakeLists.txt b/lldb/unittests/Expression/CMakeLists.txt index 25e94f4d88fdd..2f5304ab212d9 100644 --- a/lldb/unittests/Expression/CMakeLists.txt +++ b/lldb/unittests/Expression/CMakeLists.txt @@ -8,6 +8,7 @@ add_lldb_unittest(ExpressionTests LINK_LIBS lldbCore lldbPluginExpressionParserClang + lldbPluginTypeSystemClang lldbUtility lldbUtilityHelpers LLVMTestingSupport diff --git a/lldb/unittests/Expression/ClangExpressionDeclMapTest.cpp b/lldb/unittests/Expression/ClangExpressionDeclMapTest.cpp index 41a4868fa8211..7d1e0ed3b3657 100644 --- a/lldb/unittests/Expression/ClangExpressionDeclMapTest.cpp +++ b/lldb/unittests/Expression/ClangExpressionDeclMapTest.cpp @@ -7,12 +7,12 @@ //===----------------------------------------------------------------------===// #include "Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "TestingSupport/SubsystemRAII.h" #include "TestingSupport/Symbol/ClangTestUtils.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/HostInfo.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/lldb-defines.h" #include "gtest/gtest.h" diff --git a/lldb/unittests/Symbol/CMakeLists.txt b/lldb/unittests/Symbol/CMakeLists.txt index d726f6ecad098..76c7b645f277a 100644 --- a/lldb/unittests/Symbol/CMakeLists.txt +++ b/lldb/unittests/Symbol/CMakeLists.txt @@ -15,6 +15,7 @@ add_lldb_unittest(SymbolTests lldbPluginObjectFileMachO lldbPluginSymbolFileDWARF lldbPluginSymbolFileSymtab + lldbPluginTypeSystemClang LLVMTestingSupport ) diff --git a/lldb/unittests/Symbol/TestClangASTImporter.cpp b/lldb/unittests/Symbol/TestClangASTImporter.cpp index e3bf13eb068e7..bf9a25c91cb6a 100644 --- a/lldb/unittests/Symbol/TestClangASTImporter.cpp +++ b/lldb/unittests/Symbol/TestClangASTImporter.cpp @@ -8,14 +8,14 @@ #include "gtest/gtest.h" +#include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" +#include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h" +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "TestingSupport/SubsystemRAII.h" #include "TestingSupport/Symbol/ClangTestUtils.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/HostInfo.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangASTImporter.h" -#include "lldb/Symbol/ClangASTMetadata.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/Declaration.h" #include "clang/AST/DeclCXX.h" diff --git a/lldb/unittests/Symbol/TestLineEntry.cpp b/lldb/unittests/Symbol/TestLineEntry.cpp index 0dbfb65815151..d058b4f3d0430 100644 --- a/lldb/unittests/Symbol/TestLineEntry.cpp +++ b/lldb/unittests/Symbol/TestLineEntry.cpp @@ -14,9 +14,9 @@ #include "Plugins/ObjectFile/Mach-O/ObjectFileMachO.h" #include "Plugins/SymbolFile/DWARF/DWARFASTParserClang.h" #include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "TestingSupport/SubsystemRAII.h" #include "TestingSupport/TestUtilities.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Core/Module.h" #include "lldb/Host/FileSystem.h" diff --git a/lldb/unittests/Symbol/TestTypeSystemClang.cpp b/lldb/unittests/Symbol/TestTypeSystemClang.cpp index a9580e43c243d..8b716be955e80 100644 --- a/lldb/unittests/Symbol/TestTypeSystemClang.cpp +++ b/lldb/unittests/Symbol/TestTypeSystemClang.cpp @@ -6,12 +6,12 @@ // //===----------------------------------------------------------------------===// +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "TestingSupport/SubsystemRAII.h" #include "TestingSupport/Symbol/ClangTestUtils.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/HostInfo.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangUtil.h" #include "lldb/Symbol/Declaration.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/ExprCXX.h" diff --git a/lldb/unittests/SymbolFile/DWARF/CMakeLists.txt b/lldb/unittests/SymbolFile/DWARF/CMakeLists.txt index 57ee46316e03f..0a4d3cc2938da 100644 --- a/lldb/unittests/SymbolFile/DWARF/CMakeLists.txt +++ b/lldb/unittests/SymbolFile/DWARF/CMakeLists.txt @@ -9,6 +9,7 @@ add_lldb_unittest(SymbolFileDWARFTests lldbPluginObjectFilePECOFF lldbPluginSymbolFileDWARF lldbPluginSymbolFilePDB + lldbPluginTypeSystemClang lldbUtilityHelpers LINK_COMPONENTS Support diff --git a/lldb/unittests/SymbolFile/DWARF/SymbolFileDWARFTests.cpp b/lldb/unittests/SymbolFile/DWARF/SymbolFileDWARFTests.cpp index 2ee89519b19ff..065efedc70226 100644 --- a/lldb/unittests/SymbolFile/DWARF/SymbolFileDWARFTests.cpp +++ b/lldb/unittests/SymbolFile/DWARF/SymbolFileDWARFTests.cpp @@ -20,6 +20,7 @@ #include "Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h" #include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h" #include "Plugins/SymbolFile/PDB/SymbolFilePDB.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "TestingSupport/SubsystemRAII.h" #include "TestingSupport/TestUtilities.h" #include "lldb/Core/Address.h" @@ -27,7 +28,6 @@ #include "lldb/Core/ModuleSpec.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/HostInfo.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/LineTable.h" #include "lldb/Utility/ArchSpec.h" @@ -35,8 +35,6 @@ #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/StreamString.h" - - using namespace lldb; using namespace lldb_private; diff --git a/lldb/unittests/SymbolFile/PDB/CMakeLists.txt b/lldb/unittests/SymbolFile/PDB/CMakeLists.txt index 75e4b50424966..8fc2167ee6ba2 100644 --- a/lldb/unittests/SymbolFile/PDB/CMakeLists.txt +++ b/lldb/unittests/SymbolFile/PDB/CMakeLists.txt @@ -8,6 +8,7 @@ add_lldb_unittest(SymbolFilePDBTests lldbPluginObjectFilePECOFF lldbPluginSymbolFileDWARF lldbPluginSymbolFilePDB + lldbPluginTypeSystemClang lldbUtilityHelpers LLVMTestingSupport LINK_COMPONENTS diff --git a/lldb/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp b/lldb/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp index 73eef664c2b89..be3781b37f6bf 100644 --- a/lldb/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp +++ b/lldb/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp @@ -18,13 +18,13 @@ #include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h" #include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h" #include "Plugins/SymbolFile/PDB/SymbolFilePDB.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "TestingSupport/TestUtilities.h" #include "lldb/Core/Address.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/HostInfo.h" -#include "lldb/Symbol/TypeSystemClang.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/LineTable.h" #include "lldb/Symbol/TypeMap.h" diff --git a/lldb/unittests/TestingSupport/Symbol/ClangTestUtils.h b/lldb/unittests/TestingSupport/Symbol/ClangTestUtils.h index 9ee657d3a5338..896996512fcf7 100644 --- a/lldb/unittests/TestingSupport/Symbol/ClangTestUtils.h +++ b/lldb/unittests/TestingSupport/Symbol/ClangTestUtils.h @@ -9,9 +9,9 @@ #ifndef LLDB_UNITTESTS_TESTINGSUPPORT_SYMBOL_CLANGTESTUTILS_H #define LLDB_UNITTESTS_TESTINGSUPPORT_SYMBOL_CLANGTESTUTILS_H +#include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Host/HostInfo.h" -#include "lldb/Symbol/TypeSystemClang.h" -#include "lldb/Symbol/ClangUtil.h" namespace lldb_private { namespace clang_utils { From 077ce0038406b67e55d8f1fcba0c61880a5d1b09 Mon Sep 17 00:00:00 2001 From: Raphael Isemann Date: Wed, 12 Feb 2020 09:10:19 +0100 Subject: [PATCH 152/286] [lldb] Move implementation of GetDisplayName to TypeSystem class CompilerType doesn't implement logic. --- lldb/include/lldb/Symbol/TypeSystem.h | 2 ++ lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h | 4 ++++ lldb/source/Symbol/CompilerType.cpp | 6 +++++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lldb/include/lldb/Symbol/TypeSystem.h b/lldb/include/lldb/Symbol/TypeSystem.h index 83c278b9b19eb..d16e772b1c6c4 100644 --- a/lldb/include/lldb/Symbol/TypeSystem.h +++ b/lldb/include/lldb/Symbol/TypeSystem.h @@ -204,6 +204,8 @@ class TypeSystem : public PluginInterface { virtual ConstString GetTypeName(lldb::opaque_compiler_type_t type) = 0; + virtual ConstString GetDisplayTypeName(lldb::opaque_compiler_type_t type) = 0; + virtual uint32_t GetTypeInfo(lldb::opaque_compiler_type_t type, CompilerType *pointee_or_element_compiler_type) = 0; diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index b2499cbdc8f9c..fd3131f1ed515 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -570,6 +570,10 @@ class TypeSystemClang : public TypeSystem { ConstString GetTypeName(lldb::opaque_compiler_type_t type) override; + ConstString GetDisplayTypeName(lldb::opaque_compiler_type_t type) override { + return GetTypeName(type); + } + uint32_t GetTypeInfo(lldb::opaque_compiler_type_t type, CompilerType *pointee_or_element_compiler_type) override; diff --git a/lldb/source/Symbol/CompilerType.cpp b/lldb/source/Symbol/CompilerType.cpp index 379854b6ad22d..0d56e86410585 100644 --- a/lldb/source/Symbol/CompilerType.cpp +++ b/lldb/source/Symbol/CompilerType.cpp @@ -288,7 +288,11 @@ ConstString CompilerType::GetTypeName() const { return ConstString(""); } -ConstString CompilerType::GetDisplayTypeName() const { return GetTypeName(); } +ConstString CompilerType::GetDisplayTypeName() const { + if (IsValid()) + return m_type_system->GetDisplayTypeName(m_type); + return ConstString(""); +} uint32_t CompilerType::GetTypeInfo( CompilerType *pointee_or_element_compiler_type) const { From 8c4f032af3b86d6e26fa8a1ef0a88b6287f9b3cd Mon Sep 17 00:00:00 2001 From: Raphael Isemann Date: Wed, 19 Feb 2020 09:36:37 +0100 Subject: [PATCH 153/286] [lldb] Let TypeSystemClang::GetDisplayTypeName remove anonymous and inline namespaces. Summary: Currently when printing data types we include implicit scopes such as inline namespaces or anonymous namespaces. This leads to command output like this (for `std::set` with X being in an anonymous namespace): ``` (lldb) print my_set (std::__1::set<(anonymous namespace)::X, std::__1::less<(anonymous namespace)::X>, std::__1::allocator<(anonymous namespace)::X> >) $0 = size=0 {} ``` This patch removes all the implicit scopes when printing type names in TypeSystemClang::GetDisplayTypeName so that our output now looks like this: ``` (lldb) print my_set (std::set, std::allocator >) $0 = size=0 {} ``` As previously GetDisplayTypeName and GetTypeName had the same output we actually often used the two as if they are the same method (they were in fact using the same implementation), so this patch also fixes the places where we actually want the display type name and not the actual type name. Note that this doesn't touch the `GetTypeName` class that for example the data formatters use, so this patch is only changes the way we display types to the user. The full type name can also still be found when passing '-R' to see the raw output of a variable in case someone is somehow interested in that. Partly fixes rdar://problem/59292534 Reviewers: shafik, jingham Reviewed By: shafik Subscribers: christof, JDevlieghere, lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D74478 --- lldb/packages/Python/lldbsuite/test/lldbtest.py | 2 +- lldb/source/DataFormatters/FormatManager.cpp | 2 +- .../Plugins/Language/CPlusPlus/LibCxxVariant.cpp | 2 +- .../Plugins/TypeSystem/Clang/TypeSystemClang.cpp | 13 +++++++++++++ .../Plugins/TypeSystem/Clang/TypeSystemClang.h | 4 +--- .../import-std-module/basic/TestImportStdModule.py | 2 +- .../conflicts/TestStdModuleWithConflicts.py | 6 +++--- .../TestDataFormatterLibcxxForwardList.py | 3 +-- .../iterator/TestDataFormatterLibccIterator.py | 3 +-- .../libcxx/map/TestDataFormatterLibccMap.py | 2 +- .../multimap/TestDataFormatterLibccMultiMap.py | 3 +-- .../multiset/TestDataFormatterLibcxxMultiSet.py | 5 ++--- .../data-formatter-stl/libcxx/multiset/main.cpp | 9 +++------ .../libcxx/queue/TestDataFormatterLibcxxQueue.py | 5 ++--- .../libcxx/set/TestDataFormatterLibcxxSet.py | 5 ++--- .../data-formatter-stl/libcxx/set/main.cpp | 9 +++------ .../libcxx/string/TestDataFormatterLibcxxString.py | 3 +-- .../libcxx/tuple/TestDataFormatterLibcxxTuple.py | 3 +-- .../libcxx/unordered/TestDataFormatterUnordered.py | 3 +-- .../variant/TestDataFormatterLibcxxVariant.py | 2 +- lldb/test/Shell/SymbolFile/NativePDB/ast-types.cpp | 6 +++--- 21 files changed, 44 insertions(+), 48 deletions(-) diff --git a/lldb/packages/Python/lldbsuite/test/lldbtest.py b/lldb/packages/Python/lldbsuite/test/lldbtest.py index 19020ac319724..e081be59b7be3 100644 --- a/lldb/packages/Python/lldbsuite/test/lldbtest.py +++ b/lldb/packages/Python/lldbsuite/test/lldbtest.py @@ -2397,7 +2397,7 @@ def expect_expr( "Unexpected failure with msg: " + eval_result.GetError().GetCString()) if result_type: - self.assertEqual(result_type, eval_result.GetTypeName()) + self.assertEqual(result_type, eval_result.GetDisplayTypeName()) if result_value: self.assertEqual(result_value, eval_result.GetValue()) diff --git a/lldb/source/DataFormatters/FormatManager.cpp b/lldb/source/DataFormatters/FormatManager.cpp index 08fc56a72eabb..912bf38073b84 100644 --- a/lldb/source/DataFormatters/FormatManager.cpp +++ b/lldb/source/DataFormatters/FormatManager.cpp @@ -193,7 +193,7 @@ void FormatManager::GetPossibleMatches( entries.push_back( {type_name, reason, did_strip_ptr, did_strip_ref, did_strip_typedef}); - ConstString display_type_name(compiler_type.GetDisplayTypeName()); + ConstString display_type_name(compiler_type.GetTypeName()); if (display_type_name != type_name) entries.push_back({display_type_name, reason, did_strip_ptr, did_strip_ref, did_strip_typedef}); diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp index 62945bd3ce80b..1b33ecf958b54 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxVariant.cpp @@ -159,7 +159,7 @@ bool LibcxxVariantSummaryProvider(ValueObject &valobj, Stream &stream, if (!template_type) return false; - stream.Printf(" Active Type = %s ", template_type.GetTypeName().GetCString()); + stream << " Active Type = " << template_type.GetDisplayTypeName() << " "; return true; } diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index ba4a30f373009..d55ace2762bd5 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -3510,6 +3510,19 @@ ConstString TypeSystemClang::GetTypeName(lldb::opaque_compiler_type_t type) { return ConstString(type_name); } +ConstString +TypeSystemClang::GetDisplayTypeName(lldb::opaque_compiler_type_t type) { + if (!type) + return ConstString(); + + clang::QualType qual_type(GetQualType(type)); + clang::PrintingPolicy printing_policy(getASTContext().getPrintingPolicy()); + printing_policy.SuppressTagKeyword = true; + printing_policy.SuppressScope = false; + printing_policy.SuppressUnwrittenScope = true; + return ConstString(qual_type.getAsString(printing_policy)); +} + uint32_t TypeSystemClang::GetTypeInfo(lldb::opaque_compiler_type_t type, CompilerType *pointee_or_element_clang_type) { diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index fd3131f1ed515..441732ad54f62 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -570,9 +570,7 @@ class TypeSystemClang : public TypeSystem { ConstString GetTypeName(lldb::opaque_compiler_type_t type) override; - ConstString GetDisplayTypeName(lldb::opaque_compiler_type_t type) override { - return GetTypeName(type); - } + ConstString GetDisplayTypeName(lldb::opaque_compiler_type_t type) override; uint32_t GetTypeInfo(lldb::opaque_compiler_type_t type, CompilerType *pointee_or_element_compiler_type) override; diff --git a/lldb/test/API/commands/expression/import-std-module/basic/TestImportStdModule.py b/lldb/test/API/commands/expression/import-std-module/basic/TestImportStdModule.py index de0d796505e77..0cea2d372f4e2 100644 --- a/lldb/test/API/commands/expression/import-std-module/basic/TestImportStdModule.py +++ b/lldb/test/API/commands/expression/import-std-module/basic/TestImportStdModule.py @@ -25,7 +25,7 @@ def test(self): self.expect("expr std::abs(-42)", substrs=['(int) $0 = 42']) self.expect("expr std::div(2, 1).quot", substrs=['(int) $1 = 2']) # Using types from std. - self.expect("expr (std::size_t)33U", substrs=['(size_t) $2 = 33']) + self.expect_expr("(std::size_t)33U", result_type="std::size_t", result_value="33") # Calling templated functions that return non-template types. self.expect("expr char char_a = 'b'; char char_b = 'a'; std::swap(char_a, char_b); char_a", substrs=["(char) $3 = 'a'"]) diff --git a/lldb/test/API/commands/expression/import-std-module/conflicts/TestStdModuleWithConflicts.py b/lldb/test/API/commands/expression/import-std-module/conflicts/TestStdModuleWithConflicts.py index ad5322baab007..6b817c882ad87 100644 --- a/lldb/test/API/commands/expression/import-std-module/conflicts/TestStdModuleWithConflicts.py +++ b/lldb/test/API/commands/expression/import-std-module/conflicts/TestStdModuleWithConflicts.py @@ -25,8 +25,8 @@ def test(self): "// Set break point at this line.", lldb.SBFileSpec("main.cpp")) self.runCmd("settings set target.import-std-module true") - self.expect("expr std::abs(-42)", substrs=['(int) $0 = 42']) - self.expect("expr std::div(2, 1).quot", substrs=['(int) $1 = 2']) - self.expect("expr (std::size_t)33U", substrs=['(size_t) $2 = 33']) + self.expect_expr("std::abs(-42)", result_type="int", result_value="42") + self.expect_expr("std::div(2, 1).quot", result_type="int", result_value="2") + self.expect_expr("(std::size_t)33U", result_type="std::size_t", result_value="33") self.expect("expr char char_a = 'b'; char char_b = 'a'; std::swap(char_a, char_b); char_a", substrs=["(char) $3 = 'a'"]) diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/forward_list/TestDataFormatterLibcxxForwardList.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/forward_list/TestDataFormatterLibcxxForwardList.py index a9983dd045e99..efbc4c538798e 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/forward_list/TestDataFormatterLibcxxForwardList.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/forward_list/TestDataFormatterLibcxxForwardList.py @@ -17,8 +17,7 @@ class TestDataFormatterLibcxxForwardList(TestBase): def setUp(self): TestBase.setUp(self) self.line = line_number('main.cpp', '// break here') - ns = 'ndk' if lldbplatformutil.target_is_android() else '' - self.namespace = 'std::__' + ns + '1' + self.namespace = 'std' @add_test_categories(["libc++"]) def test(self): diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/iterator/TestDataFormatterLibccIterator.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/iterator/TestDataFormatterLibccIterator.py index 2ff3d63d004d9..9081edc2bfc62 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/iterator/TestDataFormatterLibccIterator.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/iterator/TestDataFormatterLibccIterator.py @@ -19,8 +19,7 @@ def setUp(self): TestBase.setUp(self) # Find the line number to break at. self.line = line_number('main.cpp', '// Set break point at this line.') - ns = 'ndk' if lldbplatformutil.target_is_android() else '' - self.namespace = 'std::__' + ns + '1' + self.namespace = 'std' @add_test_categories(["libc++"]) def test_with_run_command(self): diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/map/TestDataFormatterLibccMap.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/map/TestDataFormatterLibccMap.py index d9da0c3886e28..0644742c5fb11 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/map/TestDataFormatterLibccMap.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/map/TestDataFormatterLibccMap.py @@ -17,7 +17,7 @@ class LibcxxMapDataFormatterTestCase(TestBase): def setUp(self): TestBase.setUp(self) ns = 'ndk' if lldbplatformutil.target_is_android() else '' - self.namespace = 'std::__' + ns + '1' + self.namespace = 'std' @add_test_categories(["libc++"]) def test_with_run_command(self): diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/multimap/TestDataFormatterLibccMultiMap.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/multimap/TestDataFormatterLibccMultiMap.py index 39adc04e49ae0..3f3a2ba0cb12a 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/multimap/TestDataFormatterLibccMultiMap.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/multimap/TestDataFormatterLibccMultiMap.py @@ -17,8 +17,7 @@ class LibcxxMultiMapDataFormatterTestCase(TestBase): def setUp(self): TestBase.setUp(self) - ns = 'ndk' if lldbplatformutil.target_is_android() else '' - self.namespace = 'std::__' + ns + '1' + self.namespace = 'std' @add_test_categories(["libc++"]) def test_with_run_command(self): diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/multiset/TestDataFormatterLibcxxMultiSet.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/multiset/TestDataFormatterLibcxxMultiSet.py index 621b22a538c34..a21d537eaea28 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/multiset/TestDataFormatterLibcxxMultiSet.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/multiset/TestDataFormatterLibcxxMultiSet.py @@ -16,13 +16,12 @@ class LibcxxMultiSetDataFormatterTestCase(TestBase): def setUp(self): TestBase.setUp(self) - ns = 'ndk' if lldbplatformutil.target_is_android() else '' - self.namespace = 'std::__' + ns + '1' + self.namespace = 'std' def getVariableType(self, name): var = self.frame().FindVariable(name) self.assertTrue(var.IsValid()) - return var.GetType().GetCanonicalType().GetName() + return var.GetType().GetDisplayTypeName() def check_ii(self, var_name): """ This checks the value of the bitset stored in ii at the call to by_ref_and_ptr. diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/multiset/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/multiset/main.cpp index dd3d8be4ae915..6813b6eca395b 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/multiset/main.cpp +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/multiset/main.cpp @@ -1,9 +1,6 @@ #include #include -typedef std::multiset intset; -typedef std::multiset stringset; - int g_the_foo = 0; int thefoo_rw(int arg = 1) @@ -16,7 +13,7 @@ int thefoo_rw(int arg = 1) return g_the_foo; } -void by_ref_and_ptr(intset &ref, intset *ptr) +void by_ref_and_ptr(std::multiset &ref, std::multiset *ptr) { // Stop here to check by ref and ptr return; @@ -24,7 +21,7 @@ void by_ref_and_ptr(intset &ref, intset *ptr) int main() { - intset ii; + std::multiset ii; thefoo_rw(1); // Set break point at this line. ii.insert(0); @@ -43,7 +40,7 @@ int main() ii.clear(); thefoo_rw(1); // Set break point at this line. - stringset ss; + std::multiset ss; thefoo_rw(1); // Set break point at this line. ss.insert("a"); diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/queue/TestDataFormatterLibcxxQueue.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/queue/TestDataFormatterLibcxxQueue.py index b163fa56fae53..f2f9f670c7144 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/queue/TestDataFormatterLibcxxQueue.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/queue/TestDataFormatterLibcxxQueue.py @@ -16,15 +16,14 @@ class TestDataFormatterLibcxxQueue(TestBase): def setUp(self): TestBase.setUp(self) - ns = 'ndk' if lldbplatformutil.target_is_android() else '' - self.namespace = 'std::__' + ns + '1' + self.namespace = 'std' def check_variable(self, name): var = self.frame().FindVariable(name) self.assertTrue(var.IsValid()) queue = self.namespace + '::queue' - self.assertTrue(queue in var.GetTypeName()) + self.assertTrue(queue in var.GetDisplayTypeName()) self.assertEqual(var.GetNumChildren(), 5) for i in range(5): ch = var.GetChildAtIndex(i) diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/set/TestDataFormatterLibcxxSet.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/set/TestDataFormatterLibcxxSet.py index 738df85d05193..82f4335245f1f 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/set/TestDataFormatterLibcxxSet.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/set/TestDataFormatterLibcxxSet.py @@ -16,13 +16,12 @@ class LibcxxSetDataFormatterTestCase(TestBase): def setUp(self): TestBase.setUp(self) - ns = 'ndk' if lldbplatformutil.target_is_android() else '' - self.namespace = 'std::__' + ns + '1' + self.namespace = 'std' def getVariableType(self, name): var = self.frame().FindVariable(name) self.assertTrue(var.IsValid()) - return var.GetType().GetCanonicalType().GetName() + return var.GetType().GetDisplayTypeName() def check_ii(self, var_name): """ This checks the value of the bitset stored in ii at the call to by_ref_and_ptr. diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/set/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/set/main.cpp index df39e9746c03a..1d48f9b9ad1a5 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/set/main.cpp +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/set/main.cpp @@ -1,9 +1,6 @@ #include #include -typedef std::set intset; -typedef std::set stringset; - int g_the_foo = 0; int thefoo_rw(int arg = 1) @@ -16,7 +13,7 @@ int thefoo_rw(int arg = 1) return g_the_foo; } -void by_ref_and_ptr(intset &ref, intset *ptr) +void by_ref_and_ptr(std::set &ref, std::set *ptr) { // Stop here to check by ref and ptr return; @@ -24,7 +21,7 @@ void by_ref_and_ptr(intset &ref, intset *ptr) int main() { - intset ii; + std::set ii; thefoo_rw(1); // Set break point at this line. ii.insert(0); @@ -43,7 +40,7 @@ int main() ii.clear(); thefoo_rw(1); // Set break point at this line. - stringset ss; + std::set ss; thefoo_rw(1); // Set break point at this line. ss.insert("a"); diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/TestDataFormatterLibcxxString.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/TestDataFormatterLibcxxString.py index f04ec6d402b34..3753067113b1a 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/TestDataFormatterLibcxxString.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/TestDataFormatterLibcxxString.py @@ -20,8 +20,7 @@ def setUp(self): TestBase.setUp(self) # Find the line number to break at. self.line = line_number('main.cpp', '// Set break point at this line.') - ns = 'ndk' if lldbplatformutil.target_is_android() else '' - self.namespace = 'std::__' + ns + '1' + self.namespace = 'std' @add_test_categories(["libc++"]) @expectedFailureAll(bugnumber="llvm.org/pr36109", debug_info="gmodules", triple=".*-android") diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/tuple/TestDataFormatterLibcxxTuple.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/tuple/TestDataFormatterLibcxxTuple.py index 57b777837165e..171f9a8e5c078 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/tuple/TestDataFormatterLibcxxTuple.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/tuple/TestDataFormatterLibcxxTuple.py @@ -17,8 +17,7 @@ class TestDataFormatterLibcxxTuple(TestBase): def setUp(self): TestBase.setUp(self) self.line = line_number('main.cpp', '// break here') - ns = 'ndk' if lldbplatformutil.target_is_android() else '' - self.namespace = 'std::__' + ns + '1' + self.namespace = 'std' @add_test_categories(["libc++"]) def test(self): diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unordered/TestDataFormatterUnordered.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unordered/TestDataFormatterUnordered.py index 9566af0313092..3519daec6ec41 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unordered/TestDataFormatterUnordered.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unordered/TestDataFormatterUnordered.py @@ -16,8 +16,7 @@ class LibcxxUnorderedDataFormatterTestCase(TestBase): def setUp(self): TestBase.setUp(self) - ns = 'ndk' if lldbplatformutil.target_is_android() else '' - self.namespace = 'std::__' + ns + '1' + self.namespace = 'std' @add_test_categories(["libc++"]) def test_with_run_command(self): diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/variant/TestDataFormatterLibcxxVariant.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/variant/TestDataFormatterLibcxxVariant.py index a2a6b74faa41a..cea4fd6bf1c3f 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/variant/TestDataFormatterLibcxxVariant.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/variant/TestDataFormatterLibcxxVariant.py @@ -51,7 +51,7 @@ def test_with_run_command(self): '}']) self.expect("frame variable v_v1", - substrs=['v_v1 = Active Type = std::__1::variant {', + substrs=['v_v1 = Active Type = std::variant {', 'Value = Active Type = int {', 'Value = 12', '}', diff --git a/lldb/test/Shell/SymbolFile/NativePDB/ast-types.cpp b/lldb/test/Shell/SymbolFile/NativePDB/ast-types.cpp index 9d4ac139f5927..c4d50433a3b57 100644 --- a/lldb/test/Shell/SymbolFile/NativePDB/ast-types.cpp +++ b/lldb/test/Shell/SymbolFile/NativePDB/ast-types.cpp @@ -102,9 +102,9 @@ Anonymous>::D AnonABCVoidD; // CHECK: (A::C<-1>::D) ACNeg1D = (ACDMember = 0, CPtr = 0x{{0+}}) // CHECK: (A::D) AD = {} // CHECK: (A::D::E) ADE = (ADDMember = 0) -// CHECK: ((anonymous namespace)::Anonymous) AnonInt = (AnonymousMember = 0) -// CHECK: ((anonymous namespace)::Anonymous>) AnonABCVoid = (AnonymousMember = 0) -// CHECK: ((anonymous namespace)::Anonymous>::D) AnonABCVoidD = (AnonymousDMember = 0) +// CHECK: (Anonymous) AnonInt = (AnonymousMember = 0) +// CHECK: (Anonymous>) AnonABCVoid = (AnonymousMember = 0) +// CHECK: (Anonymous>::D) AnonABCVoidD = (AnonymousDMember = 0) // CHECK: Dumping clang ast for 1 modules. // CHECK: TranslationUnitDecl {{.*}} // CHECK: |-CXXRecordDecl {{.*}} class TrivialC definition From 45090b212f08567f215aa07489996d9875351c0d Mon Sep 17 00:00:00 2001 From: Davide Italiano Date: Mon, 6 Apr 2020 16:35:30 -0700 Subject: [PATCH 154/286] [MachineCSE] Don't carry the wrong location when hoisting PR: 45425 Differential Revision: https://reviews.llvm.org/D77604 --- llvm/lib/CodeGen/MachineCSE.cpp | 7 ++ .../X86/machinecse-wrongdebug-hoist.ll | 80 +++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 llvm/test/DebugInfo/X86/machinecse-wrongdebug-hoist.ll diff --git a/llvm/lib/CodeGen/MachineCSE.cpp b/llvm/lib/CodeGen/MachineCSE.cpp index 9561a06ce8dfd..8c195adb444d5 100644 --- a/llvm/lib/CodeGen/MachineCSE.cpp +++ b/llvm/lib/CodeGen/MachineCSE.cpp @@ -831,6 +831,13 @@ bool MachineCSE::ProcessBlockPRE(MachineDominatorTree *DT, continue; MachineInstr &NewMI = TII->duplicate(*CMBB, CMBB->getFirstTerminator(), *MI); + + // When hoisting, make sure we don't carry the debug location of + // the original instruction, as that's not correct and can cause + // unexpected jumps when debugging optimized code. + auto EmptyDL = DebugLoc(); + NewMI.setDebugLoc(EmptyDL); + NewMI.getOperand(0).setReg(NewReg); PREMap[MI] = CMBB; diff --git a/llvm/test/DebugInfo/X86/machinecse-wrongdebug-hoist.ll b/llvm/test/DebugInfo/X86/machinecse-wrongdebug-hoist.ll new file mode 100644 index 0000000000000..8f3b08a91eb57 --- /dev/null +++ b/llvm/test/DebugInfo/X86/machinecse-wrongdebug-hoist.ll @@ -0,0 +1,80 @@ +; RUN: llc %s -o - -print-after=machine-cse -mtriple=x86_64-- 2>&1 | FileCheck %s --match-full-lines + +; CHECK: %5:gr32 = SUB32ri8 %0:gr32(tied-def 0), 1, implicit-def $eflags, debug-location !24; a.c:3:13 +; CHECK-NEXT: %10:gr32 = MOVSX32rr8 %4:gr8 +; CHECK-NEXT: JCC_1 %bb.2, 15, implicit $eflags, debug-location !25; a.c:3:18 + +target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.15.0" + +@a = local_unnamed_addr global i32 0, align 4, !dbg !0 + +; Function Attrs: norecurse nounwind readonly ssp uwtable +define i32 @b(i8 signext %0) local_unnamed_addr #0 !dbg !12 { + call void @llvm.dbg.value(metadata i8 %0, metadata !17, metadata !DIExpression()), !dbg !18 + %2 = load i32, i32* @a, align 4, !dbg !19, !tbaa !20 + %3 = icmp sgt i32 %2, 1, !dbg !24 + br i1 %3, label %8, label %4, !dbg !25 + +4: ; preds = %1 + %5 = sext i8 %0 to i32, !dbg !26 + %6 = ashr i32 %5, %2, !dbg !27 + %7 = icmp eq i32 %6, 0, !dbg !27 + br i1 %7, label %10, label %8, !dbg !28 + +8: ; preds = %4, %1 + %9 = sext i8 %0 to i32, !dbg !29 + br label %10, !dbg !28 + +10: ; preds = %4, %8 + %11 = phi i32 [ %9, %8 ], [ 0, %4 ], !dbg !28 + ret i32 %11, !dbg !30 +} + +define i32 @main() local_unnamed_addr #0 !dbg !31 { + %1 = call i32 @b(i8 signext 0), !dbg !34 + ret i32 %1, !dbg !35 +} + +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!7, !8, !9, !10} +!llvm.ident = !{!11} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 11.0.0 (https://github.com/llvm/llvm-project 75cfd382201978615cca1c91c2d9f14f8b7af56d)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None, sysroot: "/") +!3 = !DIFile(filename: "a.c", directory: "/Users/davide/work/build/bin") +!4 = !{} +!5 = !{!0} +!6 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!7 = !{i32 7, !"Dwarf Version", i32 4} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"wchar_size", i32 4} +!10 = !{i32 7, !"PIC Level", i32 2} +!11 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project 75cfd382201978615cca1c91c2d9f14f8b7af56d)"} +!12 = distinct !DISubprogram(name: "b", scope: !3, file: !3, line: 2, type: !13, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !16) +!13 = !DISubroutineType(types: !14) +!14 = !{!6, !15} +!15 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!16 = !{!17} +!17 = !DILocalVariable(name: "c", arg: 1, scope: !12, file: !3, line: 2, type: !15) +!18 = !DILocation(line: 0, scope: !12) +!19 = !DILocation(line: 3, column: 11, scope: !12) +!20 = !{!21, !21, i64 0} +!21 = !{!"int", !22, i64 0} +!22 = !{!"omnipotent char", !23, i64 0} +!23 = !{!"Simple C/C++ TBAA"} +!24 = !DILocation(line: 3, column: 13, scope: !12) +!25 = !DILocation(line: 3, column: 18, scope: !12) +!26 = !DILocation(line: 3, column: 21, scope: !12) +!27 = !DILocation(line: 3, column: 23, scope: !12) +!28 = !DILocation(line: 3, column: 10, scope: !12) +!29 = !DILocation(line: 4, column: 16, scope: !12) +!30 = !DILocation(line: 3, column: 3, scope: !12) +!31 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 8, type: !32, scopeLine: 9, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !4) +!32 = !DISubroutineType(types: !33) +!33 = !{!6} +!34 = !DILocation(line: 10, column: 10, scope: !31) +!35 = !DILocation(line: 10, column: 3, scope: !31) From 2cffd7c40ea55e3b032eb5596a5a31ec9bbdafb0 Mon Sep 17 00:00:00 2001 From: Francis Visoiu Mistrih Date: Tue, 7 Apr 2020 13:49:00 -0700 Subject: [PATCH 155/286] [Driver] Only pass LTO remark arguments if the driver asks for it Previous fix missed a check to willEmitRemarks, causing remarks to always be enabled for LTO. (cherry picked from commit 9e6670b03ceaa5980eccb06e2dd037e6a9584c66) rdar://61402840 --- clang/lib/Driver/ToolChains/Darwin.cpp | 3 ++- clang/test/Driver/darwin-opt-record-ld.c | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp index c9e56f88f009a..3a86821d33e53 100644 --- a/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/clang/lib/Driver/ToolChains/Darwin.cpp @@ -541,7 +541,8 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, // we follow suite for ease of comparison. AddLinkArgs(C, Args, CmdArgs, Inputs); - if (checkRemarksOptions(getToolChain().getDriver(), Args, + if (willEmitRemarks(Args) && + checkRemarksOptions(getToolChain().getDriver(), Args, getToolChain().getTriple())) renderRemarksOptions(Args, CmdArgs, getToolChain().getTriple(), Output, JA); diff --git a/clang/test/Driver/darwin-opt-record-ld.c b/clang/test/Driver/darwin-opt-record-ld.c index 0e1e312c493d4..83630ed01da8b 100644 --- a/clang/test/Driver/darwin-opt-record-ld.c +++ b/clang/test/Driver/darwin-opt-record-ld.c @@ -2,6 +2,10 @@ // RUN: touch %t.o // +// Check that we're not passing -lto-pass-remarks-output if not requested +// RUN: %clang -target x86_64-apple-darwin12 %t.o -### -o foo/bar.out 2> %t.log +// RUN: FileCheck -check-prefix=NO_PASS_REMARKS_OUTPUT %s < %t.log +// NO_PASS_REMARKS_OUTPUT-NOT: -lto-pass-remarks // Check that we're passing -lto-pass-remarks-output for LTO // RUN: %clang -target x86_64-apple-darwin12 %t.o -fsave-optimization-record -### -o foo/bar.out 2> %t.log // RUN: FileCheck -check-prefix=PASS_REMARKS_OUTPUT %s < %t.log From 5a1164b921be5889b5c31b057bedcd8533055d3c Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Tue, 7 Apr 2020 23:06:59 +0200 Subject: [PATCH 156/286] Don't access reference to a vector after pop_back This is undefined behavior. Found by asan's detect_container_overflow. (cherry picked from commit 873b79b8675d0c8eca6055ae8a874fe52b033c28) --- lldb/source/Target/ThreadPlanStack.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lldb/source/Target/ThreadPlanStack.cpp b/lldb/source/Target/ThreadPlanStack.cpp index 6120d0ccefcbc..11102650c1092 100644 --- a/lldb/source/Target/ThreadPlanStack.cpp +++ b/lldb/source/Target/ThreadPlanStack.cpp @@ -159,7 +159,7 @@ void ThreadPlanStack::PushPlan(lldb::ThreadPlanSP new_plan_sp) { lldb::ThreadPlanSP ThreadPlanStack::PopPlan() { assert(m_plans.size() > 1 && "Can't pop the base thread plan"); - lldb::ThreadPlanSP &plan_sp = m_plans.back(); + lldb::ThreadPlanSP plan_sp = std::move(m_plans.back()); m_completed_plans.push_back(plan_sp); plan_sp->WillPop(); m_plans.pop_back(); @@ -169,7 +169,7 @@ lldb::ThreadPlanSP ThreadPlanStack::PopPlan() { lldb::ThreadPlanSP ThreadPlanStack::DiscardPlan() { assert(m_plans.size() > 1 && "Can't discard the base thread plan"); - lldb::ThreadPlanSP &plan_sp = m_plans.back(); + lldb::ThreadPlanSP plan_sp = std::move(m_plans.back()); m_discarded_plans.push_back(plan_sp); plan_sp->WillPop(); m_plans.pop_back(); From 5fa2642eb3dfe7177800311b6249444f8b0bc40e Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Tue, 7 Apr 2020 16:03:59 -0700 Subject: [PATCH 157/286] SwiftFormatters: Harden StringGuts formatter against invalid input Data formatters may encounter invalid or uninitialized objects, either due to user bugs (e.g. races, smashers, use-after-frees) or because the location range provided by the compiler begins too early. Make the string formatter not crash when it encounters input known to be invalid. rdar://61266673 --- .../Language/Swift/SwiftFormatters.cpp | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/lldb/source/Plugins/Language/Swift/SwiftFormatters.cpp b/lldb/source/Plugins/Language/Swift/SwiftFormatters.cpp index 2df321c693d89..a2f39b9962932 100644 --- a/lldb/source/Plugins/Language/Swift/SwiftFormatters.cpp +++ b/lldb/source/Plugins/Language/Swift/SwiftFormatters.cpp @@ -177,7 +177,7 @@ bool lldb_private::formatters::swift::StringGuts_SummaryProvider( return false; payload_sp = anyobject_sp->GetChildAtIndex(0, true); // "instance" } else { - lldbassert(false && "Uknown variant"); + // Unknown variant. return false; } if (!payload_sp) @@ -195,7 +195,7 @@ bool lldb_private::formatters::swift::StringGuts_SummaryProvider( raw1 = pointerBits | (discriminator << 56); } } else { - lldbassert(false && "Unsupported arch?"); + lldbassert(false && "Unsupported pointer bit-width"); return false; } @@ -292,8 +292,9 @@ bool lldb_private::formatters::swift::StringGuts_SummaryProvider( uint16_t flags = raw0 >> 48; lldb::addr_t objectAddress = (raw1 & 0x0FFFFFFFFFFFFFFF); if ((flags & 0x1000) != 0) { // Tail-allocated / biased address - lldbassert((discriminator & 0x70) == 0 && - "tail-allocation is only for natively stored or literals"); + // Tail-allocation is only for natively stored or literals. + if ((discriminator & 0x70) != 0) + return false; uint64_t bias = (ptrSize == 8 ? 32 : 20); auto address = objectAddress + bias; return readStringFromAddress( @@ -302,7 +303,9 @@ bool lldb_private::formatters::swift::StringGuts_SummaryProvider( if ((discriminator & 0xF0) == 0x00) { // Shared string // FIXME: Verify that there is a __SharedStringStorage instance at `address`. - lldbassert((flags & 0x3000) == 0); + // Shared strings must not be tail-allocated or natively stored. + if ((flags & 0x3000) != 0) + return false; uint64_t startOffset = (ptrSize == 8 ? 24 : 12); auto address = objectAddress + startOffset; lldb::addr_t start = process->ReadPointerFromMemory(address, error); @@ -313,8 +316,9 @@ bool lldb_private::formatters::swift::StringGuts_SummaryProvider( start, count, process, stream, summary_options, read_options); } - lldbassert((discriminator & 0x70) != 0 && - "native/shared strings already handled"); + // Native/shared strings should already have been handled. + if ((discriminator & 0x70) == 0) + return false; if ((discriminator & 0xE0) == 0x40) { // 010xxxxx: Bridged TypeSystemClang *clang_ast_context = @@ -336,13 +340,12 @@ bool lldb_private::formatters::swift::StringGuts_SummaryProvider( } if ((discriminator & 0xF8) == 0x18) { // 0001xxxx: Foreign - // Not currently generated - lldbassert( - false && "Foreign non-bridged strings are not currently used in Swift"); + // Not currently generated: Foreign non-bridged strings are not currently + // used in Swift. return false; } - lldbassert(false && "Invalid discriminator"); + // Invalid discriminator. return false; } From 33154ab6f15693328b5005659e45ad31d45d12fc Mon Sep 17 00:00:00 2001 From: Dan Zheng Date: Tue, 7 Apr 2020 23:48:39 -0700 Subject: [PATCH 158/286] [lldb] Handle new Swift synthesized FileUnitKind. (#1042) Friend PR: https://github.com/apple/swift/pull/30863 --- lldb/source/Symbol/SwiftASTContext.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lldb/source/Symbol/SwiftASTContext.cpp b/lldb/source/Symbol/SwiftASTContext.cpp index f8826c8d145b7..25306dd299397 100644 --- a/lldb/source/Symbol/SwiftASTContext.cpp +++ b/lldb/source/Symbol/SwiftASTContext.cpp @@ -8356,6 +8356,9 @@ static void DescribeFileUnit(Stream &s, swift::FileUnit *file_unit) { case swift::FileUnitKind::Builtin: { s.PutCString("Builtin"); } break; + case swift::FileUnitKind::Synthesized: { + s.PutCString("Synthesized"); + } break; case swift::FileUnitKind::SerializedAST: case swift::FileUnitKind::ClangModule: { if (file_unit->getKind() == swift::FileUnitKind::SerializedAST) From 79bb1dce92f95b6b5013b671d227534c45b7d5c4 Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Wed, 8 Apr 2020 00:03:43 -0700 Subject: [PATCH 159/286] Remove the old SecTaskAccess entry from debugserver's plist (#1041) (cherry picked from commit 8aa07f81b85b7af4b0678a813dd4f5a98293b955) --- lldb/tools/debugserver/resources/lldb-debugserver-Info.plist | 5 ----- 1 file changed, 5 deletions(-) diff --git a/lldb/tools/debugserver/resources/lldb-debugserver-Info.plist b/lldb/tools/debugserver/resources/lldb-debugserver-Info.plist index 343325c2765cb..ddaf0644f2cf2 100644 --- a/lldb/tools/debugserver/resources/lldb-debugserver-Info.plist +++ b/lldb/tools/debugserver/resources/lldb-debugserver-Info.plist @@ -12,10 +12,5 @@ debugserver CFBundleVersion 2 - SecTaskAccess - - allowed - debug - From 13508282d930add3261fa33a86e0da5e2197a740 Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Wed, 8 Apr 2020 02:11:30 -0700 Subject: [PATCH 160/286] Don't fail step out if remote server doesn't implement qMemoryRegionInfo (#1040) Summary: The return address validation in D71372 will fail if the memory permissions can't be determined. Many embedded stubs either don't implement the qMemoryRegionInfo packet, or don't have memory permissions at all. Remove the return from the if clause that calls GetLoadAddressPermissions, so this call failing doesn't cause the step out to abort. Instead, assume that the memory permission check doesn't apply to this type of target. Reviewers: labath, jingham, clayborg, mossberg Reviewed By: labath, jingham Subscribers: lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D72513 (cherry picked from commit 6fd818c5a9c565b8aaeaf1ca85ad14735ee0eb0c) Co-authored-by: Ted Woodward --- lldb/source/Target/ThreadPlanStepOut.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/lldb/source/Target/ThreadPlanStepOut.cpp b/lldb/source/Target/ThreadPlanStepOut.cpp index db3c84af48ed1..f8df89b1414ae 100644 --- a/lldb/source/Target/ThreadPlanStepOut.cpp +++ b/lldb/source/Target/ThreadPlanStepOut.cpp @@ -126,12 +126,9 @@ ThreadPlanStepOut::ThreadPlanStepOut( uint32_t permissions = 0; if (!m_process->GetLoadAddressPermissions(m_return_addr, permissions)) { - m_constructor_errors.Printf("Return address (0x%" PRIx64 - ") permissions not found.", - m_return_addr); - LLDB_LOGF(log, "ThreadPlanStepOut(%p): %s", static_cast(this), - m_constructor_errors.GetData()); - return; + LLDB_LOGF(log, "ThreadPlanStepOut(%p): Return address (0x%" PRIx64 + ") permissions not found.", static_cast(this), + m_return_addr); } else if (!(permissions & ePermissionsExecutable)) { m_constructor_errors.Printf("Return address (0x%" PRIx64 ") did not point to executable memory.", From 7c846c1c0bb93258fe8274b1ed8ca23ff3522f4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20K=C3=A9ri?= <1.int32@gmail.com> Date: Mon, 2 Mar 2020 11:48:19 +0100 Subject: [PATCH 161/286] [analyzer][StreamChecker] Using function description objects - NFC. Summary: Have a description object for the stream functions that can store different aspects of a single stream operation. I plan to extend the structure with other members, for example pre-callback and index of the stream argument. Reviewers: Szelethus, baloghadamsoftware, NoQ, martong, Charusso, xazax.hun Reviewed By: Szelethus Subscribers: rnkovacs, xazax.hun, baloghadamsoftware, szepet, a.sidorin, mikhail.ramalho, Szelethus, donat.nagy, dkrupp, gamesh411, Charusso, martong, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D75158 (cherry picked from commit b293a7217bae22aa8a5f5e9aab025143c0f744e8) --- .../StaticAnalyzer/Checkers/StreamChecker.cpp | 51 +++++++++++-------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp index 47099f2afb6a4..292a12fd129aa 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp @@ -49,6 +49,15 @@ struct StreamState { } }; +class StreamChecker; + +using FnCheck = std::function; + +struct FnDescription { + FnCheck EvalFn; +}; + class StreamChecker : public Checker { mutable std::unique_ptr BT_nullfp, BT_illegalwhence, @@ -59,35 +68,33 @@ class StreamChecker : public Checker; - - CallDescriptionMap Callbacks = { - {{"fopen"}, &StreamChecker::evalFopen}, - {{"freopen", 3}, &StreamChecker::evalFreopen}, - {{"tmpfile"}, &StreamChecker::evalFopen}, - {{"fclose", 1}, &StreamChecker::evalFclose}, + + CallDescriptionMap FnDescriptions = { + {{"fopen"}, {&StreamChecker::evalFopen}}, + {{"freopen", 3}, {&StreamChecker::evalFreopen}}, + {{"tmpfile"}, {&StreamChecker::evalFopen}}, + {{"fclose", 1}, {&StreamChecker::evalFclose}}, {{"fread", 4}, - std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 3)}, + {std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 3)}}, {{"fwrite", 4}, - std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 3)}, - {{"fseek", 3}, &StreamChecker::evalFseek}, + {std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 3)}}, + {{"fseek", 3}, {&StreamChecker::evalFseek}}, {{"ftell", 1}, - std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}, + {std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}}, {{"rewind", 1}, - std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}, + {std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}}, {{"fgetpos", 2}, - std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}, + {std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}}, {{"fsetpos", 2}, - std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}, + {std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}}, {{"clearerr", 1}, - std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}, + {std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}}, {{"feof", 1}, - std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}, + {std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}}, {{"ferror", 1}, - std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}, + {std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}}, {{"fileno", 1}, - std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}, + {std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}}, }; void evalFopen(const CallEvent &Call, CheckerContext &C) const; @@ -125,11 +132,11 @@ bool StreamChecker::evalCall(const CallEvent &Call, CheckerContext &C) const { return false; } - const FnCheck *Callback = Callbacks.lookup(Call); - if (!Callback) + const FnDescription *Description = FnDescriptions.lookup(Call); + if (!Description) return false; - (*Callback)(this, Call, C); + (Description->EvalFn)(this, Call, C); return C.isDifferent(); } From 5ecc286ca3819bdab4809067c8f0e6b200e7ad80 Mon Sep 17 00:00:00 2001 From: Balazs Benics Date: Tue, 3 Mar 2020 10:57:06 +0100 Subject: [PATCH 162/286] [analyzer][taint] Add isTainted debug expression inspection check Summary: This patch introduces the `clang_analyzer_isTainted` expression inspection check for checking taint. Using this we could query the analyzer whether the expression used as the argument is tainted or not. This would be useful in tests, where we don't want to issue warning for all tainted expressions in a given file (like the `debug.TaintTest` would do) but only for certain expressions. Example usage: ```lang=c++ int read_integer() { int n; clang_analyzer_isTainted(n); // expected-warning{{NO}} scanf("%d", &n); clang_analyzer_isTainted(n); // expected-warning{{YES}} clang_analyzer_isTainted(n + 2); // expected-warning{{YES}} clang_analyzer_isTainted(n > 0); // expected-warning{{YES}} int next_tainted_value = n; // no-warning return n; } ``` Reviewers: NoQ, Szelethus, baloghadamsoftware, xazax.hun, boga95 Reviewed By: Szelethus Subscribers: martong, rnkovacs, whisperity, xazax.hun, baloghadamsoftware, szepet, a.sidorin, mikhail.ramalho, donat.nagy, Charusso, cfe-commits, boga95, dkrupp, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D74131 (cherry picked from commit 859bcf4e3bb991a161821129d19d50ba00f9c56a) --- .../analyzer/developer-docs/DebugChecks.rst | 22 +++++++ .../Checkers/ExprInspectionChecker.cpp | 61 +++++++++++++------ .../Analysis/debug-exprinspection-istainted.c | 27 ++++++++ 3 files changed, 90 insertions(+), 20 deletions(-) create mode 100644 clang/test/Analysis/debug-exprinspection-istainted.c diff --git a/clang/docs/analyzer/developer-docs/DebugChecks.rst b/clang/docs/analyzer/developer-docs/DebugChecks.rst index 3f9bed78604f0..05b3e2480d3b7 100644 --- a/clang/docs/analyzer/developer-docs/DebugChecks.rst +++ b/clang/docs/analyzer/developer-docs/DebugChecks.rst @@ -275,6 +275,28 @@ ExprInspection checks See clang_analyzer_denote(). +- ``void clang_analyzer_isTainted(a single argument of any type);`` + + Queries the analyzer whether the expression used as argument is tainted or not. + This is useful in tests, where we don't want to issue warning for all tainted + expressions but only check for certain expressions. + This would help to reduce the *noise* that the `TaintTest` debug checker would + introduce and let you focus on the `expected-warning`s that you really care + about. + + Example usage:: + + int read_integer() { + int n; + clang_analyzer_isTainted(n); // expected-warning{{NO}} + scanf("%d", &n); + clang_analyzer_isTainted(n); // expected-warning{{YES}} + clang_analyzer_isTainted(n + 2); // expected-warning{{YES}} + clang_analyzer_isTainted(n > 0); // expected-warning{{YES}} + int next_tainted_value = n; // no-warning + return n; + } + Statistics ========== diff --git a/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp index 17c813962a234..c65cbf2767159 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include "Taint.h" #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Checkers/SValExplainer.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" @@ -45,6 +46,7 @@ class ExprInspectionChecker : public Checker(C.getCalleeName(CE)) - .Case("clang_analyzer_eval", &ExprInspectionChecker::analyzerEval) - .Case("clang_analyzer_checkInlined", - &ExprInspectionChecker::analyzerCheckInlined) - .Case("clang_analyzer_crash", &ExprInspectionChecker::analyzerCrash) - .Case("clang_analyzer_warnIfReached", - &ExprInspectionChecker::analyzerWarnIfReached) - .Case("clang_analyzer_warnOnDeadSymbol", - &ExprInspectionChecker::analyzerWarnOnDeadSymbol) - .StartsWith("clang_analyzer_explain", &ExprInspectionChecker::analyzerExplain) - .StartsWith("clang_analyzer_dump", &ExprInspectionChecker::analyzerDump) - .Case("clang_analyzer_getExtent", &ExprInspectionChecker::analyzerGetExtent) - .Case("clang_analyzer_printState", - &ExprInspectionChecker::analyzerPrintState) - .Case("clang_analyzer_numTimesReached", - &ExprInspectionChecker::analyzerNumTimesReached) - .Case("clang_analyzer_hashDump", &ExprInspectionChecker::analyzerHashDump) - .Case("clang_analyzer_denote", &ExprInspectionChecker::analyzerDenote) - .Case("clang_analyzer_express", &ExprInspectionChecker::analyzerExpress) - .Default(nullptr); + FnCheck Handler = + llvm::StringSwitch(C.getCalleeName(CE)) + .Case("clang_analyzer_eval", &ExprInspectionChecker::analyzerEval) + .Case("clang_analyzer_checkInlined", + &ExprInspectionChecker::analyzerCheckInlined) + .Case("clang_analyzer_crash", &ExprInspectionChecker::analyzerCrash) + .Case("clang_analyzer_warnIfReached", + &ExprInspectionChecker::analyzerWarnIfReached) + .Case("clang_analyzer_warnOnDeadSymbol", + &ExprInspectionChecker::analyzerWarnOnDeadSymbol) + .StartsWith("clang_analyzer_explain", + &ExprInspectionChecker::analyzerExplain) + .StartsWith("clang_analyzer_dump", + &ExprInspectionChecker::analyzerDump) + .Case("clang_analyzer_getExtent", + &ExprInspectionChecker::analyzerGetExtent) + .Case("clang_analyzer_printState", + &ExprInspectionChecker::analyzerPrintState) + .Case("clang_analyzer_numTimesReached", + &ExprInspectionChecker::analyzerNumTimesReached) + .Case("clang_analyzer_hashDump", + &ExprInspectionChecker::analyzerHashDump) + .Case("clang_analyzer_denote", &ExprInspectionChecker::analyzerDenote) + .Case("clang_analyzer_express", + &ExprInspectionChecker::analyzerExpress) + .StartsWith("clang_analyzer_isTainted", + &ExprInspectionChecker::analyzerIsTainted) + .Default(nullptr); if (!Handler) return false; @@ -410,6 +420,17 @@ void ExprInspectionChecker::analyzerExpress(const CallExpr *CE, reportBug(*Str, C); } +void ExprInspectionChecker::analyzerIsTainted(const CallExpr *CE, + CheckerContext &C) const { + if (CE->getNumArgs() != 1) { + reportBug("clang_analyzer_isTainted() requires exactly one argument", C); + return; + } + const bool IsTainted = + taint::isTainted(C.getState(), CE->getArg(0), C.getLocationContext()); + reportBug(IsTainted ? "YES" : "NO", C); +} + void ento::registerExprInspectionChecker(CheckerManager &Mgr) { Mgr.registerChecker(); } diff --git a/clang/test/Analysis/debug-exprinspection-istainted.c b/clang/test/Analysis/debug-exprinspection-istainted.c new file mode 100644 index 0000000000000..e2f6821e4aa9a --- /dev/null +++ b/clang/test/Analysis/debug-exprinspection-istainted.c @@ -0,0 +1,27 @@ +// RUN: %clang_analyze_cc1 -verify %s \ +// RUN: -analyzer-checker=core \ +// RUN: -analyzer-checker=debug.ExprInspection \ +// RUN: -analyzer-checker=alpha.security.taint + +int scanf(const char *restrict format, ...); +void clang_analyzer_isTainted(char); +void clang_analyzer_isTainted_any_suffix(char); +void clang_analyzer_isTainted_many_arguments(char, int, int); + +void foo() { + char buf[32] = ""; + clang_analyzer_isTainted(buf[0]); // expected-warning {{NO}} + clang_analyzer_isTainted_any_suffix(buf[0]); // expected-warning {{NO}} + scanf("%s", buf); + clang_analyzer_isTainted(buf[0]); // expected-warning {{YES}} + clang_analyzer_isTainted_any_suffix(buf[0]); // expected-warning {{YES}} + + int tainted_value = buf[0]; // no-warning +} + +void exactly_one_argument_required() { + char buf[32] = ""; + scanf("%s", buf); + clang_analyzer_isTainted_many_arguments(buf[0], 42, 42); + // expected-warning@-1 {{clang_analyzer_isTainted() requires exactly one argument}} +} From 3885ecb0b79822aeed4886647fee5623e85c5ee3 Mon Sep 17 00:00:00 2001 From: Charusso Date: Wed, 4 Mar 2020 06:24:52 +0100 Subject: [PATCH 163/286] [analyzer] FixItHint: Apply and test hints with the Clang-Tidy's script Summary: This patch introduces a way to apply the fix-its by the Analyzer: `-analyzer-config apply-fixits=true`. The fix-its should be testable, therefore I have copied the well-tested `check_clang_tidy.py` script. The idea is that the Analyzer's workflow is different so it would be very difficult to use only one script for both Tidy and the Analyzer, the script would diverge a lot. Example test: `// RUN: %check-analyzer-fixit %s %t -analyzer-checker=core` When the copy-paste happened the original authors were: @alexfh, @zinovy.nis, @JonasToth, @hokein, @gribozavr, @lebedev.ri Reviewed By: NoQ, alexfh, zinovy.nis Differential Revision: https://reviews.llvm.org/D69746 (cherry picked from commit f69c74db34f42c20c167b8fb0f93ec05a0e77b45) --- .../StaticAnalyzer/Core/AnalyzerOptions.def | 4 + .../Frontend/AnalysisConsumer.cpp | 90 +++++++++---- .../StaticAnalyzer/Frontend/CMakeLists.txt | 2 + clang/test/Analysis/analyzer-config.c | 1 + clang/test/Analysis/check-analyzer-fixit.py | 121 ++++++++++++++++++ clang/test/Analysis/virtualcall-fixit.cpp | 13 ++ clang/test/lit.cfg.py | 5 + 7 files changed, 210 insertions(+), 26 deletions(-) create mode 100644 clang/test/Analysis/check-analyzer-fixit.py create mode 100644 clang/test/Analysis/virtualcall-fixit.cpp diff --git a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def index 00febf6881954..400e953e3c6c1 100644 --- a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def +++ b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def @@ -310,6 +310,10 @@ ANALYZER_OPTION(bool, ShouldEmitFixItHintsAsRemarks, "fixits-as-remarks", "Emit fix-it hints as remarks for testing purposes", false) +ANALYZER_OPTION(bool, ShouldApplyFixIts, "apply-fixits", + "Apply the fix-it hints to the files", + false) + //===----------------------------------------------------------------------===// // Unsigned analyzer options. //===----------------------------------------------------------------------===// diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index fea8100c3b3bc..3ca0f836579f9 100644 --- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -12,7 +12,6 @@ #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h" #include "ModelInjector.h" -#include "clang/Analysis/PathDiagnostic.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" @@ -21,10 +20,12 @@ #include "clang/Analysis/CFG.h" #include "clang/Analysis/CallGraph.h" #include "clang/Analysis/CodeInjector.h" +#include "clang/Analysis/PathDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/CrossTU/CrossTranslationUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Rewrite/Core/Rewriter.h" #include "clang/StaticAnalyzer/Checkers/LocalCheckers.h" #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" @@ -33,6 +34,8 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h" +#include "clang/Tooling/Core/Replacement.h" +#include "clang/Tooling/Tooling.h" #include "llvm/ADT/PostOrderIterator.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/FileSystem.h" @@ -46,6 +49,7 @@ using namespace clang; using namespace ento; +using namespace tooling; #define DEBUG_TYPE "AnalysisConsumer" @@ -83,11 +87,16 @@ void ento::createTextPathDiagnosticConsumer( namespace { class ClangDiagPathDiagConsumer : public PathDiagnosticConsumer { DiagnosticsEngine &Diag; - bool IncludePath = false, ShouldEmitAsError = false, FixitsAsRemarks = false; + LangOptions LO; + + bool IncludePath = false; + bool ShouldEmitAsError = false; + bool FixitsAsRemarks = false; + bool ApplyFixIts = false; public: - ClangDiagPathDiagConsumer(DiagnosticsEngine &Diag) - : Diag(Diag) {} + ClangDiagPathDiagConsumer(DiagnosticsEngine &Diag, LangOptions LO) + : Diag(Diag), LO(LO) {} ~ClangDiagPathDiagConsumer() override {} StringRef getName() const override { return "ClangDiags"; } @@ -101,6 +110,7 @@ class ClangDiagPathDiagConsumer : public PathDiagnosticConsumer { void enablePaths() { IncludePath = true; } void enableWerror() { ShouldEmitAsError = true; } void enableFixitsAsRemarks() { FixitsAsRemarks = true; } + void enableApplyFixIts() { ApplyFixIts = true; } void FlushDiagnosticsImpl(std::vector &Diags, FilesMade *filesMade) override { @@ -110,29 +120,44 @@ class ClangDiagPathDiagConsumer : public PathDiagnosticConsumer { : Diag.getCustomDiagID(DiagnosticsEngine::Warning, "%0"); unsigned NoteID = Diag.getCustomDiagID(DiagnosticsEngine::Note, "%0"); unsigned RemarkID = Diag.getCustomDiagID(DiagnosticsEngine::Remark, "%0"); + SourceManager &SM = Diag.getSourceManager(); + + Replacements Repls; + auto reportPiece = [&](unsigned ID, FullSourceLoc Loc, StringRef String, + ArrayRef Ranges, + ArrayRef Fixits) { + if (!FixitsAsRemarks && !ApplyFixIts) { + Diag.Report(Loc, ID) << String << Ranges << Fixits; + return; + } + + Diag.Report(Loc, ID) << String << Ranges; + if (FixitsAsRemarks) { + for (const FixItHint &Hint : Fixits) { + llvm::SmallString<128> Str; + llvm::raw_svector_ostream OS(Str); + // FIXME: Add support for InsertFromRange and + // BeforePreviousInsertion. + assert(!Hint.InsertFromRange.isValid() && "Not implemented yet!"); + assert(!Hint.BeforePreviousInsertions && "Not implemented yet!"); + OS << SM.getSpellingColumnNumber(Hint.RemoveRange.getBegin()) << "-" + << SM.getSpellingColumnNumber(Hint.RemoveRange.getEnd()) << ": '" + << Hint.CodeToInsert << "'"; + Diag.Report(Loc, RemarkID) << OS.str(); + } + } + + if (ApplyFixIts) { + for (const FixItHint &Hint : Fixits) { + Replacement Repl(SM, Hint.RemoveRange, Hint.CodeToInsert); - auto reportPiece = - [&](unsigned ID, SourceLocation Loc, StringRef String, - ArrayRef Ranges, ArrayRef Fixits) { - if (!FixitsAsRemarks) { - Diag.Report(Loc, ID) << String << Ranges << Fixits; - } else { - Diag.Report(Loc, ID) << String << Ranges; - for (const FixItHint &Hint : Fixits) { - SourceManager &SM = Diag.getSourceManager(); - llvm::SmallString<128> Str; - llvm::raw_svector_ostream OS(Str); - // FIXME: Add support for InsertFromRange and - // BeforePreviousInsertion. - assert(!Hint.InsertFromRange.isValid() && "Not implemented yet!"); - assert(!Hint.BeforePreviousInsertions && "Not implemented yet!"); - OS << SM.getSpellingColumnNumber(Hint.RemoveRange.getBegin()) - << "-" << SM.getSpellingColumnNumber(Hint.RemoveRange.getEnd()) - << ": '" << Hint.CodeToInsert << "'"; - Diag.Report(Loc, RemarkID) << OS.str(); - } + if (llvm::Error Err = Repls.add(Repl)) { + llvm::errs() << "Error applying replacement " << Repl.toString() + << ": " << Err << "\n"; } - }; + } + } + }; for (std::vector::iterator I = Diags.begin(), E = Diags.end(); @@ -164,6 +189,16 @@ class ClangDiagPathDiagConsumer : public PathDiagnosticConsumer { Piece->getString(), Piece->getRanges(), Piece->getFixits()); } } + + if (!ApplyFixIts || Repls.empty()) + return; + + Rewriter Rewrite(SM, LO); + if (!applyAllReplacements(Repls, Rewrite)) { + llvm::errs() << "An error occured during applying fix-it.\n"; + } + + Rewrite.overwriteChangedFiles(); } }; } // end anonymous namespace @@ -256,7 +291,7 @@ class AnalysisConsumer : public AnalysisASTConsumer, if (Opts->AnalysisDiagOpt != PD_NONE) { // Create the PathDiagnosticConsumer. ClangDiagPathDiagConsumer *clangDiags = - new ClangDiagPathDiagConsumer(PP.getDiagnostics()); + new ClangDiagPathDiagConsumer(PP.getDiagnostics(), PP.getLangOpts()); PathConsumers.push_back(clangDiags); if (Opts->AnalyzerWerror) @@ -265,6 +300,9 @@ class AnalysisConsumer : public AnalysisASTConsumer, if (Opts->ShouldEmitFixItHintsAsRemarks) clangDiags->enableFixitsAsRemarks(); + if (Opts->ShouldApplyFixIts) + clangDiags->enableApplyFixIts(); + if (Opts->AnalysisDiagOpt == PD_TEXT) { clangDiags->enablePaths(); diff --git a/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt b/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt index 5e7dd8f18cd73..6f1151ab0c111 100644 --- a/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt +++ b/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt @@ -21,4 +21,6 @@ add_clang_library(clangStaticAnalyzerFrontend clangLex clangStaticAnalyzerCheckers clangStaticAnalyzerCore + clangRewrite + clangToolingCore ) diff --git a/clang/test/Analysis/analyzer-config.c b/clang/test/Analysis/analyzer-config.c index 4707da3b9a3a3..478cb7e42f180 100644 --- a/clang/test/Analysis/analyzer-config.c +++ b/clang/test/Analysis/analyzer-config.c @@ -10,6 +10,7 @@ // CHECK-NEXT: alpha.security.MmapWriteExec:MmapProtExec = 0x04 // CHECK-NEXT: alpha.security.MmapWriteExec:MmapProtRead = 0x01 // CHECK-NEXT: alpha.security.taint.TaintPropagation:Config = "" +// CHECK-NEXT: apply-fixits = false // CHECK-NEXT: avoid-suppressing-null-argument-paths = false // CHECK-NEXT: c++-allocator-inlining = true // CHECK-NEXT: c++-container-inlining = false diff --git a/clang/test/Analysis/check-analyzer-fixit.py b/clang/test/Analysis/check-analyzer-fixit.py new file mode 100644 index 0000000000000..1d159aedec91b --- /dev/null +++ b/clang/test/Analysis/check-analyzer-fixit.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python +# +#===- check-analyzer-fixit.py - Static Analyzer test helper ---*- python -*-===# +# +# 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 +# +#===------------------------------------------------------------------------===# +# +# This file copy-pasted mostly from the Clang-Tidy's 'check_clang_tidy.py'. +# +#===------------------------------------------------------------------------===# + +r""" +Clang Static Analyzer test helper +================================= + +This script runs the Analyzer in fix-it mode and verify fixes, warnings, notes. + +Usage: + check-analyzer-fixit.py [analyzer arguments] + +Example: + // RUN: %check-analyzer-fixit %s %t -analyzer-checker=core +""" + +import argparse +import os +import re +import subprocess +import sys + + +def write_file(file_name, text): + with open(file_name, 'w') as f: + f.write(text) + + +def run_test_once(args, extra_args): + input_file_name = args.input_file_name + temp_file_name = args.temp_file_name + clang_analyzer_extra_args = extra_args + + file_name_with_extension = input_file_name + _, extension = os.path.splitext(file_name_with_extension) + if extension not in ['.c', '.hpp', '.m', '.mm']: + extension = '.cpp' + temp_file_name = temp_file_name + extension + + with open(input_file_name, 'r') as input_file: + input_text = input_file.read() + + # Remove the contents of the CHECK lines to avoid CHECKs matching on + # themselves. We need to keep the comments to preserve line numbers while + # avoiding empty lines which could potentially trigger formatting-related + # checks. + cleaned_test = re.sub('// *CHECK-[A-Z0-9\-]*:[^\r\n]*', '//', input_text) + write_file(temp_file_name, cleaned_test) + + original_file_name = temp_file_name + ".orig" + write_file(original_file_name, cleaned_test) + + try: + builtin_include_dir = subprocess.check_output( + ['clang', '-print-file-name=include'], stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + print('Cannot print Clang include directory: ' + e.output.decode()) + + builtin_include_dir = os.path.normpath(builtin_include_dir) + + args = (['clang', '-cc1', '-internal-isystem', builtin_include_dir, + '-nostdsysteminc', '-analyze', '-analyzer-constraints=range', + '-analyzer-config', 'apply-fixits=true'] + + clang_analyzer_extra_args + ['-verify', temp_file_name]) + + print('Running ' + str(args) + '...') + + try: + clang_analyzer_output = \ + subprocess.check_output(args, stderr=subprocess.STDOUT).decode() + except subprocess.CalledProcessError as e: + print('Clang Static Analyzer test failed:\n' + e.output.decode()) + raise + + print('----------------- Clang Static Analyzer output -----------------\n' + + clang_analyzer_output + + '\n--------------------------------------------------------------') + + try: + diff_output = subprocess.check_output( + ['diff', '-u', original_file_name, temp_file_name], + stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + diff_output = e.output + + print('----------------------------- Fixes ----------------------------\n' + + diff_output.decode() + + '\n--------------------------------------------------------------') + + try: + subprocess.check_output( + ['FileCheck', '-input-file=' + temp_file_name, input_file_name, + '-check-prefixes=CHECK-FIXES', '-strict-whitespace'], + stderr=subprocess.STDOUT) + except subprocess.CalledProcessError as e: + print('FileCheck failed:\n' + e.output.decode()) + raise + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('input_file_name') + parser.add_argument('temp_file_name') + + args, extra_args = parser.parse_known_args() + run_test_once(args, extra_args) + + +if __name__ == '__main__': + main() diff --git a/clang/test/Analysis/virtualcall-fixit.cpp b/clang/test/Analysis/virtualcall-fixit.cpp new file mode 100644 index 0000000000000..e64e63ab0856e --- /dev/null +++ b/clang/test/Analysis/virtualcall-fixit.cpp @@ -0,0 +1,13 @@ +// RUN: %check_analyzer_fixit %s %t \ +// RUN: -analyzer-checker=core,optin.cplusplus.VirtualCall \ +// RUN: -analyzer-config optin.cplusplus.VirtualCall:ShowFixIts=true + +struct S { + virtual void foo(); + S() { + foo(); + // expected-warning@-1 {{Call to virtual method 'S::foo' during construction bypasses virtual dispatch}} + // CHECK-FIXES: S::foo(); + } + ~S(); +}; diff --git a/clang/test/lit.cfg.py b/clang/test/lit.cfg.py index 3fc75105fb797..1a819c6ded387 100644 --- a/clang/test/lit.cfg.py +++ b/clang/test/lit.cfg.py @@ -77,6 +77,11 @@ if config.clang_staticanalyzer_z3 == '1': config.available_features.add('z3') + check_analyzer_fixit_path = os.path.join( + config.test_source_root, "Analysis", "check-analyzer-fixit.py") + config.substitutions.append( + ('%check_analyzer_fixit', + '%s %s' % (config.python_executable, check_analyzer_fixit_path))) llvm_config.add_tool_substitutions(tools, tool_dirs) From 18cef5f3e6087545aa4b3347daf22ceaa05b8312 Mon Sep 17 00:00:00 2001 From: Charusso Date: Wed, 4 Mar 2020 06:55:50 +0100 Subject: [PATCH 164/286] [analyzer] AnalyzerOptions: Remove 'fixits-as-remarks' Summary: The new way of checking fix-its is `%check_analyzer_fixit`. Reviewed By: NoQ, Szelethus, xazax.hun Differential Revision: https://reviews.llvm.org/D73729 (cherry picked from commit abdd33c86a34517bbbe91adcacaae1ed5ea6b1d8) --- .../StaticAnalyzer/Core/AnalyzerOptions.def | 4 --- .../Frontend/AnalysisConsumer.cpp | 35 ++++--------------- clang/test/Analysis/analyzer-config.c | 1 - clang/test/Analysis/dead-stores.c | 31 ++++++++++------ clang/test/Analysis/virtualcall-fixit.cpp | 13 ------- clang/test/Analysis/virtualcall-fixits.cpp | 15 ++++---- 6 files changed, 35 insertions(+), 64 deletions(-) delete mode 100644 clang/test/Analysis/virtualcall-fixit.cpp diff --git a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def index 400e953e3c6c1..ee67f60df9488 100644 --- a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def +++ b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def @@ -306,10 +306,6 @@ ANALYZER_OPTION(bool, ShouldTrackConditionsDebug, "track-conditions-debug", "Whether to place an event at each tracked condition.", false) -ANALYZER_OPTION(bool, ShouldEmitFixItHintsAsRemarks, "fixits-as-remarks", - "Emit fix-it hints as remarks for testing purposes", - false) - ANALYZER_OPTION(bool, ShouldApplyFixIts, "apply-fixits", "Apply the fix-it hints to the files", false) diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index 3ca0f836579f9..847a030017193 100644 --- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -91,7 +91,6 @@ class ClangDiagPathDiagConsumer : public PathDiagnosticConsumer { bool IncludePath = false; bool ShouldEmitAsError = false; - bool FixitsAsRemarks = false; bool ApplyFixIts = false; public: @@ -109,7 +108,6 @@ class ClangDiagPathDiagConsumer : public PathDiagnosticConsumer { void enablePaths() { IncludePath = true; } void enableWerror() { ShouldEmitAsError = true; } - void enableFixitsAsRemarks() { FixitsAsRemarks = true; } void enableApplyFixIts() { ApplyFixIts = true; } void FlushDiagnosticsImpl(std::vector &Diags, @@ -119,42 +117,24 @@ class ClangDiagPathDiagConsumer : public PathDiagnosticConsumer { ? Diag.getCustomDiagID(DiagnosticsEngine::Error, "%0") : Diag.getCustomDiagID(DiagnosticsEngine::Warning, "%0"); unsigned NoteID = Diag.getCustomDiagID(DiagnosticsEngine::Note, "%0"); - unsigned RemarkID = Diag.getCustomDiagID(DiagnosticsEngine::Remark, "%0"); SourceManager &SM = Diag.getSourceManager(); Replacements Repls; auto reportPiece = [&](unsigned ID, FullSourceLoc Loc, StringRef String, ArrayRef Ranges, ArrayRef Fixits) { - if (!FixitsAsRemarks && !ApplyFixIts) { + if (!ApplyFixIts) { Diag.Report(Loc, ID) << String << Ranges << Fixits; return; } Diag.Report(Loc, ID) << String << Ranges; - if (FixitsAsRemarks) { - for (const FixItHint &Hint : Fixits) { - llvm::SmallString<128> Str; - llvm::raw_svector_ostream OS(Str); - // FIXME: Add support for InsertFromRange and - // BeforePreviousInsertion. - assert(!Hint.InsertFromRange.isValid() && "Not implemented yet!"); - assert(!Hint.BeforePreviousInsertions && "Not implemented yet!"); - OS << SM.getSpellingColumnNumber(Hint.RemoveRange.getBegin()) << "-" - << SM.getSpellingColumnNumber(Hint.RemoveRange.getEnd()) << ": '" - << Hint.CodeToInsert << "'"; - Diag.Report(Loc, RemarkID) << OS.str(); - } - } + for (const FixItHint &Hint : Fixits) { + Replacement Repl(SM, Hint.RemoveRange, Hint.CodeToInsert); - if (ApplyFixIts) { - for (const FixItHint &Hint : Fixits) { - Replacement Repl(SM, Hint.RemoveRange, Hint.CodeToInsert); - - if (llvm::Error Err = Repls.add(Repl)) { - llvm::errs() << "Error applying replacement " << Repl.toString() - << ": " << Err << "\n"; - } + if (llvm::Error Err = Repls.add(Repl)) { + llvm::errs() << "Error applying replacement " << Repl.toString() + << ": " << Err << "\n"; } } }; @@ -297,9 +277,6 @@ class AnalysisConsumer : public AnalysisASTConsumer, if (Opts->AnalyzerWerror) clangDiags->enableWerror(); - if (Opts->ShouldEmitFixItHintsAsRemarks) - clangDiags->enableFixitsAsRemarks(); - if (Opts->ShouldApplyFixIts) clangDiags->enableApplyFixIts(); diff --git a/clang/test/Analysis/analyzer-config.c b/clang/test/Analysis/analyzer-config.c index 478cb7e42f180..edd4fac7f8b24 100644 --- a/clang/test/Analysis/analyzer-config.c +++ b/clang/test/Analysis/analyzer-config.c @@ -58,7 +58,6 @@ // CHECK-NEXT: experimental-enable-naive-ctu-analysis = false // CHECK-NEXT: exploration_strategy = unexplored_first_queue // CHECK-NEXT: faux-bodies = true -// CHECK-NEXT: fixits-as-remarks = false // CHECK-NEXT: graph-trim-interval = 1000 // CHECK-NEXT: inline-lambdas = true // CHECK-NEXT: ipa = dynamic-bifurcate diff --git a/clang/test/Analysis/dead-stores.c b/clang/test/Analysis/dead-stores.c index cbfdabdcec632..a17e1692496da 100644 --- a/clang/test/Analysis/dead-stores.c +++ b/clang/test/Analysis/dead-stores.c @@ -1,16 +1,16 @@ -// RUN: %clang_analyze_cc1 -Wunused-variable -fblocks -Wno-unreachable-code \ +// RUN: %check_analyzer_fixit %s %t \ +// RUN: -Wunused-variable -fblocks -Wno-unreachable-code \ // RUN: -analyzer-checker=core,deadcode.DeadStores \ // RUN: -analyzer-config deadcode.DeadStores:ShowFixIts=true \ -// RUN: -analyzer-config fixits-as-remarks=true \ // RUN: -analyzer-config \ // RUN: deadcode.DeadStores:WarnForDeadNestedAssignments=false \ -// RUN: -verify=non-nested %s +// RUN: -verify=non-nested -// RUN: %clang_analyze_cc1 -Wunused-variable -fblocks -Wno-unreachable-code \ +// RUN: %check_analyzer_fixit %s %t \ +// RUN: -Wunused-variable -fblocks -Wno-unreachable-code \ // RUN: -analyzer-checker=core,deadcode.DeadStores \ // RUN: -analyzer-config deadcode.DeadStores:ShowFixIts=true \ -// RUN: -analyzer-config fixits-as-remarks=true \ -// RUN: -verify=non-nested,nested %s +// RUN: -verify=non-nested,nested void f1() { int k, y; // non-nested-warning {{unused variable 'k'}} @@ -18,14 +18,17 @@ void f1() { int abc = 1; long idx = abc + 3 * 5; // non-nested-warning {{never read}} // non-nested-warning@-1 {{unused variable 'idx'}} - // non-nested-remark@-2 {{11-24: ''}} + // CHECK-FIXES: int abc = 1; + // CHECK-FIXES-NEXT: long idx; } void f2(void *b) { char *c = (char *)b; // no-warning char *d = b + 1; // non-nested-warning {{never read}} // non-nested-warning@-1 {{unused variable 'd'}} - // non-nested-remark@-2 {{10-17: ''}} + // CHECK-FIXES: char *c = (char *)b; + // CHECK-FIXES-NEXT: char *d; + printf("%s", c); // non-nested-warning@-1 {{implicitly declaring library function 'printf' with type 'int (const char *, ...)'}} // non-nested-note@-2 {{include the header or explicitly provide a declaration for 'printf'}} @@ -51,7 +54,8 @@ void f5() { int x = 4; // no-warning int *p = &x; // non-nested-warning {{never read}} // non-nested-warning@-1 {{unused variable 'p'}} - // non-nested-remark@-2 {{9-13: ''}} + // CHECK-FIXES: int x = 4; + // CHECK-FIXES-NEXT: int *p; } int f6() { @@ -415,7 +419,8 @@ void f23_pos(int argc, char **argv) { int shouldLog = (argc > 1); // non-nested-warning@-1 {{Value stored to 'shouldLog' during its initialization is never read}} // non-nested-warning@-2 {{unused variable 'shouldLog'}} - // non-nested-remark@-3 {{16-28: ''}} + // CHECK-FIXES: void f23_pos(int argc, char **argv) { + // CHECK-FIXES-NEXT: int shouldLog; ^{ f23_aux("I did too use it!\n"); }(); @@ -428,7 +433,11 @@ void f24_A(int y) { int z = x + y; // non-nested-warning@-1 {{Value stored to 'z' during its initialization is never read}} // non-nested-warning@-2 {{unused variable 'z'}} - // non-nested-remark@-3 {{10-17: ''}} + // CHECK-FIXES: void f24_A(int y) { + // CHECK-FIXES-NEXT: // + // CHECK-FIXES-NEXT: int x = (y > 2); + // CHECK-FIXES-NEXT: ^{ + // CHECK-FIXES-NEXT: int z; }(); } diff --git a/clang/test/Analysis/virtualcall-fixit.cpp b/clang/test/Analysis/virtualcall-fixit.cpp deleted file mode 100644 index e64e63ab0856e..0000000000000 --- a/clang/test/Analysis/virtualcall-fixit.cpp +++ /dev/null @@ -1,13 +0,0 @@ -// RUN: %check_analyzer_fixit %s %t \ -// RUN: -analyzer-checker=core,optin.cplusplus.VirtualCall \ -// RUN: -analyzer-config optin.cplusplus.VirtualCall:ShowFixIts=true - -struct S { - virtual void foo(); - S() { - foo(); - // expected-warning@-1 {{Call to virtual method 'S::foo' during construction bypasses virtual dispatch}} - // CHECK-FIXES: S::foo(); - } - ~S(); -}; diff --git a/clang/test/Analysis/virtualcall-fixits.cpp b/clang/test/Analysis/virtualcall-fixits.cpp index ea149d52fcd21..b68fcbfea93d5 100644 --- a/clang/test/Analysis/virtualcall-fixits.cpp +++ b/clang/test/Analysis/virtualcall-fixits.cpp @@ -1,10 +1,11 @@ // RUN: %clang_analyze_cc1 -analyzer-checker=core,optin.cplusplus.VirtualCall \ // RUN: -analyzer-config optin.cplusplus.VirtualCall:ShowFixIts=true \ // RUN: %s 2>&1 | FileCheck -check-prefix=TEXT %s -// RUN: %clang_analyze_cc1 -analyzer-checker=core,optin.cplusplus.VirtualCall \ + +// RUN: %check_analyzer_fixit %s %t \ +// RUN: -analyzer-checker=core,optin.cplusplus.VirtualCall \ // RUN: -analyzer-config optin.cplusplus.VirtualCall:ShowFixIts=true \ -// RUN: -analyzer-config fixits-as-remarks=true \ -// RUN: -analyzer-output=plist -o %t.plist -verify %s +// RUN: -analyzer-output=plist -o %t.plist // RUN: cat %t.plist | FileCheck -check-prefix=PLIST %s struct S { @@ -12,7 +13,9 @@ struct S { S() { foo(); // expected-warning@-1{{Call to virtual method 'S::foo' during construction bypasses virtual dispatch}} - // expected-remark@-2{{5-5: 'S::'}} + // CHECK-FIXES: S() { + // CHECK-FIXES-NEXT: S::foo(); + // CHECK-FIXES-NEXT: } } ~S(); }; @@ -30,12 +33,12 @@ struct S { // PLIST-NEXT: remove_range // PLIST-NEXT: // PLIST-NEXT: -// PLIST-NEXT: line13 +// PLIST-NEXT: line14 // PLIST-NEXT: col5 // PLIST-NEXT: file0 // PLIST-NEXT: // PLIST-NEXT: -// PLIST-NEXT: line13 +// PLIST-NEXT: line14 // PLIST-NEXT: col4 // PLIST-NEXT: file0 // PLIST-NEXT: From 401a937db3403d38a1835d2d2661533e059e56eb Mon Sep 17 00:00:00 2001 From: Charusso Date: Wed, 4 Mar 2020 07:06:35 +0100 Subject: [PATCH 165/286] [analyzer] AnalysisDeclContext: Refactor and documentation Summary: `ScopeContext` wanted to be a thing, but sadly it is dead code. If you wish to continue the work in D19979, here was a tiny code which could be reused, but that tiny and that dead, I felt that it is unneded. Note: Other changes are truly uninteresting. Reviewed By: NoQ Differential Revision: https://reviews.llvm.org/D73519 (cherry picked from commit 7e1a6ca9e89c3ea08f8b008e9140d9fdc048d1df) --- .../clang/Analysis/AnalysisDeclContext.h | 374 ++++++++---------- clang/lib/Analysis/AnalysisDeclContext.cpp | 106 ++--- clang/lib/StaticAnalyzer/Core/MemRegion.cpp | 3 +- 3 files changed, 201 insertions(+), 282 deletions(-) diff --git a/clang/include/clang/Analysis/AnalysisDeclContext.h b/clang/include/clang/Analysis/AnalysisDeclContext.h index 9faa78cde89c2..ed554feedead6 100644 --- a/clang/include/clang/Analysis/AnalysisDeclContext.h +++ b/clang/include/clang/Analysis/AnalysisDeclContext.h @@ -1,4 +1,4 @@ -// AnalysisDeclContext.h - Analysis context for Path Sens analysis -*- C++ -*-// +//===- AnalysisDeclContext.h - Context for path sensitivity -----*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,8 +6,11 @@ // //===----------------------------------------------------------------------===// // -// This file defines AnalysisDeclContext, a class that manages the analysis -// context data for path sensitive analysis. +/// \file +/// This file defines AnalysisDeclContext, a class that manages the analysis +/// context data for context sensitive and path sensitive analysis. +/// It also defines the helper classes to model entering, leaving or inlining +/// function calls. // //===----------------------------------------------------------------------===// @@ -64,14 +67,14 @@ class ManagedAnalysis { // which creates the analysis object given an AnalysisDeclContext. }; -/// AnalysisDeclContext contains the context data for the function or method -/// under analysis. +/// AnalysisDeclContext contains the context data for the function, method +/// or block under analysis. class AnalysisDeclContext { - /// Backpoint to the AnalysisManager object that created this - /// AnalysisDeclContext. This may be null. - AnalysisDeclContextManager *Manager; + // Backpoint to the AnalysisManager object that created this + // AnalysisDeclContext. This may be null. + AnalysisDeclContextManager *ADCMgr; - const Decl * const D; + const Decl *const D; std::unique_ptr cfg, completeCFG; std::unique_ptr cfgStmtMap; @@ -86,45 +89,36 @@ class AnalysisDeclContext { llvm::BumpPtrAllocator A; - llvm::DenseMap *ReferencedBlockVars = nullptr; + llvm::DenseMap *ReferencedBlockVars = nullptr; void *ManagedAnalyses = nullptr; public: - AnalysisDeclContext(AnalysisDeclContextManager *Mgr, - const Decl *D); + AnalysisDeclContext(AnalysisDeclContextManager *Mgr, const Decl *D); - AnalysisDeclContext(AnalysisDeclContextManager *Mgr, - const Decl *D, - const CFG::BuildOptions &BuildOptions); + AnalysisDeclContext(AnalysisDeclContextManager *Mgr, const Decl *D, + const CFG::BuildOptions &BuildOptions); ~AnalysisDeclContext(); ASTContext &getASTContext() const { return D->getASTContext(); } + const Decl *getDecl() const { return D; } - /// Return the AnalysisDeclContextManager (if any) that created - /// this AnalysisDeclContext. - AnalysisDeclContextManager *getManager() const { - return Manager; - } + AnalysisDeclContextManager *getManager() const { return ADCMgr; } - /// Return the build options used to construct the CFG. - CFG::BuildOptions &getCFGBuildOptions() { - return cfgBuildOptions; - } + CFG::BuildOptions &getCFGBuildOptions() { return cfgBuildOptions; } const CFG::BuildOptions &getCFGBuildOptions() const { return cfgBuildOptions; } - /// getAddEHEdges - Return true iff we are adding exceptional edges from - /// callExprs. If this is false, then try/catch statements and blocks - /// reachable from them can appear to be dead in the CFG, analysis passes must - /// cope with that. + /// \returns Whether we are adding exception handling edges from CallExprs. + /// If this is false, then try/catch statements and blocks reachable from them + /// can appear to be dead in the CFG, analysis passes must cope with that. bool getAddEHEdges() const { return cfgBuildOptions.AddEHEdges; } bool getUseUnoptimizedCFG() const { - return !cfgBuildOptions.PruneTriviallyFalseEdges; + return !cfgBuildOptions.PruneTriviallyFalseEdges; } bool getAddImplicitDtors() const { return cfgBuildOptions.AddImplicitDtors; } bool getAddInitializers() const { return cfgBuildOptions.AddInitializers; } @@ -132,25 +126,25 @@ class AnalysisDeclContext { void registerForcedBlockExpression(const Stmt *stmt); const CFGBlock *getBlockForRegisteredExpression(const Stmt *stmt); - /// Get the body of the Declaration. + /// \returns The body of the stored Decl \c D. Stmt *getBody() const; - /// Get the body of the Declaration. + /// \copydoc AnalysisDeclContext::getBody() /// \param[out] IsAutosynthesized Specifies if the body is auto-generated /// by the BodyFarm. Stmt *getBody(bool &IsAutosynthesized) const; - /// Checks if the body of the Decl is generated by the BodyFarm. + /// \returns Whether the body of the Decl \c D is generated by the BodyFarm. /// - /// Note, the lookup is not free. We are going to call getBody behind + /// \note The lookup is not free. We are going to call getBody behind /// the scenes. /// \sa getBody bool isBodyAutosynthesized() const; - /// Checks if the body of the Decl is generated by the BodyFarm from a - /// model file. + /// \returns Whether the body of the Decl \c D is generated by the BodyFarm + /// from a model file. /// - /// Note, the lookup is not free. We are going to call getBody behind + /// \note The lookup is not free. We are going to call getBody behind /// the scenes. /// \sa getBody bool isBodyAutosynthesizedFromModelFile() const; @@ -161,40 +155,41 @@ class AnalysisDeclContext { CFGReverseBlockReachabilityAnalysis *getCFGReachablityAnalysis(); - /// Return a version of the CFG without any edges pruned. + /// \returns A version of the CFG without any edges pruned. CFG *getUnoptimizedCFG(); void dumpCFG(bool ShowColors); - /// Returns true if we have built a CFG for this analysis context. - /// Note that this doesn't correspond to whether or not a valid CFG exists, it + /// \returns Whether we have built a CFG for this analysis context. + /// + /// \note This doesn't correspond to whether or not a valid CFG exists, it /// corresponds to whether we *attempted* to build one. bool isCFGBuilt() const { return builtCFG; } ParentMap &getParentMap(); - using referenced_decls_iterator = const VarDecl * const *; + using referenced_decls_iterator = const VarDecl *const *; llvm::iterator_range getReferencedBlockVars(const BlockDecl *BD); - /// Return the ImplicitParamDecl* associated with 'self' if this - /// AnalysisDeclContext wraps an ObjCMethodDecl. Returns NULL otherwise. + /// \returns The ImplicitParamDecl associated with \c self if this + /// AnalysisDeclContext wraps an ObjCMethodDecl or nullptr otherwise. const ImplicitParamDecl *getSelfDecl() const; - const StackFrameContext *getStackFrame(LocationContext const *Parent, + /// \copydoc LocationContextManager::getStackFrame() + const StackFrameContext *getStackFrame(LocationContext const *ParentLC, const Stmt *S, const CFGBlock *Blk, - unsigned BlockCount, unsigned Idx); + unsigned BlockCount, unsigned Index); + /// \copydoc LocationContextManager::getBlockInvocationContext() const BlockInvocationContext * - getBlockInvocationContext(const LocationContext *parent, - const BlockDecl *BD, - const void *ContextData); - - /// Return the specified analysis object, lazily running the analysis if - /// necessary. Return NULL if the analysis could not run. - template - T *getAnalysis() { + getBlockInvocationContext(const LocationContext *ParentLC, + const BlockDecl *BD, const void *Data); + + /// \returns The specified analysis object, lazily running the analysis if + /// necessary or nullptr if the analysis could not run. + template T *getAnalysis() { const void *tag = T::getTag(); ManagedAnalysis *&data = getAnalysisImpl(tag); if (!data) { @@ -203,19 +198,22 @@ class AnalysisDeclContext { return static_cast(data); } - /// Returns true if the root namespace of the given declaration is the 'std' - /// C++ namespace. + /// \returns Whether the root namespace of \p D is the \c std C++ namespace. static bool isInStdNamespace(const Decl *D); private: - ManagedAnalysis *&getAnalysisImpl(const void* tag); + ManagedAnalysis *&getAnalysisImpl(const void *tag); LocationContextManager &getLocationContextManager(); }; +/// It wraps the AnalysisDeclContext to represent both the call stack with +/// the help of StackFrameContext and inside the function calls the +/// BlockInvocationContext. It is needed for context sensitive analysis to +/// model entering, leaving or inlining function calls. class LocationContext : public llvm::FoldingSetNode { public: - enum ContextKind { StackFrame, Scope, Block }; + enum ContextKind { StackFrame, Block }; private: ContextKind Kind; @@ -229,8 +227,7 @@ class LocationContext : public llvm::FoldingSetNode { protected: LocationContext(ContextKind k, AnalysisDeclContext *ctx, - const LocationContext *parent, - int64_t ID) + const LocationContext *parent, int64_t ID) : Kind(k), Ctx(ctx), Parent(parent), ID(ID) {} public: @@ -238,9 +235,7 @@ class LocationContext : public llvm::FoldingSetNode { ContextKind getKind() const { return Kind; } - int64_t getID() const { - return ID; - } + int64_t getID() const { return ID; } AnalysisDeclContext *getAnalysisDeclContext() const { return Ctx; } @@ -248,58 +243,61 @@ class LocationContext : public llvm::FoldingSetNode { bool isParentOf(const LocationContext *LC) const; - const Decl *getDecl() const { return getAnalysisDeclContext()->getDecl(); } + const Decl *getDecl() const { return Ctx->getDecl(); } - CFG *getCFG() const { return getAnalysisDeclContext()->getCFG(); } + CFG *getCFG() const { return Ctx->getCFG(); } - template - T *getAnalysis() const { - return getAnalysisDeclContext()->getAnalysis(); - } + template T *getAnalysis() const { return Ctx->getAnalysis(); } - const ParentMap &getParentMap() const { - return getAnalysisDeclContext()->getParentMap(); - } + const ParentMap &getParentMap() const { return Ctx->getParentMap(); } - const ImplicitParamDecl *getSelfDecl() const { - return Ctx->getSelfDecl(); - } + /// \copydoc AnalysisDeclContext::getSelfDecl() + const ImplicitParamDecl *getSelfDecl() const { return Ctx->getSelfDecl(); } const StackFrameContext *getStackFrame() const; - /// Return true if the current LocationContext has no caller context. + /// \returns Whether the current LocationContext has no caller context. virtual bool inTopFrame() const; virtual void Profile(llvm::FoldingSetNodeID &ID) = 0; - void dumpStack( - raw_ostream &Out, const char *NL = "\n", - std::function printMoreInfoPerContext = - [](const LocationContext *) {}) const; + /// Prints out the call stack. + /// + /// \param Out The out stream. + LLVM_DUMP_METHOD void dumpStack(raw_ostream &Out) const; + /// Prints out the call stack in \c json format. + /// + /// \param Out The out stream. + /// \param NL The newline. + /// \param Space The space count for indentation. + /// \param IsDot Whether the output format is \c dot. + /// \param printMoreInfoPerContext + /// A callback to print more information for each context, for example: + /// \code + /// [&](const LocationContext *LC) { LC->dump(); } + /// \endcode void printJson( raw_ostream &Out, const char *NL = "\n", unsigned int Space = 0, bool IsDot = false, std::function printMoreInfoPerContext = [](const LocationContext *) {}) const; - void dump() const; + LLVM_DUMP_METHOD void dump() const; -public: - static void ProfileCommon(llvm::FoldingSetNodeID &ID, - ContextKind ck, + static void ProfileCommon(llvm::FoldingSetNodeID &ID, ContextKind ck, AnalysisDeclContext *ctx, - const LocationContext *parent, - const void *data); + const LocationContext *parent, const void *data); }; +/// It represents a stack frame of the call stack (based on CallEvent). class StackFrameContext : public LocationContext { friend class LocationContextManager; - // The callsite where this stack frame is established. + // The call site where this stack frame is established. const Stmt *CallSite; - // The parent block of the callsite. + // The parent block of the call site. const CFGBlock *Block; // The number of times the 'Block' has been visited. @@ -307,14 +305,14 @@ class StackFrameContext : public LocationContext { // called multiple times in a loop. const unsigned BlockCount; - // The index of the callsite in the CFGBlock. + // The index of the call site in the CFGBlock. const unsigned Index; - StackFrameContext(AnalysisDeclContext *ctx, const LocationContext *parent, - const Stmt *s, const CFGBlock *blk, unsigned blockCount, - unsigned idx, int64_t ID) - : LocationContext(StackFrame, ctx, parent, ID), CallSite(s), Block(blk), - BlockCount(blockCount), Index(idx) {} + StackFrameContext(AnalysisDeclContext *ADC, const LocationContext *ParentLC, + const Stmt *S, const CFGBlock *Block, unsigned BlockCount, + unsigned Index, int64_t ID) + : LocationContext(StackFrame, ADC, ParentLC, ID), CallSite(S), + Block(Block), BlockCount(BlockCount), Index(Index) {} public: ~StackFrameContext() override = default; @@ -323,117 +321,98 @@ class StackFrameContext : public LocationContext { const CFGBlock *getCallSiteBlock() const { return Block; } - /// Return true if the current LocationContext has no caller context. - bool inTopFrame() const override { return getParent() == nullptr; } + bool inTopFrame() const override { return getParent() == nullptr; } unsigned getIndex() const { return Index; } void Profile(llvm::FoldingSetNodeID &ID) override; - static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx, - const LocationContext *parent, const Stmt *s, - const CFGBlock *blk, unsigned blockCount, unsigned idx) { - ProfileCommon(ID, StackFrame, ctx, parent, s); - ID.AddPointer(blk); - ID.AddInteger(blockCount); - ID.AddInteger(idx); + static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ADC, + const LocationContext *ParentLC, const Stmt *S, + const CFGBlock *Block, unsigned BlockCount, + unsigned Index) { + ProfileCommon(ID, StackFrame, ADC, ParentLC, S); + ID.AddPointer(Block); + ID.AddInteger(BlockCount); + ID.AddInteger(Index); } - static bool classof(const LocationContext *Ctx) { - return Ctx->getKind() == StackFrame; - } -}; - -class ScopeContext : public LocationContext { - friend class LocationContextManager; - - const Stmt *Enter; - - ScopeContext(AnalysisDeclContext *ctx, const LocationContext *parent, - const Stmt *s, int64_t ID) - : LocationContext(Scope, ctx, parent, ID), Enter(s) {} - -public: - ~ScopeContext() override = default; - - void Profile(llvm::FoldingSetNodeID &ID) override; - - static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx, - const LocationContext *parent, const Stmt *s) { - ProfileCommon(ID, Scope, ctx, parent, s); - } - - static bool classof(const LocationContext *Ctx) { - return Ctx->getKind() == Scope; + static bool classof(const LocationContext *LC) { + return LC->getKind() == StackFrame; } }; +/// It represents a block invocation (based on BlockCall). class BlockInvocationContext : public LocationContext { friend class LocationContextManager; const BlockDecl *BD; // FIXME: Come up with a more type-safe way to model context-sensitivity. - const void *ContextData; + const void *Data; - BlockInvocationContext(AnalysisDeclContext *ctx, - const LocationContext *parent, const BlockDecl *bd, - const void *contextData, int64_t ID) - : LocationContext(Block, ctx, parent, ID), BD(bd), - ContextData(contextData) {} + BlockInvocationContext(AnalysisDeclContext *ADC, + const LocationContext *ParentLC, const BlockDecl *BD, + const void *Data, int64_t ID) + : LocationContext(Block, ADC, ParentLC, ID), BD(BD), Data(Data) {} public: ~BlockInvocationContext() override = default; const BlockDecl *getBlockDecl() const { return BD; } - const void *getContextData() const { return ContextData; } + const void *getData() const { return Data; } void Profile(llvm::FoldingSetNodeID &ID) override; - static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx, - const LocationContext *parent, const BlockDecl *bd, - const void *contextData) { - ProfileCommon(ID, Block, ctx, parent, bd); - ID.AddPointer(contextData); + static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ADC, + const LocationContext *ParentLC, const BlockDecl *BD, + const void *Data) { + ProfileCommon(ID, Block, ADC, ParentLC, BD); + ID.AddPointer(Data); } - static bool classof(const LocationContext *Ctx) { - return Ctx->getKind() == Block; + static bool classof(const LocationContext *LC) { + return LC->getKind() == Block; } }; class LocationContextManager { llvm::FoldingSet Contexts; - /// ID used for generating a new location context. + // ID used for generating a new location context. int64_t NewID = 0; public: ~LocationContextManager(); - const StackFrameContext *getStackFrame(AnalysisDeclContext *ctx, - const LocationContext *parent, - const Stmt *s, const CFGBlock *blk, - unsigned blockCount, unsigned idx); - - const ScopeContext *getScope(AnalysisDeclContext *ctx, - const LocationContext *parent, - const Stmt *s); - + /// Obtain a context of the call stack using its parent context. + /// + /// \param ADC The AnalysisDeclContext. + /// \param ParentLC The parent context of this newly created context. + /// \param S The call. + /// \param Block The basic block. + /// \param BlockCount The current count of entering into \p Blk. + /// \param Index The index of \p Blk. + /// \returns The context for \p D with parent context \p ParentLC. + const StackFrameContext *getStackFrame(AnalysisDeclContext *ADC, + const LocationContext *ParentLC, + const Stmt *S, const CFGBlock *Block, + unsigned BlockCount, unsigned Index); + + /// Obtain a context of the block invocation using its parent context. + /// + /// \param ADC The AnalysisDeclContext. + /// \param ParentLC The parent context of this newly created context. + /// \param BD The BlockDecl. + /// \param Data The raw data to store as part of the context. const BlockInvocationContext * - getBlockInvocationContext(AnalysisDeclContext *ctx, - const LocationContext *parent, - const BlockDecl *BD, - const void *ContextData); + getBlockInvocationContext(AnalysisDeclContext *ADC, + const LocationContext *ParentLC, + const BlockDecl *BD, const void *Data); /// Discard all previously created LocationContext objects. void clear(); -private: - template - const LOC *getLocationContext(AnalysisDeclContext *ctx, - const LocationContext *parent, - const DATA *d); }; class AnalysisDeclContextManager { @@ -441,36 +420,31 @@ class AnalysisDeclContextManager { llvm::DenseMap>; ContextMap Contexts; - LocationContextManager LocContexts; + LocationContextManager LocCtxMgr; CFG::BuildOptions cfgBuildOptions; - /// Pointer to an interface that can provide function bodies for - /// declarations from external source. + // Pointer to an interface that can provide function bodies for + // declarations from external source. std::unique_ptr Injector; - /// A factory for creating and caching implementations for common - /// methods during the analysis. + // A factory for creating and caching implementations for common + // methods during the analysis. BodyFarm FunctionBodyFarm; - /// Flag to indicate whether or not bodies should be synthesized - /// for well-known functions. + // Flag to indicate whether or not bodies should be synthesized + // for well-known functions. bool SynthesizeBodies; public: - AnalysisDeclContextManager(ASTContext &ASTCtx, bool useUnoptimizedCFG = false, - bool addImplicitDtors = false, - bool addInitializers = false, - bool addTemporaryDtors = false, - bool addLifetime = false, - bool addLoopExit = false, - bool addScopes = false, - bool synthesizeBodies = false, - bool addStaticInitBranches = false, - bool addCXXNewAllocator = true, - bool addRichCXXConstructors = true, - bool markElidedCXXConstructors = true, - bool addVirtualBaseBranches = true, - CodeInjector *injector = nullptr); + AnalysisDeclContextManager( + ASTContext &ASTCtx, bool useUnoptimizedCFG = false, + bool addImplicitDtors = false, bool addInitializers = false, + bool addTemporaryDtors = false, bool addLifetime = false, + bool addLoopExit = false, bool addScopes = false, + bool synthesizeBodies = false, bool addStaticInitBranches = false, + bool addCXXNewAllocator = true, bool addRichCXXConstructors = true, + bool markElidedCXXConstructors = true, bool addVirtualBaseBranches = true, + CodeInjector *injector = nullptr); AnalysisDeclContext *getContext(const Decl *D); @@ -478,37 +452,27 @@ class AnalysisDeclContextManager { return !cfgBuildOptions.PruneTriviallyFalseEdges; } - CFG::BuildOptions &getCFGBuildOptions() { - return cfgBuildOptions; - } + CFG::BuildOptions &getCFGBuildOptions() { return cfgBuildOptions; } - /// Return true if faux bodies should be synthesized for well-known - /// functions. + /// \returns Whether faux bodies should be synthesized for known functions. bool synthesizeBodies() const { return SynthesizeBodies; } - const StackFrameContext *getStackFrame(AnalysisDeclContext *Ctx, - const LocationContext *Parent, - const Stmt *S, const CFGBlock *Blk, - unsigned BlockCount, unsigned Idx) { - return LocContexts.getStackFrame(Ctx, Parent, S, Blk, BlockCount, Idx); - } - - // Get the top level stack frame. + /// Obtain the beginning context of the analysis. + /// + /// \returns The top level stack frame for \p D. const StackFrameContext *getStackFrame(const Decl *D) { - return LocContexts.getStackFrame(getContext(D), nullptr, nullptr, nullptr, - 0, 0); + return LocCtxMgr.getStackFrame(getContext(D), nullptr, nullptr, nullptr, 0, + 0); } - // Get a stack frame with parent. - StackFrameContext const *getStackFrame(const Decl *D, + /// \copydoc LocationContextManager::getStackFrame() + const StackFrameContext *getStackFrame(AnalysisDeclContext *ADC, const LocationContext *Parent, - const Stmt *S, const CFGBlock *Blk, - unsigned BlockCount, unsigned Idx) { - return LocContexts.getStackFrame(getContext(D), Parent, S, Blk, BlockCount, - Idx); + const Stmt *S, const CFGBlock *Block, + unsigned BlockCount, unsigned Index) { + return LocCtxMgr.getStackFrame(ADC, Parent, S, Block, BlockCount, Index); } - /// Get a reference to {@code BodyFarm} instance. BodyFarm &getBodyFarm(); /// Discard all previously created AnalysisDeclContexts. @@ -517,9 +481,7 @@ class AnalysisDeclContextManager { private: friend class AnalysisDeclContext; - LocationContextManager &getLocationContextManager() { - return LocContexts; - } + LocationContextManager &getLocationContextManager() { return LocCtxMgr; } }; } // namespace clang diff --git a/clang/lib/Analysis/AnalysisDeclContext.cpp b/clang/lib/Analysis/AnalysisDeclContext.cpp index 9f58b5079c760..96d5807bcdfc0 100644 --- a/clang/lib/Analysis/AnalysisDeclContext.cpp +++ b/clang/lib/Analysis/AnalysisDeclContext.cpp @@ -52,16 +52,16 @@ using namespace clang; using ManagedAnalysisMap = llvm::DenseMap; -AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr, - const Decl *d, - const CFG::BuildOptions &buildOptions) - : Manager(Mgr), D(d), cfgBuildOptions(buildOptions) { +AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *ADCMgr, + const Decl *D, + const CFG::BuildOptions &Options) + : ADCMgr(ADCMgr), D(D), cfgBuildOptions(Options) { cfgBuildOptions.forcedBlkExprs = &forcedBlkExprs; } -AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr, - const Decl *d) - : Manager(Mgr), D(d) { +AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *ADCMgr, + const Decl *D) + : ADCMgr(ADCMgr), D(D) { cfgBuildOptions.forcedBlkExprs = &forcedBlkExprs; } @@ -96,8 +96,8 @@ Stmt *AnalysisDeclContext::getBody(bool &IsAutosynthesized) const { Stmt *Body = FD->getBody(); if (auto *CoroBody = dyn_cast_or_null(Body)) Body = CoroBody->getBody(); - if (Manager && Manager->synthesizeBodies()) { - Stmt *SynthesizedBody = Manager->getBodyFarm().getBody(FD); + if (ADCMgr && ADCMgr->synthesizeBodies()) { + Stmt *SynthesizedBody = ADCMgr->getBodyFarm().getBody(FD); if (SynthesizedBody) { Body = SynthesizedBody; IsAutosynthesized = true; @@ -107,8 +107,8 @@ Stmt *AnalysisDeclContext::getBody(bool &IsAutosynthesized) const { } else if (const auto *MD = dyn_cast(D)) { Stmt *Body = MD->getBody(); - if (Manager && Manager->synthesizeBodies()) { - Stmt *SynthesizedBody = Manager->getBodyFarm().getBody(MD); + if (ADCMgr && ADCMgr->synthesizeBodies()) { + Stmt *SynthesizedBody = ADCMgr->getBodyFarm().getBody(MD); if (SynthesizedBody) { Body = SynthesizedBody; IsAutosynthesized = true; @@ -309,19 +309,17 @@ AnalysisDeclContext *AnalysisDeclContextManager::getContext(const Decl *D) { BodyFarm &AnalysisDeclContextManager::getBodyFarm() { return FunctionBodyFarm; } const StackFrameContext * -AnalysisDeclContext::getStackFrame(LocationContext const *Parent, const Stmt *S, - const CFGBlock *Blk, unsigned BlockCount, - unsigned Idx) { - return getLocationContextManager().getStackFrame(this, Parent, S, Blk, - BlockCount, Idx); +AnalysisDeclContext::getStackFrame(const LocationContext *ParentLC, + const Stmt *S, const CFGBlock *Blk, + unsigned BlockCount, unsigned Index) { + return getLocationContextManager().getStackFrame(this, ParentLC, S, Blk, + BlockCount, Index); } -const BlockInvocationContext * -AnalysisDeclContext::getBlockInvocationContext(const LocationContext *parent, - const BlockDecl *BD, - const void *ContextData) { - return getLocationContextManager().getBlockInvocationContext(this, parent, - BD, ContextData); +const BlockInvocationContext *AnalysisDeclContext::getBlockInvocationContext( + const LocationContext *ParentLC, const BlockDecl *BD, const void *Data) { + return getLocationContextManager().getBlockInvocationContext(this, ParentLC, + BD, Data); } bool AnalysisDeclContext::isInStdNamespace(const Decl *D) { @@ -340,9 +338,10 @@ bool AnalysisDeclContext::isInStdNamespace(const Decl *D) { } LocationContextManager &AnalysisDeclContext::getLocationContextManager() { - assert(Manager && - "Cannot create LocationContexts without an AnalysisDeclContextManager!"); - return Manager->getLocationContextManager(); + assert( + ADCMgr && + "Cannot create LocationContexts without an AnalysisDeclContextManager!"); + return ADCMgr->getLocationContextManager(); } //===----------------------------------------------------------------------===// @@ -365,36 +364,14 @@ void StackFrameContext::Profile(llvm::FoldingSetNodeID &ID) { BlockCount, Index); } -void ScopeContext::Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getAnalysisDeclContext(), getParent(), Enter); -} - void BlockInvocationContext::Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, getAnalysisDeclContext(), getParent(), BD, ContextData); + Profile(ID, getAnalysisDeclContext(), getParent(), BD, Data); } //===----------------------------------------------------------------------===// // LocationContext creation. //===----------------------------------------------------------------------===// -template -const LOC* -LocationContextManager::getLocationContext(AnalysisDeclContext *ctx, - const LocationContext *parent, - const DATA *d) { - llvm::FoldingSetNodeID ID; - LOC::Profile(ID, ctx, parent, d); - void *InsertPos; - - LOC *L = cast_or_null(Contexts.FindNodeOrInsertPos(ID, InsertPos)); - - if (!L) { - L = new LOC(ctx, parent, d, ++NewID); - Contexts.InsertNode(L, InsertPos); - } - return L; -} - const StackFrameContext *LocationContextManager::getStackFrame( AnalysisDeclContext *ctx, const LocationContext *parent, const Stmt *s, const CFGBlock *blk, unsigned blockCount, unsigned idx) { @@ -410,26 +387,17 @@ const StackFrameContext *LocationContextManager::getStackFrame( return L; } -const ScopeContext * -LocationContextManager::getScope(AnalysisDeclContext *ctx, - const LocationContext *parent, - const Stmt *s) { - return getLocationContext(ctx, parent, s); -} - -const BlockInvocationContext * -LocationContextManager::getBlockInvocationContext(AnalysisDeclContext *ctx, - const LocationContext *parent, - const BlockDecl *BD, - const void *ContextData) { +const BlockInvocationContext *LocationContextManager::getBlockInvocationContext( + AnalysisDeclContext *ADC, const LocationContext *ParentLC, + const BlockDecl *BD, const void *Data) { llvm::FoldingSetNodeID ID; - BlockInvocationContext::Profile(ID, ctx, parent, BD, ContextData); + BlockInvocationContext::Profile(ID, ADC, ParentLC, BD, Data); void *InsertPos; auto *L = cast_or_null(Contexts.FindNodeOrInsertPos(ID, InsertPos)); if (!L) { - L = new BlockInvocationContext(ctx, parent, BD, ContextData, ++NewID); + L = new BlockInvocationContext(ADC, ParentLC, BD, Data, ++NewID); Contexts.InsertNode(L, InsertPos); } return L; @@ -473,9 +441,7 @@ static void printLocation(raw_ostream &Out, const SourceManager &SM, Loc.print(Out, SM); } -void LocationContext::dumpStack(raw_ostream &Out, const char *NL, - std::function - printMoreInfoPerContext) const { +void LocationContext::dumpStack(raw_ostream &Out) const { ASTContext &Ctx = getAnalysisDeclContext()->getASTContext(); PrintingPolicy PP(Ctx.getLangOpts()); PP.TerseOutput = 1; @@ -498,9 +464,6 @@ void LocationContext::dumpStack(raw_ostream &Out, const char *NL, printLocation(Out, SM, S->getBeginLoc()); } break; - case Scope: - Out << "Entering scope"; - break; case Block: Out << "Invoking block"; if (const Decl *D = cast(LCtx)->getDecl()) { @@ -509,9 +472,7 @@ void LocationContext::dumpStack(raw_ostream &Out, const char *NL, } break; } - Out << NL; - - printMoreInfoPerContext(LCtx); + Out << '\n'; } } @@ -548,9 +509,6 @@ void LocationContext::printJson(raw_ostream &Out, const char *NL, Out << ", \"items\": "; break; - case Scope: - Out << "Entering scope\" "; - break; case Block: Out << "Invoking block\" "; if (const Decl *D = cast(LCtx)->getDecl()) { diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp index a10d7e69ad7e7..1482c627cdd4c 100644 --- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -825,8 +825,7 @@ getStackOrCaptureRegionForDeclContext(const LocationContext *LC, return SFC; } if (const auto *BC = dyn_cast(LC)) { - const auto *BR = - static_cast(BC->getContextData()); + const auto *BR = static_cast(BC->getData()); // FIXME: This can be made more efficient. for (BlockDataRegion::referenced_vars_iterator I = BR->referenced_vars_begin(), From 4138074a53859aed91bbe89ac6dfbc645dc12d3c Mon Sep 17 00:00:00 2001 From: Balazs Benics Date: Wed, 4 Mar 2020 17:03:59 +0100 Subject: [PATCH 166/286] [analyzer][NFC] Use CallEvent checker callback in GenericTaintChecker Summary: Intended to be a non-functional change but it turned out CallEvent handles constructor calls unlike CallExpr which doesn't triggered for constructors. All in all, this change shouldn't be observable since constructors are not yet propagating taintness like functions. In the future constructors should propagate taintness as well. This change includes: - NFCi change all uses of the CallExpr to CallEvent - NFC rename some functions, mark static them etc. - NFC omit explicit TaintPropagationRule type in switches - NFC apply some clang-tidy fixits Reviewers: NoQ, Szelethus, boga95 Reviewed By: Szelethus Subscribers: martong, whisperity, xazax.hun, baloghadamsoftware, szepet, a.sidorin, mikhail.ramalho, donat.nagy, dkrupp, Charusso, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D72035 (cherry picked from commit 95a94df5a9c3d7d2aa92b6beb13e82d8d5832e2e) --- .../Checkers/GenericTaintChecker.cpp | 338 +++++++++--------- 1 file changed, 172 insertions(+), 166 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp index 302d5bb1bea86..564f7e850b1b0 100644 --- a/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp @@ -22,11 +22,14 @@ #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" #include "llvm/Support/YAMLTraits.h" + #include #include +#include #include #include @@ -35,17 +38,15 @@ using namespace ento; using namespace taint; namespace { -class GenericTaintChecker - : public Checker, check::PreStmt> { +class GenericTaintChecker : public Checker { public: static void *getTag() { static int Tag; return &Tag; } - void checkPostStmt(const CallExpr *CE, CheckerContext &C) const; - - void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; + void checkPreCall(const CallEvent &Call, CheckerContext &C) const; + void checkPostCall(const CallEvent &Call, CheckerContext &C) const; void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const override; @@ -81,7 +82,7 @@ class GenericTaintChecker /// Convert SignedArgVector to ArgVector. ArgVector convertToArgVector(CheckerManager &Mgr, const std::string &Option, - SignedArgVector Args); + const SignedArgVector &Args); /// Parse the config. void parseConfiguration(CheckerManager &Mgr, const std::string &Option, @@ -96,7 +97,8 @@ class GenericTaintChecker mutable std::unique_ptr BT; void initBugType() const { if (!BT) - BT.reset(new BugType(this, "Use of Untrusted Data", "Untrusted Data")); + BT = std::make_unique(this, "Use of Untrusted Data", + "Untrusted Data"); } struct FunctionData { @@ -106,9 +108,10 @@ class GenericTaintChecker FunctionData &operator=(const FunctionData &) = delete; FunctionData &operator=(FunctionData &&) = delete; - static Optional create(const CallExpr *CE, + static Optional create(const CallEvent &Call, const CheckerContext &C) { - const FunctionDecl *FDecl = C.getCalleeDecl(CE); + assert(Call.getDecl()); + const FunctionDecl *FDecl = Call.getDecl()->getAsFunction(); if (!FDecl || (FDecl->getKind() != Decl::Function && FDecl->getKind() != Decl::CXXMethod)) return None; @@ -132,33 +135,33 @@ class GenericTaintChecker /// Catch taint related bugs. Check if tainted data is passed to a /// system call etc. Returns true on matching. - bool checkPre(const CallExpr *CE, const FunctionData &FData, + bool checkPre(const CallEvent &Call, const FunctionData &FData, CheckerContext &C) const; /// Add taint sources on a pre-visit. Returns true on matching. - bool addSourcesPre(const CallExpr *CE, const FunctionData &FData, + bool addSourcesPre(const CallEvent &Call, const FunctionData &FData, CheckerContext &C) const; /// Mark filter's arguments not tainted on a pre-visit. Returns true on /// matching. - bool addFiltersPre(const CallExpr *CE, const FunctionData &FData, + bool addFiltersPre(const CallEvent &Call, const FunctionData &FData, CheckerContext &C) const; /// Propagate taint generated at pre-visit. Returns true on matching. - bool propagateFromPre(const CallExpr *CE, CheckerContext &C) const; + static bool propagateFromPre(const CallEvent &Call, CheckerContext &C); /// Check if the region the expression evaluates to is the standard input, /// and thus, is tainted. static bool isStdin(const Expr *E, CheckerContext &C); /// Given a pointer argument, return the value it points to. - static Optional getPointedToSVal(CheckerContext &C, const Expr *Arg); + static Optional getPointeeOf(CheckerContext &C, const Expr *Arg); /// Check for CWE-134: Uncontrolled Format String. static constexpr llvm::StringLiteral MsgUncontrolledFormatString = "Untrusted data is used as a format string " "(CWE-134: Uncontrolled Format String)"; - bool checkUncontrolledFormatString(const CallExpr *CE, + bool checkUncontrolledFormatString(const CallEvent &Call, CheckerContext &C) const; /// Check for: @@ -167,7 +170,7 @@ class GenericTaintChecker static constexpr llvm::StringLiteral MsgSanitizeSystemArgs = "Untrusted data is passed to a system call " "(CERT/STR02-C. Sanitize data passed to complex subsystems)"; - bool checkSystemCall(const CallExpr *CE, StringRef Name, + bool checkSystemCall(const CallEvent &Call, StringRef Name, CheckerContext &C) const; /// Check if tainted data is used as a buffer size ins strn.. functions, @@ -176,13 +179,12 @@ class GenericTaintChecker "Untrusted data is used to specify the buffer size " "(CERT/STR31-C. Guarantee that storage for strings has sufficient space " "for character data and the null terminator)"; - bool checkTaintedBufferSize(const CallExpr *CE, const FunctionDecl *FDecl, - CheckerContext &C) const; + bool checkTaintedBufferSize(const CallEvent &Call, CheckerContext &C) const; /// Check if tainted data is used as a custom sink's parameter. static constexpr llvm::StringLiteral MsgCustomSink = "Untrusted data is passed to a user-defined sink"; - bool checkCustomSinks(const CallExpr *CE, const FunctionData &FData, + bool checkCustomSinks(const CallEvent &Call, const FunctionData &FData, CheckerContext &C) const; /// Generate a report if the expression is tainted or points to tainted data. @@ -212,7 +214,7 @@ class GenericTaintChecker /// ReturnValueIndex is added to the dst list, the return value will be /// tainted. struct TaintPropagationRule { - using PropagationFuncType = bool (*)(bool IsTainted, const CallExpr *, + using PropagationFuncType = bool (*)(bool IsTainted, const CallEvent &Call, CheckerContext &C); /// List of arguments which can be taint sources and should be checked. @@ -256,7 +258,8 @@ class GenericTaintChecker return (llvm::find(DstArgs, ArgNum) != DstArgs.end()); } - static bool isTaintedOrPointsToTainted(const Expr *E, ProgramStateRef State, + static bool isTaintedOrPointsToTainted(const Expr *E, + const ProgramStateRef &State, CheckerContext &C) { if (isTainted(State, E, C.getLocationContext()) || isStdin(E, C)) return true; @@ -264,16 +267,16 @@ class GenericTaintChecker if (!E->getType().getTypePtr()->isPointerType()) return false; - Optional V = getPointedToSVal(C, E); + Optional V = getPointeeOf(C, E); return (V && isTainted(State, *V)); } /// Pre-process a function which propagates taint according to the /// taint rule. - ProgramStateRef process(const CallExpr *CE, CheckerContext &C) const; + ProgramStateRef process(const CallEvent &Call, CheckerContext &C) const; // Functions for custom taintedness propagation. - static bool postSocket(bool IsTainted, const CallExpr *CE, + static bool postSocket(bool IsTainted, const CallEvent &Call, CheckerContext &C); }; @@ -351,8 +354,10 @@ template <> struct MappingTraits { /// points to data, which should be tainted on return. REGISTER_SET_WITH_PROGRAMSTATE(TaintArgsOnPostVisit, unsigned) -GenericTaintChecker::ArgVector GenericTaintChecker::convertToArgVector( - CheckerManager &Mgr, const std::string &Option, SignedArgVector Args) { +GenericTaintChecker::ArgVector +GenericTaintChecker::convertToArgVector(CheckerManager &Mgr, + const std::string &Option, + const SignedArgVector &Args) { ArgVector Result; for (int Arg : Args) { if (Arg == -1) @@ -419,125 +424,125 @@ GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule( llvm::StringSwitch(FData.FullName) // Source functions // TODO: Add support for vfscanf & family. - .Case("fdopen", TaintPropagationRule({}, {ReturnValueIndex})) - .Case("fopen", TaintPropagationRule({}, {ReturnValueIndex})) - .Case("freopen", TaintPropagationRule({}, {ReturnValueIndex})) - .Case("getch", TaintPropagationRule({}, {ReturnValueIndex})) - .Case("getchar", TaintPropagationRule({}, {ReturnValueIndex})) - .Case("getchar_unlocked", - TaintPropagationRule({}, {ReturnValueIndex})) - .Case("getenv", TaintPropagationRule({}, {ReturnValueIndex})) - .Case("gets", TaintPropagationRule({}, {0, ReturnValueIndex})) - .Case("scanf", TaintPropagationRule({}, {}, VariadicType::Dst, 1)) - .Case("socket", - TaintPropagationRule({}, {ReturnValueIndex}, VariadicType::None, - InvalidArgIndex, - &TaintPropagationRule::postSocket)) - .Case("wgetch", TaintPropagationRule({}, {ReturnValueIndex})) + .Case("fdopen", {{}, {ReturnValueIndex}}) + .Case("fopen", {{}, {ReturnValueIndex}}) + .Case("freopen", {{}, {ReturnValueIndex}}) + .Case("getch", {{}, {ReturnValueIndex}}) + .Case("getchar", {{}, {ReturnValueIndex}}) + .Case("getchar_unlocked", {{}, {ReturnValueIndex}}) + .Case("getenv", {{}, {ReturnValueIndex}}) + .Case("gets", {{}, {0, ReturnValueIndex}}) + .Case("scanf", {{}, {}, VariadicType::Dst, 1}) + .Case("socket", {{}, + {ReturnValueIndex}, + VariadicType::None, + InvalidArgIndex, + &TaintPropagationRule::postSocket}) + .Case("wgetch", {{}, {ReturnValueIndex}}) // Propagating functions - .Case("atoi", TaintPropagationRule({0}, {ReturnValueIndex})) - .Case("atol", TaintPropagationRule({0}, {ReturnValueIndex})) - .Case("atoll", TaintPropagationRule({0}, {ReturnValueIndex})) - .Case("fgetc", TaintPropagationRule({0}, {ReturnValueIndex})) - .Case("fgetln", TaintPropagationRule({0}, {ReturnValueIndex})) - .Case("fgets", TaintPropagationRule({2}, {0, ReturnValueIndex})) - .Case("fscanf", TaintPropagationRule({0}, {}, VariadicType::Dst, 2)) - .Case("getc", TaintPropagationRule({0}, {ReturnValueIndex})) - .Case("getc_unlocked", TaintPropagationRule({0}, {ReturnValueIndex})) - .Case("getdelim", TaintPropagationRule({3}, {0})) - .Case("getline", TaintPropagationRule({2}, {0})) - .Case("getw", TaintPropagationRule({0}, {ReturnValueIndex})) - .Case("pread", - TaintPropagationRule({0, 1, 2, 3}, {1, ReturnValueIndex})) - .Case("read", TaintPropagationRule({0, 2}, {1, ReturnValueIndex})) - .Case("strchr", TaintPropagationRule({0}, {ReturnValueIndex})) - .Case("strrchr", TaintPropagationRule({0}, {ReturnValueIndex})) - .Case("tolower", TaintPropagationRule({0}, {ReturnValueIndex})) - .Case("toupper", TaintPropagationRule({0}, {ReturnValueIndex})) - .Default(TaintPropagationRule()); + .Case("atoi", {{0}, {ReturnValueIndex}}) + .Case("atol", {{0}, {ReturnValueIndex}}) + .Case("atoll", {{0}, {ReturnValueIndex}}) + .Case("fgetc", {{0}, {ReturnValueIndex}}) + .Case("fgetln", {{0}, {ReturnValueIndex}}) + .Case("fgets", {{2}, {0, ReturnValueIndex}}) + .Case("fscanf", {{0}, {}, VariadicType::Dst, 2}) + .Case("sscanf", {{0}, {}, VariadicType::Dst, 2}) + .Case("getc", {{0}, {ReturnValueIndex}}) + .Case("getc_unlocked", {{0}, {ReturnValueIndex}}) + .Case("getdelim", {{3}, {0}}) + .Case("getline", {{2}, {0}}) + .Case("getw", {{0}, {ReturnValueIndex}}) + .Case("pread", {{0, 1, 2, 3}, {1, ReturnValueIndex}}) + .Case("read", {{0, 2}, {1, ReturnValueIndex}}) + .Case("strchr", {{0}, {ReturnValueIndex}}) + .Case("strrchr", {{0}, {ReturnValueIndex}}) + .Case("tolower", {{0}, {ReturnValueIndex}}) + .Case("toupper", {{0}, {ReturnValueIndex}}) + .Default({}); if (!Rule.isNull()) return Rule; + assert(FData.FDecl); // Check if it's one of the memory setting/copying functions. // This check is specialized but faster then calling isCLibraryFunction. const FunctionDecl *FDecl = FData.FDecl; unsigned BId = 0; - if ((BId = FDecl->getMemoryFunctionKind())) + if ((BId = FDecl->getMemoryFunctionKind())) { switch (BId) { case Builtin::BImemcpy: case Builtin::BImemmove: case Builtin::BIstrncpy: case Builtin::BIstrncat: - return TaintPropagationRule({1, 2}, {0, ReturnValueIndex}); + return {{1, 2}, {0, ReturnValueIndex}}; case Builtin::BIstrlcpy: case Builtin::BIstrlcat: - return TaintPropagationRule({1, 2}, {0}); + return {{1, 2}, {0}}; case Builtin::BIstrndup: - return TaintPropagationRule({0, 1}, {ReturnValueIndex}); + return {{0, 1}, {ReturnValueIndex}}; default: break; - }; + } + } // Process all other functions which could be defined as builtins. if (Rule.isNull()) { - if (C.isCLibraryFunction(FDecl, "snprintf")) - return TaintPropagationRule({1}, {0, ReturnValueIndex}, VariadicType::Src, - 3); - else if (C.isCLibraryFunction(FDecl, "sprintf")) - return TaintPropagationRule({}, {0, ReturnValueIndex}, VariadicType::Src, - 2); - else if (C.isCLibraryFunction(FDecl, "strcpy") || - C.isCLibraryFunction(FDecl, "stpcpy") || - C.isCLibraryFunction(FDecl, "strcat")) - return TaintPropagationRule({1}, {0, ReturnValueIndex}); - else if (C.isCLibraryFunction(FDecl, "bcopy")) - return TaintPropagationRule({0, 2}, {1}); - else if (C.isCLibraryFunction(FDecl, "strdup") || - C.isCLibraryFunction(FDecl, "strdupa")) - return TaintPropagationRule({0}, {ReturnValueIndex}); - else if (C.isCLibraryFunction(FDecl, "wcsdup")) - return TaintPropagationRule({0}, {ReturnValueIndex}); + const auto OneOf = [FDecl](const auto &... Name) { + // FIXME: use fold expression in C++17 + using unused = int[]; + bool ret = false; + static_cast(unused{ + 0, (ret |= CheckerContext::isCLibraryFunction(FDecl, Name), 0)...}); + return ret; + }; + if (OneOf("snprintf")) + return {{1}, {0, ReturnValueIndex}, VariadicType::Src, 3}; + if (OneOf("sprintf")) + return {{}, {0, ReturnValueIndex}, VariadicType::Src, 2}; + if (OneOf("strcpy", "stpcpy", "strcat")) + return {{1}, {0, ReturnValueIndex}}; + if (OneOf("bcopy")) + return {{0, 2}, {1}}; + if (OneOf("strdup", "strdupa", "wcsdup")) + return {{0}, {ReturnValueIndex}}; } - // Skipping the following functions, since they might be used for cleansing - // or smart memory copy: + // Skipping the following functions, since they might be used for cleansing or + // smart memory copy: // - memccpy - copying until hitting a special character. auto It = findFunctionInConfig(CustomPropagations, FData); - if (It != CustomPropagations.end()) { - const auto &Value = It->second; - return Value.second; - } - - return TaintPropagationRule(); + if (It != CustomPropagations.end()) + return It->second.second; + return {}; } -void GenericTaintChecker::checkPreStmt(const CallExpr *CE, +void GenericTaintChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const { - Optional FData = FunctionData::create(CE, C); + Optional FData = FunctionData::create(Call, C); if (!FData) return; // Check for taintedness related errors first: system call, uncontrolled // format string, tainted buffer size. - if (checkPre(CE, *FData, C)) + if (checkPre(Call, *FData, C)) return; // Marks the function's arguments and/or return value tainted if it present in // the list. - if (addSourcesPre(CE, *FData, C)) + if (addSourcesPre(Call, *FData, C)) return; - addFiltersPre(CE, *FData, C); + addFiltersPre(Call, *FData, C); } -void GenericTaintChecker::checkPostStmt(const CallExpr *CE, +void GenericTaintChecker::checkPostCall(const CallEvent &Call, CheckerContext &C) const { // Set the marked values as tainted. The return value only accessible from // checkPostStmt. - propagateFromPre(CE, C); + propagateFromPre(Call, C); } void GenericTaintChecker::printState(raw_ostream &Out, ProgramStateRef State, @@ -545,14 +550,14 @@ void GenericTaintChecker::printState(raw_ostream &Out, ProgramStateRef State, printTaint(State, Out, NL, Sep); } -bool GenericTaintChecker::addSourcesPre(const CallExpr *CE, +bool GenericTaintChecker::addSourcesPre(const CallEvent &Call, const FunctionData &FData, CheckerContext &C) const { // First, try generating a propagation rule for this function. TaintPropagationRule Rule = TaintPropagationRule::getTaintPropagationRule( this->CustomPropagations, FData, C); if (!Rule.isNull()) { - ProgramStateRef State = Rule.process(CE, C); + ProgramStateRef State = Rule.process(Call, C); if (State) { C.addTransition(State); return true; @@ -561,7 +566,7 @@ bool GenericTaintChecker::addSourcesPre(const CallExpr *CE, return false; } -bool GenericTaintChecker::addFiltersPre(const CallExpr *CE, +bool GenericTaintChecker::addFiltersPre(const CallEvent &Call, const FunctionData &FData, CheckerContext &C) const { auto It = findFunctionInConfig(CustomFilters, FData); @@ -572,11 +577,11 @@ bool GenericTaintChecker::addFiltersPre(const CallExpr *CE, const auto &Value = It->second; const ArgVector &Args = Value.second; for (unsigned ArgNum : Args) { - if (ArgNum >= CE->getNumArgs()) + if (ArgNum >= Call.getNumArgs()) continue; - const Expr *Arg = CE->getArg(ArgNum); - Optional V = getPointedToSVal(C, Arg); + const Expr *Arg = Call.getArgExpr(ArgNum); + Optional V = getPointeeOf(C, Arg); if (V) State = removeTaint(State, *V); } @@ -588,8 +593,8 @@ bool GenericTaintChecker::addFiltersPre(const CallExpr *CE, return false; } -bool GenericTaintChecker::propagateFromPre(const CallExpr *CE, - CheckerContext &C) const { +bool GenericTaintChecker::propagateFromPre(const CallEvent &Call, + CheckerContext &C) { ProgramStateRef State = C.getState(); // Depending on what was tainted at pre-visit, we determined a set of @@ -602,16 +607,16 @@ bool GenericTaintChecker::propagateFromPre(const CallExpr *CE, for (unsigned ArgNum : TaintArgs) { // Special handling for the tainted return value. if (ArgNum == ReturnValueIndex) { - State = addTaint(State, CE, C.getLocationContext()); + State = addTaint(State, Call.getReturnValue()); continue; } // The arguments are pointer arguments. The data they are pointing at is // tainted after the call. - if (CE->getNumArgs() < (ArgNum + 1)) + if (Call.getNumArgs() < (ArgNum + 1)) return false; - const Expr *Arg = CE->getArg(ArgNum); - Optional V = getPointedToSVal(C, Arg); + const Expr *Arg = Call.getArgExpr(ArgNum); + Optional V = getPointeeOf(C, Arg); if (V) State = addTaint(State, *V); } @@ -626,27 +631,23 @@ bool GenericTaintChecker::propagateFromPre(const CallExpr *CE, return false; } -bool GenericTaintChecker::checkPre(const CallExpr *CE, +bool GenericTaintChecker::checkPre(const CallEvent &Call, const FunctionData &FData, CheckerContext &C) const { - - if (checkUncontrolledFormatString(CE, C)) + if (checkUncontrolledFormatString(Call, C)) return true; - if (checkSystemCall(CE, FData.Name, C)) + if (checkSystemCall(Call, FData.Name, C)) return true; - if (checkTaintedBufferSize(CE, FData.FDecl, C)) + if (checkTaintedBufferSize(Call, C)) return true; - if (checkCustomSinks(CE, FData, C)) - return true; - - return false; + return checkCustomSinks(Call, FData, C); } -Optional GenericTaintChecker::getPointedToSVal(CheckerContext &C, - const Expr *Arg) { +Optional GenericTaintChecker::getPointeeOf(CheckerContext &C, + const Expr *Arg) { ProgramStateRef State = C.getState(); SVal AddrVal = C.getSVal(Arg->IgnoreParens()); if (AddrVal.isUnknownOrUndef()) @@ -671,31 +672,33 @@ Optional GenericTaintChecker::getPointedToSVal(CheckerContext &C, } ProgramStateRef -GenericTaintChecker::TaintPropagationRule::process(const CallExpr *CE, +GenericTaintChecker::TaintPropagationRule::process(const CallEvent &Call, CheckerContext &C) const { ProgramStateRef State = C.getState(); // Check for taint in arguments. bool IsTainted = true; for (unsigned ArgNum : SrcArgs) { - if (ArgNum >= CE->getNumArgs()) + if (ArgNum >= Call.getNumArgs()) continue; - if ((IsTainted = isTaintedOrPointsToTainted(CE->getArg(ArgNum), State, C))) + if ((IsTainted = + isTaintedOrPointsToTainted(Call.getArgExpr(ArgNum), State, C))) break; } // Check for taint in variadic arguments. if (!IsTainted && VariadicType::Src == VarType) { // Check if any of the arguments is tainted - for (unsigned i = VariadicIndex; i < CE->getNumArgs(); ++i) { - if ((IsTainted = isTaintedOrPointsToTainted(CE->getArg(i), State, C))) + for (unsigned i = VariadicIndex; i < Call.getNumArgs(); ++i) { + if ((IsTainted = + isTaintedOrPointsToTainted(Call.getArgExpr(i), State, C))) break; } } if (PropagationFunc) - IsTainted = PropagationFunc(IsTainted, CE, C); + IsTainted = PropagationFunc(IsTainted, Call, C); if (!IsTainted) return State; @@ -708,7 +711,7 @@ GenericTaintChecker::TaintPropagationRule::process(const CallExpr *CE, continue; } - if (ArgNum >= CE->getNumArgs()) + if (ArgNum >= Call.getNumArgs()) continue; // Mark the given argument. @@ -721,14 +724,15 @@ GenericTaintChecker::TaintPropagationRule::process(const CallExpr *CE, // If they are not pointing to const data, mark data as tainted. // TODO: So far we are just going one level down; ideally we'd need to // recurse here. - for (unsigned i = VariadicIndex; i < CE->getNumArgs(); ++i) { - const Expr *Arg = CE->getArg(i); + for (unsigned i = VariadicIndex; i < Call.getNumArgs(); ++i) { + const Expr *Arg = Call.getArgExpr(i); // Process pointer argument. const Type *ArgTy = Arg->getType().getTypePtr(); QualType PType = ArgTy->getPointeeType(); if ((!PType.isNull() && !PType.isConstQualified()) || - (ArgTy->isReferenceType() && !Arg->getType().isConstQualified())) + (ArgTy->isReferenceType() && !Arg->getType().isConstQualified())) { State = State->add(i); + } } } @@ -736,16 +740,14 @@ GenericTaintChecker::TaintPropagationRule::process(const CallExpr *CE, } // If argument 0(protocol domain) is network, the return value should get taint. -bool GenericTaintChecker::TaintPropagationRule::postSocket(bool /*IsTainted*/, - const CallExpr *CE, - CheckerContext &C) { - SourceLocation DomLoc = CE->getArg(0)->getExprLoc(); +bool GenericTaintChecker::TaintPropagationRule::postSocket( + bool /*IsTainted*/, const CallEvent &Call, CheckerContext &C) { + SourceLocation DomLoc = Call.getArgExpr(0)->getExprLoc(); StringRef DomName = C.getMacroNameOrSpelling(DomLoc); // White list the internal communication protocols. if (DomName.equals("AF_SYSTEM") || DomName.equals("AF_LOCAL") || DomName.equals("AF_UNIX") || DomName.equals("AF_RESERVED_36")) return false; - return true; } @@ -757,16 +759,15 @@ bool GenericTaintChecker::isStdin(const Expr *E, CheckerContext &C) { const MemRegion *MemReg = Val.getAsRegion(); // The region should be symbolic, we do not know it's value. - const SymbolicRegion *SymReg = dyn_cast_or_null(MemReg); + const auto *SymReg = dyn_cast_or_null(MemReg); if (!SymReg) return false; // Get it's symbol and find the declaration region it's pointing to. - const SymbolRegionValue *Sm = - dyn_cast(SymReg->getSymbol()); + const auto *Sm = dyn_cast(SymReg->getSymbol()); if (!Sm) return false; - const DeclRegion *DeclReg = dyn_cast_or_null(Sm->getRegion()); + const auto *DeclReg = dyn_cast_or_null(Sm->getRegion()); if (!DeclReg) return false; @@ -784,23 +785,24 @@ bool GenericTaintChecker::isStdin(const Expr *E, CheckerContext &C) { return false; } -static bool getPrintfFormatArgumentNum(const CallExpr *CE, +static bool getPrintfFormatArgumentNum(const CallEvent &Call, const CheckerContext &C, unsigned &ArgNum) { // Find if the function contains a format string argument. // Handles: fprintf, printf, sprintf, snprintf, vfprintf, vprintf, vsprintf, // vsnprintf, syslog, custom annotated functions. - const FunctionDecl *FDecl = C.getCalleeDecl(CE); + const FunctionDecl *FDecl = Call.getDecl()->getAsFunction(); if (!FDecl) return false; for (const auto *Format : FDecl->specific_attrs()) { ArgNum = Format->getFormatIdx() - 1; - if ((Format->getType()->getName() == "printf") && CE->getNumArgs() > ArgNum) + if ((Format->getType()->getName() == "printf") && + Call.getNumArgs() > ArgNum) return true; } // Or if a function is named setproctitle (this is a heuristic). - if (C.getCalleeName(CE).find("setproctitle") != StringRef::npos) { + if (C.getCalleeName(FDecl).find("setproctitle") != StringRef::npos) { ArgNum = 0; return true; } @@ -814,7 +816,7 @@ bool GenericTaintChecker::generateReportIfTainted(const Expr *E, StringRef Msg, // Check for taint. ProgramStateRef State = C.getState(); - Optional PointedToSVal = getPointedToSVal(C, E); + Optional PointedToSVal = getPointeeOf(C, E); SVal TaintedSVal; if (PointedToSVal && isTainted(State, *PointedToSVal)) TaintedSVal = *PointedToSVal; @@ -836,19 +838,19 @@ bool GenericTaintChecker::generateReportIfTainted(const Expr *E, StringRef Msg, } bool GenericTaintChecker::checkUncontrolledFormatString( - const CallExpr *CE, CheckerContext &C) const { + const CallEvent &Call, CheckerContext &C) const { // Check if the function contains a format string argument. unsigned ArgNum = 0; - if (!getPrintfFormatArgumentNum(CE, C, ArgNum)) + if (!getPrintfFormatArgumentNum(Call, C, ArgNum)) return false; // If either the format string content or the pointer itself are tainted, // warn. - return generateReportIfTainted(CE->getArg(ArgNum), + return generateReportIfTainted(Call.getArgExpr(ArgNum), MsgUncontrolledFormatString, C); } -bool GenericTaintChecker::checkSystemCall(const CallExpr *CE, StringRef Name, +bool GenericTaintChecker::checkSystemCall(const CallEvent &Call, StringRef Name, CheckerContext &C) const { // TODO: It might make sense to run this check on demand. In some cases, // we should check if the environment has been cleansed here. We also might @@ -866,21 +868,22 @@ bool GenericTaintChecker::checkSystemCall(const CallExpr *CE, StringRef Name, .Case("dlopen", 0) .Default(InvalidArgIndex); - if (ArgNum == InvalidArgIndex || CE->getNumArgs() < (ArgNum + 1)) + if (ArgNum == InvalidArgIndex || Call.getNumArgs() < (ArgNum + 1)) return false; - return generateReportIfTainted(CE->getArg(ArgNum), MsgSanitizeSystemArgs, C); + return generateReportIfTainted(Call.getArgExpr(ArgNum), MsgSanitizeSystemArgs, + C); } // TODO: Should this check be a part of the CString checker? // If yes, should taint be a global setting? -bool GenericTaintChecker::checkTaintedBufferSize(const CallExpr *CE, - const FunctionDecl *FDecl, +bool GenericTaintChecker::checkTaintedBufferSize(const CallEvent &Call, CheckerContext &C) const { + const auto *FDecl = Call.getDecl()->getAsFunction(); // If the function has a buffer size argument, set ArgNum. unsigned ArgNum = InvalidArgIndex; unsigned BId = 0; - if ((BId = FDecl->getMemoryFunctionKind())) + if ((BId = FDecl->getMemoryFunctionKind())) { switch (BId) { case Builtin::BImemcpy: case Builtin::BImemmove: @@ -892,26 +895,29 @@ bool GenericTaintChecker::checkTaintedBufferSize(const CallExpr *CE, break; default: break; - }; + } + } if (ArgNum == InvalidArgIndex) { - if (C.isCLibraryFunction(FDecl, "malloc") || - C.isCLibraryFunction(FDecl, "calloc") || - C.isCLibraryFunction(FDecl, "alloca")) + using CCtx = CheckerContext; + if (CCtx::isCLibraryFunction(FDecl, "malloc") || + CCtx::isCLibraryFunction(FDecl, "calloc") || + CCtx::isCLibraryFunction(FDecl, "alloca")) ArgNum = 0; - else if (C.isCLibraryFunction(FDecl, "memccpy")) + else if (CCtx::isCLibraryFunction(FDecl, "memccpy")) ArgNum = 3; - else if (C.isCLibraryFunction(FDecl, "realloc")) + else if (CCtx::isCLibraryFunction(FDecl, "realloc")) ArgNum = 1; - else if (C.isCLibraryFunction(FDecl, "bcopy")) + else if (CCtx::isCLibraryFunction(FDecl, "bcopy")) ArgNum = 2; } - return ArgNum != InvalidArgIndex && CE->getNumArgs() > ArgNum && - generateReportIfTainted(CE->getArg(ArgNum), MsgTaintedBufferSize, C); + return ArgNum != InvalidArgIndex && Call.getNumArgs() > ArgNum && + generateReportIfTainted(Call.getArgExpr(ArgNum), MsgTaintedBufferSize, + C); } -bool GenericTaintChecker::checkCustomSinks(const CallExpr *CE, +bool GenericTaintChecker::checkCustomSinks(const CallEvent &Call, const FunctionData &FData, CheckerContext &C) const { auto It = findFunctionInConfig(CustomSinks, FData); @@ -921,10 +927,10 @@ bool GenericTaintChecker::checkCustomSinks(const CallExpr *CE, const auto &Value = It->second; const GenericTaintChecker::ArgVector &Args = Value.second; for (unsigned ArgNum : Args) { - if (ArgNum >= CE->getNumArgs()) + if (ArgNum >= Call.getNumArgs()) continue; - if (generateReportIfTainted(CE->getArg(ArgNum), MsgCustomSink, C)) + if (generateReportIfTainted(Call.getArgExpr(ArgNum), MsgCustomSink, C)) return true; } From f88c884362d6f8d6125a929b8b450be2fa0af962 Mon Sep 17 00:00:00 2001 From: Jeremy Morse Date: Wed, 4 Mar 2020 17:08:17 +0000 Subject: [PATCH 167/286] [analyzer] decode() a bytes object to make Python3 happy The output of subprocess.check_output is decode()'d through the rest of this python program, but one appears to have been missed for the output of the call to "clang -print-file-name=include". On Windows, with Python 3.6, this leads to the 'args' array being a mix of bytes and strings, which causes exceptions later down the line. I can't easily test with python2 on Windows, but python2 on Ubuntu 18.04 was happy with this change. (cherry picked from commit d4f9675b5509e26573058318682a9ed5d7aaf320) --- clang/test/Analysis/check-analyzer-fixit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Analysis/check-analyzer-fixit.py b/clang/test/Analysis/check-analyzer-fixit.py index 1d159aedec91b..6a8f6859f816b 100644 --- a/clang/test/Analysis/check-analyzer-fixit.py +++ b/clang/test/Analysis/check-analyzer-fixit.py @@ -63,7 +63,7 @@ def run_test_once(args, extra_args): try: builtin_include_dir = subprocess.check_output( - ['clang', '-print-file-name=include'], stderr=subprocess.STDOUT) + ['clang', '-print-file-name=include'], stderr=subprocess.STDOUT).decode() except subprocess.CalledProcessError as e: print('Cannot print Clang include directory: ' + e.output.decode()) From 59ed9d5d93e572f928b2325e8c1a148de996e3da Mon Sep 17 00:00:00 2001 From: Gabor Marton Date: Mon, 9 Mar 2020 11:58:20 +0100 Subject: [PATCH 168/286] [analyzer] Skip analysis of inherited ctor as top-level function Summary: This fixes a regression introduced in https://reviews.llvm.org/D74735 Reviewers: NoQ, Szelethus Tags: #clang Differential Revision: https://reviews.llvm.org/D75678 (cherry picked from commit 59a960b83c2d1559f31e1dd75728dd24fae2f68c) --- .../Core/PathSensitive/CallEvent.h | 17 ++++++++++++++++ .../Frontend/AnalysisConsumer.cpp | 7 +++++++ .../Analysis/cxx-inherited-ctor-init-expr.cpp | 16 +++++++++++++++ ...inherited-ctor-is-skipped-as-top-level.cpp | 20 +++++++++++++++++++ 4 files changed, 60 insertions(+) create mode 100644 clang/test/Analysis/cxx-inherited-ctor-is-skipped-as-top-level.cpp diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h index ab6a704ab8cf5..323a1a212bce8 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h @@ -889,6 +889,23 @@ class CXXConstructorCall : public AnyCXXConstructorCall { /// Represents a call to a C++ inherited constructor. /// /// Example: \c class T : public S { using S::S; }; T(1); +/// +// Note, it is difficult to model the parameters. This is one of the reasons +// why we skip analysis of inheriting constructors as top-level functions. +// CXXInheritedCtorInitExpr doesn't take arguments and doesn't model parameter +// initialization because there is none: the arguments in the outer +// CXXConstructExpr directly initialize the parameters of the base class +// constructor, and no copies are made. (Making a copy of the parameter is +// incorrect, at least if it's done in an observable way.) The derived class +// constructor doesn't even exist in the formal model. +/// E.g., in: +/// +/// struct X { X *p = this; ~X() {} }; +/// struct A { A(X x) : b(x.p == &x) {} bool b; }; +/// struct B : A { using A::A; }; +/// B b = X{}; +/// +/// ... b.b is initialized to true. class CXXInheritedConstructorCall : public AnyCXXConstructorCall { friend class CallEventManager; diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index 847a030017193..c15cee410c74f 100644 --- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -518,6 +518,13 @@ static bool shouldSkipFunction(const Decl *D, if (VisitedAsTopLevel.count(D)) return true; + // Skip analysis of inheriting constructors as top-level functions. These + // constructors don't even have a body written down in the code, so even if + // we find a bug, we won't be able to display it. + if (const auto *CD = dyn_cast(D)) + if (CD->isInheritingConstructor()) + return true; + // We want to re-analyse the functions as top level in the following cases: // - The 'init' methods should be reanalyzed because // ObjCNonNilReturnValueChecker assumes that '[super init]' never returns diff --git a/clang/test/Analysis/cxx-inherited-ctor-init-expr.cpp b/clang/test/Analysis/cxx-inherited-ctor-init-expr.cpp index ff82c129bc700..8370ebfbde09b 100644 --- a/clang/test/Analysis/cxx-inherited-ctor-init-expr.cpp +++ b/clang/test/Analysis/cxx-inherited-ctor-init-expr.cpp @@ -57,3 +57,19 @@ void test_B() { clang_analyzer_eval(b.z == 3); // expected-warning{{TRUE}} } } // namespace arguments_with_constructors + +namespace inherited_constructor_crash { +class a { +public: + a(int); +}; +struct b : a { + using a::a; // Ihnerited ctor. +}; +void c() { + int d; + // This construct expr utilizes the inherited ctor. + // Note that d must be uninitialized to cause the crash. + (b(d)); // expected-warning{{1st function call argument is an uninitialized value}} +} +} // namespace inherited_constructor_crash diff --git a/clang/test/Analysis/cxx-inherited-ctor-is-skipped-as-top-level.cpp b/clang/test/Analysis/cxx-inherited-ctor-is-skipped-as-top-level.cpp new file mode 100644 index 0000000000000..be7982e641148 --- /dev/null +++ b/clang/test/Analysis/cxx-inherited-ctor-is-skipped-as-top-level.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-display-progress %s 2>&1 | FileCheck %s + +// Test that inheriting constructors are not analyzed as top-level functions. + +// CHECK: ANALYZE (Path, Inline_Regular): {{.*}} c() +// CHECK: ANALYZE (Path, Inline_Regular): {{.*}} a::a(int) +// CHECK-NOT: ANALYZE (Path, Inline_Regular): {{.*}} b::a(int) + +class a { +public: + a(int) {} +}; +struct b : a { + using a::a; // Ihnerited ctor. +}; +void c() { + int d; + (b(d)); + (a(d)); +} From e08513cb2d837d75acf7bd0533366c0662877b8d Mon Sep 17 00:00:00 2001 From: Adam Balogh Date: Mon, 9 Mar 2020 10:48:56 +0100 Subject: [PATCH 169/286] [Analyzer] Mark constant member functions const in CheckerManager Most of the getter functions (and a reporter function) in `CheckerManager` are constant but not marked as `const`. This prevents functions having only a constant reference to `CheckerManager` using these member functions. This patch fixes this issue. Differential Revision: https://reviews.llvm.org/D75839 (cherry picked from commit 57f70d187706f572227b74c82c7446a3096f862f) --- clang/include/clang/StaticAnalyzer/Core/CheckerManager.h | 8 ++++---- clang/lib/StaticAnalyzer/Core/CheckerManager.cpp | 5 +++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h index 246ff8f90d354..4454d7603b27f 100644 --- a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -140,14 +140,14 @@ class CheckerManager { void finishedCheckerRegistration(); const LangOptions &getLangOpts() const { return LangOpts; } - AnalyzerOptions &getAnalyzerOptions() { return AOptions; } - ASTContext &getASTContext() { return Context; } + AnalyzerOptions &getAnalyzerOptions() const { return AOptions; } + ASTContext &getASTContext() const { return Context; } /// Emits an error through a DiagnosticsEngine about an invalid user supplied /// checker option value. void reportInvalidCheckerOptionValue(const CheckerBase *C, StringRef OptionName, - StringRef ExpectedValueDesc); + StringRef ExpectedValueDesc) const; using CheckerRef = CheckerBase *; using CheckerTag = const void *; @@ -620,7 +620,7 @@ class CheckerManager { /// Returns the checkers that have registered for callbacks of the /// given \p Kind. const std::vector & - getObjCMessageCheckers(ObjCMessageVisitKind Kind); + getObjCMessageCheckers(ObjCMessageVisitKind Kind) const; std::vector PreObjCMessageCheckers; std::vector PostObjCMessageCheckers; diff --git a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp index a9361837cf68b..ce5e4a46d3e2c 100644 --- a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -61,7 +61,8 @@ void CheckerManager::finishedCheckerRegistration() { } void CheckerManager::reportInvalidCheckerOptionValue( - const CheckerBase *C, StringRef OptionName, StringRef ExpectedValueDesc) { + const CheckerBase *C, StringRef OptionName, + StringRef ExpectedValueDesc) const { Context.getDiagnostics() .Report(diag::err_analyzer_checker_option_invalid_input) @@ -249,7 +250,7 @@ void CheckerManager::runCheckersForObjCMessage(ObjCMessageVisitKind visitKind, } const std::vector & -CheckerManager::getObjCMessageCheckers(ObjCMessageVisitKind Kind) { +CheckerManager::getObjCMessageCheckers(ObjCMessageVisitKind Kind) const { switch (Kind) { case ObjCMessageVisitKind::Pre: return PreObjCMessageCheckers; From 76b38c6d053bd20f16f2a941c8c6ad4ff715825f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirst=C3=B3f=20Umann?= Date: Thu, 12 Sep 2019 22:20:58 +0200 Subject: [PATCH 170/286] [analyzer][NFC] Refactor the checker registration unit test file Nothing exciting to see here! The new interface allows for more fine tuning (register but disable a checker, add custom checker registry functions, etc), that was basically the point. Differential Revision: https://reviews.llvm.org/D67335 (cherry picked from commit 58884eb6489880646896d72fcd723813f8a13299) --- .../StaticAnalyzer/Frontend/CheckerRegistry.h | 11 +-- .../StaticAnalyzer/CheckerRegistration.h | 81 +++++++++++++++++ .../RegisterCustomCheckersTest.cpp | 87 ++++++++----------- 3 files changed, 119 insertions(+), 60 deletions(-) create mode 100644 clang/unittests/StaticAnalyzer/CheckerRegistration.h diff --git a/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h b/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h index bc258160ada49..269c226f2e1d1 100644 --- a/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h +++ b/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistry.h @@ -204,16 +204,14 @@ class CheckerRegistry { using PackageInfoList = llvm::SmallVector; -private: - template static void initializeManager(CheckerManager &mgr) { + template static void addToCheckerMgr(CheckerManager &mgr) { mgr.registerChecker(); } - template static bool returnTrue(const LangOptions &LO) { + static bool returnTrue(const LangOptions &LO) { return true; } -public: /// Adds a checker to the registry. Use this non-templated overload when your /// checker requires custom initialization. void addChecker(InitializationFunction Fn, ShouldRegisterFunction sfn, @@ -227,9 +225,8 @@ class CheckerRegistry { bool IsHidden = false) { // Avoid MSVC's Compiler Error C2276: // http://msdn.microsoft.com/en-us/library/850cstw1(v=VS.80).aspx - addChecker(&CheckerRegistry::initializeManager, - &CheckerRegistry::returnTrue, FullName, Desc, DocsUri, - IsHidden); + addChecker(&CheckerRegistry::addToCheckerMgr, + &CheckerRegistry::returnTrue, FullName, Desc, DocsUri, IsHidden); } /// Makes the checker with the full name \p fullName depends on the checker diff --git a/clang/unittests/StaticAnalyzer/CheckerRegistration.h b/clang/unittests/StaticAnalyzer/CheckerRegistration.h new file mode 100644 index 0000000000000..0bbed9b7784ff --- /dev/null +++ b/clang/unittests/StaticAnalyzer/CheckerRegistration.h @@ -0,0 +1,81 @@ +//===- unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp ------------===// +// +// 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 "clang/Frontend/CompilerInstance.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" +#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h" +#include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h" +#include "clang/Tooling/Tooling.h" + +namespace clang { +namespace ento { + +class DiagConsumer : public PathDiagnosticConsumer { + llvm::raw_ostream &Output; + +public: + DiagConsumer(llvm::raw_ostream &Output) : Output(Output) {} + void FlushDiagnosticsImpl(std::vector &Diags, + FilesMade *filesMade) override { + for (const auto *PD : Diags) + Output << PD->getCheckerName() << ":" << PD->getShortDescription() << '\n'; + } + + StringRef getName() const override { return "Test"; } +}; + +using AddCheckerFn = void(AnalysisASTConsumer &AnalysisConsumer, + AnalyzerOptions &AnOpts); + +template +void addChecker(AnalysisASTConsumer &AnalysisConsumer, + AnalyzerOptions &AnOpts) { + Fn1(AnalysisConsumer, AnOpts); + addChecker(AnalysisConsumer, AnOpts); +} + +template +void addChecker(AnalysisASTConsumer &AnalysisConsumer, + AnalyzerOptions &AnOpts) { + Fn1(AnalysisConsumer, AnOpts); +} + +template +class TestAction : public ASTFrontendAction { + llvm::raw_ostream &DiagsOutput; + +public: + TestAction(llvm::raw_ostream &DiagsOutput) : DiagsOutput(DiagsOutput) {} + + std::unique_ptr CreateASTConsumer(CompilerInstance &Compiler, + StringRef File) override { + std::unique_ptr AnalysisConsumer = + CreateAnalysisConsumer(Compiler); + AnalysisConsumer->AddDiagnosticConsumer(new DiagConsumer(DiagsOutput)); + addChecker(*AnalysisConsumer, *Compiler.getAnalyzerOpts()); + return std::move(AnalysisConsumer); + } +}; + +template +bool runCheckerOnCode(const std::string &Code, std::string &Diags) { + llvm::raw_string_ostream OS(Diags); + return tooling::runToolOnCode(std::make_unique>(OS), Code); +} + +template +bool runCheckerOnCode(const std::string &Code) { + std::string Diags; + return runCheckerOnCode(Code, Diags); +} + +} // namespace ento +} // namespace clang diff --git a/clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp b/clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp index 4f504d2384cf0..d0cf291eb2b8e 100644 --- a/clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp +++ b/clang/unittests/StaticAnalyzer/RegisterCustomCheckersTest.cpp @@ -6,11 +6,13 @@ // //===----------------------------------------------------------------------===// +#include "CheckerRegistration.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h" #include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h" #include "clang/Tooling/Tooling.h" @@ -20,53 +22,10 @@ namespace clang { namespace ento { namespace { -template -class TestAction : public ASTFrontendAction { - class DiagConsumer : public PathDiagnosticConsumer { - llvm::raw_ostream &Output; - - public: - DiagConsumer(llvm::raw_ostream &Output) : Output(Output) {} - void FlushDiagnosticsImpl(std::vector &Diags, - FilesMade *filesMade) override { - for (const auto *PD : Diags) - Output << PD->getCheckerName() << ":" << PD->getShortDescription(); - } - - StringRef getName() const override { return "Test"; } - }; - - llvm::raw_ostream &DiagsOutput; - -public: - TestAction(llvm::raw_ostream &DiagsOutput) : DiagsOutput(DiagsOutput) {} - - std::unique_ptr CreateASTConsumer(CompilerInstance &Compiler, - StringRef File) override { - std::unique_ptr AnalysisConsumer = - CreateAnalysisConsumer(Compiler); - AnalysisConsumer->AddDiagnosticConsumer(new DiagConsumer(DiagsOutput)); - Compiler.getAnalyzerOpts()->CheckersAndPackages = { - {"custom.CustomChecker", true}}; - AnalysisConsumer->AddCheckerRegistrationFn([](CheckerRegistry &Registry) { - Registry.addChecker("custom.CustomChecker", "Description", ""); - }); - return std::move(AnalysisConsumer); - } -}; - -template -bool runCheckerOnCode(const std::string &Code, std::string &Diags) { - llvm::raw_string_ostream OS(Diags); - return tooling::runToolOnCode(std::make_unique>(OS), - Code); -} -template -bool runCheckerOnCode(const std::string &Code) { - std::string Diags; - return runCheckerOnCode(Code, Diags); -} - +//===----------------------------------------------------------------------===// +// Just a minimal test for how checker registration works with statically +// linked, non TableGen generated checkers. +//===----------------------------------------------------------------------===// class CustomChecker : public Checker { public: @@ -78,12 +37,25 @@ class CustomChecker : public Checker { } }; +void addCustomChecker(AnalysisASTConsumer &AnalysisConsumer, + AnalyzerOptions &AnOpts) { + AnOpts.CheckersAndPackages = {{"custom.CustomChecker", true}}; + AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) { + Registry.addChecker("custom.CustomChecker", "Description", + ""); + }); +} + TEST(RegisterCustomCheckers, RegisterChecker) { std::string Diags; - EXPECT_TRUE(runCheckerOnCode("void f() {;}", Diags)); - EXPECT_EQ(Diags, "custom.CustomChecker:Custom diagnostic description"); + EXPECT_TRUE(runCheckerOnCode("void f() {;}", Diags)); + EXPECT_EQ(Diags, "custom.CustomChecker:Custom diagnostic description\n"); } +//===----------------------------------------------------------------------===// +// Pretty much the same. +//===----------------------------------------------------------------------===// + class LocIncDecChecker : public Checker { public: void checkLocation(SVal Loc, bool IsLoad, const Stmt *S, @@ -95,11 +67,20 @@ class LocIncDecChecker : public Checker { } }; +void addLocIncDecChecker(AnalysisASTConsumer &AnalysisConsumer, + AnalyzerOptions &AnOpts) { + AnOpts.CheckersAndPackages = {{"test.LocIncDecChecker", true}}; + AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) { + Registry.addChecker("test.LocIncDecChecker", "Description", + ""); + }); +} + TEST(RegisterCustomCheckers, CheckLocationIncDec) { EXPECT_TRUE( - runCheckerOnCode("void f() { int *p; (*p)++; }")); + runCheckerOnCode("void f() { int *p; (*p)++; }")); } -} -} -} +} // namespace +} // namespace ento +} // namespace clang From 8595655fa43f48eb20a81e70557f17c71b5158d1 Mon Sep 17 00:00:00 2001 From: Adam Balogh Date: Tue, 10 Mar 2020 09:05:16 +0100 Subject: [PATCH 171/286] [Analyzer][NFC] Change parameter of NoteTag lambdas to PathSensitiveBugReport Lambdas creating path notes using NoteTags still take BugReport as their parameter. Since path notes obviously only appear in PathSensitiveBugReports it is straightforward that lambdas of NoteTags take PathSensitiveBugReport as their parameter. Differential Revision: https://reviews.llvm.org/D75898 (cherry picked from commit 20a3d64c8883c8be550f0759525b1550b7c2d35f) --- .../Core/BugReporter/BugReporter.h | 5 +++-- .../Core/PathSensitive/CheckerContext.h | 15 +++++++++----- .../Checkers/CXXSelfAssignmentChecker.cpp | 4 ++-- .../Checkers/FuchsiaHandleChecker.cpp | 4 ++-- .../StaticAnalyzer/Checkers/MIGChecker.cpp | 20 ++++++++++--------- .../Checkers/ReturnValueChecker.cpp | 2 +- clang/lib/StaticAnalyzer/Core/CoreEngine.cpp | 2 +- 7 files changed, 30 insertions(+), 22 deletions(-) diff --git a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h index 69593e2b6c931..7112fa125ef0e 100644 --- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h +++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h @@ -722,7 +722,8 @@ class BugReporterContext { class NoteTag : public ProgramPointTag { public: using Callback = - std::function; + std::function; private: static int Kind; @@ -739,7 +740,7 @@ class NoteTag : public ProgramPointTag { } Optional generateMessage(BugReporterContext &BRC, - BugReport &R) const { + PathSensitiveBugReport &R) const { std::string Msg = Cb(BRC, R); if (Msg.empty()) return None; diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h index bd8760cf0ce0c..f4181f3beab99 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h @@ -256,10 +256,12 @@ class CheckerContext { /// @param IsPrunable Whether the note is prunable. It allows BugReporter /// to omit the note from the report if it would make the displayed /// bug path significantly shorter. - const NoteTag *getNoteTag(std::function &&Cb, - bool IsPrunable = false) { + const NoteTag + *getNoteTag(std::function &&Cb, + bool IsPrunable = false) { return getNoteTag( - [Cb](BugReporterContext &, BugReport &BR) { return Cb(BR); }, + [Cb](BugReporterContext &, + PathSensitiveBugReport &BR) { return Cb(BR); }, IsPrunable); } @@ -272,7 +274,8 @@ class CheckerContext { /// bug path significantly shorter. const NoteTag *getNoteTag(std::function &&Cb, bool IsPrunable = false) { - return getNoteTag([Cb](BugReporterContext &, BugReport &) { return Cb(); }, + return getNoteTag([Cb](BugReporterContext &, + PathSensitiveBugReport &) { return Cb(); }, IsPrunable); } @@ -284,7 +287,9 @@ class CheckerContext { /// bug path significantly shorter. const NoteTag *getNoteTag(StringRef Note, bool IsPrunable = false) { return getNoteTag( - [Note](BugReporterContext &, BugReport &) { return Note; }, IsPrunable); + [Note](BugReporterContext &, + PathSensitiveBugReport &) { return std::string(Note); }, + IsPrunable); } /// Returns the word that should be used to refer to the declaration diff --git a/clang/lib/StaticAnalyzer/Checkers/CXXSelfAssignmentChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CXXSelfAssignmentChecker.cpp index 01f5b9c889e32..dc6f7722a8e62 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CXXSelfAssignmentChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CXXSelfAssignmentChecker.cpp @@ -53,7 +53,7 @@ void CXXSelfAssignmentChecker::checkBeginFunction(CheckerContext &C) const { ProgramStateRef SelfAssignState = State->bindLoc(Param, ThisVal, LCtx); const NoteTag *SelfAssignTag = - C.getNoteTag([MD](BugReport &BR) -> std::string { + C.getNoteTag([MD](PathSensitiveBugReport &BR) -> std::string { SmallString<256> Msg; llvm::raw_svector_ostream Out(Msg); Out << "Assuming " << MD->getParamDecl(0)->getName() << " == *this"; @@ -63,7 +63,7 @@ void CXXSelfAssignmentChecker::checkBeginFunction(CheckerContext &C) const { ProgramStateRef NonSelfAssignState = State->bindLoc(Param, ParamVal, LCtx); const NoteTag *NonSelfAssignTag = - C.getNoteTag([MD](BugReport &BR) -> std::string { + C.getNoteTag([MD](PathSensitiveBugReport &BR) -> std::string { SmallString<256> Msg; llvm::raw_svector_ostream Out(Msg); Out << "Assuming " << MD->getParamDecl(0)->getName() << " != *this"; diff --git a/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp index 861dfef02393a..67a4c7fb82d05 100644 --- a/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp @@ -357,8 +357,8 @@ void FuchsiaHandleChecker::checkPostCall(const CallEvent &Call, } const NoteTag *T = nullptr; if (!Notes.empty()) { - T = C.getNoteTag( - [this, Notes{std::move(Notes)}](BugReport &BR) -> std::string { + T = C.getNoteTag([this, Notes{std::move(Notes)}]( + PathSensitiveBugReport &BR) -> std::string { if (&BR.getBugType() != &UseAfterReleaseBugType && &BR.getBugType() != &LeakBugType && &BR.getBugType() != &DoubleReleaseBugType) diff --git a/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp index d73e2eb92d420..794d74c54b730 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp @@ -210,15 +210,17 @@ void MIGChecker::checkPostCall(const CallEvent &Call, CheckerContext &C) const { if (!PVD || State->contains(PVD)) return; - const NoteTag *T = C.getNoteTag([this, PVD](BugReport &BR) -> std::string { - if (&BR.getBugType() != &BT) - return ""; - SmallString<64> Str; - llvm::raw_svector_ostream OS(Str); - OS << "Value passed through parameter '" << PVD->getName() - << "\' is deallocated"; - return OS.str(); - }); + const NoteTag *T = + C.getNoteTag([this, PVD](PathSensitiveBugReport &BR) -> std::string { + if (&BR.getBugType() != &BT) + return ""; + SmallString<64> Str; + llvm::raw_svector_ostream OS(Str); + OS << "Value passed through parameter '" << PVD->getName() + << "\' is deallocated"; + return std::string(OS.str()); + }); + C.addTransition(State->set(true), T); } diff --git a/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp index 103208d8b5a51..eec26728347f9 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp @@ -99,7 +99,7 @@ void ReturnValueChecker::checkPostCall(const CallEvent &Call, std::string Name = getName(Call); const NoteTag *CallTag = C.getNoteTag( - [Name, ExpectedValue](BugReport &) -> std::string { + [Name, ExpectedValue](PathSensitiveBugReport &) -> std::string { SmallString<128> Msg; llvm::raw_svector_ostream Out(Msg); diff --git a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp index 94cf74de82931..5a49b18aecf12 100644 --- a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -221,7 +221,7 @@ void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) { if (L.getSrc()->getTerminator().isVirtualBaseBranch() && L.getDst() == *L.getSrc()->succ_begin()) { ProgramPoint P = L.withTag(getNoteTags().makeNoteTag( - [](BugReporterContext &, BugReport &) -> std::string { + [](BugReporterContext &, PathSensitiveBugReport &) -> std::string { // TODO: Just call out the name of the most derived class // when we know it. return "Virtual base initialization skipped because " From 3cdb0d84ba263d7199971ddedbb3d332a431a1be Mon Sep 17 00:00:00 2001 From: Aaron Ballman Date: Tue, 10 Mar 2020 14:21:55 -0400 Subject: [PATCH 172/286] Convert a reachable llvm_unreachable into an assert. (cherry picked from commit 4a0267e3ad8c4d47f267d7d960f127e099fb4818) --- clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp index 01ac2bc83bb6b..99e16752b51a4 100644 --- a/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp +++ b/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp @@ -134,9 +134,9 @@ StringRef AnalyzerOptions::getCheckerStringOption(StringRef CheckerName, CheckerName = CheckerName.substr(0, Pos); } while (!CheckerName.empty() && SearchInParents); - llvm_unreachable("Unknown checker option! Did you call getChecker*Option " - "with incorrect parameters? User input must've been " - "verified by CheckerRegistry."); + assert(false && "Unknown checker option! Did you call getChecker*Option " + "with incorrect parameters? User input must've been " + "verified by CheckerRegistry."); return ""; } From 501ffc6b627cce901d54665fbbf9d4ab2704860a Mon Sep 17 00:00:00 2001 From: Nico Weber Date: Tue, 31 Mar 2020 19:32:26 -0400 Subject: [PATCH 173/286] [analyzer] Use IgnoreImpCasts() instead of reimplementing it. No intended behavior change. Differential Revision: https://reviews.llvm.org/D77022 (cherry picked from commit 7ea64ae3afe4ad98e6753b9f74b30019113f719c) --- clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp index 922048733c7c4..d793474cac34a 100644 --- a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp @@ -508,13 +508,7 @@ void NullabilityChecker::checkEvent(ImplicitNullDerefEvent Event) const { /// return expressions of ObjC types when the return type of the function or /// method is non-null but the express is not. static const Expr *lookThroughImplicitCasts(const Expr *E) { - assert(E); - - while (auto *ICE = dyn_cast(E)) { - E = ICE->getSubExpr(); - } - - return E; + return E->IgnoreImpCasts(); } /// This method check when nullable pointer or null value is returned from a From f01c2754c395c8a5dae19d4abb09b918967de808 Mon Sep 17 00:00:00 2001 From: Artem Dergachev Date: Wed, 1 Apr 2020 18:15:00 +0300 Subject: [PATCH 174/286] [analyzer] RetainCountChecker: Add a suppression for OSSymbols. OSSymbol objects are particular XNU OSObjects that aren't really reference-counted. Therefore you cannot do any harm by over- or under-releasing them. (cherry picked from commit 3500cc8d891bb3825bb3275affe6db8b12f2f695) --- clang/lib/Analysis/RetainSummaryManager.cpp | 4 +++- clang/test/Analysis/osobject-retain-release.cpp | 10 ++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/clang/lib/Analysis/RetainSummaryManager.cpp b/clang/lib/Analysis/RetainSummaryManager.cpp index 05f3e388d806f..583be169c8024 100644 --- a/clang/lib/Analysis/RetainSummaryManager.cpp +++ b/clang/lib/Analysis/RetainSummaryManager.cpp @@ -145,7 +145,9 @@ static bool isSubclass(const Decl *D, } static bool isOSObjectSubclass(const Decl *D) { - return D && isSubclass(D, "OSMetaClassBase"); + // OSSymbols are particular OSObjects that are allocated globally + // and therefore aren't really refcounted, so we ignore them. + return D && isSubclass(D, "OSMetaClassBase") && !isSubclass(D, "OSSymbol"); } static bool isOSObjectDynamicCast(StringRef S) { diff --git a/clang/test/Analysis/osobject-retain-release.cpp b/clang/test/Analysis/osobject-retain-release.cpp index 41606a30c39f4..d88349dcd807e 100644 --- a/clang/test/Analysis/osobject-retain-release.cpp +++ b/clang/test/Analysis/osobject-retain-release.cpp @@ -53,6 +53,9 @@ struct MyArray : public OSArray { OSObject *generateObject(OSObject *input) override; }; +// These are never refcounted. +struct OSSymbol : OSObject {}; + struct OtherStruct { static void doNothingToArray(OSArray *array); OtherStruct(OSArray *arr); @@ -754,3 +757,10 @@ void test() { b(0); } } // namespace inherited_constructor_crash + +namespace ossymbol_suppression { +OSSymbol *createSymbol(); +void test() { + OSSymbol *sym = createSymbol(); // no-warning +} +} // namespace ossymbol_suppression From 68a786d3f7551f186984bcaba3101b8e2de9e88d Mon Sep 17 00:00:00 2001 From: Artem Dergachev Date: Mon, 6 Apr 2020 20:27:40 +0300 Subject: [PATCH 175/286] [analyzer] Fix NSErrorChecker false positives on constructors. Constructors and delete operators cannot return a boolean value. Therefore they cannot possibly follow the NS/CFError-related coding conventions. Patch by Valeriy Savchenko! Differential Revision: https://reviews.llvm.org/D77551 (cherry picked from commit 9b1e4a8218b7fcb8900d0382704fdb4e38b52eb0) --- .../Checkers/NSErrorChecker.cpp | 11 ++++++++ .../test/Analysis/SpecialFunctionsCFError.cpp | 28 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 clang/test/Analysis/SpecialFunctionsCFError.cpp diff --git a/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp index 85370bf133cd7..fe7ede8101889 100644 --- a/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp @@ -95,6 +95,15 @@ class CFErrorFunctionChecker }; } +static bool hasReservedReturnType(const FunctionDecl *D) { + if (isa(D)) + return true; + + // operators delete and delete[] are required to have 'void' return type + auto OperatorKind = D->getOverloadedOperator(); + return OperatorKind == OO_Delete || OperatorKind == OO_Array_Delete; +} + void CFErrorFunctionChecker::checkASTDecl(const FunctionDecl *D, AnalysisManager &mgr, BugReporter &BR) const { @@ -102,6 +111,8 @@ void CFErrorFunctionChecker::checkASTDecl(const FunctionDecl *D, return; if (!D->getReturnType()->isVoidType()) return; + if (hasReservedReturnType(D)) + return; if (!II) II = &D->getASTContext().Idents.get("CFErrorRef"); diff --git a/clang/test/Analysis/SpecialFunctionsCFError.cpp b/clang/test/Analysis/SpecialFunctionsCFError.cpp new file mode 100644 index 0000000000000..3517933f6bcc6 --- /dev/null +++ b/clang/test/Analysis/SpecialFunctionsCFError.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.coreFoundation.CFError \ +// RUN: -verify %s + +typedef unsigned long size_t; +struct __CFError {}; +typedef struct __CFError *CFErrorRef; +void *malloc(size_t); + +class Foo { +public: + Foo(CFErrorRef *error) {} // no-warning + + void operator delete(void *pointer, CFErrorRef *error) { // no-warning + return; + } + + void operator delete[](void *pointer, CFErrorRef *error) { // no-warning + return; + } + + // Check that we report warnings for operators when it can be useful + void operator()(CFErrorRef *error) {} // expected-warning {{Function accepting CFErrorRef* should have a non-void return value to indicate whether or not an error occurred}} +}; + +// Check that global delete operator is not bothered as well +void operator delete(void *pointer, CFErrorRef *error) { // no-warning + return; +} From eab0476dead4fc4ac32a677c2851811ea5925a2b Mon Sep 17 00:00:00 2001 From: Davide Italiano Date: Tue, 7 Apr 2020 16:27:29 -0700 Subject: [PATCH 176/286] [ManualDWARFIndex] Remove dead code, in preparation for moving this function. --- .../SymbolFile/DWARF/ManualDWARFIndex.cpp | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp index aff8b5d8c15fd..70a135b78f49d 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp @@ -165,12 +165,6 @@ void ManualDWARFIndex::IndexUnitImpl(DWARFUnit &unit, is_declaration = form_value.Unsigned() != 0; break; - // case DW_AT_artificial: - // if (attributes.ExtractFormValueAtIndex(i, - // form_value)) - // is_artificial = form_value.Unsigned() != 0; - // break; - case DW_AT_MIPS_linkage_name: case DW_AT_linkage_name: if (attributes.ExtractFormValueAtIndex(i, form_value)) @@ -203,20 +197,6 @@ void ManualDWARFIndex::IndexUnitImpl(DWARFUnit &unit, // location describes a hard coded address, but we don't want // the performance penalty of that right now. is_global_or_static_variable = false; - // if (attributes.ExtractFormValueAtIndex(dwarf, i, - // form_value)) { - // // If we have valid block data, then we have location - // // expression bytesthat are fixed (not a location list). - // const uint8_t *block_data = form_value.BlockData(); - // if (block_data) { - // uint32_t block_length = form_value.Unsigned(); - // if (block_length == 1 + - // attributes.UnitAtIndex(i)->GetAddressByteSize()) { - // if (block_data[0] == DW_OP_addr) - // add_die = true; - // } - // } - // } parent_die = nullptr; // Terminate the while loop. break; From 0b060b656b6f5714bcfca9e9d25d51239e3ea2ea Mon Sep 17 00:00:00 2001 From: Davide Italiano Date: Wed, 8 Apr 2020 11:06:00 -0700 Subject: [PATCH 177/286] [DWARF] Not all the constant variables are "static". Fixes rdar://problem/61402307 Differential Revision: https://reviews.llvm.org/D77698 --- .../SymbolFile/DWARF/DWARFDebugInfoEntry.cpp | 23 ++ .../SymbolFile/DWARF/DWARFDebugInfoEntry.h | 2 + .../SymbolFile/DWARF/ManualDWARFIndex.cpp | 31 +- .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 2 +- .../Shell/SymbolFile/DWARF/static_scope.s | 312 ++++++++++++++++++ 5 files changed, 340 insertions(+), 30 deletions(-) create mode 100644 lldb/test/Shell/SymbolFile/DWARF/static_scope.s diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp index 5612c59059bed..9c8ea07ee73e8 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp @@ -1230,6 +1230,29 @@ DWARFDebugInfoEntry::GetAbbreviationDeclarationPtr(const DWARFUnit *cu) const { return nullptr; } +bool DWARFDebugInfoEntry::IsGlobalOrStaticVariable() const { + if (Tag() != DW_TAG_variable) + return false; + const DWARFDebugInfoEntry *parent_die = GetParent(); + while (parent_die != nullptr) { + switch (parent_die->Tag()) { + case DW_TAG_subprogram: + case DW_TAG_lexical_block: + case DW_TAG_inlined_subroutine: + return false; + + case DW_TAG_compile_unit: + case DW_TAG_partial_unit: + return true; + + default: + break; + } + parent_die = parent_die->GetParent(); + } + return false; +} + bool DWARFDebugInfoEntry::operator==(const DWARFDebugInfoEntry &rhs) const { return m_offset == rhs.m_offset && m_parent_idx == rhs.m_parent_idx && m_sibling_idx == rhs.m_sibling_idx && diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h index f35af6e7d498a..666d7070f4fe9 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h @@ -172,6 +172,8 @@ class DWARFDebugInfoEntry { void SetSiblingIndex(uint32_t idx) { m_sibling_idx = idx; } void SetParentIndex(uint32_t idx) { m_parent_idx = idx; } + bool IsGlobalOrStaticVariable() const; + protected: dw_offset_t m_offset; // Offset within the .debug_info/.debug_types uint32_t m_parent_idx; // How many to subtract from "this" to get the parent. diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp index 70a135b78f49d..a1a8a79f58002 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp @@ -184,35 +184,8 @@ void ManualDWARFIndex::IndexUnitImpl(DWARFUnit &unit, case DW_AT_location: case DW_AT_const_value: has_location_or_const_value = true; - if (tag == DW_TAG_variable) { - const DWARFDebugInfoEntry *parent_die = die.GetParent(); - while (parent_die != nullptr) { - switch (parent_die->Tag()) { - case DW_TAG_subprogram: - case DW_TAG_lexical_block: - case DW_TAG_inlined_subroutine: - // Even if this is a function level static, we don't add it. We - // could theoretically add these if we wanted to by - // introspecting into the DW_AT_location and seeing if the - // location describes a hard coded address, but we don't want - // the performance penalty of that right now. - is_global_or_static_variable = false; - parent_die = nullptr; // Terminate the while loop. - break; - - case DW_TAG_compile_unit: - case DW_TAG_partial_unit: - is_global_or_static_variable = true; - parent_die = nullptr; // Terminate the while loop. - break; - - default: - parent_die = - parent_die->GetParent(); // Keep going in the while loop. - break; - } - } - } + is_global_or_static_variable = die.IsGlobalOrStaticVariable(); + break; case DW_AT_specification: diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 49dd49c26a206..1bd5030033128 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -3546,7 +3546,7 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, } } } else { - if (location_is_const_value_data) + if (location_is_const_value_data && die.GetDIE()->IsGlobalOrStaticVariable()) scope = eValueTypeVariableStatic; else { scope = eValueTypeVariableLocal; diff --git a/lldb/test/Shell/SymbolFile/DWARF/static_scope.s b/lldb/test/Shell/SymbolFile/DWARF/static_scope.s new file mode 100644 index 0000000000000..17b2485798494 --- /dev/null +++ b/lldb/test/Shell/SymbolFile/DWARF/static_scope.s @@ -0,0 +1,312 @@ +# Test that the DWARF parser assigns the right scope to the +# variable `b`, which is `local` and not `static`. + +# REQUIRES: x86 +# UNSUPPORTED: lldb-repro + +# RUN: llvm-mc -triple=x86_64-apple-macosx10.15.0 -filetype=obj %s > %t.o +# RUN: lldb-test symbols %t.o | FileCheck %s + +# CHECK: Variable{{.*}}, name = "b", type = {{.*}} (int), scope = local + + .section __TEXT,__text,regular,pure_instructions + .macosx_version_min 10, 15 + .file 1 "/Users/davide/work/build/bin" "a.c" + .globl _main ## -- Begin function main + .p2align 4, 0x90 +_main: ## @main +Lfunc_begin0: + .loc 1 2 0 ## a.c:2:0 + .cfi_startproc +## %bb.0: + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp +Ltmp0: + ##DEBUG_VALUE: b <- 3 + .loc 1 5 9 prologue_end ## a.c:5:9 + movl _a(%rip), %eax +Ltmp1: + .loc 1 7 5 ## a.c:7:5 + xorl %eax, %eax + popq %rbp + retq +Ltmp2: +Lfunc_end0: + .cfi_endproc + ## -- End function + .globl _a ## @a +.zerofill __DATA,__common,_a,4,2 + .section __DWARF,__debug_abbrev,regular,debug +Lsection_abbrev: + .byte 1 ## Abbreviation Code + .byte 17 ## DW_TAG_compile_unit + .byte 1 ## DW_CHILDREN_yes + .byte 37 ## DW_AT_producer + .byte 14 ## DW_FORM_strp + .byte 19 ## DW_AT_language + .byte 5 ## DW_FORM_data2 + .byte 3 ## DW_AT_name + .byte 14 ## DW_FORM_strp + .ascii "\202|" ## DW_AT_LLVM_sysroot + .byte 14 ## DW_FORM_strp + .byte 16 ## DW_AT_stmt_list + .byte 23 ## DW_FORM_sec_offset + .byte 27 ## DW_AT_comp_dir + .byte 14 ## DW_FORM_strp + .ascii "\341\177" ## DW_AT_APPLE_optimized + .byte 25 ## DW_FORM_flag_present + .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 14 ## DW_FORM_strp + .byte 73 ## DW_AT_type + .byte 19 ## DW_FORM_ref4 + .byte 63 ## DW_AT_external + .byte 25 ## DW_FORM_flag_present + .byte 58 ## DW_AT_decl_file + .byte 11 ## DW_FORM_data1 + .byte 59 ## DW_AT_decl_line + .byte 11 ## DW_FORM_data1 + .byte 2 ## DW_AT_location + .byte 24 ## DW_FORM_exprloc + .byte 0 ## EOM(1) + .byte 0 ## EOM(2) + .byte 3 ## Abbreviation Code + .byte 53 ## DW_TAG_volatile_type + .byte 0 ## DW_CHILDREN_no + .byte 73 ## DW_AT_type + .byte 19 ## DW_FORM_ref4 + .byte 0 ## EOM(1) + .byte 0 ## EOM(2) + .byte 4 ## Abbreviation Code + .byte 36 ## DW_TAG_base_type + .byte 0 ## DW_CHILDREN_no + .byte 3 ## DW_AT_name + .byte 14 ## DW_FORM_strp + .byte 62 ## DW_AT_encoding + .byte 11 ## DW_FORM_data1 + .byte 11 ## DW_AT_byte_size + .byte 11 ## DW_FORM_data1 + .byte 0 ## EOM(1) + .byte 0 ## EOM(2) + .byte 5 ## Abbreviation Code + .byte 46 ## DW_TAG_subprogram + .byte 1 ## DW_CHILDREN_yes + .byte 17 ## DW_AT_low_pc + .byte 1 ## DW_FORM_addr + .byte 18 ## DW_AT_high_pc + .byte 6 ## DW_FORM_data4 + .byte 64 ## DW_AT_frame_base + .byte 24 ## DW_FORM_exprloc + .byte 122 ## DW_AT_call_all_calls + .byte 25 ## DW_FORM_flag_present + .byte 3 ## DW_AT_name + .byte 14 ## DW_FORM_strp + .byte 58 ## DW_AT_decl_file + .byte 11 ## DW_FORM_data1 + .byte 59 ## DW_AT_decl_line + .byte 11 ## DW_FORM_data1 + .byte 73 ## DW_AT_type + .byte 19 ## DW_FORM_ref4 + .byte 63 ## DW_AT_external + .byte 25 ## DW_FORM_flag_present + .ascii "\341\177" ## DW_AT_APPLE_optimized + .byte 25 ## DW_FORM_flag_present + .byte 0 ## EOM(1) + .byte 0 ## EOM(2) + .byte 6 ## Abbreviation Code + .byte 11 ## DW_TAG_lexical_block + .byte 1 ## DW_CHILDREN_yes + .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 7 ## Abbreviation Code + .byte 52 ## DW_TAG_variable + .byte 0 ## DW_CHILDREN_no + .byte 28 ## DW_AT_const_value + .byte 13 ## DW_FORM_sdata + .byte 3 ## DW_AT_name + .byte 14 ## DW_FORM_strp + .byte 58 ## DW_AT_decl_file + .byte 11 ## DW_FORM_data1 + .byte 59 ## DW_AT_decl_line + .byte 11 ## DW_FORM_data1 + .byte 73 ## DW_AT_type + .byte 19 ## DW_FORM_ref4 + .byte 0 ## EOM(1) + .byte 0 ## EOM(2) + .byte 0 ## EOM(3) + .section __DWARF,__debug_info,regular,debug +Lsection_info: +Lcu_begin0: +.set Lset0, Ldebug_info_end0-Ldebug_info_start0 ## Length of Unit + .long Lset0 +Ldebug_info_start0: + .short 4 ## DWARF version number +.set Lset1, Lsection_abbrev-Lsection_abbrev ## Offset Into Abbrev. Section + .long Lset1 + .byte 8 ## Address Size (in bytes) + .byte 1 ## Abbrev [1] 0xb:0x79 DW_TAG_compile_unit + .long 0 ## DW_AT_producer + .short 12 ## DW_AT_language + .long 101 ## DW_AT_name + .long 105 ## DW_AT_LLVM_sysroot +.set Lset2, Lline_table_start0-Lsection_line ## DW_AT_stmt_list + .long Lset2 + .long 107 ## DW_AT_comp_dir + ## DW_AT_APPLE_optimized + .quad Lfunc_begin0 ## DW_AT_low_pc +.set Lset3, Lfunc_end0-Lfunc_begin0 ## DW_AT_high_pc + .long Lset3 + .byte 2 ## Abbrev [2] 0x2e:0x15 DW_TAG_variable + .long 136 ## DW_AT_name + .long 67 ## DW_AT_type + ## DW_AT_external + .byte 1 ## DW_AT_decl_file + .byte 1 ## DW_AT_decl_line + .byte 9 ## DW_AT_location + .byte 3 + .quad _a + .byte 3 ## Abbrev [3] 0x43:0x5 DW_TAG_volatile_type + .long 72 ## DW_AT_type + .byte 4 ## Abbrev [4] 0x48:0x7 DW_TAG_base_type + .long 138 ## DW_AT_name + .byte 5 ## DW_AT_encoding + .byte 4 ## DW_AT_byte_size + .byte 5 ## Abbrev [5] 0x4f:0x34 DW_TAG_subprogram + .quad Lfunc_begin0 ## DW_AT_low_pc +.set Lset4, Lfunc_end0-Lfunc_begin0 ## DW_AT_high_pc + .long Lset4 + .byte 1 ## DW_AT_frame_base + .byte 86 + ## DW_AT_call_all_calls + .long 142 ## DW_AT_name + .byte 1 ## DW_AT_decl_file + .byte 2 ## DW_AT_decl_line + .long 72 ## DW_AT_type + ## DW_AT_external + ## DW_AT_APPLE_optimized + .byte 6 ## Abbrev [6] 0x68:0x1a DW_TAG_lexical_block + .quad Ltmp0 ## DW_AT_low_pc +.set Lset5, Ltmp1-Ltmp0 ## DW_AT_high_pc + .long Lset5 + .byte 7 ## Abbrev [7] 0x75:0xc DW_TAG_variable + .byte 3 ## DW_AT_const_value + .long 147 ## DW_AT_name + .byte 1 ## DW_AT_decl_file + .byte 4 ## DW_AT_decl_line + .long 72 ## DW_AT_type + .byte 0 ## End Of Children Mark + .byte 0 ## End Of Children Mark + .byte 0 ## End Of Children Mark +Ldebug_info_end0: + .section __DWARF,__debug_str,regular,debug +Linfo_string: + .asciz "clang version 11.0.0 (https://github.com/llvm/llvm-project f30ebf437851d3c68fd0eee82afbc0cef7373c00)" ## string offset=0 + .asciz "a.c" ## string offset=101 + .asciz "/" ## string offset=105 + .asciz "/Users/davide/work/build/bin" ## string offset=107 + .asciz "a" ## string offset=136 + .asciz "int" ## string offset=138 + .asciz "main" ## string offset=142 + .asciz "b" ## string offset=147 + .section __DWARF,__apple_names,regular,debug +Lnames_begin: + .long 1212240712 ## Header Magic + .short 1 ## Header Version + .short 0 ## Header Hash Function + .long 2 ## Header Bucket Count + .long 2 ## Header Hash Count + .long 12 ## Header Data Length + .long 0 ## HeaderData Die Offset Base + .long 1 ## HeaderData Atom Count + .short 1 ## DW_ATOM_die_offset + .short 6 ## DW_FORM_data4 + .long 0 ## Bucket 0 + .long -1 ## Bucket 1 + .long 177670 ## Hash in Bucket 0 + .long 2090499946 ## Hash in Bucket 0 +.set Lset6, LNames0-Lnames_begin ## Offset in Bucket 0 + .long Lset6 +.set Lset7, LNames1-Lnames_begin ## Offset in Bucket 0 + .long Lset7 +LNames0: + .long 136 ## a + .long 1 ## Num DIEs + .long 46 + .long 0 +LNames1: + .long 142 ## main + .long 1 ## Num DIEs + .long 79 + .long 0 + .section __DWARF,__apple_objc,regular,debug +Lobjc_begin: + .long 1212240712 ## Header Magic + .short 1 ## Header Version + .short 0 ## Header Hash Function + .long 1 ## Header Bucket Count + .long 0 ## Header Hash Count + .long 12 ## Header Data Length + .long 0 ## HeaderData Die Offset Base + .long 1 ## HeaderData Atom Count + .short 1 ## DW_ATOM_die_offset + .short 6 ## DW_FORM_data4 + .long -1 ## Bucket 0 + .section __DWARF,__apple_namespac,regular,debug +Lnamespac_begin: + .long 1212240712 ## Header Magic + .short 1 ## Header Version + .short 0 ## Header Hash Function + .long 1 ## Header Bucket Count + .long 0 ## Header Hash Count + .long 12 ## Header Data Length + .long 0 ## HeaderData Die Offset Base + .long 1 ## HeaderData Atom Count + .short 1 ## DW_ATOM_die_offset + .short 6 ## DW_FORM_data4 + .long -1 ## Bucket 0 + .section __DWARF,__apple_types,regular,debug +Ltypes_begin: + .long 1212240712 ## Header Magic + .short 1 ## Header Version + .short 0 ## Header Hash Function + .long 1 ## Header Bucket Count + .long 1 ## Header Hash Count + .long 20 ## Header Data Length + .long 0 ## HeaderData Die Offset Base + .long 3 ## HeaderData Atom Count + .short 1 ## DW_ATOM_die_offset + .short 6 ## DW_FORM_data4 + .short 3 ## DW_ATOM_die_tag + .short 5 ## DW_FORM_data2 + .short 4 ## DW_ATOM_type_flags + .short 11 ## DW_FORM_data1 + .long 0 ## Bucket 0 + .long 193495088 ## Hash in Bucket 0 +.set Lset8, Ltypes0-Ltypes_begin ## Offset in Bucket 0 + .long Lset8 +Ltypes0: + .long 138 ## int + .long 1 ## Num DIEs + .long 72 + .short 36 + .byte 0 + .long 0 +.subsections_via_symbols + .section __DWARF,__debug_line,regular,debug +Lsection_line: +Lline_table_start0: From 7d0b07c08a38077c9d6bddac4d91d4468a94324c Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Tue, 18 Feb 2020 14:33:54 -0800 Subject: [PATCH 178/286] [IR] Lazily number instructions for local dominance queries Essentially, fold OrderedBasicBlock into BasicBlock, and make it auto-invalidate the instruction ordering when new instructions are added. Notably, we don't need to invalidate it when removing instructions, which is helpful when a pass mostly delete dead instructions rather than transforming them. The downside is that Instruction grows from 56 bytes to 64 bytes. The resulting LLVM code is substantially simpler and automatically handles invalidation, which makes me think that this is the right speed and size tradeoff. The important change is in SymbolTableTraitsImpl.h, where the numbering is invalidated. Everything else should be straightforward. We probably want to implement a fancier re-numbering scheme so that local updates don't invalidate the ordering, but I plan for that to be future work, maybe for someone else. Reviewed By: lattner, vsk, fhahn, dexonsmith Differential Revision: https://reviews.llvm.org/D51664 --- llvm/include/llvm/Analysis/AliasAnalysis.h | 12 +- llvm/include/llvm/Analysis/CaptureTracking.h | 5 +- .../llvm/Analysis/MemoryDependenceAnalysis.h | 9 +- .../include/llvm/Analysis/OrderedBasicBlock.h | 74 ---------- .../llvm/Analysis/OrderedInstructions.h | 18 +-- llvm/include/llvm/IR/BasicBlock.h | 61 ++++++++- llvm/include/llvm/IR/Instruction.h | 12 ++ llvm/lib/Analysis/AliasAnalysis.cpp | 9 +- llvm/lib/Analysis/CMakeLists.txt | 1 - llvm/lib/Analysis/CaptureTracking.cpp | 24 +--- .../InstructionPrecedenceTracking.cpp | 4 - .../lib/Analysis/MemoryDependenceAnalysis.cpp | 25 +--- llvm/lib/Analysis/OrderedBasicBlock.cpp | 111 --------------- llvm/lib/Analysis/OrderedInstructions.cpp | 11 +- llvm/lib/IR/BasicBlock.cpp | 32 +++++ llvm/lib/IR/Instruction.cpp | 9 ++ llvm/lib/IR/SymbolTableListTraitsImpl.h | 15 ++- llvm/lib/Target/ARM/ARMParallelDSP.cpp | 22 ++- .../Scalar/DeadStoreElimination.cpp | 41 +++--- .../Vectorize/LoadStoreVectorizer.cpp | 16 +-- llvm/unittests/Analysis/CMakeLists.txt | 1 - .../Analysis/CaptureTrackingTest.cpp | 8 +- .../Analysis/OrderedBasicBlockTest.cpp | 57 -------- llvm/unittests/IR/BasicBlockTest.cpp | 127 ++++++++++++++++++ .../gn/secondary/llvm/lib/Analysis/BUILD.gn | 1 - .../llvm/unittests/Analysis/BUILD.gn | 1 - 26 files changed, 315 insertions(+), 391 deletions(-) delete mode 100644 llvm/include/llvm/Analysis/OrderedBasicBlock.h delete mode 100644 llvm/lib/Analysis/OrderedBasicBlock.cpp delete mode 100644 llvm/unittests/Analysis/OrderedBasicBlockTest.cpp diff --git a/llvm/include/llvm/Analysis/AliasAnalysis.h b/llvm/include/llvm/Analysis/AliasAnalysis.h index 7c42a261ebb68..4ae2cb24040cc 100644 --- a/llvm/include/llvm/Analysis/AliasAnalysis.h +++ b/llvm/include/llvm/Analysis/AliasAnalysis.h @@ -59,7 +59,6 @@ class AnalysisUsage; class BasicAAResult; class BasicBlock; class DominatorTree; -class OrderedBasicBlock; class Value; /// The possible results of an alias query. @@ -643,19 +642,16 @@ class AAResults { /// Return information about whether a particular call site modifies /// or reads the specified memory location \p MemLoc before instruction \p I - /// in a BasicBlock. An ordered basic block \p OBB can be used to speed up - /// instruction ordering queries inside the BasicBlock containing \p I. + /// in a BasicBlock. /// Early exits in callCapturesBefore may lead to ModRefInfo::Must not being /// set. ModRefInfo callCapturesBefore(const Instruction *I, - const MemoryLocation &MemLoc, DominatorTree *DT, - OrderedBasicBlock *OBB = nullptr); + const MemoryLocation &MemLoc, DominatorTree *DT); /// A convenience wrapper to synthesize a memory location. ModRefInfo callCapturesBefore(const Instruction *I, const Value *P, - LocationSize Size, DominatorTree *DT, - OrderedBasicBlock *OBB = nullptr) { - return callCapturesBefore(I, MemoryLocation(P, Size), DT, OBB); + LocationSize Size, DominatorTree *DT) { + return callCapturesBefore(I, MemoryLocation(P, Size), DT); } /// @} diff --git a/llvm/include/llvm/Analysis/CaptureTracking.h b/llvm/include/llvm/Analysis/CaptureTracking.h index 29921a51d5be0..5f72f82f95663 100644 --- a/llvm/include/llvm/Analysis/CaptureTracking.h +++ b/llvm/include/llvm/Analysis/CaptureTracking.h @@ -20,7 +20,6 @@ namespace llvm { class DataLayout; class Instruction; class DominatorTree; - class OrderedBasicBlock; /// The default value for MaxUsesToExplore argument. It's relatively small to /// keep the cost of analysis reasonable for clients like BasicAliasAnalysis, @@ -53,14 +52,12 @@ namespace llvm { /// it or not. The boolean StoreCaptures specified whether storing the value /// (or part of it) into memory anywhere automatically counts as capturing it /// or not. Captures by the provided instruction are considered if the - /// final parameter is true. An ordered basic block in \p OBB could be used - /// to speed up capture-tracker queries. + /// final parameter is true. /// MaxUsesToExplore specifies how many uses should the analysis explore for /// one value before giving up due too "too many uses". bool PointerMayBeCapturedBefore(const Value *V, bool ReturnCaptures, bool StoreCaptures, const Instruction *I, const DominatorTree *DT, bool IncludeI = false, - OrderedBasicBlock *OBB = nullptr, unsigned MaxUsesToExplore = DefaultMaxUsesToExplore); /// This callback is used in conjunction with PointerMayBeCaptured. In diff --git a/llvm/include/llvm/Analysis/MemoryDependenceAnalysis.h b/llvm/include/llvm/Analysis/MemoryDependenceAnalysis.h index e89e5690fad03..e48f2b23a1cb9 100644 --- a/llvm/include/llvm/Analysis/MemoryDependenceAnalysis.h +++ b/llvm/include/llvm/Analysis/MemoryDependenceAnalysis.h @@ -384,8 +384,7 @@ class MemoryDependenceResults { /// /// See the class comment for more details. It is illegal to call this on /// non-memory instructions. - MemDepResult getDependency(Instruction *QueryInst, - OrderedBasicBlock *OBB = nullptr); + MemDepResult getDependency(Instruction *QueryInst); /// Perform a full dependency query for the specified call, returning the set /// of blocks that the value is potentially live across. @@ -451,14 +450,12 @@ class MemoryDependenceResults { BasicBlock::iterator ScanIt, BasicBlock *BB, Instruction *QueryInst = nullptr, - unsigned *Limit = nullptr, - OrderedBasicBlock *OBB = nullptr); + unsigned *Limit = nullptr); MemDepResult getSimplePointerDependencyFrom(const MemoryLocation &MemLoc, bool isLoad, BasicBlock::iterator ScanIt, BasicBlock *BB, - Instruction *QueryInst, unsigned *Limit, - OrderedBasicBlock *OBB); + Instruction *QueryInst, unsigned *Limit); /// This analysis looks for other loads and stores with invariant.group /// metadata and the same pointer operand. Returns Unknown if it does not diff --git a/llvm/include/llvm/Analysis/OrderedBasicBlock.h b/llvm/include/llvm/Analysis/OrderedBasicBlock.h deleted file mode 100644 index ae64c0189f5ec..0000000000000 --- a/llvm/include/llvm/Analysis/OrderedBasicBlock.h +++ /dev/null @@ -1,74 +0,0 @@ -//===- llvm/Analysis/OrderedBasicBlock.h --------------------- -*- 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 -// -//===----------------------------------------------------------------------===// -// -// This file defines the OrderedBasicBlock class. OrderedBasicBlock maintains -// an interface where clients can query if one instruction comes before another -// in a BasicBlock. Since BasicBlock currently lacks a reliable way to query -// relative position between instructions one can use OrderedBasicBlock to do -// such queries. OrderedBasicBlock is lazily built on a source BasicBlock and -// maintains an internal Instruction -> Position map. A OrderedBasicBlock -// instance should be discarded whenever the source BasicBlock changes. -// -// It's currently used by the CaptureTracker in order to find relative -// positions of a pair of instructions inside a BasicBlock. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_ANALYSIS_ORDEREDBASICBLOCK_H -#define LLVM_ANALYSIS_ORDEREDBASICBLOCK_H - -#include "llvm/ADT/DenseMap.h" -#include "llvm/IR/BasicBlock.h" - -namespace llvm { - -class Instruction; -class BasicBlock; - -class OrderedBasicBlock { -private: - /// Map a instruction to its position in a BasicBlock. - SmallDenseMap NumberedInsts; - - /// Keep track of last instruction inserted into \p NumberedInsts. - /// It speeds up queries for uncached instructions by providing a start point - /// for new queries in OrderedBasicBlock::comesBefore. - BasicBlock::const_iterator LastInstFound; - - /// The position/number to tag the next instruction to be found. - unsigned NextInstPos; - - /// The source BasicBlock to map. - const BasicBlock *BB; - - /// Given no cached results, find if \p A comes before \p B in \p BB. - /// Cache and number out instruction while walking \p BB. - bool comesBefore(const Instruction *A, const Instruction *B); - -public: - OrderedBasicBlock(const BasicBlock *BasicB); - - /// Find out whether \p A dominates \p B, meaning whether \p A - /// comes before \p B in \p BB. This is a simplification that considers - /// cached instruction positions and ignores other basic blocks, being - /// only relevant to compare relative instructions positions inside \p BB. - /// Returns false for A == B. - bool dominates(const Instruction *A, const Instruction *B); - - /// Remove \p from the ordering, if it is present. - void eraseInstruction(const Instruction *I); - - /// Replace \p Old with \p New in the ordering. \p New is assigned the - /// numbering of \p Old, so it must be inserted at the same position in the - /// IR. - void replaceInstruction(const Instruction *Old, const Instruction *New); -}; - -} // End llvm namespace - -#endif diff --git a/llvm/include/llvm/Analysis/OrderedInstructions.h b/llvm/include/llvm/Analysis/OrderedInstructions.h index 967b146b52deb..302509380a03a 100644 --- a/llvm/include/llvm/Analysis/OrderedInstructions.h +++ b/llvm/include/llvm/Analysis/OrderedInstructions.h @@ -9,10 +9,9 @@ // This file defines an efficient way to check for dominance relation between 2 // instructions. // -// This interface dispatches to appropriate dominance check given 2 -// instructions, i.e. in case the instructions are in the same basic block, -// OrderedBasicBlock (with instruction numbering and caching) are used. -// Otherwise, dominator tree is used. +// FIXME: This is really just a convenience wrapper to check dominance between +// two arbitrary instructions in different basic blocks. We should fold it into +// DominatorTree, which is the more widely used interface. // //===----------------------------------------------------------------------===// @@ -20,17 +19,12 @@ #define LLVM_ANALYSIS_ORDEREDINSTRUCTIONS_H #include "llvm/ADT/DenseMap.h" -#include "llvm/Analysis/OrderedBasicBlock.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Operator.h" namespace llvm { class OrderedInstructions { - /// Used to check dominance for instructions in same basic block. - mutable DenseMap> - OBBMap; - /// The dominator tree of the parent function. DominatorTree *DT; @@ -51,12 +45,6 @@ class OrderedInstructions { /// or if the first instruction comes before the second in the same basic /// block. bool dfsBefore(const Instruction *, const Instruction *) const; - - /// Invalidate the OrderedBasicBlock cache when its basic block changes. - /// i.e. If an instruction is deleted or added to the basic block, the user - /// should call this function to invalidate the OrderedBasicBlock cache for - /// this basic block. - void invalidateBlock(const BasicBlock *BB) { OBBMap.erase(BB); } }; } // end namespace llvm diff --git a/llvm/include/llvm/IR/BasicBlock.h b/llvm/include/llvm/IR/BasicBlock.h index d594145f8636c..f347cc5ff818f 100644 --- a/llvm/include/llvm/IR/BasicBlock.h +++ b/llvm/include/llvm/IR/BasicBlock.h @@ -393,7 +393,9 @@ class BasicBlock final : public Value, // Basic blocks are data objects also /// Returns true if there are any uses of this basic block other than /// direct branches, switches, etc. to it. - bool hasAddressTaken() const { return getSubclassDataFromValue() != 0; } + bool hasAddressTaken() const { + return getBasicBlockBits().BlockAddressRefCount != 0; + } /// Update all phi nodes in this basic block to refer to basic block \p New /// instead of basic block \p Old. @@ -428,16 +430,61 @@ class BasicBlock final : public Value, // Basic blocks are data objects also Optional getIrrLoopHeaderWeight() const; + /// Returns true if the Order field of child Instructions is valid. + bool isInstrOrderValid() const { + return getBasicBlockBits().InstrOrderValid; + } + + /// Mark instruction ordering invalid. Done on every instruction insert. + void invalidateOrders() { + validateInstrOrdering(); + BasicBlockBits Bits = getBasicBlockBits(); + Bits.InstrOrderValid = false; + setBasicBlockBits(Bits); + } + + /// Renumber instructions and mark the ordering as valid. + void renumberInstructions(); + + /// Returns false if the instruction ordering is incorrect in an debug build. + /// Always returns true when assertions are disabled. The method does not + /// assert internally so that we get better location info. + void validateInstrOrdering() const; + private: + /// Bitfield to help interpret the bits in Value::SubclassData. + struct BasicBlockBits { + unsigned short BlockAddressRefCount : 15; + unsigned short InstrOrderValid : 1; + }; + + /// Safely reinterpret the subclass data bits to a more useful form. + BasicBlockBits getBasicBlockBits() const { + static_assert(sizeof(BasicBlockBits) == sizeof(unsigned short), + "too many bits for Value::SubclassData"); + unsigned short ValueData = getSubclassDataFromValue(); + BasicBlockBits AsBits; + memcpy(&AsBits, &ValueData, sizeof(AsBits)); + return AsBits; + } + + /// Reinterpret our subclass bits and store them back into Value. + void setBasicBlockBits(BasicBlockBits AsBits) { + unsigned short D; + memcpy(&D, &AsBits, sizeof(D)); + Value::setValueSubclassData(D); + } + /// Increment the internal refcount of the number of BlockAddresses /// referencing this BasicBlock by \p Amt. /// /// This is almost always 0, sometimes one possibly, but almost never 2, and /// inconceivably 3 or more. void AdjustBlockAddressRefCount(int Amt) { - setValueSubclassData(getSubclassDataFromValue()+Amt); - assert((int)(signed char)getSubclassDataFromValue() >= 0 && - "Refcount wrap-around"); + BasicBlockBits Bits = getBasicBlockBits(); + Bits.BlockAddressRefCount += Amt; + setBasicBlockBits(Bits); + assert(Bits.BlockAddressRefCount < 255 && "Refcount wrap-around"); } /// Shadow Value::setValueSubclassData with a private forwarding method so @@ -454,6 +501,12 @@ DEFINE_SIMPLE_CONVERSION_FUNCTIONS(BasicBlock, LLVMBasicBlockRef) /// This assumes that \p It is not at the end of a block. BasicBlock::iterator skipDebugIntrinsics(BasicBlock::iterator It); +#ifdef NDEBUG +/// In release builds, this is a no-op. For !NDEBUG builds, the checks are +/// implemented in the .cpp file to avoid circular header deps. +inline void Instruction::validateInstrOrdering() const {} +#endif + } // end namespace llvm #endif // LLVM_IR_BASICBLOCK_H diff --git a/llvm/include/llvm/IR/Instruction.h b/llvm/include/llvm/IR/Instruction.h index 3bfa0e4afc398..b15ececc677cc 100644 --- a/llvm/include/llvm/IR/Instruction.h +++ b/llvm/include/llvm/IR/Instruction.h @@ -45,6 +45,10 @@ class Instruction : public User, BasicBlock *Parent; DebugLoc DbgLoc; // 'dbg' Metadata cache. + /// Relative order of this instruction in its parent basic block. Used for + /// O(1) local dominance checks between instructions. + mutable unsigned Order = 0; + enum { /// This is a bit stored in the SubClassData field which indicates whether /// this instruction has metadata attached to it or not. @@ -117,6 +121,13 @@ class Instruction : public User, /// the basic block that MovePos lives in, right after MovePos. void moveAfter(Instruction *MovePos); + /// Given an instruction Other in the same basic block as this instruction, + /// return true if this instruction comes before Other. In this worst case, + /// this takes linear time in the number of instructions in the block. The + /// results are cached, so in common cases when the block remains unmodified, + /// it takes constant time. + bool comesBefore(const Instruction *Other) const; + //===--------------------------------------------------------------------===// // Subclass classification. //===--------------------------------------------------------------------===// @@ -738,6 +749,7 @@ class Instruction : public User, private: friend class SymbolTableListTraits; + friend class BasicBlock; // For renumbering. // Shadow Value::setValueSubclassData with a private forwarding method so that // subclasses cannot accidentally use it. diff --git a/llvm/lib/Analysis/AliasAnalysis.cpp b/llvm/lib/Analysis/AliasAnalysis.cpp index 1c7678a602d81..3f05b6146feff 100644 --- a/llvm/lib/Analysis/AliasAnalysis.cpp +++ b/llvm/lib/Analysis/AliasAnalysis.cpp @@ -631,16 +631,14 @@ ModRefInfo AAResults::getModRefInfo(const AtomicRMWInst *RMW, /// Return information about whether a particular call site modifies /// or reads the specified memory location \p MemLoc before instruction \p I -/// in a BasicBlock. An ordered basic block \p OBB can be used to speed up -/// instruction-ordering queries inside the BasicBlock containing \p I. +/// in a BasicBlock. /// FIXME: this is really just shoring-up a deficiency in alias analysis. /// BasicAA isn't willing to spend linear time determining whether an alloca /// was captured before or after this particular call, while we are. However, /// with a smarter AA in place, this test is just wasting compile time. ModRefInfo AAResults::callCapturesBefore(const Instruction *I, const MemoryLocation &MemLoc, - DominatorTree *DT, - OrderedBasicBlock *OBB) { + DominatorTree *DT) { if (!DT) return ModRefInfo::ModRef; @@ -656,8 +654,7 @@ ModRefInfo AAResults::callCapturesBefore(const Instruction *I, if (PointerMayBeCapturedBefore(Object, /* ReturnCaptures */ true, /* StoreCaptures */ true, I, DT, - /* include Object */ true, - /* OrderedBasicBlock */ OBB)) + /* include Object */ true)) return ModRefInfo::ModRef; unsigned ArgNo = 0; diff --git a/llvm/lib/Analysis/CMakeLists.txt b/llvm/lib/Analysis/CMakeLists.txt index cc9ff0bc1f570..34140e18677d2 100644 --- a/llvm/lib/Analysis/CMakeLists.txt +++ b/llvm/lib/Analysis/CMakeLists.txt @@ -70,7 +70,6 @@ add_llvm_component_library(LLVMAnalysis ObjCARCAnalysisUtils.cpp ObjCARCInstKind.cpp OptimizationRemarkEmitter.cpp - OrderedBasicBlock.cpp OrderedInstructions.cpp PHITransAddr.cpp PhiValues.cpp diff --git a/llvm/lib/Analysis/CaptureTracking.cpp b/llvm/lib/Analysis/CaptureTracking.cpp index 20e2f06540a38..3d1f266a2e578 100644 --- a/llvm/lib/Analysis/CaptureTracking.cpp +++ b/llvm/lib/Analysis/CaptureTracking.cpp @@ -20,7 +20,6 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/CFG.h" -#include "llvm/Analysis/OrderedBasicBlock.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Dominators.h" @@ -76,8 +75,8 @@ namespace { struct CapturesBefore : public CaptureTracker { CapturesBefore(bool ReturnCaptures, const Instruction *I, const DominatorTree *DT, - bool IncludeI, OrderedBasicBlock *IC) - : OrderedBB(IC), BeforeHere(I), DT(DT), + bool IncludeI) + : BeforeHere(I), DT(DT), ReturnCaptures(ReturnCaptures), IncludeI(IncludeI), Captured(false) {} void tooManyUses() override { Captured = true; } @@ -90,9 +89,7 @@ namespace { return true; // Compute the case where both instructions are inside the same basic - // block. Since instructions in the same BB as BeforeHere are numbered in - // 'OrderedBB', avoid using 'dominates' and 'isPotentiallyReachable' - // which are very expensive for large basic blocks. + // block. if (BB == BeforeHere->getParent()) { // 'I' dominates 'BeforeHere' => not safe to prune. // @@ -102,7 +99,7 @@ namespace { // UseBB == BB, avoid pruning. if (isa(BeforeHere) || isa(I) || I == BeforeHere) return false; - if (!OrderedBB->dominates(BeforeHere, I)) + if (!BeforeHere->comesBefore(I)) return false; // 'BeforeHere' comes before 'I', it's safe to prune if we also @@ -153,7 +150,6 @@ namespace { return true; } - OrderedBasicBlock *OrderedBB; const Instruction *BeforeHere; const DominatorTree *DT; @@ -196,31 +192,23 @@ bool llvm::PointerMayBeCaptured(const Value *V, /// returning the value (or part of it) from the function counts as capturing /// it or not. The boolean StoreCaptures specified whether storing the value /// (or part of it) into memory anywhere automatically counts as capturing it -/// or not. A ordered basic block \p OBB can be used in order to speed up -/// queries about relative order among instructions in the same basic block. +/// or not. bool llvm::PointerMayBeCapturedBefore(const Value *V, bool ReturnCaptures, bool StoreCaptures, const Instruction *I, const DominatorTree *DT, bool IncludeI, - OrderedBasicBlock *OBB, unsigned MaxUsesToExplore) { assert(!isa(V) && "It doesn't make sense to ask whether a global is captured."); - bool UseNewOBB = OBB == nullptr; if (!DT) return PointerMayBeCaptured(V, ReturnCaptures, StoreCaptures, MaxUsesToExplore); - if (UseNewOBB) - OBB = new OrderedBasicBlock(I->getParent()); // TODO: See comment in PointerMayBeCaptured regarding what could be done // with StoreCaptures. - CapturesBefore CB(ReturnCaptures, I, DT, IncludeI, OBB); + CapturesBefore CB(ReturnCaptures, I, DT, IncludeI); PointerMayBeCaptured(V, &CB, MaxUsesToExplore); - - if (UseNewOBB) - delete OBB; return CB.Captured; } diff --git a/llvm/lib/Analysis/InstructionPrecedenceTracking.cpp b/llvm/lib/Analysis/InstructionPrecedenceTracking.cpp index 415797d6a3783..3f5a161c8659f 100644 --- a/llvm/lib/Analysis/InstructionPrecedenceTracking.cpp +++ b/llvm/lib/Analysis/InstructionPrecedenceTracking.cpp @@ -104,18 +104,14 @@ void InstructionPrecedenceTracking::insertInstructionTo(const Instruction *Inst, const BasicBlock *BB) { if (isSpecialInstruction(Inst)) FirstSpecialInsts.erase(BB); - OI.invalidateBlock(BB); } void InstructionPrecedenceTracking::removeInstruction(const Instruction *Inst) { if (isSpecialInstruction(Inst)) FirstSpecialInsts.erase(Inst->getParent()); - OI.invalidateBlock(Inst->getParent()); } void InstructionPrecedenceTracking::clear() { - for (auto It : FirstSpecialInsts) - OI.invalidateBlock(It.first); FirstSpecialInsts.clear(); #ifndef NDEBUG // The map should be valid after clearing (at least empty). diff --git a/llvm/lib/Analysis/MemoryDependenceAnalysis.cpp b/llvm/lib/Analysis/MemoryDependenceAnalysis.cpp index a97a56e258050..8a08bdc4949b8 100644 --- a/llvm/lib/Analysis/MemoryDependenceAnalysis.cpp +++ b/llvm/lib/Analysis/MemoryDependenceAnalysis.cpp @@ -23,7 +23,6 @@ #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/MemoryBuiltins.h" #include "llvm/Analysis/MemoryLocation.h" -#include "llvm/Analysis/OrderedBasicBlock.h" #include "llvm/Analysis/PHITransAddr.h" #include "llvm/Analysis/PhiValues.h" #include "llvm/Analysis/TargetLibraryInfo.h" @@ -327,8 +326,7 @@ static bool isVolatile(Instruction *Inst) { MemDepResult MemoryDependenceResults::getPointerDependencyFrom( const MemoryLocation &MemLoc, bool isLoad, BasicBlock::iterator ScanIt, - BasicBlock *BB, Instruction *QueryInst, unsigned *Limit, - OrderedBasicBlock *OBB) { + BasicBlock *BB, Instruction *QueryInst, unsigned *Limit) { MemDepResult InvariantGroupDependency = MemDepResult::getUnknown(); if (QueryInst != nullptr) { if (auto *LI = dyn_cast(QueryInst)) { @@ -339,7 +337,7 @@ MemDepResult MemoryDependenceResults::getPointerDependencyFrom( } } MemDepResult SimpleDep = getSimplePointerDependencyFrom( - MemLoc, isLoad, ScanIt, BB, QueryInst, Limit, OBB); + MemLoc, isLoad, ScanIt, BB, QueryInst, Limit); if (SimpleDep.isDef()) return SimpleDep; // Non-local invariant group dependency indicates there is non local Def @@ -440,8 +438,7 @@ MemoryDependenceResults::getInvariantGroupPointerDependency(LoadInst *LI, MemDepResult MemoryDependenceResults::getSimplePointerDependencyFrom( const MemoryLocation &MemLoc, bool isLoad, BasicBlock::iterator ScanIt, - BasicBlock *BB, Instruction *QueryInst, unsigned *Limit, - OrderedBasicBlock *OBB) { + BasicBlock *BB, Instruction *QueryInst, unsigned *Limit) { bool isInvariantLoad = false; unsigned DefaultLimit = getDefaultBlockScanLimit(); @@ -488,15 +485,6 @@ MemDepResult MemoryDependenceResults::getSimplePointerDependencyFrom( const DataLayout &DL = BB->getModule()->getDataLayout(); - // If the caller did not provide an ordered basic block, - // create one to lazily compute and cache instruction - // positions inside a BB. This is used to provide fast queries for relative - // position between two instructions in a BB and can be used by - // AliasAnalysis::callCapturesBefore. - OrderedBasicBlock OBBTmp(BB); - if (!OBB) - OBB = &OBBTmp; - // Return "true" if and only if the instruction I is either a non-simple // load or a non-simple store. auto isNonSimpleLoadOrStore = [](Instruction *I) -> bool { @@ -686,7 +674,7 @@ MemDepResult MemoryDependenceResults::getSimplePointerDependencyFrom( ModRefInfo MR = AA.getModRefInfo(Inst, MemLoc); // If necessary, perform additional analysis. if (isModAndRefSet(MR)) - MR = AA.callCapturesBefore(Inst, MemLoc, &DT, OBB); + MR = AA.callCapturesBefore(Inst, MemLoc, &DT); switch (clearMust(MR)) { case ModRefInfo::NoModRef: // If the call has no effect on the queried pointer, just ignore it. @@ -712,8 +700,7 @@ MemDepResult MemoryDependenceResults::getSimplePointerDependencyFrom( return MemDepResult::getNonFuncLocal(); } -MemDepResult MemoryDependenceResults::getDependency(Instruction *QueryInst, - OrderedBasicBlock *OBB) { +MemDepResult MemoryDependenceResults::getDependency(Instruction *QueryInst) { Instruction *ScanPos = QueryInst; // Check for a cached result @@ -753,7 +740,7 @@ MemDepResult MemoryDependenceResults::getDependency(Instruction *QueryInst, LocalCache = getPointerDependencyFrom(MemLoc, isLoad, ScanPos->getIterator(), - QueryParent, QueryInst, nullptr, OBB); + QueryParent, QueryInst, nullptr); } else if (auto *QueryCall = dyn_cast(QueryInst)) { bool isReadOnly = AA.onlyReadsMemory(QueryCall); LocalCache = getCallDependencyFrom(QueryCall, isReadOnly, diff --git a/llvm/lib/Analysis/OrderedBasicBlock.cpp b/llvm/lib/Analysis/OrderedBasicBlock.cpp deleted file mode 100644 index 48f2a4020c666..0000000000000 --- a/llvm/lib/Analysis/OrderedBasicBlock.cpp +++ /dev/null @@ -1,111 +0,0 @@ -//===- OrderedBasicBlock.cpp --------------------------------- -*- 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 -// -//===----------------------------------------------------------------------===// -// -// This file implements the OrderedBasicBlock class. OrderedBasicBlock -// maintains an interface where clients can query if one instruction comes -// before another in a BasicBlock. Since BasicBlock currently lacks a reliable -// way to query relative position between instructions one can use -// OrderedBasicBlock to do such queries. OrderedBasicBlock is lazily built on a -// source BasicBlock and maintains an internal Instruction -> Position map. A -// OrderedBasicBlock instance should be discarded whenever the source -// BasicBlock changes. -// -// It's currently used by the CaptureTracker in order to find relative -// positions of a pair of instructions inside a BasicBlock. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Analysis/OrderedBasicBlock.h" -#include "llvm/IR/Instruction.h" -using namespace llvm; - -OrderedBasicBlock::OrderedBasicBlock(const BasicBlock *BasicB) - : NextInstPos(0), BB(BasicB) { - LastInstFound = BB->end(); -} - -/// Given no cached results, find if \p A comes before \p B in \p BB. -/// Cache and number out instruction while walking \p BB. -bool OrderedBasicBlock::comesBefore(const Instruction *A, - const Instruction *B) { - const Instruction *Inst = nullptr; - assert(!(LastInstFound == BB->end() && NextInstPos != 0) && - "Instruction supposed to be in NumberedInsts"); - assert(A->getParent() == BB && "Instruction supposed to be in the block!"); - assert(B->getParent() == BB && "Instruction supposed to be in the block!"); - - // Start the search with the instruction found in the last lookup round. - auto II = BB->begin(); - auto IE = BB->end(); - if (LastInstFound != IE) - II = std::next(LastInstFound); - - // Number all instructions up to the point where we find 'A' or 'B'. - for (; II != IE; ++II) { - Inst = cast(II); - NumberedInsts[Inst] = NextInstPos++; - if (Inst == A || Inst == B) - break; - } - - assert(II != IE && "Instruction not found?"); - assert((Inst == A || Inst == B) && "Should find A or B"); - LastInstFound = II; - return Inst != B; -} - -/// Find out whether \p A dominates \p B, meaning whether \p A -/// comes before \p B in \p BB. This is a simplification that considers -/// cached instruction positions and ignores other basic blocks, being -/// only relevant to compare relative instructions positions inside \p BB. -bool OrderedBasicBlock::dominates(const Instruction *A, const Instruction *B) { - assert(A->getParent() == B->getParent() && - "Instructions must be in the same basic block!"); - assert(A->getParent() == BB && "Instructions must be in the tracked block!"); - - // First we lookup the instructions. If they don't exist, lookup will give us - // back ::end(). If they both exist, we compare the numbers. Otherwise, if NA - // exists and NB doesn't, it means NA must come before NB because we would - // have numbered NB as well if it didn't. The same is true for NB. If it - // exists, but NA does not, NA must come after it. If neither exist, we need - // to number the block and cache the results (by calling comesBefore). - auto NAI = NumberedInsts.find(A); - auto NBI = NumberedInsts.find(B); - if (NAI != NumberedInsts.end() && NBI != NumberedInsts.end()) - return NAI->second < NBI->second; - if (NAI != NumberedInsts.end()) - return true; - if (NBI != NumberedInsts.end()) - return false; - - return comesBefore(A, B); -} - -void OrderedBasicBlock::eraseInstruction(const Instruction *I) { - if (LastInstFound != BB->end() && I == &*LastInstFound) { - if (LastInstFound == BB->begin()) { - LastInstFound = BB->end(); - NextInstPos = 0; - } else - LastInstFound--; - } - - NumberedInsts.erase(I); -} - -void OrderedBasicBlock::replaceInstruction(const Instruction *Old, - const Instruction *New) { - auto OI = NumberedInsts.find(Old); - if (OI == NumberedInsts.end()) - return; - - NumberedInsts.insert({New, OI->second}); - if (LastInstFound != BB->end() && Old == &*LastInstFound) - LastInstFound = New->getIterator(); - NumberedInsts.erase(Old); -} diff --git a/llvm/lib/Analysis/OrderedInstructions.cpp b/llvm/lib/Analysis/OrderedInstructions.cpp index e947e5e388a83..11ab3e0927d2e 100644 --- a/llvm/lib/Analysis/OrderedInstructions.cpp +++ b/llvm/lib/Analysis/OrderedInstructions.cpp @@ -18,16 +18,11 @@ bool OrderedInstructions::localDominates(const Instruction *InstA, assert(InstA->getParent() == InstB->getParent() && "Instructions must be in the same basic block"); - const BasicBlock *IBB = InstA->getParent(); - auto OBB = OBBMap.find(IBB); - if (OBB == OBBMap.end()) - OBB = OBBMap.insert({IBB, std::make_unique(IBB)}).first; - return OBB->second->dominates(InstA, InstB); + return InstA->comesBefore(InstB); } -/// Given 2 instructions, use OrderedBasicBlock to check for dominance relation -/// if the instructions are in the same basic block, Otherwise, use dominator -/// tree. +/// Given 2 instructions, check for dominance relation if the instructions are +/// in the same basic block. Otherwise, use dominator tree. bool OrderedInstructions::dominates(const Instruction *InstA, const Instruction *InstB) const { // Use ordered basic block to do dominance check in case the 2 instructions diff --git a/llvm/lib/IR/BasicBlock.cpp b/llvm/lib/IR/BasicBlock.cpp index bdee6990f9324..7c6395e4dccb5 100644 --- a/llvm/lib/IR/BasicBlock.cpp +++ b/llvm/lib/IR/BasicBlock.cpp @@ -33,6 +33,10 @@ LLVMContext &BasicBlock::getContext() const { return getType()->getContext(); } +template <> void llvm::invalidateParentIListOrdering(BasicBlock *BB) { + BB->invalidateOrders(); +} + // Explicit instantiation of SymbolTableListTraits since some of the methods // are not in the public header file... template class llvm::SymbolTableListTraits; @@ -61,6 +65,8 @@ void BasicBlock::insertInto(Function *NewParent, BasicBlock *InsertBefore) { } BasicBlock::~BasicBlock() { + validateInstrOrdering(); + // If the address of the block is taken and it is being deleted (e.g. because // it is dead), this means that there is either a dangling constant expr // hanging off the block, or an undefined use of the block (source code @@ -494,3 +500,29 @@ BasicBlock::iterator llvm::skipDebugIntrinsics(BasicBlock::iterator It) { ++It; return It; } + +void BasicBlock::renumberInstructions() { + unsigned Order = 0; + for (Instruction &I : *this) + I.Order = Order++; + + // Set the bit to indicate that the instruction order valid and cached. + BasicBlockBits Bits = getBasicBlockBits(); + Bits.InstrOrderValid = true; + setBasicBlockBits(Bits); +} + +#ifndef NDEBUG +/// In asserts builds, this checks the numbering. In non-asserts builds, it +/// is defined as an inline function returning true in BasicBlock.h. +void BasicBlock::validateInstrOrdering() const { + if (!isInstrOrderValid()) + return; + const Instruction *Prev = nullptr; + for (const Instruction &I : *this) { + assert((!Prev || Prev->comesBefore(&I)) && + "cached instruction ordering is incorrect"); + Prev = &I; + } +} +#endif diff --git a/llvm/lib/IR/Instruction.cpp b/llvm/lib/IR/Instruction.cpp index 7da1697128965..2ef109067dd69 100644 --- a/llvm/lib/IR/Instruction.cpp +++ b/llvm/lib/IR/Instruction.cpp @@ -97,6 +97,15 @@ void Instruction::moveBefore(BasicBlock &BB, BB.getInstList().splice(I, getParent()->getInstList(), getIterator()); } +bool Instruction::comesBefore(const Instruction *Other) const { + assert(Parent && Other->Parent && + "instructions without BB parents have no order"); + assert(Parent == Other->Parent && "cross-BB instruction order comparison"); + if (!Parent->isInstrOrderValid()) + Parent->renumberInstructions(); + return Order < Other->Order; +} + void Instruction::setHasNoUnsignedWrap(bool b) { cast(this)->setHasNoUnsignedWrap(b); } diff --git a/llvm/lib/IR/SymbolTableListTraitsImpl.h b/llvm/lib/IR/SymbolTableListTraitsImpl.h index f399c823d6fb0..4283744bd058d 100644 --- a/llvm/lib/IR/SymbolTableListTraitsImpl.h +++ b/llvm/lib/IR/SymbolTableListTraitsImpl.h @@ -20,6 +20,11 @@ namespace llvm { +/// Notify basic blocks when an instruction is inserted. +template +inline void invalidateParentIListOrdering(ParentClass *Parent) {} +template <> void invalidateParentIListOrdering(BasicBlock *BB); + /// setSymTabObject - This is called when (f.e.) the parent of a basic block /// changes. This requires us to remove all the instruction symtab entries from /// the current function and reinsert them into the new function. @@ -64,6 +69,7 @@ void SymbolTableListTraits::addNodeToList(ValueSubClass *V) { assert(!V->getParent() && "Value already in a container!!"); ItemParentClass *Owner = getListOwner(); V->setParent(Owner); + invalidateParentIListOrdering(Owner); if (V->hasName()) if (ValueSymbolTable *ST = getSymTab(Owner)) ST->reinsertValue(V); @@ -81,8 +87,13 @@ void SymbolTableListTraits::removeNodeFromList( template void SymbolTableListTraits::transferNodesFromList( SymbolTableListTraits &L2, iterator first, iterator last) { - // We only have to do work here if transferring instructions between BBs - ItemParentClass *NewIP = getListOwner(), *OldIP = L2.getListOwner(); + // Transfering nodes, even within the same BB, invalidates the ordering. The + // list that we removed the nodes from still has a valid ordering. + ItemParentClass *NewIP = getListOwner(); + invalidateParentIListOrdering(NewIP); + + // Nothing else needs to be done if we're reording nodes within the same list. + ItemParentClass *OldIP = L2.getListOwner(); if (NewIP == OldIP) return; diff --git a/llvm/lib/Target/ARM/ARMParallelDSP.cpp b/llvm/lib/Target/ARM/ARMParallelDSP.cpp index e2c9335db4190..0d619e76e9bb0 100644 --- a/llvm/lib/Target/ARM/ARMParallelDSP.cpp +++ b/llvm/lib/Target/ARM/ARMParallelDSP.cpp @@ -20,7 +20,6 @@ #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/LoopAccessAnalysis.h" -#include "llvm/Analysis/OrderedBasicBlock.h" #include "llvm/CodeGen/TargetPassConfig.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicsARM.h" @@ -352,7 +351,6 @@ bool ARMParallelDSP::RecordMemoryOps(BasicBlock *BB) { SmallVector Writes; LoadPairs.clear(); WideLoads.clear(); - OrderedBasicBlock OrderedBB(BB); // Collect loads and instruction that may write to memory. For now we only // record loads which are simple, sign-extended and have a single user. @@ -384,7 +382,7 @@ bool ARMParallelDSP::RecordMemoryOps(BasicBlock *BB) { if (!isModOrRefSet(intersectModRef(AA->getModRefInfo(Write, ReadLoc), ModRefInfo::ModRef))) continue; - if (OrderedBB.dominates(Write, Read)) + if (Write->comesBefore(Read)) RAWDeps[Read].insert(Write); } } @@ -392,8 +390,9 @@ bool ARMParallelDSP::RecordMemoryOps(BasicBlock *BB) { // Check whether there's not a write between the two loads which would // prevent them from being safely merged. auto SafeToPair = [&](LoadInst *Base, LoadInst *Offset) { - LoadInst *Dominator = OrderedBB.dominates(Base, Offset) ? Base : Offset; - LoadInst *Dominated = OrderedBB.dominates(Base, Offset) ? Offset : Base; + bool BaseFirst = Base->comesBefore(Offset); + LoadInst *Dominator = BaseFirst ? Base : Offset; + LoadInst *Dominated = BaseFirst ? Offset : Base; if (RAWDeps.count(Dominated)) { InstSet &WritesBefore = RAWDeps[Dominated]; @@ -401,7 +400,7 @@ bool ARMParallelDSP::RecordMemoryOps(BasicBlock *BB) { for (auto Before : WritesBefore) { // We can't move the second load backward, past a write, to merge // with the first load. - if (OrderedBB.dominates(Dominator, Before)) + if (Dominator->comesBefore(Before)) return false; } } @@ -705,12 +704,11 @@ void ARMParallelDSP::InsertParallelMACs(Reduction &R) { } // Roughly sort the mul pairs in their program order. - OrderedBasicBlock OrderedBB(R.getRoot()->getParent()); - llvm::sort(R.getMulPairs(), [&OrderedBB](auto &PairA, auto &PairB) { - const Instruction *A = PairA.first->Root; - const Instruction *B = PairB.first->Root; - return OrderedBB.dominates(A, B); - }); + llvm::sort(R.getMulPairs(), [](auto &PairA, auto &PairB) { + const Instruction *A = PairA.first->Root; + const Instruction *B = PairB.first->Root; + return A->comesBefore(B); + }); IntegerType *Ty = IntegerType::get(M->getContext(), 32); for (auto &Pair : R.getMulPairs()) { diff --git a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp index d4b4c193ca009..77ad46edf3264 100644 --- a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp +++ b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp @@ -31,7 +31,6 @@ #include "llvm/Analysis/MemoryLocation.h" #include "llvm/Analysis/MemorySSA.h" #include "llvm/Analysis/MemorySSAUpdater.h" -#include "llvm/Analysis/OrderedBasicBlock.h" #include "llvm/Analysis/PostDominators.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/ValueTracking.h" @@ -122,7 +121,7 @@ using InstOverlapIntervalsTy = DenseMap; static void deleteDeadInstruction(Instruction *I, BasicBlock::iterator *BBI, MemoryDependenceResults &MD, const TargetLibraryInfo &TLI, - InstOverlapIntervalsTy &IOL, OrderedBasicBlock &OBB, + InstOverlapIntervalsTy &IOL, MapVector &ThrowableInst, SmallSetVector *ValueSet = nullptr) { SmallVector NowDeadInsts; @@ -165,7 +164,6 @@ deleteDeadInstruction(Instruction *I, BasicBlock::iterator *BBI, if (ValueSet) ValueSet->remove(DeadInst); IOL.erase(DeadInst); - OBB.eraseInstruction(DeadInst); if (NewIter == DeadInst->getIterator()) NewIter = DeadInst->eraseFromParent(); @@ -688,7 +686,7 @@ static void findUnconditionalPreds(SmallVectorImpl &Blocks, static bool handleFree(CallInst *F, AliasAnalysis *AA, MemoryDependenceResults *MD, DominatorTree *DT, const TargetLibraryInfo *TLI, - InstOverlapIntervalsTy &IOL, OrderedBasicBlock &OBB, + InstOverlapIntervalsTy &IOL, MapVector &ThrowableInst) { bool MadeChange = false; @@ -723,7 +721,7 @@ static bool handleFree(CallInst *F, AliasAnalysis *AA, // DCE instructions only used to calculate that store. BasicBlock::iterator BBI(Dependency); - deleteDeadInstruction(Dependency, &BBI, *MD, *TLI, IOL, OBB, + deleteDeadInstruction(Dependency, &BBI, *MD, *TLI, IOL, ThrowableInst); ++NumFastStores; MadeChange = true; @@ -781,7 +779,7 @@ static void removeAccessedObjects(const MemoryLocation &LoadedLoc, static bool handleEndBlock(BasicBlock &BB, AliasAnalysis *AA, MemoryDependenceResults *MD, const TargetLibraryInfo *TLI, - InstOverlapIntervalsTy &IOL, OrderedBasicBlock &OBB, + InstOverlapIntervalsTy &IOL, MapVector &ThrowableInst) { bool MadeChange = false; @@ -843,7 +841,7 @@ static bool handleEndBlock(BasicBlock &BB, AliasAnalysis *AA, << '\n'); // DCE instructions only used to calculate that store. - deleteDeadInstruction(Dead, &BBI, *MD, *TLI, IOL, OBB, ThrowableInst, + deleteDeadInstruction(Dead, &BBI, *MD, *TLI, IOL, ThrowableInst, &DeadStackObjects); ++NumFastStores; MadeChange = true; @@ -855,7 +853,7 @@ static bool handleEndBlock(BasicBlock &BB, AliasAnalysis *AA, if (isInstructionTriviallyDead(&*BBI, TLI)) { LLVM_DEBUG(dbgs() << "DSE: Removing trivially dead instruction:\n DEAD: " << *&*BBI << '\n'); - deleteDeadInstruction(&*BBI, &BBI, *MD, *TLI, IOL, OBB, ThrowableInst, + deleteDeadInstruction(&*BBI, &BBI, *MD, *TLI, IOL, ThrowableInst, &DeadStackObjects); ++NumFastOther; MadeChange = true; @@ -1062,7 +1060,6 @@ static bool eliminateNoopStore(Instruction *Inst, BasicBlock::iterator &BBI, const DataLayout &DL, const TargetLibraryInfo *TLI, InstOverlapIntervalsTy &IOL, - OrderedBasicBlock &OBB, MapVector &ThrowableInst) { // Must be a store instruction. StoreInst *SI = dyn_cast(Inst); @@ -1079,7 +1076,7 @@ static bool eliminateNoopStore(Instruction *Inst, BasicBlock::iterator &BBI, dbgs() << "DSE: Remove Store Of Load from same pointer:\n LOAD: " << *DepLoad << "\n STORE: " << *SI << '\n'); - deleteDeadInstruction(SI, &BBI, *MD, *TLI, IOL, OBB, ThrowableInst); + deleteDeadInstruction(SI, &BBI, *MD, *TLI, IOL, ThrowableInst); ++NumRedundantStores; return true; } @@ -1097,7 +1094,7 @@ static bool eliminateNoopStore(Instruction *Inst, BasicBlock::iterator &BBI, dbgs() << "DSE: Remove null store to the calloc'ed object:\n DEAD: " << *Inst << "\n OBJECT: " << *UnderlyingPointer << '\n'); - deleteDeadInstruction(SI, &BBI, *MD, *TLI, IOL, OBB, ThrowableInst); + deleteDeadInstruction(SI, &BBI, *MD, *TLI, IOL, ThrowableInst); ++NumRedundantStores; return true; } @@ -1111,7 +1108,6 @@ static bool eliminateDeadStores(BasicBlock &BB, AliasAnalysis *AA, const DataLayout &DL = BB.getModule()->getDataLayout(); bool MadeChange = false; - OrderedBasicBlock OBB(&BB); MapVector ThrowableInst; // A map of interval maps representing partially-overwritten value parts. @@ -1121,7 +1117,7 @@ static bool eliminateDeadStores(BasicBlock &BB, AliasAnalysis *AA, for (BasicBlock::iterator BBI = BB.begin(), BBE = BB.end(); BBI != BBE; ) { // Handle 'free' calls specially. if (CallInst *F = isFreeCall(&*BBI, TLI)) { - MadeChange |= handleFree(F, AA, MD, DT, TLI, IOL, OBB, ThrowableInst); + MadeChange |= handleFree(F, AA, MD, DT, TLI, IOL, ThrowableInst); // Increment BBI after handleFree has potentially deleted instructions. // This ensures we maintain a valid iterator. ++BBI; @@ -1140,14 +1136,14 @@ static bool eliminateDeadStores(BasicBlock &BB, AliasAnalysis *AA, continue; // eliminateNoopStore will update in iterator, if necessary. - if (eliminateNoopStore(Inst, BBI, AA, MD, DL, TLI, IOL, OBB, + if (eliminateNoopStore(Inst, BBI, AA, MD, DL, TLI, IOL, ThrowableInst)) { MadeChange = true; continue; } // If we find something that writes memory, get its memory dependence. - MemDepResult InstDep = MD->getDependency(Inst, &OBB); + MemDepResult InstDep = MD->getDependency(Inst); // Ignore any store where we can't find a local dependence. // FIXME: cross-block DSE would be fun. :) @@ -1198,7 +1194,7 @@ static bool eliminateDeadStores(BasicBlock &BB, AliasAnalysis *AA, // If the underlying object is a non-escaping memory allocation, any store // to it is dead along the unwind edge. Otherwise, we need to preserve // the store. - if (LastThrowing && OBB.dominates(DepWrite, LastThrowing)) { + if (LastThrowing && DepWrite->comesBefore(LastThrowing)) { const Value* Underlying = GetUnderlyingObject(DepLoc.Ptr, DL); bool IsStoreDeadOnUnwind = isa(Underlying); if (!IsStoreDeadOnUnwind) { @@ -1229,13 +1225,13 @@ static bool eliminateDeadStores(BasicBlock &BB, AliasAnalysis *AA, << "\n KILLER: " << *Inst << '\n'); // Delete the store and now-dead instructions that feed it. - deleteDeadInstruction(DepWrite, &BBI, *MD, *TLI, IOL, OBB, + deleteDeadInstruction(DepWrite, &BBI, *MD, *TLI, IOL, ThrowableInst); ++NumFastStores; MadeChange = true; // We erased DepWrite; start over. - InstDep = MD->getDependency(Inst, &OBB); + InstDep = MD->getDependency(Inst); continue; } else if ((OR == OW_End && isShortenableAtTheEnd(DepWrite)) || ((OR == OW_Begin && @@ -1308,13 +1304,10 @@ static bool eliminateDeadStores(BasicBlock &BB, AliasAnalysis *AA, SI->copyMetadata(*DepWrite, MDToKeep); ++NumModifiedStores; - // Remove earlier, wider, store - OBB.replaceInstruction(DepWrite, SI); - // Delete the old stores and now-dead instructions that feed them. - deleteDeadInstruction(Inst, &BBI, *MD, *TLI, IOL, OBB, + deleteDeadInstruction(Inst, &BBI, *MD, *TLI, IOL, ThrowableInst); - deleteDeadInstruction(DepWrite, &BBI, *MD, *TLI, IOL, OBB, + deleteDeadInstruction(DepWrite, &BBI, *MD, *TLI, IOL, ThrowableInst); MadeChange = true; @@ -1350,7 +1343,7 @@ static bool eliminateDeadStores(BasicBlock &BB, AliasAnalysis *AA, // If this block ends in a return, unwind, or unreachable, all allocas are // dead at its end, which means stores to them are also dead. if (BB.getTerminator()->getNumSuccessors() == 0) - MadeChange |= handleEndBlock(BB, AA, MD, TLI, IOL, OBB, ThrowableInst); + MadeChange |= handleEndBlock(BB, AA, MD, TLI, IOL, ThrowableInst); return MadeChange; } diff --git a/llvm/lib/Transforms/Vectorize/LoadStoreVectorizer.cpp b/llvm/lib/Transforms/Vectorize/LoadStoreVectorizer.cpp index 7478daa2a0a52..4c3df04c7e788 100644 --- a/llvm/lib/Transforms/Vectorize/LoadStoreVectorizer.cpp +++ b/llvm/lib/Transforms/Vectorize/LoadStoreVectorizer.cpp @@ -50,7 +50,6 @@ #include "llvm/ADT/iterator_range.h" #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/MemoryLocation.h" -#include "llvm/Analysis/OrderedBasicBlock.h" #include "llvm/Analysis/ScalarEvolution.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Analysis/ValueTracking.h" @@ -503,7 +502,6 @@ bool Vectorizer::lookThroughSelects(Value *PtrA, Value *PtrB, } void Vectorizer::reorder(Instruction *I) { - OrderedBasicBlock OBB(I->getParent()); SmallPtrSet InstructionsToMove; SmallVector Worklist; @@ -521,7 +519,7 @@ void Vectorizer::reorder(Instruction *I) { if (IM->getParent() != I->getParent()) continue; - if (!OBB.dominates(IM, I)) { + if (!IM->comesBefore(I)) { InstructionsToMove.insert(IM); Worklist.push_back(IM); } @@ -637,8 +635,6 @@ Vectorizer::getVectorizablePrefix(ArrayRef Chain) { } } - OrderedBasicBlock OBB(Chain[0]->getParent()); - // Loop until we find an instruction in ChainInstrs that we can't vectorize. unsigned ChainInstrIdx = 0; Instruction *BarrierMemoryInstr = nullptr; @@ -648,14 +644,14 @@ Vectorizer::getVectorizablePrefix(ArrayRef Chain) { // If a barrier memory instruction was found, chain instructions that follow // will not be added to the valid prefix. - if (BarrierMemoryInstr && OBB.dominates(BarrierMemoryInstr, ChainInstr)) + if (BarrierMemoryInstr && BarrierMemoryInstr->comesBefore(ChainInstr)) break; // Check (in BB order) if any instruction prevents ChainInstr from being // vectorized. Find and store the first such "conflicting" instruction. for (Instruction *MemInstr : MemoryInstrs) { // If a barrier memory instruction was found, do not check past it. - if (BarrierMemoryInstr && OBB.dominates(BarrierMemoryInstr, MemInstr)) + if (BarrierMemoryInstr && BarrierMemoryInstr->comesBefore(MemInstr)) break; auto *MemLoad = dyn_cast(MemInstr); @@ -674,12 +670,12 @@ Vectorizer::getVectorizablePrefix(ArrayRef Chain) { // vectorize it (the vectorized load is inserted at the location of the // first load in the chain). if (isa(MemInstr) && ChainLoad && - (IsInvariantLoad(ChainLoad) || OBB.dominates(ChainLoad, MemInstr))) + (IsInvariantLoad(ChainLoad) || ChainLoad->comesBefore(MemInstr))) continue; // Same case, but in reverse. if (MemLoad && isa(ChainInstr) && - (IsInvariantLoad(MemLoad) || OBB.dominates(MemLoad, ChainInstr))) + (IsInvariantLoad(MemLoad) || MemLoad->comesBefore(ChainInstr))) continue; if (!AA.isNoAlias(MemoryLocation::get(MemInstr), @@ -705,7 +701,7 @@ Vectorizer::getVectorizablePrefix(ArrayRef Chain) { // the basic block. if (IsLoadChain && BarrierMemoryInstr) { // The BarrierMemoryInstr is a store that precedes ChainInstr. - assert(OBB.dominates(BarrierMemoryInstr, ChainInstr)); + assert(BarrierMemoryInstr->comesBefore(ChainInstr)); break; } } diff --git a/llvm/unittests/Analysis/CMakeLists.txt b/llvm/unittests/Analysis/CMakeLists.txt index 4b4ea416ed8dd..91f583dfd7239 100644 --- a/llvm/unittests/Analysis/CMakeLists.txt +++ b/llvm/unittests/Analysis/CMakeLists.txt @@ -23,7 +23,6 @@ add_llvm_unittest(AnalysisTests LoopInfoTest.cpp MemoryBuiltinsTest.cpp MemorySSATest.cpp - OrderedBasicBlockTest.cpp OrderedInstructionsTest.cpp PhiValuesTest.cpp ProfileSummaryInfoTest.cpp diff --git a/llvm/unittests/Analysis/CaptureTrackingTest.cpp b/llvm/unittests/Analysis/CaptureTrackingTest.cpp index 86a0aa16a066a..e4c8a9ff0f744 100644 --- a/llvm/unittests/Analysis/CaptureTrackingTest.cpp +++ b/llvm/unittests/Analysis/CaptureTrackingTest.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "llvm/Analysis/CaptureTracking.h" -#include "llvm/Analysis/OrderedBasicBlock.h" #include "llvm/AsmParser/Parser.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Instructions.h" @@ -62,14 +61,13 @@ TEST(CaptureTracking, MaxUsesToExplore) { BasicBlock *EntryBB = &F->getEntryBlock(); DominatorTree DT(*F); - OrderedBasicBlock OBB(EntryBB); Instruction *Ret = EntryBB->getTerminator(); ASSERT_TRUE(isa(Ret)); - ASSERT_FALSE(PointerMayBeCapturedBefore(Arg, true, true, Ret, &DT, false, - &OBB, FalseMaxUsesLimit)); + ASSERT_FALSE(PointerMayBeCapturedBefore(Arg, true, true, Ret, &DT, false, + FalseMaxUsesLimit)); ASSERT_TRUE(PointerMayBeCapturedBefore(Arg, true, true, Ret, &DT, false, - &OBB, TrueMaxUsesLimit)); + TrueMaxUsesLimit)); }; Test("test_few_uses", 6, 4); diff --git a/llvm/unittests/Analysis/OrderedBasicBlockTest.cpp b/llvm/unittests/Analysis/OrderedBasicBlockTest.cpp deleted file mode 100644 index 4cccb38daff35..0000000000000 --- a/llvm/unittests/Analysis/OrderedBasicBlockTest.cpp +++ /dev/null @@ -1,57 +0,0 @@ -//===- OrderedBasicBlockTest.cpp - OrderedBasicBlock unit tests -----------===// -// -// 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/Analysis/OrderedBasicBlock.h" -#include "llvm/AsmParser/Parser.h" -#include "llvm/IR/BasicBlock.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/Module.h" -#include "llvm/Support/DataTypes.h" -#include "llvm/Support/SourceMgr.h" -#include "gtest/gtest.h" - -namespace llvm { -namespace { - -class OrderedBasicBlockTest : public testing::Test { -protected: - LLVMContext C; - - std::unique_ptr makeLLVMModule() { - const char *ModuleString = R"(define i32 @f(i32 %x) { - %add = add i32 %x, 42 - ret i32 %add - })"; - SMDiagnostic Err; - auto foo = parseAssemblyString(ModuleString, Err, C); - return foo; - } -}; - -TEST_F(OrderedBasicBlockTest, Basic) { - auto M = makeLLVMModule(); - Function *F = M->getFunction("f"); - BasicBlock::iterator I = F->front().begin(); - Instruction *Add = &*I++; - Instruction *Ret = &*I++; - - OrderedBasicBlock OBB(&F->front()); - // Intentionally duplicated to verify cached and uncached are the same. - EXPECT_FALSE(OBB.dominates(Add, Add)); - EXPECT_FALSE(OBB.dominates(Add, Add)); - EXPECT_TRUE(OBB.dominates(Add, Ret)); - EXPECT_TRUE(OBB.dominates(Add, Ret)); - EXPECT_FALSE(OBB.dominates(Ret, Add)); - EXPECT_FALSE(OBB.dominates(Ret, Add)); - EXPECT_FALSE(OBB.dominates(Ret, Ret)); - EXPECT_FALSE(OBB.dominates(Ret, Ret)); -} - -} // end anonymous namespace -} // end namespace llvm diff --git a/llvm/unittests/IR/BasicBlockTest.cpp b/llvm/unittests/IR/BasicBlockTest.cpp index ad446ee6ebab2..fcdc9c2c07fba 100644 --- a/llvm/unittests/IR/BasicBlockTest.cpp +++ b/llvm/unittests/IR/BasicBlockTest.cpp @@ -8,11 +8,13 @@ #include "llvm/IR/BasicBlock.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/AsmParser/Parser.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/NoFolder.h" +#include "llvm/Support/SourceMgr.h" #include "gmock/gmock-matchers.h" #include "gtest/gtest.h" #include @@ -129,5 +131,130 @@ TEST(BasicBlockTest, TestInstructionsWithoutDebug) { delete V; } +TEST(BasicBlockTest, ComesBefore) { + const char *ModuleString = R"(define i32 @f(i32 %x) { + %add = add i32 %x, 42 + ret i32 %add + })"; + LLVMContext Ctx; + SMDiagnostic Err; + auto M = parseAssemblyString(ModuleString, Err, Ctx); + ASSERT_TRUE(M.get()); + + Function *F = M->getFunction("f"); + BasicBlock &BB = F->front(); + BasicBlock::iterator I = BB.begin(); + Instruction *Add = &*I++; + Instruction *Ret = &*I++; + + // Intentionally duplicated to verify cached and uncached are the same. + EXPECT_FALSE(BB.isInstrOrderValid()); + EXPECT_FALSE(Add->comesBefore(Add)); + EXPECT_TRUE(BB.isInstrOrderValid()); + EXPECT_FALSE(Add->comesBefore(Add)); + BB.invalidateOrders(); + EXPECT_FALSE(BB.isInstrOrderValid()); + EXPECT_TRUE(Add->comesBefore(Ret)); + EXPECT_TRUE(BB.isInstrOrderValid()); + EXPECT_TRUE(Add->comesBefore(Ret)); + BB.invalidateOrders(); + EXPECT_FALSE(Ret->comesBefore(Add)); + EXPECT_FALSE(Ret->comesBefore(Add)); + BB.invalidateOrders(); + EXPECT_FALSE(Ret->comesBefore(Ret)); + EXPECT_FALSE(Ret->comesBefore(Ret)); +} + +class InstrOrderInvalidationTest : public ::testing::Test { +protected: + void SetUp() override { + M.reset(new Module("MyModule", Ctx)); + Nop = Intrinsic::getDeclaration(M.get(), Intrinsic::donothing); + FunctionType *FT = FunctionType::get(Type::getVoidTy(Ctx), {}, false); + Function *F = Function::Create(FT, Function::ExternalLinkage, "foo", *M); + BB = BasicBlock::Create(Ctx, "entry", F); + + IRBuilder<> Builder(BB); + I1 = Builder.CreateCall(Nop); + I2 = Builder.CreateCall(Nop); + I3 = Builder.CreateCall(Nop); + Ret = Builder.CreateRetVoid(); + } + + LLVMContext Ctx; + std::unique_ptr M; + Function *Nop = nullptr; + BasicBlock *BB = nullptr; + Instruction *I1 = nullptr; + Instruction *I2 = nullptr; + Instruction *I3 = nullptr; + Instruction *Ret = nullptr; +}; + +TEST_F(InstrOrderInvalidationTest, InsertInvalidation) { + EXPECT_FALSE(BB->isInstrOrderValid()); + EXPECT_TRUE(I1->comesBefore(I2)); + EXPECT_TRUE(BB->isInstrOrderValid()); + EXPECT_TRUE(I2->comesBefore(I3)); + EXPECT_TRUE(I3->comesBefore(Ret)); + EXPECT_TRUE(BB->isInstrOrderValid()); + + // Invalidate orders. + IRBuilder<> Builder(BB, I2->getIterator()); + Instruction *I1a = Builder.CreateCall(Nop); + EXPECT_FALSE(BB->isInstrOrderValid()); + EXPECT_TRUE(I1->comesBefore(I1a)); + EXPECT_TRUE(BB->isInstrOrderValid()); + EXPECT_TRUE(I1a->comesBefore(I2)); + EXPECT_TRUE(I2->comesBefore(I3)); + EXPECT_TRUE(I3->comesBefore(Ret)); + EXPECT_TRUE(BB->isInstrOrderValid()); +} + +TEST_F(InstrOrderInvalidationTest, SpliceInvalidation) { + EXPECT_TRUE(I1->comesBefore(I2)); + EXPECT_TRUE(I2->comesBefore(I3)); + EXPECT_TRUE(I3->comesBefore(Ret)); + EXPECT_TRUE(BB->isInstrOrderValid()); + + // Use Instruction::moveBefore, which uses splice. + I2->moveBefore(I1); + EXPECT_FALSE(BB->isInstrOrderValid()); + + EXPECT_TRUE(I2->comesBefore(I1)); + EXPECT_TRUE(I1->comesBefore(I3)); + EXPECT_TRUE(I3->comesBefore(Ret)); + EXPECT_TRUE(BB->isInstrOrderValid()); +} + +TEST_F(InstrOrderInvalidationTest, RemoveNoInvalidation) { + // Cache the instruction order. + EXPECT_FALSE(BB->isInstrOrderValid()); + EXPECT_TRUE(I1->comesBefore(I2)); + EXPECT_TRUE(BB->isInstrOrderValid()); + + // Removing does not invalidate instruction order. + I2->removeFromParent(); + I2->deleteValue(); + I2 = nullptr; + EXPECT_TRUE(BB->isInstrOrderValid()); + EXPECT_TRUE(I1->comesBefore(I3)); + EXPECT_EQ(std::next(I1->getIterator()), I3->getIterator()); +} + +TEST_F(InstrOrderInvalidationTest, EraseNoInvalidation) { + // Cache the instruction order. + EXPECT_FALSE(BB->isInstrOrderValid()); + EXPECT_TRUE(I1->comesBefore(I2)); + EXPECT_TRUE(BB->isInstrOrderValid()); + + // Removing does not invalidate instruction order. + I2->eraseFromParent(); + I2 = nullptr; + EXPECT_TRUE(BB->isInstrOrderValid()); + EXPECT_TRUE(I1->comesBefore(I3)); + EXPECT_EQ(std::next(I1->getIterator()), I3->getIterator()); +} + } // End anonymous namespace. } // End llvm namespace. diff --git a/llvm/utils/gn/secondary/llvm/lib/Analysis/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/Analysis/BUILD.gn index cbbe1499a560b..328d819fd1f05 100644 --- a/llvm/utils/gn/secondary/llvm/lib/Analysis/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/lib/Analysis/BUILD.gn @@ -84,7 +84,6 @@ static_library("Analysis") { "ObjCARCAnalysisUtils.cpp", "ObjCARCInstKind.cpp", "OptimizationRemarkEmitter.cpp", - "OrderedBasicBlock.cpp", "OrderedInstructions.cpp", "PHITransAddr.cpp", "PhiValues.cpp", diff --git a/llvm/utils/gn/secondary/llvm/unittests/Analysis/BUILD.gn b/llvm/utils/gn/secondary/llvm/unittests/Analysis/BUILD.gn index 1e4b1581722fa..76a055e989fc5 100644 --- a/llvm/utils/gn/secondary/llvm/unittests/Analysis/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/unittests/Analysis/BUILD.gn @@ -25,7 +25,6 @@ unittest("AnalysisTests") { "LoopInfoTest.cpp", "MemoryBuiltinsTest.cpp", "MemorySSATest.cpp", - "OrderedBasicBlockTest.cpp", "OrderedInstructionsTest.cpp", "PhiValuesTest.cpp", "ProfileSummaryInfoTest.cpp", From 9a4b0a0265514c2fef96bbfa43bc86dba4ec102b Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Tue, 18 Feb 2020 15:12:32 -0800 Subject: [PATCH 179/286] Fix NDEBUG build after instruction ordering --- llvm/include/llvm/IR/BasicBlock.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/include/llvm/IR/BasicBlock.h b/llvm/include/llvm/IR/BasicBlock.h index f347cc5ff818f..24bc740d32204 100644 --- a/llvm/include/llvm/IR/BasicBlock.h +++ b/llvm/include/llvm/IR/BasicBlock.h @@ -504,7 +504,7 @@ BasicBlock::iterator skipDebugIntrinsics(BasicBlock::iterator It); #ifdef NDEBUG /// In release builds, this is a no-op. For !NDEBUG builds, the checks are /// implemented in the .cpp file to avoid circular header deps. -inline void Instruction::validateInstrOrdering() const {} +inline void BasicBlock::validateInstrOrdering() const {} #endif } // end namespace llvm From 3bce03e453f404a608a2510e7462220fbe5107ff Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Fri, 13 Mar 2020 12:15:17 -0700 Subject: [PATCH 180/286] [ObjC][ARC] Don't remove autoreleaseRV/retainRV pairs if the call isn't a tail call This reapplies the patch in https://reviews.llvm.org/rG1f5b471b8bf4, which was reverted because it was causing crashes. https://bugs.chromium.org/p/chromium/issues/detail?id=1061289#c2 Check that HasSafePathToCall is true before checking the call is a tail call. Original commit message: Previosly ARC optimizer removed the autoreleaseRV/retainRV pair in the following code, which caused the object returned by @something to be placed in the autorelease pool because the call to @something isn't a tail call: ``` %call = call i8* @something(...) %2 = call i8* @objc_retainAutoreleasedReturnValue(i8* %call) %3 = call i8* @objc_autoreleaseReturnValue(i8* %2) ret i8* %3 ``` Fix the bug by checking whether @something is a tail call. rdar://problem/59275894 (cherry picked from commit c6f1713c46e61bbb8ece9ac5ac329d02e7f93228) --- llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp | 8 ++++ llvm/test/Transforms/ObjCARC/rv.ll | 42 ++++++++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp index 577a744f30626..9da202eba95e6 100644 --- a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp +++ b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp @@ -2344,6 +2344,14 @@ void ObjCARCOpt::OptimizeReturns(Function &F) { bool HasSafePathToCall = HasSafePathToPredecessorCall(Arg, Retain, DependingInstructions, Visited, PA); + + // Don't remove retainRV/autoreleaseRV pairs if the call isn't a tail call. + if (HasSafePathToCall && + GetBasicARCInstKind(Retain) == ARCInstKind::RetainRV && + GetBasicARCInstKind(Autorelease) == ARCInstKind::AutoreleaseRV && + !cast(*DependingInstructions.begin())->isTailCall()) + continue; + DependingInstructions.clear(); Visited.clear(); diff --git a/llvm/test/Transforms/ObjCARC/rv.ll b/llvm/test/Transforms/ObjCARC/rv.ll index 3d0d56ca0e536..0a1f4665afc6b 100644 --- a/llvm/test/Transforms/ObjCARC/rv.ll +++ b/llvm/test/Transforms/ObjCARC/rv.ll @@ -21,6 +21,8 @@ declare void @callee() declare void @callee_fnptr(void ()*) declare void @invokee() declare i8* @returner() +declare i8* @returner1(i8*) +declare i32 @__gxx_personality_v0(...) ; Test that retain+release elimination is suppressed when the ; retain is an objc_retainAutoreleasedReturnValue, since it's @@ -77,7 +79,7 @@ define void @test2() { ; CHECK-NEXT: ret i8* %call define i8* @test3() { entry: - %call = call i8* @returner() + %call = tail call i8* @returner() %0 = call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %call) nounwind %1 = call i8* @llvm.objc.autoreleaseReturnValue(i8* %0) nounwind ret i8* %1 @@ -387,6 +389,44 @@ bb3: ret i32* %retval } +; Don't eliminate the retainRV/autoreleaseRV pair if the call isn't a tail call. + +; CHECK-LABEL: define i8* @test28( +; CHECK: call i8* @returner() +; CHECK: call i8* @llvm.objc.retainAutoreleasedReturnValue( +; CHECK: call i8* @llvm.objc.autoreleaseReturnValue( +define i8* @test28() { +entry: + %call = call i8* @returner() + %0 = call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %call) nounwind + %1 = call i8* @llvm.objc.autoreleaseReturnValue(i8* %0) nounwind + ret i8* %1 +} + +; CHECK-LABEL: define i8* @test29( +; CHECK: call i8* @llvm.objc.retainAutoreleasedReturnValue( +; CHECK: call i8* @llvm.objc.autoreleaseReturnValue( + +define i8* @test29(i8* %k) local_unnamed_addr personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +entry: + %0 = tail call i8* @llvm.objc.retain(i8* %k) + %call = invoke i8* @returner1(i8* %k) + to label %invoke.cont unwind label %lpad + +invoke.cont: + %1 = bitcast i8* %call to i8* + %2 = notail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %1) + tail call void @llvm.objc.release(i8* %k), !clang.imprecise_release !0 + %3 = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %1) + ret i8* %call + +lpad: + %4 = landingpad { i8*, i32 } + cleanup + tail call void @llvm.objc.release(i8* %k) #1, !clang.imprecise_release !0 + resume { i8*, i32 } %4 +} + !0 = !{} ; CHECK: attributes [[NUW]] = { nounwind } From 1989778e64dc00b29244e3555ee846ea4386a6ae Mon Sep 17 00:00:00 2001 From: Davide Italiano Date: Tue, 7 Apr 2020 16:27:29 -0700 Subject: [PATCH 181/286] [ManualDWARFIndex] Remove dead code, in preparation for moving this function. --- .../SymbolFile/DWARF/ManualDWARFIndex.cpp | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp index e8a095cffb291..d30b2bfbd433d 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp @@ -170,12 +170,6 @@ void ManualDWARFIndex::IndexUnitImpl(DWARFUnit &unit, is_declaration = form_value.Unsigned() != 0; break; - // case DW_AT_artificial: - // if (attributes.ExtractFormValueAtIndex(i, - // form_value)) - // is_artificial = form_value.Unsigned() != 0; - // break; - case DW_AT_MIPS_linkage_name: case DW_AT_linkage_name: if (attributes.ExtractFormValueAtIndex(i, form_value)) @@ -208,20 +202,6 @@ void ManualDWARFIndex::IndexUnitImpl(DWARFUnit &unit, // location describes a hard coded address, but we don't want // the performance penalty of that right now. is_global_or_static_variable = false; - // if (attributes.ExtractFormValueAtIndex(dwarf, i, - // form_value)) { - // // If we have valid block data, then we have location - // // expression bytesthat are fixed (not a location list). - // const uint8_t *block_data = form_value.BlockData(); - // if (block_data) { - // uint32_t block_length = form_value.Unsigned(); - // if (block_length == 1 + - // attributes.UnitAtIndex(i)->GetAddressByteSize()) { - // if (block_data[0] == DW_OP_addr) - // add_die = true; - // } - // } - // } parent_die = nullptr; // Terminate the while loop. break; From 9a42d97705758aae0cb5d51791af672027874047 Mon Sep 17 00:00:00 2001 From: Davide Italiano Date: Wed, 8 Apr 2020 11:06:00 -0700 Subject: [PATCH 182/286] [DWARF] Not all the constant variables are "static". Fixes rdar://problem/61402307 Differential Revision: https://reviews.llvm.org/D77698 --- .../SymbolFile/DWARF/DWARFDebugInfoEntry.cpp | 23 ++ .../SymbolFile/DWARF/DWARFDebugInfoEntry.h | 2 + .../SymbolFile/DWARF/ManualDWARFIndex.cpp | 31 +- .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 2 +- .../Shell/SymbolFile/DWARF/static_scope.s | 312 ++++++++++++++++++ 5 files changed, 340 insertions(+), 30 deletions(-) create mode 100644 lldb/test/Shell/SymbolFile/DWARF/static_scope.s diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp index 5612c59059bed..9c8ea07ee73e8 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp @@ -1230,6 +1230,29 @@ DWARFDebugInfoEntry::GetAbbreviationDeclarationPtr(const DWARFUnit *cu) const { return nullptr; } +bool DWARFDebugInfoEntry::IsGlobalOrStaticVariable() const { + if (Tag() != DW_TAG_variable) + return false; + const DWARFDebugInfoEntry *parent_die = GetParent(); + while (parent_die != nullptr) { + switch (parent_die->Tag()) { + case DW_TAG_subprogram: + case DW_TAG_lexical_block: + case DW_TAG_inlined_subroutine: + return false; + + case DW_TAG_compile_unit: + case DW_TAG_partial_unit: + return true; + + default: + break; + } + parent_die = parent_die->GetParent(); + } + return false; +} + bool DWARFDebugInfoEntry::operator==(const DWARFDebugInfoEntry &rhs) const { return m_offset == rhs.m_offset && m_parent_idx == rhs.m_parent_idx && m_sibling_idx == rhs.m_sibling_idx && diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h index f35af6e7d498a..666d7070f4fe9 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h @@ -172,6 +172,8 @@ class DWARFDebugInfoEntry { void SetSiblingIndex(uint32_t idx) { m_sibling_idx = idx; } void SetParentIndex(uint32_t idx) { m_parent_idx = idx; } + bool IsGlobalOrStaticVariable() const; + protected: dw_offset_t m_offset; // Offset within the .debug_info/.debug_types uint32_t m_parent_idx; // How many to subtract from "this" to get the parent. diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp index d30b2bfbd433d..cd706b2f16b3b 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp @@ -189,35 +189,8 @@ void ManualDWARFIndex::IndexUnitImpl(DWARFUnit &unit, case DW_AT_location: case DW_AT_const_value: has_location_or_const_value = true; - if (tag == DW_TAG_variable) { - const DWARFDebugInfoEntry *parent_die = die.GetParent(); - while (parent_die != nullptr) { - switch (parent_die->Tag()) { - case DW_TAG_subprogram: - case DW_TAG_lexical_block: - case DW_TAG_inlined_subroutine: - // Even if this is a function level static, we don't add it. We - // could theoretically add these if we wanted to by - // introspecting into the DW_AT_location and seeing if the - // location describes a hard coded address, but we don't want - // the performance penalty of that right now. - is_global_or_static_variable = false; - parent_die = nullptr; // Terminate the while loop. - break; - - case DW_TAG_compile_unit: - case DW_TAG_partial_unit: - is_global_or_static_variable = true; - parent_die = nullptr; // Terminate the while loop. - break; - - default: - parent_die = - parent_die->GetParent(); // Keep going in the while loop. - break; - } - } - } + is_global_or_static_variable = die.IsGlobalOrStaticVariable(); + break; case DW_AT_specification: diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 1573954ae5b8d..6a60033fe2490 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -3620,7 +3620,7 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, } } } else { - if (location_is_const_value_data && + if (location_is_const_value_data && die.GetDIE()->IsGlobalOrStaticVariable() !IsSwiftLanguage(sc.comp_unit->GetLanguage())) scope = eValueTypeVariableStatic; else { diff --git a/lldb/test/Shell/SymbolFile/DWARF/static_scope.s b/lldb/test/Shell/SymbolFile/DWARF/static_scope.s new file mode 100644 index 0000000000000..17b2485798494 --- /dev/null +++ b/lldb/test/Shell/SymbolFile/DWARF/static_scope.s @@ -0,0 +1,312 @@ +# Test that the DWARF parser assigns the right scope to the +# variable `b`, which is `local` and not `static`. + +# REQUIRES: x86 +# UNSUPPORTED: lldb-repro + +# RUN: llvm-mc -triple=x86_64-apple-macosx10.15.0 -filetype=obj %s > %t.o +# RUN: lldb-test symbols %t.o | FileCheck %s + +# CHECK: Variable{{.*}}, name = "b", type = {{.*}} (int), scope = local + + .section __TEXT,__text,regular,pure_instructions + .macosx_version_min 10, 15 + .file 1 "/Users/davide/work/build/bin" "a.c" + .globl _main ## -- Begin function main + .p2align 4, 0x90 +_main: ## @main +Lfunc_begin0: + .loc 1 2 0 ## a.c:2:0 + .cfi_startproc +## %bb.0: + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp +Ltmp0: + ##DEBUG_VALUE: b <- 3 + .loc 1 5 9 prologue_end ## a.c:5:9 + movl _a(%rip), %eax +Ltmp1: + .loc 1 7 5 ## a.c:7:5 + xorl %eax, %eax + popq %rbp + retq +Ltmp2: +Lfunc_end0: + .cfi_endproc + ## -- End function + .globl _a ## @a +.zerofill __DATA,__common,_a,4,2 + .section __DWARF,__debug_abbrev,regular,debug +Lsection_abbrev: + .byte 1 ## Abbreviation Code + .byte 17 ## DW_TAG_compile_unit + .byte 1 ## DW_CHILDREN_yes + .byte 37 ## DW_AT_producer + .byte 14 ## DW_FORM_strp + .byte 19 ## DW_AT_language + .byte 5 ## DW_FORM_data2 + .byte 3 ## DW_AT_name + .byte 14 ## DW_FORM_strp + .ascii "\202|" ## DW_AT_LLVM_sysroot + .byte 14 ## DW_FORM_strp + .byte 16 ## DW_AT_stmt_list + .byte 23 ## DW_FORM_sec_offset + .byte 27 ## DW_AT_comp_dir + .byte 14 ## DW_FORM_strp + .ascii "\341\177" ## DW_AT_APPLE_optimized + .byte 25 ## DW_FORM_flag_present + .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 14 ## DW_FORM_strp + .byte 73 ## DW_AT_type + .byte 19 ## DW_FORM_ref4 + .byte 63 ## DW_AT_external + .byte 25 ## DW_FORM_flag_present + .byte 58 ## DW_AT_decl_file + .byte 11 ## DW_FORM_data1 + .byte 59 ## DW_AT_decl_line + .byte 11 ## DW_FORM_data1 + .byte 2 ## DW_AT_location + .byte 24 ## DW_FORM_exprloc + .byte 0 ## EOM(1) + .byte 0 ## EOM(2) + .byte 3 ## Abbreviation Code + .byte 53 ## DW_TAG_volatile_type + .byte 0 ## DW_CHILDREN_no + .byte 73 ## DW_AT_type + .byte 19 ## DW_FORM_ref4 + .byte 0 ## EOM(1) + .byte 0 ## EOM(2) + .byte 4 ## Abbreviation Code + .byte 36 ## DW_TAG_base_type + .byte 0 ## DW_CHILDREN_no + .byte 3 ## DW_AT_name + .byte 14 ## DW_FORM_strp + .byte 62 ## DW_AT_encoding + .byte 11 ## DW_FORM_data1 + .byte 11 ## DW_AT_byte_size + .byte 11 ## DW_FORM_data1 + .byte 0 ## EOM(1) + .byte 0 ## EOM(2) + .byte 5 ## Abbreviation Code + .byte 46 ## DW_TAG_subprogram + .byte 1 ## DW_CHILDREN_yes + .byte 17 ## DW_AT_low_pc + .byte 1 ## DW_FORM_addr + .byte 18 ## DW_AT_high_pc + .byte 6 ## DW_FORM_data4 + .byte 64 ## DW_AT_frame_base + .byte 24 ## DW_FORM_exprloc + .byte 122 ## DW_AT_call_all_calls + .byte 25 ## DW_FORM_flag_present + .byte 3 ## DW_AT_name + .byte 14 ## DW_FORM_strp + .byte 58 ## DW_AT_decl_file + .byte 11 ## DW_FORM_data1 + .byte 59 ## DW_AT_decl_line + .byte 11 ## DW_FORM_data1 + .byte 73 ## DW_AT_type + .byte 19 ## DW_FORM_ref4 + .byte 63 ## DW_AT_external + .byte 25 ## DW_FORM_flag_present + .ascii "\341\177" ## DW_AT_APPLE_optimized + .byte 25 ## DW_FORM_flag_present + .byte 0 ## EOM(1) + .byte 0 ## EOM(2) + .byte 6 ## Abbreviation Code + .byte 11 ## DW_TAG_lexical_block + .byte 1 ## DW_CHILDREN_yes + .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 7 ## Abbreviation Code + .byte 52 ## DW_TAG_variable + .byte 0 ## DW_CHILDREN_no + .byte 28 ## DW_AT_const_value + .byte 13 ## DW_FORM_sdata + .byte 3 ## DW_AT_name + .byte 14 ## DW_FORM_strp + .byte 58 ## DW_AT_decl_file + .byte 11 ## DW_FORM_data1 + .byte 59 ## DW_AT_decl_line + .byte 11 ## DW_FORM_data1 + .byte 73 ## DW_AT_type + .byte 19 ## DW_FORM_ref4 + .byte 0 ## EOM(1) + .byte 0 ## EOM(2) + .byte 0 ## EOM(3) + .section __DWARF,__debug_info,regular,debug +Lsection_info: +Lcu_begin0: +.set Lset0, Ldebug_info_end0-Ldebug_info_start0 ## Length of Unit + .long Lset0 +Ldebug_info_start0: + .short 4 ## DWARF version number +.set Lset1, Lsection_abbrev-Lsection_abbrev ## Offset Into Abbrev. Section + .long Lset1 + .byte 8 ## Address Size (in bytes) + .byte 1 ## Abbrev [1] 0xb:0x79 DW_TAG_compile_unit + .long 0 ## DW_AT_producer + .short 12 ## DW_AT_language + .long 101 ## DW_AT_name + .long 105 ## DW_AT_LLVM_sysroot +.set Lset2, Lline_table_start0-Lsection_line ## DW_AT_stmt_list + .long Lset2 + .long 107 ## DW_AT_comp_dir + ## DW_AT_APPLE_optimized + .quad Lfunc_begin0 ## DW_AT_low_pc +.set Lset3, Lfunc_end0-Lfunc_begin0 ## DW_AT_high_pc + .long Lset3 + .byte 2 ## Abbrev [2] 0x2e:0x15 DW_TAG_variable + .long 136 ## DW_AT_name + .long 67 ## DW_AT_type + ## DW_AT_external + .byte 1 ## DW_AT_decl_file + .byte 1 ## DW_AT_decl_line + .byte 9 ## DW_AT_location + .byte 3 + .quad _a + .byte 3 ## Abbrev [3] 0x43:0x5 DW_TAG_volatile_type + .long 72 ## DW_AT_type + .byte 4 ## Abbrev [4] 0x48:0x7 DW_TAG_base_type + .long 138 ## DW_AT_name + .byte 5 ## DW_AT_encoding + .byte 4 ## DW_AT_byte_size + .byte 5 ## Abbrev [5] 0x4f:0x34 DW_TAG_subprogram + .quad Lfunc_begin0 ## DW_AT_low_pc +.set Lset4, Lfunc_end0-Lfunc_begin0 ## DW_AT_high_pc + .long Lset4 + .byte 1 ## DW_AT_frame_base + .byte 86 + ## DW_AT_call_all_calls + .long 142 ## DW_AT_name + .byte 1 ## DW_AT_decl_file + .byte 2 ## DW_AT_decl_line + .long 72 ## DW_AT_type + ## DW_AT_external + ## DW_AT_APPLE_optimized + .byte 6 ## Abbrev [6] 0x68:0x1a DW_TAG_lexical_block + .quad Ltmp0 ## DW_AT_low_pc +.set Lset5, Ltmp1-Ltmp0 ## DW_AT_high_pc + .long Lset5 + .byte 7 ## Abbrev [7] 0x75:0xc DW_TAG_variable + .byte 3 ## DW_AT_const_value + .long 147 ## DW_AT_name + .byte 1 ## DW_AT_decl_file + .byte 4 ## DW_AT_decl_line + .long 72 ## DW_AT_type + .byte 0 ## End Of Children Mark + .byte 0 ## End Of Children Mark + .byte 0 ## End Of Children Mark +Ldebug_info_end0: + .section __DWARF,__debug_str,regular,debug +Linfo_string: + .asciz "clang version 11.0.0 (https://github.com/llvm/llvm-project f30ebf437851d3c68fd0eee82afbc0cef7373c00)" ## string offset=0 + .asciz "a.c" ## string offset=101 + .asciz "/" ## string offset=105 + .asciz "/Users/davide/work/build/bin" ## string offset=107 + .asciz "a" ## string offset=136 + .asciz "int" ## string offset=138 + .asciz "main" ## string offset=142 + .asciz "b" ## string offset=147 + .section __DWARF,__apple_names,regular,debug +Lnames_begin: + .long 1212240712 ## Header Magic + .short 1 ## Header Version + .short 0 ## Header Hash Function + .long 2 ## Header Bucket Count + .long 2 ## Header Hash Count + .long 12 ## Header Data Length + .long 0 ## HeaderData Die Offset Base + .long 1 ## HeaderData Atom Count + .short 1 ## DW_ATOM_die_offset + .short 6 ## DW_FORM_data4 + .long 0 ## Bucket 0 + .long -1 ## Bucket 1 + .long 177670 ## Hash in Bucket 0 + .long 2090499946 ## Hash in Bucket 0 +.set Lset6, LNames0-Lnames_begin ## Offset in Bucket 0 + .long Lset6 +.set Lset7, LNames1-Lnames_begin ## Offset in Bucket 0 + .long Lset7 +LNames0: + .long 136 ## a + .long 1 ## Num DIEs + .long 46 + .long 0 +LNames1: + .long 142 ## main + .long 1 ## Num DIEs + .long 79 + .long 0 + .section __DWARF,__apple_objc,regular,debug +Lobjc_begin: + .long 1212240712 ## Header Magic + .short 1 ## Header Version + .short 0 ## Header Hash Function + .long 1 ## Header Bucket Count + .long 0 ## Header Hash Count + .long 12 ## Header Data Length + .long 0 ## HeaderData Die Offset Base + .long 1 ## HeaderData Atom Count + .short 1 ## DW_ATOM_die_offset + .short 6 ## DW_FORM_data4 + .long -1 ## Bucket 0 + .section __DWARF,__apple_namespac,regular,debug +Lnamespac_begin: + .long 1212240712 ## Header Magic + .short 1 ## Header Version + .short 0 ## Header Hash Function + .long 1 ## Header Bucket Count + .long 0 ## Header Hash Count + .long 12 ## Header Data Length + .long 0 ## HeaderData Die Offset Base + .long 1 ## HeaderData Atom Count + .short 1 ## DW_ATOM_die_offset + .short 6 ## DW_FORM_data4 + .long -1 ## Bucket 0 + .section __DWARF,__apple_types,regular,debug +Ltypes_begin: + .long 1212240712 ## Header Magic + .short 1 ## Header Version + .short 0 ## Header Hash Function + .long 1 ## Header Bucket Count + .long 1 ## Header Hash Count + .long 20 ## Header Data Length + .long 0 ## HeaderData Die Offset Base + .long 3 ## HeaderData Atom Count + .short 1 ## DW_ATOM_die_offset + .short 6 ## DW_FORM_data4 + .short 3 ## DW_ATOM_die_tag + .short 5 ## DW_FORM_data2 + .short 4 ## DW_ATOM_type_flags + .short 11 ## DW_FORM_data1 + .long 0 ## Bucket 0 + .long 193495088 ## Hash in Bucket 0 +.set Lset8, Ltypes0-Ltypes_begin ## Offset in Bucket 0 + .long Lset8 +Ltypes0: + .long 138 ## int + .long 1 ## Num DIEs + .long 72 + .short 36 + .byte 0 + .long 0 +.subsections_via_symbols + .section __DWARF,__debug_line,regular,debug +Lsection_line: +Lline_table_start0: From df1541a9e104134b5acd9bd187589d0c33555f97 Mon Sep 17 00:00:00 2001 From: Davide Italiano Date: Thu, 9 Apr 2020 13:43:22 -0700 Subject: [PATCH 183/286] [SymbolFileDWARF] Remove a swift-specific hack that was working around a bug. --- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 6a60033fe2490..43b785dc9cbff 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -3620,8 +3620,7 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, } } } else { - if (location_is_const_value_data && die.GetDIE()->IsGlobalOrStaticVariable() - !IsSwiftLanguage(sc.comp_unit->GetLanguage())) + if (location_is_const_value_data && die.GetDIE()->IsGlobalOrStaticVariable()) scope = eValueTypeVariableStatic; else { scope = eValueTypeVariableLocal; From 22f43f1fb47bafb043851c61730aa43da2b21044 Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Tue, 10 Mar 2020 14:06:25 -0700 Subject: [PATCH 184/286] [CodeGen] Emit destructor calls to destruct compound literals Fix a bug in IRGen where it wasn't destructing compound literals in C that are ObjC pointer arrays or non-trivial structs. Also diagnose jumps that enter or exit the lifetime of the compound literals. rdar://problem/51867864 Differential Revision: https://reviews.llvm.org/D64464 (cherry picked from commit 40568fec7e3eb51554cbdaf63a8044830be93fa4) Conflicts: clang/test/CodeGenObjC/strong-in-c-struct.m --- clang/include/clang/AST/ASTImporter.h | 5 + clang/include/clang/AST/ExprCXX.h | 12 ++- clang/include/clang/AST/TextNodeDumper.h | 1 + .../clang/Basic/DiagnosticSemaKinds.td | 4 + clang/include/clang/Sema/Sema.h | 5 +- .../include/clang/Serialization/ASTBitCodes.h | 3 + clang/lib/AST/ASTImporter.cpp | 12 +++ clang/lib/AST/JSONNodeDumper.cpp | 11 +- clang/lib/AST/TextNodeDumper.cpp | 19 +++- clang/lib/CodeGen/CGBlocks.cpp | 6 +- clang/lib/CodeGen/CGExpr.cpp | 8 ++ clang/lib/CodeGen/CGExprAgg.cpp | 14 +++ clang/lib/CodeGen/CGExprScalar.cpp | 5 + clang/lib/Sema/JumpDiagnostics.cpp | 25 ++++- clang/lib/Sema/SemaExpr.cpp | 18 +++- clang/lib/Serialization/ASTReaderStmt.cpp | 14 ++- clang/lib/Serialization/ASTWriterStmt.cpp | 11 +- clang/test/AST/ast-dump-objc-arc-json.m | 36 +++++++ clang/test/AST/ast-dump-stmt.m | 15 ++- clang/test/CodeGenObjC/arc-ternary-op.m | 56 ++++++++++ clang/test/CodeGenObjC/arc.m | 37 +++++++ clang/test/CodeGenObjC/strong-in-c-struct.m | 100 ++++++++++++++++++ .../Import/objc-arc/Inputs/cleanup-objects.m | 10 ++ .../Import/objc-arc/test-cleanup-object.m | 10 ++ .../test/PCH/non-trivial-c-compound-literal.m | 29 +++++ clang/test/SemaObjC/strong-in-c-struct.m | 18 ++++ .../clang-import-test/clang-import-test.cpp | 5 + 27 files changed, 461 insertions(+), 28 deletions(-) create mode 100644 clang/test/AST/ast-dump-objc-arc-json.m create mode 100644 clang/test/Import/objc-arc/Inputs/cleanup-objects.m create mode 100644 clang/test/Import/objc-arc/test-cleanup-object.m create mode 100644 clang/test/PCH/non-trivial-c-compound-literal.m diff --git a/clang/include/clang/AST/ASTImporter.h b/clang/include/clang/AST/ASTImporter.h index 490b34bf95e82..205d7ec67754f 100644 --- a/clang/include/clang/AST/ASTImporter.h +++ b/clang/include/clang/AST/ASTImporter.h @@ -16,6 +16,7 @@ #include "clang/AST/DeclBase.h" #include "clang/AST/DeclarationName.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" @@ -349,6 +350,10 @@ class TypeSourceInfo; return ToOrErr.takeError(); } + /// Import cleanup objects owned by ExprWithCleanup. + llvm::Expected + Import(ExprWithCleanups::CleanupObject From); + /// Import the given type from the "from" context into the "to" /// context. A null type is imported as a null type (no error). /// diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index 1a16aa7aacec6..d16bd27edc23e 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -3306,13 +3306,15 @@ class DependentScopeDeclRefExpr final /// literal is the extent of the enclosing scope. class ExprWithCleanups final : public FullExpr, - private llvm::TrailingObjects { + private llvm::TrailingObjects< + ExprWithCleanups, + llvm::PointerUnion> { public: /// The type of objects that are kept in the cleanup. - /// It's useful to remember the set of blocks; we could also - /// remember the set of temporaries, but there's currently - /// no need. - using CleanupObject = BlockDecl *; + /// It's useful to remember the set of blocks and block-scoped compound + /// literals; we could also remember the set of temporaries, but there's + /// currently no need. + using CleanupObject = llvm::PointerUnion; private: friend class ASTStmtReader; diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h index d293ea190aa43..c675beef63553 100644 --- a/clang/include/clang/AST/TextNodeDumper.h +++ b/clang/include/clang/AST/TextNodeDumper.h @@ -184,6 +184,7 @@ class TextNodeDumper void dumpBareDeclRef(const Decl *D); void dumpName(const NamedDecl *ND); void dumpAccessSpecifier(AccessSpecifier AS); + void dumpCleanupObject(const ExprWithCleanups::CleanupObject &C); void dumpDeclRef(const Decl *D, StringRef Label = {}); diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 5b9f764443fe2..c849b224c01b2 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -5509,6 +5509,8 @@ def note_enters_block_captures_weak : Note< def note_enters_block_captures_non_trivial_c_struct : Note< "jump enters lifetime of block which captures a C struct that is non-trivial " "to destroy">; +def note_enters_compound_literal_scope : Note< + "jump enters lifetime of a compound literal that is non-trivial to destruct">; def note_exits_cleanup : Note< "jump exits scope of variable with __attribute__((cleanup))">; @@ -5552,6 +5554,8 @@ def note_exits_block_captures_weak : Note< def note_exits_block_captures_non_trivial_c_struct : Note< "jump exits lifetime of block which captures a C struct that is non-trivial " "to destroy">; +def note_exits_compound_literal_scope : Note< + "jump exits lifetime of a compound literal that is non-trivial to destruct">; def err_func_returning_qualified_void : ExtWarn< "function cannot return qualified void type %0">, diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index a260aec2a536b..64c467acce8c2 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -603,9 +603,8 @@ class Sema final { CleanupInfo Cleanup; /// ExprCleanupObjects - This is the stack of objects requiring - /// cleanup that are created by the current full expression. The - /// element type here is ExprWithCleanups::Object. - SmallVector ExprCleanupObjects; + /// cleanup that are created by the current full expression. + SmallVector ExprCleanupObjects; /// Store a set of either DeclRefExprs or MemberExprs that contain a reference /// to a variable (constant) that may or may not be odr-used in this Expr, and diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index f748f04298a9b..e2e057714742d 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1876,6 +1876,9 @@ namespace serialization { CTOR_INITIALIZER_INDIRECT_MEMBER }; + /// Kinds of cleanup objects owned by ExprWithCleanups. + enum CleanupObjectKind { COK_Block, COK_CompoundLiteral }; + /// Describes the redeclarations of a declaration. struct LocalRedeclarationsInfo { // The ID of the first declaration diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index f1d97c96916e6..b6cc8e0592198 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -8045,6 +8045,18 @@ void ASTImporter::RegisterImportedDecl(Decl *FromD, Decl *ToD) { MapImported(FromD, ToD); } +llvm::Expected +ASTImporter::Import(ExprWithCleanups::CleanupObject From) { + if (auto *CLE = From.dyn_cast()) { + if (Expected R = Import(CLE)) + return ExprWithCleanups::CleanupObject(cast(*R)); + } + + // FIXME: Handle BlockDecl when we implement importing BlockExpr in + // ASTNodeImporter. + return make_error(ImportError::UnsupportedConstruct); +} + Expected ASTImporter::Import(QualType FromT) { if (FromT.isNull()) return QualType{}; diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp index fa5fe0bcbc0ba..569ac14c8f90a 100644 --- a/clang/lib/AST/JSONNodeDumper.cpp +++ b/clang/lib/AST/JSONNodeDumper.cpp @@ -1335,7 +1335,16 @@ void JSONNodeDumper::VisitExprWithCleanups(const ExprWithCleanups *EWC) { if (EWC->getNumObjects()) { JOS.attributeArray("cleanups", [this, EWC] { for (const ExprWithCleanups::CleanupObject &CO : EWC->getObjects()) - JOS.value(createBareDeclRef(CO)); + if (auto *BD = CO.dyn_cast()) { + JOS.value(createBareDeclRef(BD)); + } else if (auto *CLE = CO.dyn_cast()) { + llvm::json::Object Obj; + Obj["id"] = createPointerRepresentation(CLE); + Obj["kind"] = CLE->getStmtClassName(); + JOS.value(std::move(Obj)); + } else { + llvm_unreachable("unexpected cleanup object type"); + } }); } } diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 5ad8fd77d5eb0..86ae7eedfed68 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -447,6 +447,23 @@ void TextNodeDumper::dumpAccessSpecifier(AccessSpecifier AS) { } } +void TextNodeDumper::dumpCleanupObject( + const ExprWithCleanups::CleanupObject &C) { + if (auto *BD = C.dyn_cast()) + dumpDeclRef(BD, "cleanup"); + else if (auto *CLE = C.dyn_cast()) + AddChild([=] { + OS << "cleanup "; + { + ColorScope Color(OS, ShowColors, StmtColor); + OS << CLE->getStmtClassName(); + } + dumpPointer(CLE); + }); + else + llvm_unreachable("unexpected cleanup type"); +} + void TextNodeDumper::dumpDeclRef(const Decl *D, StringRef Label) { if (!D) return; @@ -952,7 +969,7 @@ void TextNodeDumper::VisitMaterializeTemporaryExpr( void TextNodeDumper::VisitExprWithCleanups(const ExprWithCleanups *Node) { for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i) - dumpDeclRef(Node->getObject(i), "cleanup"); + dumpCleanupObject(Node->getObject(i)); } void TextNodeDumper::VisitSizeOfPackExpr(const SizeOfPackExpr *Node) { diff --git a/clang/lib/CodeGen/CGBlocks.cpp b/clang/lib/CodeGen/CGBlocks.cpp index 8a1d67b466ceb..ca6ff0a80a7d6 100644 --- a/clang/lib/CodeGen/CGBlocks.cpp +++ b/clang/lib/CodeGen/CGBlocks.cpp @@ -868,13 +868,13 @@ static void enterBlockScope(CodeGenFunction &CGF, BlockDecl *block) { } /// Enter a full-expression with a non-trivial number of objects to -/// clean up. This is in this file because, at the moment, the only -/// kind of cleanup object is a BlockDecl*. +/// clean up. void CodeGenFunction::enterNonTrivialFullExpression(const FullExpr *E) { if (const auto EWC = dyn_cast(E)) { assert(EWC->getNumObjects() != 0); for (const ExprWithCleanups::CleanupObject &C : EWC->getObjects()) - enterBlockScope(*this, C); + if (auto *BD = C.dyn_cast()) + enterBlockScope(*this, BD); } } diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 575df186e2cd2..3914cd23ce573 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -4280,6 +4280,14 @@ LValue CodeGenFunction::EmitCompoundLiteralLValue(const CompoundLiteralExpr *E){ EmitAnyExprToMem(InitExpr, DeclPtr, E->getType().getQualifiers(), /*Init*/ true); + // Block-scope compound literals are destroyed at the end of the enclosing + // scope in C. + if (!getLangOpts().CPlusPlus) + if (QualType::DestructionKind DtorKind = E->getType().isDestructedType()) + pushLifetimeExtendedDestroy(getCleanupKind(DtorKind), DeclPtr, + E->getType(), getDestroyer(DtorKind), + DtorKind & EHCleanup); + return Result; } diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index 8de609a2ccd98..9881d28fe25ce 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -659,7 +659,21 @@ AggExprEmitter::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { } AggValueSlot Slot = EnsureSlot(E->getType()); + + // Block-scope compound literals are destroyed at the end of the enclosing + // scope in C. + bool Destruct = + !CGF.getLangOpts().CPlusPlus && !Slot.isExternallyDestructed(); + if (Destruct) + Slot.setExternallyDestructed(); + CGF.EmitAggExpr(E->getInitializer(), Slot); + + if (Destruct) + if (QualType::DestructionKind DtorKind = E->getType().isDestructedType()) + CGF.pushLifetimeExtendedDestroy( + CGF.getCleanupKind(DtorKind), Slot.getAddress(), E->getType(), + CGF.getDestroyer(DtorKind), DtorKind & EHCleanup); } /// Attempt to look through various unimportant expressions to find a diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 82618367ed003..e427847ddb4a0 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -556,6 +556,11 @@ class ScalarExprEmitter Value *VisitMemberExpr(MemberExpr *E); Value *VisitExtVectorElementExpr(Expr *E) { return EmitLoadOfLValue(E); } Value *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { + // Strictly speaking, we shouldn't be calling EmitLoadOfLValue, which + // transitively calls EmitCompoundLiteralLValue, here in C++ since compound + // literals aren't l-values in C++. We do so simply because that's the + // cleanest way to handle compound literals in C++. + // See the discussion here: https://reviews.llvm.org/D64464 return EmitLoadOfLValue(E); } diff --git a/clang/lib/Sema/JumpDiagnostics.cpp b/clang/lib/Sema/JumpDiagnostics.cpp index 960e62d4a2db8..b34243edea35e 100644 --- a/clang/lib/Sema/JumpDiagnostics.cpp +++ b/clang/lib/Sema/JumpDiagnostics.cpp @@ -75,6 +75,7 @@ class JumpScopeChecker { void BuildScopeInformation(Decl *D, unsigned &ParentScope); void BuildScopeInformation(VarDecl *D, const BlockDecl *BDecl, unsigned &ParentScope); + void BuildScopeInformation(CompoundLiteralExpr *CLE, unsigned &ParentScope); void BuildScopeInformation(Stmt *S, unsigned &origParentScope); void VerifyJumps(); @@ -276,6 +277,16 @@ void JumpScopeChecker::BuildScopeInformation(VarDecl *D, } } +/// Build scope information for compound literals of C struct types that are +/// non-trivial to destruct. +void JumpScopeChecker::BuildScopeInformation(CompoundLiteralExpr *CLE, + unsigned &ParentScope) { + unsigned InDiag = diag::note_enters_compound_literal_scope; + unsigned OutDiag = diag::note_exits_compound_literal_scope; + Scopes.push_back(GotoScope(ParentScope, InDiag, OutDiag, CLE->getExprLoc())); + ParentScope = Scopes.size() - 1; +} + /// BuildScopeInformation - The statements from CI to CE are known to form a /// coherent VLA scope with a specified parent node. Walk through the /// statements, adding any labels or gotos to LabelAndGotoScopes and recursively @@ -529,11 +540,15 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, // implementable but a lot of work which we haven't felt up to doing. ExprWithCleanups *EWC = cast(S); for (unsigned i = 0, e = EWC->getNumObjects(); i != e; ++i) { - const BlockDecl *BDecl = EWC->getObject(i); - for (const auto &CI : BDecl->captures()) { - VarDecl *variable = CI.getVariable(); - BuildScopeInformation(variable, BDecl, origParentScope); - } + if (auto *BDecl = EWC->getObject(i).dyn_cast()) + for (const auto &CI : BDecl->captures()) { + VarDecl *variable = CI.getVariable(); + BuildScopeInformation(variable, BDecl, origParentScope); + } + else if (auto *CLE = EWC->getObject(i).dyn_cast()) + BuildScopeInformation(CLE, origParentScope); + else + llvm_unreachable("unexpected cleanup object type"); } break; } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 68f3c6284068e..4d4d63cdf9233 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -6231,14 +6231,24 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, return ExprError(); } - // Compound literals that have automatic storage duration are destroyed at - // the end of the scope. Emit diagnostics if it is or contains a C union type - // that is non-trivial to destruct. - if (!isFileScope) + if (!isFileScope && !getLangOpts().CPlusPlus) { + // Compound literals that have automatic storage duration are destroyed at + // the end of the scope in C; in C++, they're just temporaries. + + // Emit diagnostics if it is or contains a C union type that is non-trivial + // to destruct. if (E->getType().hasNonTrivialToPrimitiveDestructCUnion()) checkNonTrivialCUnion(E->getType(), E->getExprLoc(), NTCUC_CompoundLiteral, NTCUK_Destruct); + // Diagnose jumps that enter or exit the lifetime of the compound literal. + if (literalType.isDestructedType()) { + Cleanup.setExprNeedsCleanups(true); + ExprCleanupObjects.push_back(E); + getCurFunction()->setHasBranchProtectedScope(); + } + } + if (E->getType().hasNonTrivialToPrimitiveDefaultInitializeCUnion() || E->getType().hasNonTrivialToPrimitiveCopyCUnion()) checkNonTrivialCUnionInInitializer(E->getInitializer(), diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 533502116ed76..8367472feee08 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -1689,9 +1689,17 @@ void ASTStmtReader::VisitExprWithCleanups(ExprWithCleanups *E) { unsigned NumObjects = Record.readInt(); assert(NumObjects == E->getNumObjects()); - for (unsigned i = 0; i != NumObjects; ++i) - E->getTrailingObjects()[i] = - readDeclAs(); + for (unsigned i = 0; i != NumObjects; ++i) { + unsigned CleanupKind = Record.readInt(); + ExprWithCleanups::CleanupObject Obj; + if (CleanupKind == COK_Block) + Obj = readDeclAs(); + else if (CleanupKind == COK_CompoundLiteral) + Obj = cast(Record.readSubExpr()); + else + llvm_unreachable("unexpected cleanup object type"); + E->getTrailingObjects()[i] = Obj; + } E->ExprWithCleanupsBits.CleanupsHaveSideEffects = Record.readInt(); E->SubExpr = Record.readSubExpr(); diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index e671c78fe97b8..f73108de92c79 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -1642,8 +1642,15 @@ void ASTStmtWriter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) { void ASTStmtWriter::VisitExprWithCleanups(ExprWithCleanups *E) { VisitExpr(E); Record.push_back(E->getNumObjects()); - for (unsigned i = 0, e = E->getNumObjects(); i != e; ++i) - Record.AddDeclRef(E->getObject(i)); + for (auto &Obj : E->getObjects()) { + if (auto *BD = Obj.dyn_cast()) { + Record.push_back(serialization::COK_Block); + Record.AddDeclRef(BD); + } else if (auto *CLE = Obj.dyn_cast()) { + Record.push_back(serialization::COK_CompoundLiteral); + Record.AddStmt(CLE); + } + } Record.push_back(E->cleanupsHaveSideEffects()); Record.AddStmt(E->getSubExpr()); diff --git a/clang/test/AST/ast-dump-objc-arc-json.m b/clang/test/AST/ast-dump-objc-arc-json.m new file mode 100644 index 0000000000000..bb9268b28ef65 --- /dev/null +++ b/clang/test/AST/ast-dump-objc-arc-json.m @@ -0,0 +1,36 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -x objective-c -fobjc-arc -ast-dump=json -ast-dump-filter Test %s | FileCheck %s + +typedef struct { + id f; +} S; + +id TestCompoundLiteral(id a) { + return ((S){ .f = a }).f; +} + +// CHECK: "kind": "ExprWithCleanups", +// CHECK-NEXT: "range": { +// CHECK-NEXT: "begin": { +// CHECK-NEXT: "offset": 202, +// CHECK-NEXT: "col": 10, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: }, +// CHECK-NEXT: "end": { +// CHECK-NEXT: "offset": 218, +// CHECK-NEXT: "col": 26, +// CHECK-NEXT: "tokLen": 1 +// CHECK-NEXT: } +// CHECK-NEXT: }, +// CHECK-NEXT: "type": { +// CHECK-NEXT: "desugaredQualType": "id", +// CHECK-NEXT: "qualType": "id", +// CHECK-NEXT: "typeAliasDeclId": "0x{{.*}}" +// CHECK-NEXT: }, +// CHECK-NEXT: "valueCategory": "rvalue", +// CHECK-NEXT: "cleanupsHaveSideEffects": true, +// CHECK-NEXT: "cleanups": [ +// CHECK-NEXT: { +// CHECK-NEXT: "id": "0x{{.*}}", +// CHECK-NEXT: "kind": "CompoundLiteralExpr" +// CHECK-NEXT: } +// CHECK-NEXT: ], diff --git a/clang/test/AST/ast-dump-stmt.m b/clang/test/AST/ast-dump-stmt.m index 8c0ca897e5114..9744e7a43c3e8 100644 --- a/clang/test/AST/ast-dump-stmt.m +++ b/clang/test/AST/ast-dump-stmt.m @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -Wno-unused -fblocks -fobjc-exceptions -ast-dump -ast-dump-filter Test %s | FileCheck -strict-whitespace %s +// RUN: %clang_cc1 -Wno-unused -fobjc-arc -fblocks -fobjc-exceptions -ast-dump -ast-dump-filter Test %s | FileCheck -strict-whitespace %s void TestBlockExpr(int x) { ^{ x; }; @@ -34,3 +34,16 @@ void TestObjCAtCatchStmt() { // CHECK-NEXT: ObjCAtCatchStmt{{.*}} catch all // CHECK-NEXT: CompoundStmt // CHECK-NEXT: ObjCAtFinallyStmt + +typedef struct { + id f; +} S; + +id TestCompoundLiteral(id a) { + return ((S){ .f = a }).f; +} + +// CHECK: FunctionDecl{{.*}}TestCompoundLiteral +// CHECK: ExprWithCleanups +// CHECK-NEXT: cleanup CompoundLiteralExpr +// CHECK: CompoundLiteralExpr{{.*}}'S':'S' lvalue diff --git a/clang/test/CodeGenObjC/arc-ternary-op.m b/clang/test/CodeGenObjC/arc-ternary-op.m index 4883143791a24..28567fcbe22e6 100644 --- a/clang/test/CodeGenObjC/arc-ternary-op.m +++ b/clang/test/CodeGenObjC/arc-ternary-op.m @@ -1,5 +1,7 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -O2 -disable-llvm-passes -o - %s | FileCheck %s +id g0, g1; + void test0(_Bool cond) { id test0_helper(void) __attribute__((ns_returns_retained)); @@ -147,4 +149,58 @@ void test2(int cond) { // CHECK: call void @llvm.objc.release(i8* [[RESULT]]) } +void test3(int cond) { + __strong id *p = cond ? (__strong id[]){g0, g1} : (__strong id[]){g1, g0}; + test2(cond); + + // CHECK: define void @test3( + // CHECK: %[[P:.*]] = alloca i8**, align 8 + // CHECK: %[[_COMPOUNDLITERAL:.*]] = alloca [2 x i8*], align 8 + // CHECK: %[[CLEANUP_COND:.*]] = alloca i1, align 1 + // CHECK: %[[_COMPOUNDLITERAL1:.*]] = alloca [2 x i8*], align 8 + // CHECK: %[[CLEANUP_COND4:.*]] = alloca i1, align 1 + + // CHECK: %[[ARRAYINIT_BEGIN:.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* %[[_COMPOUNDLITERAL]], i64 0, i64 0 + // CHECK: %[[V2:.*]] = load i8*, i8** @g0, align 8 + // CHECK: %[[V3:.*]] = call i8* @llvm.objc.retain(i8* %[[V2]]) + // CHECK: store i8* %[[V3]], i8** %[[ARRAYINIT_BEGIN]], align 8 + // CHECK: %[[ARRAYINIT_ELEMENT:.*]] = getelementptr inbounds i8*, i8** %[[ARRAYINIT_BEGIN]], i64 1 + // CHECK: %[[V4:.*]] = load i8*, i8** @g1, align 8 + // CHECK: %[[V5:.*]] = call i8* @llvm.objc.retain(i8* %[[V4]]) + // CHECK: store i8* %[[V5]], i8** %[[ARRAYINIT_ELEMENT]], align 8 + // CHECK: store i1 true, i1* %[[CLEANUP_COND]], align 1 + // CHECK: %[[ARRAYDECAY:.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* %[[_COMPOUNDLITERAL]], i64 0, i64 0 + + // CHECK: %[[ARRAYINIT_BEGIN2:.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* %[[_COMPOUNDLITERAL1]], i64 0, i64 0 + // CHECK: %[[V6:.*]] = load i8*, i8** @g1, align 8 + // CHECK: %[[V7:.*]] = call i8* @llvm.objc.retain(i8* %[[V6]]) + // CHECK: store i8* %[[V7]], i8** %[[ARRAYINIT_BEGIN2]], align 8 + // CHECK: %[[ARRAYINIT_ELEMENT3:.*]] = getelementptr inbounds i8*, i8** %[[ARRAYINIT_BEGIN2]], i64 1 + // CHECK: %[[V8:.*]] = load i8*, i8** @g0, align 8 + // CHECK: %[[V9:.*]] = call i8* @llvm.objc.retain(i8* %[[V8]]) + // CHECK: store i8* %[[V9]], i8** %[[ARRAYINIT_ELEMENT3]], align 8 + // CHECK: store i1 true, i1* %[[CLEANUP_COND4]], align 1 + // CHECK: %[[ARRAYDECAY5:.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* %[[_COMPOUNDLITERAL1]], i64 0, i64 0 + + // CHECK: %[[COND6:.*]] = phi i8** [ %[[ARRAYDECAY]], %{{.*}} ], [ %[[ARRAYDECAY5]], %{{.*}} ] + // CHECK: store i8** %[[COND6]], i8*** %[[P]], align 8 + // CHECK: call void @test2( + + // CHECK: %[[ARRAY_BEGIN:.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* %[[_COMPOUNDLITERAL1]], i32 0, i32 0 + // CHECK: %[[V11:.*]] = getelementptr inbounds i8*, i8** %[[ARRAY_BEGIN]], i64 2 + + // CHECK: %[[ARRAYDESTROY_ELEMENTPAST:.*]] = phi i8** [ %[[V11]], %{{.*}} ], [ %[[ARRAYDESTROY_ELEMENT:.*]], %{{.*}} ] + // CHECK: %[[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds i8*, i8** %[[ARRAYDESTROY_ELEMENTPAST]], i64 -1 + // CHECK: %[[V12:.*]] = load i8*, i8** %[[ARRAYDESTROY_ELEMENT]], align 8 + // CHECK: call void @llvm.objc.release(i8* %[[V12]]) + + // CHECK: %[[ARRAY_BEGIN10:.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* %[[_COMPOUNDLITERAL]], i32 0, i32 0 + // CHECK: %[[V13:.*]] = getelementptr inbounds i8*, i8** %[[ARRAY_BEGIN10]], i64 2 + + // CHECK: %[[ARRAYDESTROY_ELEMENTPAST12:.*]] = phi i8** [ %[[V13]], %{{.*}} ], [ %[[ARRAYDESTROY_ELEMENT13:.*]], %{{.*}} ] + // CHECK: %[[ARRAYDESTROY_ELEMENT13]] = getelementptr inbounds i8*, i8** %[[ARRAYDESTROY_ELEMENTPAST12]], i64 -1 + // CHECK: %[[V14:.*]] = load i8*, i8** %[[ARRAYDESTROY_ELEMENT13]], align 8 + // CHECK: call void @llvm.objc.release(i8* %[[V14]]) +} + // CHECK: attributes [[NUW]] = { nounwind } diff --git a/clang/test/CodeGenObjC/arc.m b/clang/test/CodeGenObjC/arc.m index 45296fbd54ef6..4c71a67d00be8 100644 --- a/clang/test/CodeGenObjC/arc.m +++ b/clang/test/CodeGenObjC/arc.m @@ -1557,6 +1557,43 @@ void test71(void) { getAggDtor(); } +// Check that no extra release calls are emitted to detruct the compond literal. + +// CHECK: define void @test72(i8* %[[A:.*]], i8* %[[B:.*]]) +// CHECK: %[[A_ADDR:.*]] = alloca i8*, align 8 +// CHECK: %[[B_ADDR:.*]] = alloca i8*, align 8 +// CHECK: %[[T:.*]] = alloca [2 x i8*], align 16 +// CHECK: %[[V0:.*]] = call i8* @llvm.objc.retain(i8* %[[A]]) +// CHECK: %[[V1:.*]] = call i8* @llvm.objc.retain(i8* %[[B]]) #2 +// CHECK: %[[ARRAYINIT_BEGIN:.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* %[[T]], i64 0, i64 0 +// CHECK: %[[V3:.*]] = load i8*, i8** %[[A_ADDR]], align 8, !tbaa !7 +// CHECK: %[[V4:.*]] = call i8* @llvm.objc.retain(i8* %[[V3]]) #2 +// CHECK: store i8* %[[V4]], i8** %[[ARRAYINIT_BEGIN]], align 8, !tbaa !7 +// CHECK: %[[ARRAYINIT_ELEMENT:.*]] = getelementptr inbounds i8*, i8** %[[ARRAYINIT_BEGIN]], i64 1 +// CHECK: %[[V5:.*]] = load i8*, i8** %[[B_ADDR]], align 8, !tbaa !7 +// CHECK: %[[V6:.*]] = call i8* @llvm.objc.retain(i8* %[[V5]]) #2 +// CHECK: store i8* %[[V6]], i8** %[[ARRAYINIT_ELEMENT]], align 8, !tbaa !7 +// CHECK: %[[ARRAY_BEGIN:.*]] = getelementptr inbounds [2 x i8*], [2 x i8*]* %[[T]], i32 0, i32 0 +// CHECK: %[[V7:.*]] = getelementptr inbounds i8*, i8** %[[ARRAY_BEGIN]], i64 2 + +// CHECK-NOT: call void @llvm.objc.release + +// CHECK: %[[ARRAYDESTROY_ELEMENTPAST:.*]] = phi i8** [ %[[V7]], %{{.*}} ], [ %[[ARRAYDESTROY_ELEMENT:.*]], %{{.*}} ] +// CHECK: %[[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds i8*, i8** %[[ARRAYDESTROY_ELEMENTPAST]], i64 -1 +// CHECK: %[[V8:.*]] = load i8*, i8** %[[ARRAYDESTROY_ELEMENT]], align 8 +// CHECK: call void @llvm.objc.release(i8* %[[V8]]) #2, !clang.imprecise_release !10 + +// CHECK-NOT: call void @llvm.objc.release + +// CHECK: %[[V10:.*]] = load i8*, i8** %[[B_ADDR]], align 8 +// CHECK: call void @llvm.objc.release(i8* %[[V10]]) #2, !clang.imprecise_release !10 +// CHECK: %[[V11:.*]] = load i8*, i8** %[[A_ADDR]], align 8 +// CHECK: call void @llvm.objc.release(i8* %[[V11]]) #2, !clang.imprecise_release !10 + +void test72(id a, id b) { + __strong id t[] = (__strong id[]){a, b}; +} + // ARC-ALIEN: attributes [[NLB]] = { nonlazybind } // ARC-NATIVE: attributes [[NLB]] = { nonlazybind } // CHECK: attributes [[NUW]] = { nounwind } diff --git a/clang/test/CodeGenObjC/strong-in-c-struct.m b/clang/test/CodeGenObjC/strong-in-c-struct.m index 01887c5fb9b32..ebb4761b3b467 100644 --- a/clang/test/CodeGenObjC/strong-in-c-struct.m +++ b/clang/test/CodeGenObjC/strong-in-c-struct.m @@ -709,6 +709,105 @@ void test_copy_constructor_VolatileArray(VolatileArray *a) { VolatileArray t = *a; } +// CHECK: define void @test_compound_literal0( +// CHECK: %[[P:.*]] = alloca %[[STRUCT_STRONGSMALL]]*, align 8 +// CHECK: %[[_COMPOUNDLITERAL:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8 +// CHECK: %[[CLEANUP_COND:.*]] = alloca i1, align 1 +// CHECK: %[[_COMPOUNDLITERAL1:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8 +// CHECK: %[[CLEANUP_COND4:.*]] = alloca i1, align 1 + +// CHECK: %[[I:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL]], i32 0, i32 0 +// CHECK: store i32 1, i32* %[[I]], align 8 +// CHECK: %[[F1:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL]], i32 0, i32 1 +// CHECK: store i8* null, i8** %[[F1]], align 8 +// CHECK: store i1 true, i1* %[[CLEANUP_COND]], align 1 + +// CHECK: %[[I2:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL1]], i32 0, i32 0 +// CHECK: store i32 2, i32* %[[I2]], align 8 +// CHECK: %[[F13:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL1]], i32 0, i32 1 +// CHECK: store i8* null, i8** %[[F13]], align 8 +// CHECK: store i1 true, i1* %[[CLEANUP_COND4]], align 1 + +// CHECK: %[[COND:.*]] = phi %[[STRUCT_STRONGSMALL]]* [ %[[_COMPOUNDLITERAL]], %{{.*}} ], [ %[[_COMPOUNDLITERAL1]], %{{.*}} ] +// CHECK: store %[[STRUCT_STRONGSMALL]]* %[[COND]], %[[STRUCT_STRONGSMALL]]** %[[P]], align 8 +// CHECK: call void @func( + +// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL1]] to i8** +// CHECK: call void @__destructor_8_s8(i8** %[[V1]]) + +// CHECK: %[[V2:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL]] to i8** +// CHECK: call void @__destructor_8_s8(i8** %[[V2]]) + +void test_compound_literal0(int c) { + StrongSmall *p = c ? &(StrongSmall){ 1, 0 } : &(StrongSmall){ 2, 0 }; + func(0); +} + +// Check that there is only one destructor call, which destructs 't'. + +// CHECK: define void @test_compound_literal1( +// CHECK: %[[T:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8 + +// CHECK: %[[I:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[T]], i32 0, i32 0 +// CHECK: store i32 1, i32* %[[I]], align 8 +// CHECK: %[[F1:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[T]], i32 0, i32 1 +// CHECK: store i8* null, i8** %[[F1]], align 8 + +// CHECK: %[[I1:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[T]], i32 0, i32 0 +// CHECK: store i32 2, i32* %[[I1]], align 8 +// CHECK: %[[F12:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[T]], i32 0, i32 1 +// CHECK: store i8* null, i8** %[[F12]], align 8 + +// CHECK: call void @func( +// CHECK-NOT: call void +// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[T]] to i8** +// CHECK: call void @__destructor_8_s8(i8** %[[V1]]) +// CHECK-NOT: call void + +void test_compound_literal1(int c) { + StrongSmall t = c ? (StrongSmall){ 1, 0 } : (StrongSmall){ 2, 0 }; + func(0); +} + +// CHECK: define void @test_compound_literal2( +// CHECK: %[[P_ADDR:.*]] = alloca %[[STRUCT_STRONGSMALL]]*, align 8 +// CHECK: %[[_COMPOUNDLITERAL:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8 +// CHECK: %[[CLEANUP_COND:.*]] = alloca i1, align 1 +// CHECK: %[[_COMPOUNDLITERAL1:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8 +// CHECK: %[[CLEANUP_COND4:.*]] = alloca i1, align 1 +// CHECK: %[[V0:.*]] = load %[[STRUCT_STRONGSMALL]]*, %[[STRUCT_STRONGSMALL]]** %[[P_ADDR]], align 8 + +// CHECK: %[[I:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL]], i32 0, i32 0 +// CHECK: store i32 1, i32* %[[I]], align 8 +// CHECK: %[[F1:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL]], i32 0, i32 1 +// CHECK: store i8* null, i8** %[[F1]], align 8 +// CHECK: store i1 true, i1* %[[CLEANUP_COND]], align 1 +// CHECK: %[[V2:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[V0]] to i8** +// CHECK: %[[V3:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL]] to i8** +// CHECK: call void @__copy_assignment_8_8_t0w4_s8(i8** %[[V2]], i8** %[[V3]]) + +// CHECK: %[[I2:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL1]], i32 0, i32 0 +// CHECK: store i32 2, i32* %[[I2]], align 8 +// CHECK: %[[F13:.*]] = getelementptr inbounds %[[STRUCT_STRONGSMALL]], %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL1]], i32 0, i32 1 +// CHECK: store i8* null, i8** %[[F13]], align 8 +// CHECK: store i1 true, i1* %[[CLEANUP_COND4]], align 1 +// CHECK: %[[V4:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[V0]] to i8** +// CHECK: %[[V5:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL1]] to i8** +// CHECK: call void @__copy_assignment_8_8_t0w4_s8(i8** %[[V4]], i8** %[[V5]]) + +// CHECK: call void @func( + +// CHECK: %[[V6:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL1]] to i8** +// CHECK: call void @__destructor_8_s8(i8** %[[V6]]) + +// CHECK: %[[V7:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[_COMPOUNDLITERAL]] to i8** +// CHECK: call void @__destructor_8_s8(i8** %[[V7]]) + +void test_compound_literal2(int c, StrongSmall *p) { + *p = c ? (StrongSmall){ 1, 0 } : (StrongSmall){ 2, 0 }; + func(0); +} + struct ZeroBitfield { int : 0; id strong; @@ -721,4 +820,5 @@ void test_zero_bitfield() { struct ZeroBitfield volatile a, b; a = b; } + #endif /* USESTRUCT */ diff --git a/clang/test/Import/objc-arc/Inputs/cleanup-objects.m b/clang/test/Import/objc-arc/Inputs/cleanup-objects.m new file mode 100644 index 0000000000000..9c18399259f9d --- /dev/null +++ b/clang/test/Import/objc-arc/Inputs/cleanup-objects.m @@ -0,0 +1,10 @@ +typedef struct { + id x; +} S; + +id getObj(int c, id a) { + // Commenting out the following line because AST importer crashes when trying + // to import a BlockExpr. + // return c ? ^{ return a; }() : ((S){ .x = a }).x; + return ((S){ .x = a }).x; +} diff --git a/clang/test/Import/objc-arc/test-cleanup-object.m b/clang/test/Import/objc-arc/test-cleanup-object.m new file mode 100644 index 0000000000000..aab1cd377a2e7 --- /dev/null +++ b/clang/test/Import/objc-arc/test-cleanup-object.m @@ -0,0 +1,10 @@ +// RUN: clang-import-test -x objective-c -objc-arc -import %S/Inputs/cleanup-objects.m -dump-ast -expression %s | FileCheck %s + +// CHECK: FunctionDecl {{.*}} getObj ' +// CHECK: ExprWithCleanups +// CHECK-NEXT: cleanup CompoundLiteralExpr + +void test(int c, id a) { + (void)getObj(c, a); +} + diff --git a/clang/test/PCH/non-trivial-c-compound-literal.m b/clang/test/PCH/non-trivial-c-compound-literal.m new file mode 100644 index 0000000000000..d4e3c1f12df27 --- /dev/null +++ b/clang/test/PCH/non-trivial-c-compound-literal.m @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -x objective-c -fobjc-arc -emit-pch -o %t %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -x objective-c -fobjc-arc -include-pch %t -emit-llvm -o - %s | FileCheck %s + +#ifndef HEADER +#define HEADER + +typedef struct { + id f; +} S; + +static inline id getObj(id a) { + S *p = &(S){ .f = a }; + return p->f; +} + +#else + +// CHECK: %[[STRUCT_S:.*]] = type { i8* } + +// CHECK: define internal i8* @getObj( +// CHECK: %[[_COMPOUNDLITERAL:.*]] = alloca %[[STRUCT_S]], +// CHECK: %[[V5:.*]] = bitcast %[[STRUCT_S]]* %[[_COMPOUNDLITERAL]] to i8** +// CHECK: call void @__destructor_8_s0(i8** %[[V5]]) + +id test(id a) { + return getObj(a); +} + +#endif diff --git a/clang/test/SemaObjC/strong-in-c-struct.m b/clang/test/SemaObjC/strong-in-c-struct.m index 5dd5f94af8301..5d2f4e496c2e3 100644 --- a/clang/test/SemaObjC/strong-in-c-struct.m +++ b/clang/test/SemaObjC/strong-in-c-struct.m @@ -54,3 +54,21 @@ void test_block_scope1(void) { func(^{ func2(x); }); goto *ips; // expected-error {{cannot jump}} } + +void test_compound_literal0(int cond, id x) { + switch (cond) { + case 0: + (void)(Strong){ .a = x }; // expected-note {{jump enters lifetime of a compound literal that is non-trivial to destruct}} + break; + default: // expected-error {{cannot jump from switch statement to this case label}} + break; + } +} + +void test_compound_literal1(id x) { + static void *ips[] = { &&L0 }; +L0: // expected-note {{possible target of indirect goto}} + ; + (void)(Strong){ .a = x }; // expected-note {{jump exits lifetime of a compound literal that is non-trivial to destruct}} + goto *ips; // expected-error {{cannot jump}} +} diff --git a/clang/tools/clang-import-test/clang-import-test.cpp b/clang/tools/clang-import-test/clang-import-test.cpp index b42c93e8d3819..f76f850ff41f3 100644 --- a/clang/tools/clang-import-test/clang-import-test.cpp +++ b/clang/tools/clang-import-test/clang-import-test.cpp @@ -64,6 +64,9 @@ static llvm::cl::opt llvm::cl::desc("The language to parse (default: c++)"), llvm::cl::init("c++")); +static llvm::cl::opt ObjCARC("objc-arc", llvm::cl::init(false), + llvm::cl::desc("Emable ObjC ARC")); + static llvm::cl::opt DumpAST("dump-ast", llvm::cl::init(false), llvm::cl::desc("Dump combined AST")); @@ -183,6 +186,8 @@ std::unique_ptr BuildCompilerInstance() { Inv->getLangOpts()->ObjC = 1; } } + Inv->getLangOpts()->ObjCAutoRefCount = ObjCARC; + Inv->getLangOpts()->Bool = true; Inv->getLangOpts()->WChar = true; Inv->getLangOpts()->Blocks = true; From 526baedc52f58266319870ab32faade1c3420177 Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Wed, 20 Nov 2019 18:13:44 -0800 Subject: [PATCH 185/286] [CodeGen] Emit destructor calls to destruct non-trivial C struct objects returned by function calls or loaded from volatile objects rdar://problem/51867864 Differential Revision: https://reviews.llvm.org/D66094 (cherry picked from commit d35a454170da3da9c9bb0b5627f5796113195283) Conflicts: clang/test/CodeGenObjC/arc.m clang/test/CodeGenObjC/strong-in-c-struct.m --- clang/lib/AST/Expr.cpp | 3 + clang/lib/CodeGen/CGCall.cpp | 5 ++ clang/lib/CodeGen/CGCall.h | 33 +++++---- clang/lib/CodeGen/CGClass.cpp | 4 +- clang/lib/CodeGen/CGExprAgg.cpp | 21 ++++-- clang/lib/CodeGen/CGExprConstant.cpp | 4 +- clang/lib/CodeGen/CGVTables.cpp | 3 +- clang/lib/Sema/SemaDecl.cpp | 3 + clang/lib/Sema/SemaExpr.cpp | 3 + clang/lib/Sema/SemaExprCXX.cpp | 3 + clang/test/CodeGenObjC/arc.m | 11 ++- clang/test/CodeGenObjC/strong-in-c-struct.m | 79 +++++++++++++++++++++ 12 files changed, 137 insertions(+), 35 deletions(-) diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index d39e437e3bcfa..b25afb87bb5d0 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -3211,6 +3211,9 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef, switch (getStmtClass()) { default: break; + case Stmt::ExprWithCleanupsClass: + return cast(this)->getSubExpr()->isConstantInitializer( + Ctx, IsForRef, Culprit); case StringLiteralClass: case ObjCEncodeExprClass: return true; diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 6cb0d8e5142cb..bfb7977e35162 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -4692,6 +4692,11 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, for (CallLifetimeEnd &LifetimeEnd : CallLifetimeEndAfterCall) LifetimeEnd.Emit(*this, /*Flags=*/{}); + if (!ReturnValue.isExternallyDestructed() && + RetTy.isDestructedType() == QualType::DK_nontrivial_c_struct) + pushDestroy(QualType::DK_nontrivial_c_struct, Ret.getAggregateAddress(), + RetTy); + return Ret; } diff --git a/clang/lib/CodeGen/CGCall.h b/clang/lib/CodeGen/CGCall.h index 6cdd5fb1a0728..ba3a6e4c0a674 100644 --- a/clang/lib/CodeGen/CGCall.h +++ b/clang/lib/CodeGen/CGCall.h @@ -401,27 +401,26 @@ class FunctionArgList : public SmallVector {}; /// ReturnValueSlot - Contains the address where the return value of a /// function can be stored, and whether the address is volatile or not. class ReturnValueSlot { - llvm::PointerIntPair Value; - CharUnits Alignment; + Address Addr = Address::invalid(); // Return value slot flags - enum Flags { - IS_VOLATILE = 0x1, - IS_UNUSED = 0x2, - }; + unsigned IsVolatile : 1; + unsigned IsUnused : 1; + unsigned IsExternallyDestructed : 1; public: - ReturnValueSlot() {} - ReturnValueSlot(Address Addr, bool IsVolatile, bool IsUnused = false) - : Value(Addr.isValid() ? Addr.getPointer() : nullptr, - (IsVolatile ? IS_VOLATILE : 0) | (IsUnused ? IS_UNUSED : 0)), - Alignment(Addr.isValid() ? Addr.getAlignment() : CharUnits::Zero()) {} - - bool isNull() const { return !getValue().isValid(); } - - bool isVolatile() const { return Value.getInt() & IS_VOLATILE; } - Address getValue() const { return Address(Value.getPointer(), Alignment); } - bool isUnused() const { return Value.getInt() & IS_UNUSED; } + ReturnValueSlot() + : IsVolatile(false), IsUnused(false), IsExternallyDestructed(false) {} + ReturnValueSlot(Address Addr, bool IsVolatile, bool IsUnused = false, + bool IsExternallyDestructed = false) + : Addr(Addr), IsVolatile(IsVolatile), IsUnused(IsUnused), + IsExternallyDestructed(IsExternallyDestructed) {} + + bool isNull() const { return !Addr.isValid(); } + bool isVolatile() const { return IsVolatile; } + Address getValue() const { return Addr; } + bool isUnused() const { return IsUnused; } + bool isExternallyDestructed() const { return IsExternallyDestructed; } }; } // end namespace CodeGen diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp index 58b866ecafbe5..4dedfc02f551b 100644 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -2874,7 +2874,9 @@ void CodeGenFunction::EmitForwardingCallToLambda( if (!resultType->isVoidType() && calleeFnInfo.getReturnInfo().getKind() == ABIArgInfo::Indirect && !hasScalarEvaluationKind(calleeFnInfo.getReturnType())) - returnSlot = ReturnValueSlot(ReturnValue, resultType.isVolatileQualified()); + returnSlot = + ReturnValueSlot(ReturnValue, resultType.isVolatileQualified(), + /*IsUnused=*/false, /*IsExternallyDestructed=*/true); // We don't need to separately arrange the call arguments because // the call can't be variadic anyway --- it's impossible to forward diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index 9881d28fe25ce..df576decd69d6 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -249,7 +249,7 @@ void AggExprEmitter::withReturnValueSlot( const Expr *E, llvm::function_ref EmitCall) { QualType RetTy = E->getType(); bool RequiresDestruction = - Dest.isIgnored() && + !Dest.isExternallyDestructed() && RetTy.isDestructedType() == QualType::DK_nontrivial_c_struct; // If it makes no observable difference, save a memcpy + temporary. @@ -287,10 +287,8 @@ void AggExprEmitter::withReturnValueSlot( } RValue Src = - EmitCall(ReturnValueSlot(RetAddr, Dest.isVolatile(), IsResultUnused)); - - if (RequiresDestruction) - CGF.pushDestroy(RetTy.isDestructedType(), Src.getAggregateAddress(), RetTy); + EmitCall(ReturnValueSlot(RetAddr, Dest.isVolatile(), IsResultUnused, + Dest.isExternallyDestructed())); if (!UseTemp) return; @@ -827,8 +825,19 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { // If we're loading from a volatile type, force the destination // into existence. if (E->getSubExpr()->getType().isVolatileQualified()) { + bool Destruct = + !Dest.isExternallyDestructed() && + E->getType().isDestructedType() == QualType::DK_nontrivial_c_struct; + if (Destruct) + Dest.setExternallyDestructed(); EnsureDest(E->getType()); - return Visit(E->getSubExpr()); + Visit(E->getSubExpr()); + + if (Destruct) + CGF.pushDestroy(QualType::DK_nontrivial_c_struct, Dest.getAddress(), + E->getType()); + + return; } LLVM_FALLTHROUGH; diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index a4e6e470a9055..3377f7d9b0888 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -1167,9 +1167,7 @@ class ConstExprEmitter : } llvm::Constant *VisitExprWithCleanups(ExprWithCleanups *E, QualType T) { - if (!E->cleanupsHaveSideEffects()) - return Visit(E->getSubExpr(), T); - return nullptr; + return Visit(E->getSubExpr(), T); } llvm::Constant *VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E, diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp index 0409434961379..6ec05d64be385 100644 --- a/clang/lib/CodeGen/CGVTables.cpp +++ b/clang/lib/CodeGen/CGVTables.cpp @@ -364,7 +364,8 @@ void CodeGenFunction::EmitCallAndReturnForThunk(llvm::FunctionCallee Callee, ReturnValueSlot Slot; if (!ResultType->isVoidType() && CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect) - Slot = ReturnValueSlot(ReturnValue, ResultType.isVolatileQualified()); + Slot = ReturnValueSlot(ReturnValue, ResultType.isVolatileQualified(), + /*IsUnused=*/false, /*IsExternallyDestructed=*/true); // Now emit our call. llvm::CallBase *CallOrInvoke; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 73428b8209b14..d4ba3a8d5cf5c 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -11380,6 +11380,9 @@ bool Sema::DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit, void Sema::checkNonTrivialCUnionInInitializer(const Expr *Init, SourceLocation Loc) { + if (auto *EWC = dyn_cast(Init)) + Init = EWC->getSubExpr(); + if (auto *CE = dyn_cast(Init)) Init = CE->getSubExpr(); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 4d4d63cdf9233..c9d9224d7e3ae 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -637,6 +637,9 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) { if (E->getType().getObjCLifetime() == Qualifiers::OCL_Weak) Cleanup.setExprNeedsCleanups(true); + if (E->getType().isDestructedType() == QualType::DK_nontrivial_c_struct) + Cleanup.setExprNeedsCleanups(true); + // C++ [conv.lval]p3: // If T is cv std::nullptr_t, the result is a null pointer constant. CastKind CK = T->isNullPtrType() ? CK_NullToPointer : CK_LValueToRValue; diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index cfb3a05e9c146..e7c70e9b57278 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -6475,6 +6475,9 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) { VK_RValue); } + if (E->getType().isDestructedType() == QualType::DK_nontrivial_c_struct) + Cleanup.setExprNeedsCleanups(true); + if (!getLangOpts().CPlusPlus) return E; diff --git a/clang/test/CodeGenObjC/arc.m b/clang/test/CodeGenObjC/arc.m index 4c71a67d00be8..375ad8ed7b416 100644 --- a/clang/test/CodeGenObjC/arc.m +++ b/clang/test/CodeGenObjC/arc.m @@ -1536,12 +1536,13 @@ void test70(id i) { // CHECK-LABEL: define void @test71 void test71(void) { - // FIXME: It would be nice if the __destructor_8_s40 for the first call (and - // the following lifetime.end) came before the second call. - // // CHECK: %[[T:[^ ]+]] = bitcast %struct.AggDtor* %[[TMP1:[^ ]+]] to i8* // CHECK: call void @llvm.lifetime.start.p0i8({{[^,]+}}, i8* %[[T]]) // CHECK: call void @getAggDtor(%struct.AggDtor* sret align 8 %[[TMP1]]) + // CHECK: %[[T:[^ ]+]] = bitcast %struct.AggDtor* %[[TMP1]] to i8** + // CHECK: call void @__destructor_8_s40(i8** %[[T]]) + // CHECK: %[[T:[^ ]+]] = bitcast %struct.AggDtor* %[[TMP1:[^ ]+]] to i8* + // CHECK: call void @llvm.lifetime.end.p0i8({{[^,]+}}, i8* %[[T]]) // CHECK: %[[T:[^ ]+]] = bitcast %struct.AggDtor* %[[TMP2:[^ ]+]] to i8* // CHECK: call void @llvm.lifetime.start.p0i8({{[^,]+}}, i8* %[[T]]) // CHECK: call void @getAggDtor(%struct.AggDtor* sret align 8 %[[TMP2]]) @@ -1549,10 +1550,6 @@ void test71(void) { // CHECK: call void @__destructor_8_s40(i8** %[[T]]) // CHECK: %[[T:[^ ]+]] = bitcast %struct.AggDtor* %[[TMP2:[^ ]+]] to i8* // CHECK: call void @llvm.lifetime.end.p0i8({{[^,]+}}, i8* %[[T]]) - // CHECK: %[[T:[^ ]+]] = bitcast %struct.AggDtor* %[[TMP1]] to i8** - // CHECK: call void @__destructor_8_s40(i8** %[[T]]) - // CHECK: %[[T:[^ ]+]] = bitcast %struct.AggDtor* %[[TMP1:[^ ]+]] to i8* - // CHECK: call void @llvm.lifetime.end.p0i8({{[^,]+}}, i8* %[[T]]) getAggDtor(); getAggDtor(); } diff --git a/clang/test/CodeGenObjC/strong-in-c-struct.m b/clang/test/CodeGenObjC/strong-in-c-struct.m index ebb4761b3b467..f0227119279f4 100644 --- a/clang/test/CodeGenObjC/strong-in-c-struct.m +++ b/clang/test/CodeGenObjC/strong-in-c-struct.m @@ -89,6 +89,13 @@ void calleeStrongSmall(StrongSmall); void func(Strong *); +@interface C +- (StrongSmall)getStrongSmall; ++ (StrongSmall)getStrongSmallClass; +@end + +id g0; + // CHECK: %[[STRUCT_STRONGOUTER:.*]] = type { %[[STRUCT_STRONG:.*]], i8*, double } // CHECK: %[[STRUCT_STRONG]] = type { %[[STRUCT_TRIVIAL:.*]], i8* } // CHECK: %[[STRUCT_TRIVIAL]] = type { [4 x i32] } @@ -476,6 +483,18 @@ void test_destructor_ignored_result(void) { getStrongSmall(); } +// CHECK: define void @test_destructor_ignored_result2(%{{.*}}* %[[C:.*]]) +// CHECK: %[[TMP:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8 +// CHECK: %[[CALL:.*]] = call [2 x i64]{{.*}}@objc_msgSend +// CHECK: %[[V5:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TMP]] to [2 x i64]* +// CHECK: store [2 x i64] %[[CALL]], [2 x i64]* %[[V5]], align 8 +// CHECK: %[[V6:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TMP]] to i8** +// CHECK: call void @__destructor_8_s8(i8** %[[V6]]) + +void test_destructor_ignored_result2(C *c) { + [c getStrongSmall]; +} + // CHECK: define void @test_copy_constructor_StrongBlock( // CHECK: call void @__copy_constructor_8_8_sb0( // CHECK: call void @__destructor_8_sb0( @@ -520,7 +539,9 @@ void test_copy_assignment_StrongBlock(StrongBlock *d, StrongBlock *s) { // CHECK: define void @test_copy_constructor_StrongVolatile0( // CHECK: call void @__copy_constructor_8_8_t0w4_sv8( +// CHECK-NOT: call // CHECK: call void @__destructor_8_sv8( +// CHECK-NOT: call // CHECK: define linkonce_odr hidden void @__copy_constructor_8_8_t0w4_sv8( // CHECK: %[[V8:.*]] = load volatile i8*, i8** %{{.*}}, align 8 @@ -808,6 +829,64 @@ void test_compound_literal2(int c, StrongSmall *p) { func(0); } +// CHECK: define void @test_member_access( +// CHECK: %[[TMP:.*]] = alloca %[[STRUCT_STRONGSMALL]], +// CHECK: %[[V3:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[TMP]] to i8** +// CHECK: call void @__destructor_8_s8(i8** %[[V3]]) +// CHECK: call void @func( + +void test_member_access(void) { + g0 = getStrongSmall().f1; + func(0); +} + +// CHECK: define void @test_member_access2(%{{.*}}* %[[C:.*]]) +// CHECK: %[[COERCE:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8 +// CHECK: %[[V8:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[COERCE]] to i8** +// CHECK: call void @__destructor_8_s8(i8** %[[V8]]) +// CHECK: call void @func( + +void test_member_access2(C *c) { + g0 = [c getStrongSmall].f1; + func(0); +} + +// CHECK: define void @test_member_access3( +// CHECK: %[[COERCE:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8 +// CHECK: %[[V8:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[COERCE]] to i8** +// CHECK: call void @__destructor_8_s8(i8** %[[V8]]) +// CHECK: call void @func( + +void test_member_access3(void) { + g0 = [C getStrongSmallClass].f1; + func(0); +} + +// CHECK: define void @test_member_access4() +// CHECK: %[[COERCE:.*]] = alloca %[[STRUCT_STRONGSMALL]], align 8 +// CHECK: %[[V5:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[COERCE]] to i8** +// CHECK: call void @__destructor_8_s8(i8** %[[V5]]) +// CHECK: call void @func( + +void test_member_access4(void) { + g0 = ^{ StrongSmall s; return s; }().f1; + func(0); +} + +// CHECK: define void @test_volatile_variable_reference( +// CHECK: %[[AGG_TMP_ENSURED:.*]] = alloca %[[STRUCT_STRONGSMALL]], +// CHECK: %[[V1:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[AGG_TMP_ENSURED]] to i8** +// CHECK: %[[V2:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %{{.*}} to i8** +// CHECK: call void @__copy_constructor_8_8_tv0w32_sv8(i8** %[[V1]], i8** %[[V2]]) +// CHECK: %[[V3:.*]] = bitcast %[[STRUCT_STRONGSMALL]]* %[[AGG_TMP_ENSURED]] to i8** +// CHECK: call void @__destructor_8_s8(i8** %[[V3]]) +// CHECK: call void @func( + +void test_volatile_variable_reference(volatile StrongSmall *a) { + (void)*a; + func(0); +} + struct ZeroBitfield { int : 0; id strong; From 3d807e27aacb4a4a9c7e5c8017f119633292c201 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Tue, 3 Mar 2020 13:01:51 -0800 Subject: [PATCH 186/286] Add an opque payload field to lldb::Type (NFC). Differential Revision: https://reviews.llvm.org/D75562 (cherry picked from commit 7b06cb4523083206ad79776c80a564cd26bd8326) Conflicts: lldb/include/lldb/Symbol/Type.h lldb/include/lldb/Symbol/TypeSystemClang.h --- lldb/include/lldb/Symbol/SwiftASTContext.h | 23 ++++++++++++ lldb/include/lldb/Symbol/Type.h | 26 ++++---------- lldb/source/Core/ValueObjectVariable.cpp | 32 +++++++++-------- .../ObjC/ObjCLanguageRuntime.cpp | 2 +- .../SymbolFile/DWARF/DWARFASTParserClang.cpp | 11 +++--- .../SymbolFile/DWARF/DWARFASTParserSwift.cpp | 2 +- .../TypeSystem/Clang/TypeSystemClang.cpp | 4 +++ .../TypeSystem/Clang/TypeSystemClang.h | 35 +++++++++++++++++++ lldb/source/Symbol/SwiftASTContext.cpp | 4 +++ lldb/source/Symbol/Type.cpp | 9 +++-- 10 files changed, 102 insertions(+), 46 deletions(-) diff --git a/lldb/include/lldb/Symbol/SwiftASTContext.h b/lldb/include/lldb/Symbol/SwiftASTContext.h index 919a29caeec54..3eee07fae57c4 100644 --- a/lldb/include/lldb/Symbol/SwiftASTContext.h +++ b/lldb/include/lldb/Symbol/SwiftASTContext.h @@ -70,6 +70,29 @@ struct SourceModule; class SwiftASTContext; CompilerType ToCompilerType(swift::Type qual_type); +/// The implementation of lldb::Type's m_payload field for TypeSystemSwift. +class TypePayloadSwift { + /// Layout: bit 1 ... IsFixedValueBuffer. + uint32_t m_payload = 0; + + static constexpr unsigned FixedValueBufferBit = 1; +public: + TypePayloadSwift() = default; + explicit TypePayloadSwift(bool is_fixed_value_buffer); + explicit TypePayloadSwift(uint32_t opaque_payload) : m_payload(opaque_payload) {} + operator uint32_t() { return m_payload; } + + /// \return whether this is a Swift fixed-size buffer. Resilient variables in + /// fixed-size buffers may be indirect depending on the runtime size of the + /// type. This is more a property of the value than of its type. + bool IsFixedValueBuffer() { return Flags(m_payload).Test(FixedValueBufferBit); } + void SetIsFixedValueBuffer(bool is_fixed_value_buffer) { + m_payload = is_fixed_value_buffer + ? Flags(m_payload).Set(FixedValueBufferBit) + : Flags(m_payload).Clear(FixedValueBufferBit); + } +}; + /// Abstract base class for all Swift TypeSystems. /// /// Swift CompilerTypes are either a mangled name or a Swift AST diff --git a/lldb/include/lldb/Symbol/Type.h b/lldb/include/lldb/Symbol/Type.h index 3c424f43f7e71..474e3ad1872ad 100644 --- a/lldb/include/lldb/Symbol/Type.h +++ b/lldb/include/lldb/Symbol/Type.h @@ -97,7 +97,7 @@ class Type : public std::enable_shared_from_this, public UserID { llvm::Optional byte_size, SymbolContextScope *context, lldb::user_id_t encoding_uid, EncodingDataType encoding_uid_type, const Declaration &decl, const CompilerType &compiler_qual_type, - ResolveState compiler_type_resolve_state); + ResolveState compiler_type_resolve_state, uint32_t opaque_payload = 0); // This makes an invalid type. Used for functions that return a Type when // they get an error. @@ -197,22 +197,10 @@ class Type : public std::enable_shared_from_this, public UserID { uint32_t GetEncodingMask(); - bool IsCompleteObjCClass() { return m_is_complete_objc_class; } - - void SetIsCompleteObjCClass(bool is_complete_objc_class) { - m_is_complete_objc_class = is_complete_objc_class; - } - - /// \return whether this is a Swift fixed-size buffer. Resilient variables in - /// fixed-size buffers may be indirect depending on the runtime size of the - /// type. This is more a property of the value than of its type. - bool IsSwiftFixedValueBuffer() const { - return m_is_swift_fixed_value_buffer; - } - - void SetSwiftFixedValueBuffer(bool is_swift_fixed_value_buffer) { - m_is_swift_fixed_value_buffer = is_swift_fixed_value_buffer; - } + /// Return the language-specific payload. + uint32_t GetPayload() { return m_payload; } + /// Return the language-specific payload. + void SetPayload(uint32_t opaque_payload) { m_payload = opaque_payload; } protected: ConstString m_name; @@ -227,8 +215,8 @@ class Type : public std::enable_shared_from_this, public UserID { Declaration m_decl; CompilerType m_compiler_type; ResolveState m_compiler_type_resolve_state; - bool m_is_complete_objc_class; - bool m_is_swift_fixed_value_buffer = false; + /// Language-specific flags. + uint32_t m_payload; Type *GetEncodingType(); diff --git a/lldb/source/Core/ValueObjectVariable.cpp b/lldb/source/Core/ValueObjectVariable.cpp index 027b891bd59c6..f0c4acfd5b3db 100644 --- a/lldb/source/Core/ValueObjectVariable.cpp +++ b/lldb/source/Core/ValueObjectVariable.cpp @@ -258,22 +258,26 @@ bool ValueObjectVariable::UpdateValue() { } // BEGIN Swift - if (variable->GetType() && variable->GetType()->IsSwiftFixedValueBuffer()) - if (auto process_sp = GetProcessSP()) - if (auto runtime = process_sp->GetLanguageRuntime( - compiler_type.GetMinimumLanguage())) { - if (!runtime->IsStoredInlineInBuffer(compiler_type)) { - lldb::addr_t addr = - m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); - if (addr != LLDB_INVALID_ADDRESS) { - Target &target = process_sp->GetTarget(); - size_t ptr_size = process_sp->GetAddressByteSize(); - lldb::addr_t deref_addr; - target.ReadMemory(addr, false, &deref_addr, ptr_size, m_error); - m_value.GetScalar() = deref_addr; + if (auto type = variable->GetType()) + if (llvm::dyn_cast_or_null( + type->GetForwardCompilerType().GetTypeSystem()) && + TypePayloadSwift(type->GetPayload()).IsFixedValueBuffer()) + if (auto process_sp = GetProcessSP()) + if (auto runtime = process_sp->GetLanguageRuntime( + compiler_type.GetMinimumLanguage())) { + if (!runtime->IsStoredInlineInBuffer(compiler_type)) { + lldb::addr_t addr = + m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); + if (addr != LLDB_INVALID_ADDRESS) { + Target &target = process_sp->GetTarget(); + size_t ptr_size = process_sp->GetAddressByteSize(); + lldb::addr_t deref_addr; + target.ReadMemory(addr, false, &deref_addr, ptr_size, + m_error); + m_value.GetScalar() = deref_addr; + } } } - } // END Swift switch (value_type) { diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp index 1b2286ae19d1c..4c2230944537c 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp @@ -129,7 +129,7 @@ ObjCLanguageRuntime::LookupInCompleteClassCache(ConstString &name) { if (TypeSystemClang::IsObjCObjectOrInterfaceType( type_sp->GetForwardCompilerType())) { - if (type_sp->IsCompleteObjCClass()) { + if (TypePayloadClang(type_sp->GetPayload()).IsCompleteObjCClass()) { m_complete_class_cache[name] = type_sp; return type_sp; } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index 59604a25fad6f..f3077c4cdfade 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -1637,12 +1637,11 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, // parameters in any class methods need it for the clang types for // function prototypes. LinkDeclContextToDIE(m_ast.GetDeclContextForType(clang_type), die); - type_sp = std::make_shared(die.GetID(), dwarf, attrs.name, - attrs.byte_size, nullptr, LLDB_INVALID_UID, - Type::eEncodingIsUID, &attrs.decl, - clang_type, Type::ResolveState::Forward); - - type_sp->SetIsCompleteObjCClass(attrs.is_complete_objc_class); + type_sp = std::make_shared( + die.GetID(), dwarf, attrs.name, attrs.byte_size, nullptr, + LLDB_INVALID_UID, Type::eEncodingIsUID, &attrs.decl, clang_type, + Type::ResolveState::Forward, + TypePayloadClang(attrs.is_complete_objc_class)); // Add our type to the unique type map so we don't end up creating many // copies of the same type over and over in the ASTContext for our diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserSwift.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserSwift.cpp index 07fd14e50df4c..5265fe0c0c57d 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserSwift.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserSwift.cpp @@ -130,7 +130,7 @@ lldb::TypeSP DWARFASTParserSwift::ParseTypeFromDWARF(const SymbolContext &sc, if (auto wrapped_type = get_type(die.GetFirstChild())) { // Create a unique pointer for the type + fixed buffer flag. type_sp.reset(new Type(*wrapped_type)); - type_sp->SetSwiftFixedValueBuffer(true); + type_sp->SetPayload(TypePayloadSwift(true)); return type_sp; } } diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 1a0bf2087ab3b..143a68ef708a4 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -313,6 +313,10 @@ static ClangASTMap &GetASTMap() { return *g_map_ptr; } +TypePayloadClang::TypePayloadClang(bool is_complete_objc_class) { + SetIsCompleteObjCClass(is_complete_objc_class); +} + char TypeSystemClang::ID; bool TypeSystemClang::IsOperator(llvm::StringRef name, diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index 442e41211c17c..8852a1507b48b 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -31,6 +31,7 @@ #include "lldb/Symbol/TypeSystem.h" #include "lldb/Target/Target.h" #include "lldb/Utility/ConstString.h" +#include "lldb/Utility/Flags.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/Logging.h" #include "lldb/lldb-enumerations.h" @@ -38,10 +39,44 @@ class DWARFASTParserClang; class PDBASTParser; +namespace clang { +class FileManager; +class HeaderSearch; +class ModuleMap; +} // namespace clang + namespace lldb_private { class Declaration; +/// The implementation of lldb::Type's m_payload field for TypeSystemClang. +class TypePayloadClang { + /// Layout: bit 31 ... IsCompleteObjCClass. + uint32_t m_payload = 0; +public: + TypePayloadClang() = default; + explicit TypePayloadClang(bool is_complete_objc_class); + explicit TypePayloadClang(uint32_t opaque_payload) : m_payload(opaque_payload) {} + operator uint32_t() { return m_payload; } + + static constexpr unsigned ObjCClassBit = 1 << 31; + bool IsCompleteObjCClass() { return Flags(m_payload).Test(ObjCClassBit); } + void SetIsCompleteObjCClass(bool is_complete_objc_class) { + m_payload = is_complete_objc_class ? Flags(m_payload).Set(ObjCClassBit) + : Flags(m_payload).Clear(ObjCClassBit); + } +}; + +/// A TypeSystem implementation based on Clang. +/// +/// This class uses a single clang::ASTContext as the backend for storing +/// its types and declarations. Every clang::ASTContext should also just have +/// a single associated TypeSystemClang instance that manages it. +/// +/// The clang::ASTContext instance can either be created by TypeSystemClang +/// itself or it can adopt an existing clang::ASTContext (for example, when +/// it is necessary to provide a TypeSystem interface for an existing +/// clang::ASTContext that was created by clang::CompilerInstance). class TypeSystemClang : public TypeSystem { // LLVM RTTI support static char ID; diff --git a/lldb/source/Symbol/SwiftASTContext.cpp b/lldb/source/Symbol/SwiftASTContext.cpp index 1f4cc17b607df..12a72bb0c1a6e 100644 --- a/lldb/source/Symbol/SwiftASTContext.cpp +++ b/lldb/source/Symbol/SwiftASTContext.cpp @@ -177,6 +177,10 @@ CompilerType lldb_private::ToCompilerType(swift::Type qual_type) { qual_type.getPointer()); } +TypePayloadSwift::TypePayloadSwift(bool is_fixed_value_buffer) { + SetIsFixedValueBuffer(is_fixed_value_buffer); +} + CompilerType SwiftASTContext::GetCompilerType(ConstString mangled_name) { return m_typeref_typesystem.GetTypeFromMangledTypename(mangled_name); } diff --git a/lldb/source/Symbol/Type.cpp b/lldb/source/Symbol/Type.cpp index 968ae1f7c2415..d440cc050b18c 100644 --- a/lldb/source/Symbol/Type.cpp +++ b/lldb/source/Symbol/Type.cpp @@ -143,15 +143,14 @@ Type::Type(lldb::user_id_t uid, SymbolFile *symbol_file, ConstString name, llvm::Optional byte_size, SymbolContextScope *context, user_id_t encoding_uid, EncodingDataType encoding_uid_type, const Declaration &decl, const CompilerType &compiler_type, - ResolveState compiler_type_resolve_state) + ResolveState compiler_type_resolve_state, uint32_t opaque_payload) : std::enable_shared_from_this(), UserID(uid), m_name(name), m_symbol_file(symbol_file), m_context(context), m_encoding_type(nullptr), m_encoding_uid(encoding_uid), m_encoding_uid_type(encoding_uid_type), m_decl(decl), m_compiler_type(compiler_type), - m_compiler_type_resolve_state( - compiler_type ? compiler_type_resolve_state - : ResolveState::Unresolved), - m_is_complete_objc_class(false) { + m_compiler_type_resolve_state(compiler_type ? compiler_type_resolve_state + : ResolveState::Unresolved), + m_payload(opaque_payload) { if (byte_size) { m_byte_size = *byte_size; m_byte_size_has_value = true; From 9b6bce2f39d7faf15647b0a874bed98881a7a3a8 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Tue, 31 Mar 2020 14:12:11 -0700 Subject: [PATCH 187/286] Add a Type::Payload typedef. (NFC) This addresses review feedback from Raphael that I missed before landing the change that introduced the payload field. (cherry picked from commit 00efcd6fffa533e5a4aa5646e678d57df0f9aca8) --- lldb/include/lldb/Symbol/Type.h | 7 ++++--- lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lldb/include/lldb/Symbol/Type.h b/lldb/include/lldb/Symbol/Type.h index 474e3ad1872ad..61adff96c9147 100644 --- a/lldb/include/lldb/Symbol/Type.h +++ b/lldb/include/lldb/Symbol/Type.h @@ -197,10 +197,11 @@ class Type : public std::enable_shared_from_this, public UserID { uint32_t GetEncodingMask(); + typedef uint32_t Payload; /// Return the language-specific payload. - uint32_t GetPayload() { return m_payload; } + Payload GetPayload() { return m_payload; } /// Return the language-specific payload. - void SetPayload(uint32_t opaque_payload) { m_payload = opaque_payload; } + void SetPayload(Payload opaque_payload) { m_payload = opaque_payload; } protected: ConstString m_name; @@ -216,7 +217,7 @@ class Type : public std::enable_shared_from_this, public UserID { CompilerType m_compiler_type; ResolveState m_compiler_type_resolve_state; /// Language-specific flags. - uint32_t m_payload; + Payload m_payload; Type *GetEncodingType(); diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index 8852a1507b48b..8cae85ef5f10c 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -52,7 +52,7 @@ class Declaration; /// The implementation of lldb::Type's m_payload field for TypeSystemClang. class TypePayloadClang { /// Layout: bit 31 ... IsCompleteObjCClass. - uint32_t m_payload = 0; + Type::Payload m_payload = 0; public: TypePayloadClang() = default; explicit TypePayloadClang(bool is_complete_objc_class); From 5f5e02c75d76f2000b40d26af8b31abf6a8aec4a Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Tue, 31 Mar 2020 14:58:25 -0700 Subject: [PATCH 188/286] Replace uint32_t with typedef (NFC) (cherry picked from commit ec11c5615a7c153a68d098903edebbb92719f5f9) --- lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index 8cae85ef5f10c..32c42e4aec2d6 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -57,7 +57,7 @@ class TypePayloadClang { TypePayloadClang() = default; explicit TypePayloadClang(bool is_complete_objc_class); explicit TypePayloadClang(uint32_t opaque_payload) : m_payload(opaque_payload) {} - operator uint32_t() { return m_payload; } + operator Type::Payload() { return m_payload; } static constexpr unsigned ObjCClassBit = 1 << 31; bool IsCompleteObjCClass() { return Flags(m_payload).Test(ObjCClassBit); } From 499656620190098346df5379723af6a4a95e6f2b Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Tue, 31 Mar 2020 15:21:38 -0700 Subject: [PATCH 189/286] Use typedef (NFC) --- lldb/include/lldb/Symbol/SwiftASTContext.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lldb/include/lldb/Symbol/SwiftASTContext.h b/lldb/include/lldb/Symbol/SwiftASTContext.h index 3eee07fae57c4..9a673da795b7f 100644 --- a/lldb/include/lldb/Symbol/SwiftASTContext.h +++ b/lldb/include/lldb/Symbol/SwiftASTContext.h @@ -73,14 +73,15 @@ CompilerType ToCompilerType(swift::Type qual_type); /// The implementation of lldb::Type's m_payload field for TypeSystemSwift. class TypePayloadSwift { /// Layout: bit 1 ... IsFixedValueBuffer. - uint32_t m_payload = 0; + Type::Payload m_payload = 0; static constexpr unsigned FixedValueBufferBit = 1; public: TypePayloadSwift() = default; explicit TypePayloadSwift(bool is_fixed_value_buffer); - explicit TypePayloadSwift(uint32_t opaque_payload) : m_payload(opaque_payload) {} - operator uint32_t() { return m_payload; } + explicit TypePayloadSwift(Type::Payload opaque_payload) + : m_payload(opaque_payload) {} + operator Type::Payload() { return m_payload; } /// \return whether this is a Swift fixed-size buffer. Resilient variables in /// fixed-size buffers may be indirect depending on the runtime size of the From 3e305f95617f9b4f2ff1ccdb747c4de3995e34f5 Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Wed, 4 Mar 2020 18:35:07 -0800 Subject: [PATCH 190/286] Fix the type of the capture passed to LambdaIntroducer::addCapture in RebuildLambdaScopeInfo Previously the type of the variable was being passed, which was causing clang to crash when a non-reference variable was captured by reference or a reference variable was captured by value by a lambda and a block nested inside the lambda body was referencing the variable. Original patch by JF Bastien. rdar://problem/47550338 Differential Revision: https://reviews.llvm.org/D58164 (cherry picked from commit e4dfc9f5bda3171e159f2ff62390c8795d9497e7) --- clang/lib/Sema/SemaDecl.cpp | 3 +- .../CodeGenObjCXX/block-nested-in-lambda.mm | 64 ++++++++++++++++--- 2 files changed, 57 insertions(+), 10 deletions(-) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index d4ba3a8d5cf5c..c96f3764dad1d 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -13601,13 +13601,12 @@ static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator, VarDecl *VD = C.getCapturedVar(); if (VD->isInitCapture()) S.CurrentInstantiationScope->InstantiatedLocal(VD, VD); - QualType CaptureType = VD->getType(); const bool ByRef = C.getCaptureKind() == LCK_ByRef; LSI->addCapture(VD, /*IsBlock*/false, ByRef, /*RefersToEnclosingVariableOrCapture*/true, C.getLocation(), /*EllipsisLoc*/C.isPackExpansion() ? C.getEllipsisLoc() : SourceLocation(), - CaptureType, /*Invalid*/false); + I->getType(), /*Invalid*/false); } else if (C.capturesThis()) { LSI->addThisCapture(/*Nested*/ false, C.getLocation(), I->getType(), diff --git a/clang/test/CodeGenObjCXX/block-nested-in-lambda.mm b/clang/test/CodeGenObjCXX/block-nested-in-lambda.mm index be1ad8117cd25..c7b9a043a9e95 100644 --- a/clang/test/CodeGenObjCXX/block-nested-in-lambda.mm +++ b/clang/test/CodeGenObjCXX/block-nested-in-lambda.mm @@ -1,6 +1,9 @@ -// RUN: %clang_cc1 -triple=x86_64-apple-darwin10 -emit-llvm -std=c++11 -fblocks -fobjc-arc -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple=x86_64-apple-darwin10 -emit-llvm -std=c++14 -fblocks -fobjc-arc -o - %s | FileCheck %s // CHECK: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 } +// CHECK: %[[S:.*]] = type { i32 } +// CHECK: %[[CLASS_ANON_2:.*]] = type { %[[S]]* } +// CHECK: %[[CLASS_ANON_3:.*]] = type { %[[S]] } // CHECK: %[[BLOCK_CAPTURED0:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32*, i32* }>, <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i32*, i32* }>* %[[BLOCK:.*]], i32 0, i32 5 // CHECK: %[[V0:.*]] = getelementptr inbounds %[[LAMBDA_CLASS:.*]], %[[LAMBDA_CLASS]]* %[[THIS:.*]], i32 0, i32 0 @@ -33,7 +36,7 @@ void block_in_lambda(int &s1, int &s2) { // reference. // CHECK-LABEL: define void @_ZN18CaptureByReference5test0Ev( -// CHECK-LABEL: define internal void @"_ZZN18CaptureByReference5test0EvENK3$_1clEv"( +// CHECK-LABEL: define internal void @"_ZZN18CaptureByReference5test0EvENK3$_3clEv"( // CHECK: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8** }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8** }>* %{{.*}}, i32 0, i32 4 // CHECK: store %[[STRUCT_BLOCK_DESCRIPTOR]]* bitcast ({ i64, i64, i8*, i64 }* @"__block_descriptor_40_e5_v8\01?0ls32l8" to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8 @@ -46,10 +49,60 @@ void test0() { // is captured by reference. // CHECK-LABEL: define void @_ZN18CaptureByReference5test1Ev( -// CHECK-LABEL: define internal void @"_ZZN18CaptureByReference5test1EvENK3$_2clEv"( +// CHECK-LABEL: define internal void @"_ZZN18CaptureByReference5test1EvENK3$_4clEv"( // CHECK: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8** }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8** }>* %{{.*}}, i32 0, i32 4 // CHECK: store %[[STRUCT_BLOCK_DESCRIPTOR]]* bitcast ({ i64, i64, i8*, i8*, i8*, i64 }* @"__block_descriptor_56_8_32s40s_e5_v8\01?0l" to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8 +void test1() { + id a = getObj(), b = getObj(), c = getObj(); + [&a, b, c]{ ^{ a = 0; use(b); use(c); }(); }(); +} + +struct S { + int val() const; + int a; + S(); + S(const S&); + S &operator=(const S&); + S(S&&); + S &operator=(S&&); +}; + +S getS(); + +// CHECK: define internal i32 @"_ZZN18CaptureByReference5test2EvENK3$_1clIiEEDaT_"(%[[CLASS_ANON_2]]* %{{.*}}, i32 %{{.*}}) +// CHECK: %[[BLOCK:.*]] = alloca <{ i8*, i32, i32, i8*, %{{.*}}, %[[S]]* }>, align 8 +// CHECK: %[[BLOCK_CAPTURED:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %{{.*}}, %[[S]]* }>, <{ i8*, i32, i32, i8*, %{{.*}}, %[[S]]* }>* %[[BLOCK]], i32 0, i32 5 +// CHECK: %[[V0:.*]] = getelementptr inbounds %[[CLASS_ANON_2]], %[[CLASS_ANON_2]]* %{{.*}}, i32 0, i32 0 +// CHECK: %[[V1:.*]] = load %[[S]]*, %[[S]]** %[[V0]], align 8 +// CHECK: store %[[S]]* %[[V1]], %[[S]]** %[[BLOCK_CAPTURED]], align 8 + +int test2() { + S s; + auto fn = [&](const auto a){ + return ^{ + return s.val(); + }(); + }; + return fn(123); +} + +// CHECK: define internal i32 @"_ZZN18CaptureByReference5test3EvENK3$_2clIiEEDaT_"(%[[CLASS_ANON_3]]* %{{.*}}, i32 %{{.*}}) +// CHECK: %[[BLOCK:.*]] = alloca <{ i8*, i32, i32, i8*, %{{.*}}*, %[[S]] }>, align 8 +// CHECK: %[[BLOCK_CAPTURED:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %{{.*}}*, %[[S]] }>, <{ i8*, i32, i32, i8*, %{{.*}}*, %[[S]] }>* %[[BLOCK]], i32 0, i32 5 +// CHECK: %[[V0:.*]] = getelementptr inbounds %[[CLASS_ANON_3]], %[[CLASS_ANON_3]]* %{{.*}}, i32 0, i32 0 +// CHECK: call void @_ZN18CaptureByReference1SC1ERKS0_(%[[S]]* %[[BLOCK_CAPTURED]], %[[S]]* {{.*}} %[[V0]]) + +int test3() { + const S &s = getS(); + auto fn = [=](const auto a){ + return ^{ + return s.val(); + }(); + }; + return fn(123); +} + // CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_8_32s40s( // CHECK-NOT: call void @llvm.objc.storeStrong( // CHECK: %[[V4:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8** }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8*, i8** }>* %{{.*}}, i32 0, i32 5 @@ -74,9 +127,4 @@ void test0() { // CHECK-NOT: call void @llvm.objc.storeStrong( // CHECK: ret void -void test1() { - id a = getObj(), b = getObj(), c = getObj(); - [&a, b, c]{ ^{ a = 0; use(b); use(c); }(); }(); -} - } From e1771f53f6f6953fe492b95607ce530ecfcfffa5 Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Thu, 9 Apr 2020 16:10:37 -0700 Subject: [PATCH 191/286] Fix a couple of problems caused by merging ThreadPlanStack changes to this branch. --- lldb/source/Target/ThreadPlanStepOut.cpp | 2 +- lldb/source/Target/ThreadPlanStepRange.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lldb/source/Target/ThreadPlanStepOut.cpp b/lldb/source/Target/ThreadPlanStepOut.cpp index f8df89b1414ae..3d79887aee03a 100644 --- a/lldb/source/Target/ThreadPlanStepOut.cpp +++ b/lldb/source/Target/ThreadPlanStepOut.cpp @@ -124,7 +124,7 @@ ThreadPlanStepOut::ThreadPlanStepOut( // Perform some additional validation on the return address. uint32_t permissions = 0; - if (!m_process->GetLoadAddressPermissions(m_return_addr, + if (!m_process.GetLoadAddressPermissions(m_return_addr, permissions)) { LLDB_LOGF(log, "ThreadPlanStepOut(%p): Return address (0x%" PRIx64 ") permissions not found.", static_cast(this), diff --git a/lldb/source/Target/ThreadPlanStepRange.cpp b/lldb/source/Target/ThreadPlanStepRange.cpp index 90cdac5b98099..548d9a78a35a3 100644 --- a/lldb/source/Target/ThreadPlanStepRange.cpp +++ b/lldb/source/Target/ThreadPlanStepRange.cpp @@ -263,7 +263,7 @@ InstructionList *ThreadPlanStepRange::GetInstructionsForAddress( if (!m_instruction_ranges[i]) { // Disassemble the address range given: - ExecutionContext exe_ctx(m_thread.GetProcess()); + ExecutionContext exe_ctx(&m_process); const char *plugin_name = nullptr; const char *flavor = nullptr; const bool prefer_file_cache = true; From 0f8aa955a3112903665f7b33ea10347fd05a1863 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Fri, 6 Mar 2020 11:13:04 -0800 Subject: [PATCH 192/286] Fix test broken by simulator triple changes. (cherry picked from commit 33b696b57acb6f944cbf22bf81274713c803329e) --- .../DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp | 9 +++++++++ .../API/tools/lldb-server/TestAppleSimulatorOSType.py | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp index 1a5d9e21bed34..e9778ba43cae6 100644 --- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp +++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp @@ -399,6 +399,15 @@ bool DynamicLoaderDarwin::JSONImageInformationIntoImageInfo( else if (os_name == "maccatalyst") { image_infos[i].os_type = llvm::Triple::IOS; image_infos[i].os_env = llvm::Triple::MacABI; + } else if (os_name == "iossimulator") { + image_infos[i].os_type = llvm::Triple::IOS; + image_infos[i].os_env = llvm::Triple::Simulator; + } else if (os_name == "tvossimulator") { + image_infos[i].os_type = llvm::Triple::TvOS; + image_infos[i].os_env = llvm::Triple::Simulator; + } else if (os_name == "watchossimulator") { + image_infos[i].os_type = llvm::Triple::WatchOS; + image_infos[i].os_env = llvm::Triple::Simulator; } } if (image->HasKey("min_version_os_sdk")) { diff --git a/lldb/test/API/tools/lldb-server/TestAppleSimulatorOSType.py b/lldb/test/API/tools/lldb-server/TestAppleSimulatorOSType.py index 5ea55c3f64438..86b54dd3e8e5e 100644 --- a/lldb/test/API/tools/lldb-server/TestAppleSimulatorOSType.py +++ b/lldb/test/API/tools/lldb-server/TestAppleSimulatorOSType.py @@ -82,7 +82,7 @@ def check_simulator_ostype(self, sdk, platform, arch='x86_64'): self.assertIsNotNone(process_info) # Check that ostype is correct - self.assertEquals(process_info['ostype'], platform) + self.assertEquals(process_info['ostype'], platform + 'simulator') # Now for dylibs dylib_info_raw = context.get("dylib_info_raw") @@ -97,7 +97,7 @@ def check_simulator_ostype(self, sdk, platform, arch='x86_64'): break self.assertIsNotNone(image_info) - self.assertEquals(image['min_version_os_name'], platform) + self.assertEquals(image['min_version_os_name'], platform + 'simulator') @apple_simulator_test('iphone') From 024743127eb6b99a71ef2db41ef1860a059d6cea Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Fri, 6 Mar 2020 11:13:04 -0800 Subject: [PATCH 193/286] Update debugserver test for new ostype names (cherry picked from commit ae73ab64b66d1889b447303d432f4d217d222def) --- .../test/API/tools/lldb-server/TestAppleSimulatorOSType.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lldb/test/API/tools/lldb-server/TestAppleSimulatorOSType.py b/lldb/test/API/tools/lldb-server/TestAppleSimulatorOSType.py index 86b54dd3e8e5e..2a2d174afeebd 100644 --- a/lldb/test/API/tools/lldb-server/TestAppleSimulatorOSType.py +++ b/lldb/test/API/tools/lldb-server/TestAppleSimulatorOSType.py @@ -105,18 +105,19 @@ def check_simulator_ostype(self, sdk, platform, arch='x86_64'): @skipIfRemote def test_simulator_ostype_ios(self): self.check_simulator_ostype(sdk='iphonesimulator', - platform='ios') + platform='iossimulator') @apple_simulator_test('appletv') @debugserver_test @skipIfRemote def test_simulator_ostype_tvos(self): self.check_simulator_ostype(sdk='appletvsimulator', - platform='tvos') + platform='tvossimulator') @apple_simulator_test('watch') @debugserver_test @skipIfRemote def test_simulator_ostype_watchos(self): self.check_simulator_ostype(sdk='watchsimulator', - platform='watchos', arch='i386') + platform='watchossimulator', + arch='i386') From 106e66474fe71014a162c9ef30136a77b5cc0993 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Tue, 3 Mar 2020 12:54:04 -0800 Subject: [PATCH 194/286] Make Decl::setOwningModuleID() public. (NFC) This API is going to be used by LLDB to recreate owning module information for Decls deserialized from DWARF. Differential Revision: https://reviews.llvm.org/D75560 (cherry picked from commit 2b366e75d41341e7cb2e763b20c4fc8fd3bd4b3c) --- clang/include/clang/AST/Decl.h | 2 ++ clang/include/clang/AST/DeclBase.h | 11 ++++++++++- clang/include/clang/AST/DeclCXX.h | 3 +-- clang/include/clang/AST/DeclTemplate.h | 4 ++++ 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 256daf1c13969..f5f5a0840b4dc 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -3500,6 +3500,7 @@ class EnumDecl : public TagDecl { /// negative enumerators of this enum. (see getNumNegativeBits) void setNumNegativeBits(unsigned Num) { EnumDeclBits.NumNegativeBits = Num; } +public: /// True if this tag declaration is a scoped enumeration. Only /// possible in C++11 mode. void setScoped(bool Scoped = true) { EnumDeclBits.IsScoped = Scoped; } @@ -3516,6 +3517,7 @@ class EnumDecl : public TagDecl { /// Microsoft-style enumeration with a fixed underlying type. void setFixed(bool Fixed = true) { EnumDeclBits.IsFixed = Fixed; } +private: /// True if a valid hash is stored in ODRHash. bool hasODRHash() const { return EnumDeclBits.HasODRHash; } void setHasODRHash(bool Hash = true) { EnumDeclBits.HasODRHash = Hash; } diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index 6dcebb4c5807b..dd639dec9ef02 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -626,7 +626,16 @@ class alignas(8) Decl { setModuleOwnershipKind(ModuleOwnershipKind::ModulePrivate); } - /// Set the owning module ID. +public: + /// Set the FromASTFile flag. This indicates that this declaration + /// was deserialized and not parsed from source code and enables + /// features such as module ownership information. + void setFromASTFile() { + FromASTFile = true; + } + + /// Set the owning module ID. This may only be called for + /// deserialized Decls. void setOwningModuleID(unsigned ID) { assert(isFromASTFile() && "Only works on a deserialized declaration"); *((unsigned*)this - 2) = ID; diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 7e8b27626af31..c2f84f1887cd2 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -2688,8 +2688,6 @@ class CXXConversionDecl : public CXXMethodDecl { ExplicitSpecifier ExplicitSpec; - void setExplicitSpecifier(ExplicitSpecifier ES) { ExplicitSpec = ES; } - public: friend class ASTDeclReader; friend class ASTDeclWriter; @@ -2711,6 +2709,7 @@ class CXXConversionDecl : public CXXMethodDecl { /// Return true if the declartion is already resolved to be explicit. bool isExplicit() const { return getExplicitSpecifier().isExplicit(); } + void setExplicitSpecifier(ExplicitSpecifier ES) { ExplicitSpec = ES; } /// Returns the type that this conversion function is converting to. QualType getConversionType() const { diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index 8b2c271fbf25c..88579beaafe0c 100755 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -1730,6 +1730,10 @@ class ClassTemplateSpecializationDecl return *TemplateArgs; } + void setTemplateArgs(TemplateArgumentList *Args) { + TemplateArgs = Args; + } + /// Determine the kind of specialization that this /// declaration represents. TemplateSpecializationKind getSpecializationKind() const { From 859ee788775f51869b11942ea7c4477e0ae73127 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Tue, 3 Mar 2020 16:05:23 -0800 Subject: [PATCH 195/286] Add debug info support for Swift/Clang APINotes. In order for dsymutil to collect .apinotes files (which capture attributes such as nullability, Swift import names, and availability), I want to propose adding an apinotes: field to DIModule that gets translated into a DW_AT_LLVM_apinotes (path) nested inside DW_TAG_module. This will be primarily used by LLDB to indirectly extract the Swift names of Clang declarations that were deserialized from DWARF. Differential Revision: https://reviews.llvm.org/D75585 (cherry picked from commit d5180ea134796f96b0c6c4ab23c592d58f25733d) --- llvm/include/llvm/BinaryFormat/Dwarf.def | 1 + 1 file changed, 1 insertion(+) diff --git a/llvm/include/llvm/BinaryFormat/Dwarf.def b/llvm/include/llvm/BinaryFormat/Dwarf.def index e50ae58ddca9a..c31c5a750db87 100644 --- a/llvm/include/llvm/BinaryFormat/Dwarf.def +++ b/llvm/include/llvm/BinaryFormat/Dwarf.def @@ -420,6 +420,7 @@ HANDLE_DW_AT(0x3e06, APPLE_ptrauth_extra_discriminator, 0, LLVM) HANDLE_DW_AT(0x3e07, LLVM_apinotes, 0, APPLE) // Apple extensions. + HANDLE_DW_AT(0x3fe1, APPLE_optimized, 0, APPLE) HANDLE_DW_AT(0x3fe2, APPLE_flags, 0, APPLE) HANDLE_DW_AT(0x3fe3, APPLE_isa, 0, APPLE) From 960a8941e6bc893138c23fd6db3884aa55d0641e Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Wed, 11 Mar 2020 19:30:11 -0700 Subject: [PATCH 196/286] Add newly-missing include (cherry picked from commit cd4c1adabeae8ea2939ee2d00d9d57aba3767960) --- lldb/unittests/Host/HostInfoTest.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/unittests/Host/HostInfoTest.cpp b/lldb/unittests/Host/HostInfoTest.cpp index c332606a4dad2..450cb9edc5cd6 100644 --- a/lldb/unittests/Host/HostInfoTest.cpp +++ b/lldb/unittests/Host/HostInfoTest.cpp @@ -11,6 +11,7 @@ #include "TestingSupport/TestUtilities.h" #include "lldb/Host/FileSystem.h" #include "lldb/lldb-defines.h" +#include "llvm/Support/Host.h" #include "gtest/gtest.h" using namespace lldb_private; From b85af127d3bafb2a2a17f2a0f44e46425a3605a2 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Wed, 11 Mar 2020 21:32:12 -0700 Subject: [PATCH 197/286] Revert "Update debugserver test for new ostype names" I accidentally commited this while cherry-picking commits out of my reflog. This reverts commit ae73ab64b66d1889b447303d432f4d217d222def. (cherry picked from commit 5161194fad8cdd0b496c63c410855290c5e5190b) --- .../test/API/tools/lldb-server/TestAppleSimulatorOSType.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lldb/test/API/tools/lldb-server/TestAppleSimulatorOSType.py b/lldb/test/API/tools/lldb-server/TestAppleSimulatorOSType.py index 2a2d174afeebd..86b54dd3e8e5e 100644 --- a/lldb/test/API/tools/lldb-server/TestAppleSimulatorOSType.py +++ b/lldb/test/API/tools/lldb-server/TestAppleSimulatorOSType.py @@ -105,19 +105,18 @@ def check_simulator_ostype(self, sdk, platform, arch='x86_64'): @skipIfRemote def test_simulator_ostype_ios(self): self.check_simulator_ostype(sdk='iphonesimulator', - platform='iossimulator') + platform='ios') @apple_simulator_test('appletv') @debugserver_test @skipIfRemote def test_simulator_ostype_tvos(self): self.check_simulator_ostype(sdk='appletvsimulator', - platform='tvossimulator') + platform='tvos') @apple_simulator_test('watch') @debugserver_test @skipIfRemote def test_simulator_ostype_watchos(self): self.check_simulator_ostype(sdk='watchsimulator', - platform='watchossimulator', - arch='i386') + platform='watchos', arch='i386') From 014186928718c016e8b16172deb1486cfcb60939 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Mon, 16 Mar 2020 08:05:46 -0700 Subject: [PATCH 198/286] Fix typo in parameter name. (cherry picked from commit 5c261c9c452959985de19540c168b224af24e2d3) --- llvm/include/llvm-c/DebugInfo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/include/llvm-c/DebugInfo.h b/llvm/include/llvm-c/DebugInfo.h index 61702253f69b8..cdf5f5a0cca86 100644 --- a/llvm/include/llvm-c/DebugInfo.h +++ b/llvm/include/llvm-c/DebugInfo.h @@ -296,7 +296,7 @@ LLVMDIBuilderCreateModule(LLVMDIBuilderRef Builder, LLVMMetadataRef ParentScope, const char *Name, size_t NameLen, const char *ConfigMacros, size_t ConfigMacrosLen, const char *IncludePath, size_t IncludePathLen, - const char *APINotestFile, size_t APINotestFileLen); + const char *APINotesFile, size_t APINotesFileLen); /** * Creates a new descriptor for a namespace with the specified parent scope. From 67d07f7dc7e66ad00f3158f00ef003511b28dec7 Mon Sep 17 00:00:00 2001 From: Raphael Isemann Date: Tue, 11 Feb 2020 08:19:59 +0100 Subject: [PATCH 199/286] [lldb][NFC] Refactor TypeSystemClang::GetTypeName (cherry picked from commit 14ecbd7b8ded18af6c95f6a9957da541d1ec0e80) --- .../TypeSystem/Clang/TypeSystemClang.cpp | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index d55ace2762bd5..e32217fe7a5cd 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -3493,21 +3493,20 @@ bool TypeSystemClang::GetCompleteType(lldb::opaque_compiler_type_t type) { } ConstString TypeSystemClang::GetTypeName(lldb::opaque_compiler_type_t type) { - std::string type_name; - if (type) { - clang::PrintingPolicy printing_policy(getASTContext().getPrintingPolicy()); - clang::QualType qual_type(GetQualType(type)); - printing_policy.SuppressTagKeyword = true; - const clang::TypedefType *typedef_type = - qual_type->getAs(); - if (typedef_type) { - const clang::TypedefNameDecl *typedef_decl = typedef_type->getDecl(); - type_name = typedef_decl->getQualifiedNameAsString(); - } else { - type_name = qual_type.getAsString(printing_policy); - } + if (!type) + return ConstString(); + + clang::QualType qual_type(GetQualType(type)); + + // For a typedef just return the qualified name. + if (const auto *typedef_type = qual_type->getAs()) { + const clang::TypedefNameDecl *typedef_decl = typedef_type->getDecl(); + return ConstString(typedef_decl->getQualifiedNameAsString()); } - return ConstString(type_name); + + clang::PrintingPolicy printing_policy(getASTContext().getPrintingPolicy()); + printing_policy.SuppressTagKeyword = true; + return ConstString(qual_type.getAsString(printing_policy)); } ConstString From ea9bad1f2cc5c9f7dcc0b2bba10fb7df0237c2f7 Mon Sep 17 00:00:00 2001 From: Raphael Isemann Date: Tue, 14 Jan 2020 13:06:31 +0100 Subject: [PATCH 200/286] [lldb][NFC] Make name parameter in AddMethodToCXXRecordType a StringRef (cherry picked from commit 3f944a8b8ca895667f04748f62d350f07ee1416b) Conflicts: lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp --- .../Plugins/TypeSystem/Clang/TypeSystemClang.cpp | 13 ++++++------- .../Plugins/TypeSystem/Clang/TypeSystemClang.h | 12 +++++------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index e32217fe7a5cd..f8c7f5a6dfd12 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -7132,12 +7132,11 @@ clang::VarDecl *TypeSystemClang::AddVariableToRecordType( } clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType( - lldb::opaque_compiler_type_t type, const char *name, const char *mangled_name, - const CompilerType &method_clang_type, lldb::AccessType access, - bool is_virtual, bool is_static, bool is_inline, bool is_explicit, - bool is_attr_used, bool is_artificial) { - if (!type || !method_clang_type.IsValid() || name == nullptr || - name[0] == '\0') + lldb::opaque_compiler_type_t type, llvm::StringRef name, + const char *mangled_name, const CompilerType &method_clang_type, + lldb::AccessType access, bool is_virtual, bool is_static, bool is_inline, + bool is_explicit, bool is_attr_used, bool is_artificial) { + if (!type || !method_clang_type.IsValid() || name.empty()) return nullptr; clang::QualType record_qual_type(GetCanonicalQualType(type)); @@ -7178,7 +7177,7 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType( nullptr /*expr*/, is_explicit ? clang::ExplicitSpecKind::ResolvedTrue : clang::ExplicitSpecKind::ResolvedFalse); - if (name[0] == '~') { + if (name.startswith("~")) { cxx_dtor_decl = clang::CXXDestructorDecl::Create( getASTContext(), cxx_record_decl, clang::SourceLocation(), clang::DeclarationNameInfo( diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index 441732ad54f62..c38f6f7347f9e 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -774,13 +774,11 @@ class TypeSystemClang : public TypeSystem { const CompilerType &var_type, lldb::AccessType access); - clang::CXXMethodDecl * - AddMethodToCXXRecordType(lldb::opaque_compiler_type_t type, const char *name, - const char *mangled_name, - const CompilerType &method_type, - lldb::AccessType access, bool is_virtual, - bool is_static, bool is_inline, bool is_explicit, - bool is_attr_used, bool is_artificial); + clang::CXXMethodDecl *AddMethodToCXXRecordType( + lldb::opaque_compiler_type_t type, llvm::StringRef name, + const char *mangled_name, const CompilerType &method_type, + lldb::AccessType access, bool is_virtual, bool is_static, bool is_inline, + bool is_explicit, bool is_attr_used, bool is_artificial); void AddMethodOverridesForCXXRecordType(lldb::opaque_compiler_type_t type); From b3eb7b3faf42068732f03781f297764e95d0da38 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Thu, 5 Mar 2020 15:46:28 -0800 Subject: [PATCH 201/286] Switch to TypeSystemClang over to CreateDeserialized() (NFC) which is the more appropriate API for its use-case. Differential Revision: https://reviews.llvm.org/D75715 (cherry picked from commit 90a2fbdb044bcf285646e79f3b096ccb196f6d02) Conflicts: lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp --- clang/include/clang/AST/DeclCXX.h | 22 +- clang/include/clang/AST/DeclTemplate.h | 4 + .../TypeSystem/Clang/TypeSystemClang.cpp | 369 ++++++++++-------- 3 files changed, 221 insertions(+), 174 deletions(-) diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index c2f84f1887cd2..3fd329393ec82 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -2387,17 +2387,6 @@ class CXXConstructorDecl final : ExplicitSpecKind::ResolvedFalse); } - void setExplicitSpecifier(ExplicitSpecifier ES) { - assert((!ES.getExpr() || - CXXConstructorDeclBits.HasTrailingExplicitSpecifier) && - "cannot set this explicit specifier. no trail-allocated space for " - "explicit"); - if (ES.getExpr()) - *getCanonicalDecl()->getTrailingObjects() = ES; - else - CXXConstructorDeclBits.IsSimpleExplicit = ES.isExplicit(); - } - enum TraillingAllocKind { TAKInheritsConstructor = 1, TAKHasTailExplicit = 1 << 1, @@ -2422,6 +2411,17 @@ class CXXConstructorDecl final ConstexprSpecKind ConstexprKind, InheritedConstructor Inherited = InheritedConstructor()); + void setExplicitSpecifier(ExplicitSpecifier ES) { + assert((!ES.getExpr() || + CXXConstructorDeclBits.HasTrailingExplicitSpecifier) && + "cannot set this explicit specifier. no trail-allocated space for " + "explicit"); + if (ES.getExpr()) + *getCanonicalDecl()->getTrailingObjects() = ES; + else + CXXConstructorDeclBits.IsSimpleExplicit = ES.isExplicit(); + } + ExplicitSpecifier getExplicitSpecifier() { return getCanonicalDecl()->getExplicitSpecifierInternal(); } diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index 88579beaafe0c..a974c8baad9b9 100755 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -1766,6 +1766,10 @@ class ClassTemplateSpecializationDecl getTemplateSpecializationKind()); } + void setSpecializedTemplate(ClassTemplateDecl *Specialized) { + SpecializedTemplate = Specialized; + } + void setSpecializationKind(TemplateSpecializationKind TSK) { SpecializationKind = TSK; } diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index f8c7f5a6dfd12..fa12ef13f86d9 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -1197,10 +1197,11 @@ CompilerType TypeSystemClang::CreateRecordType(DeclContext *decl_ctx, // complete definition just in case. bool has_name = !name.empty(); - - CXXRecordDecl *decl = CXXRecordDecl::Create( - ast, (TagDecl::TagKind)kind, decl_ctx, SourceLocation(), SourceLocation(), - has_name ? &ast.Idents.get(name) : nullptr); + CXXRecordDecl *decl = CXXRecordDecl::CreateDeserialized(ast, 0); + decl->setTagKind(static_cast(kind)); + decl->setDeclContext(decl_ctx); + if (has_name) + decl->setDeclName(&ast.Idents.get(name)); if (!has_name) { // In C++ a lambda is also represented as an unnamed class. This is @@ -1318,9 +1319,12 @@ clang::FunctionTemplateDecl *TypeSystemClang::CreateFunctionTemplateDecl( TemplateParameterList *template_param_list = CreateTemplateParameterList( ast, template_param_infos, template_param_decls); - FunctionTemplateDecl *func_tmpl_decl = FunctionTemplateDecl::Create( - ast, decl_ctx, func_decl->getLocation(), func_decl->getDeclName(), - template_param_list, func_decl); + FunctionTemplateDecl *func_tmpl_decl = + FunctionTemplateDecl::CreateDeserialized(ast, 0); + func_tmpl_decl->setDeclContext(decl_ctx); + func_tmpl_decl->setLocation(func_decl->getLocation()); + func_tmpl_decl->setDeclName(func_decl->getDeclName()); + func_tmpl_decl->init(func_decl, template_param_list); for (size_t i = 0, template_param_decl_count = template_param_decls.size(); i < template_param_decl_count; ++i) { @@ -1371,11 +1375,11 @@ ClassTemplateDecl *TypeSystemClang::CreateClassTemplateDecl( TemplateParameterList *template_param_list = CreateTemplateParameterList( ast, template_param_infos, template_param_decls); - CXXRecordDecl *template_cxx_decl = CXXRecordDecl::Create( - ast, (TagDecl::TagKind)kind, - decl_ctx, // What decl context do we use here? TU? The actual decl - // context? - SourceLocation(), SourceLocation(), &identifier_info); + CXXRecordDecl *template_cxx_decl = CXXRecordDecl::CreateDeserialized(ast, 0); + template_cxx_decl->setTagKind(static_cast(kind)); + // What decl context do we use here? TU? The actual decl context? + template_cxx_decl->setDeclContext(decl_ctx); + template_cxx_decl->setDeclName(decl_name); for (size_t i = 0, template_param_decl_count = template_param_decls.size(); i < template_param_decl_count; ++i) { @@ -1387,11 +1391,11 @@ ClassTemplateDecl *TypeSystemClang::CreateClassTemplateDecl( // template_cxx_decl->startDefinition(); // template_cxx_decl->completeDefinition(); - class_template_decl = ClassTemplateDecl::Create( - ast, - decl_ctx, // What decl context do we use here? TU? The actual decl - // context? - SourceLocation(), decl_name, template_param_list, template_cxx_decl); + class_template_decl = ClassTemplateDecl::CreateDeserialized(ast, 0); + // What decl context do we use here? TU? The actual decl context? + class_template_decl->setDeclContext(decl_ctx); + class_template_decl->setDeclName(decl_name); + class_template_decl->init(template_cxx_decl, template_param_list); template_cxx_decl->setDescribedClassTemplate(class_template_decl); if (class_template_decl) { @@ -1450,9 +1454,16 @@ TypeSystemClang::CreateClassTemplateSpecializationDecl( ast, template_param_infos.packed_args->args); } ClassTemplateSpecializationDecl *class_template_specialization_decl = - ClassTemplateSpecializationDecl::Create( - ast, (TagDecl::TagKind)kind, decl_ctx, SourceLocation(), - SourceLocation(), class_template_decl, args, nullptr); + ClassTemplateSpecializationDecl::CreateDeserialized(ast, 0); + class_template_specialization_decl->setTagKind( + static_cast(kind)); + class_template_specialization_decl->setDeclContext(decl_ctx); + class_template_specialization_decl->setInstantiationOf(class_template_decl); + class_template_specialization_decl->setTemplateArgs( + TemplateArgumentList::CreateCopy(ast, args)); + ast.getTypeDeclType(class_template_specialization_decl, nullptr); + class_template_specialization_decl->setDeclName( + class_template_decl->getDeclName()); class_template_specialization_decl->setSpecializationKind( TSK_ExplicitSpecialization); @@ -1581,11 +1592,11 @@ CompilerType TypeSystemClang::CreateObjCClass(llvm::StringRef name, if (decl_ctx == nullptr) decl_ctx = ast.getTranslationUnitDecl(); - ObjCInterfaceDecl *decl = ObjCInterfaceDecl::Create( - ast, decl_ctx, SourceLocation(), &ast.Idents.get(name), nullptr, nullptr, - SourceLocation(), - /*isForwardDecl,*/ - isInternal); + ObjCInterfaceDecl *decl = ObjCInterfaceDecl::CreateDeserialized(ast, 0); + decl->setDeclContext(decl_ctx); + decl->setDeclName(&ast.Idents.get(name)); + /*isForwardDecl,*/ + decl->setImplicit(isInternal); if (decl && metadata) SetMetadata(decl, *metadata); @@ -1623,7 +1634,7 @@ TypeSystemClang::GetNumBaseClasses(const CXXRecordDecl *cxx_record_decl, #pragma mark Namespace Declarations NamespaceDecl *TypeSystemClang::GetUniqueNamespaceDeclaration( - const char *name, DeclContext *decl_ctx, bool is_inline) { + const char *name, clang::DeclContext *decl_ctx, bool is_inline) { NamespaceDecl *namespace_decl = nullptr; ASTContext &ast = getASTContext(); TranslationUnitDecl *translation_unit_decl = ast.getTranslationUnitDecl(); @@ -1684,9 +1695,10 @@ NamespaceDecl *TypeSystemClang::GetUniqueNamespaceDeclaration( clang::BlockDecl * TypeSystemClang::CreateBlockDeclaration(clang::DeclContext *ctx) { - if (ctx != nullptr) { + if (ctx) { clang::BlockDecl *decl = - clang::BlockDecl::Create(getASTContext(), ctx, clang::SourceLocation()); + clang::BlockDecl::CreateDeserialized(getASTContext(), 0); + decl->setDeclContext(ctx); ctx->addDecl(decl); return decl; } @@ -1712,15 +1724,16 @@ clang::DeclContext *FindLCABetweenDecls(clang::DeclContext *left, clang::UsingDirectiveDecl *TypeSystemClang::CreateUsingDirectiveDeclaration( clang::DeclContext *decl_ctx, clang::NamespaceDecl *ns_decl) { - if (decl_ctx != nullptr && ns_decl != nullptr) { + if (decl_ctx && ns_decl) { auto *translation_unit = getASTContext().getTranslationUnitDecl(); clang::UsingDirectiveDecl *using_decl = clang::UsingDirectiveDecl::Create( - getASTContext(), decl_ctx, clang::SourceLocation(), - clang::SourceLocation(), clang::NestedNameSpecifierLoc(), - clang::SourceLocation(), ns_decl, - FindLCABetweenDecls(decl_ctx, ns_decl, translation_unit)); - decl_ctx->addDecl(using_decl); - return using_decl; + getASTContext(), decl_ctx, clang::SourceLocation(), + clang::SourceLocation(), clang::NestedNameSpecifierLoc(), + clang::SourceLocation(), ns_decl, + FindLCABetweenDecls(decl_ctx, ns_decl, + translation_unit)); + decl_ctx->addDecl(using_decl); + return using_decl; } return nullptr; } @@ -1744,12 +1757,13 @@ TypeSystemClang::CreateUsingDeclaration(clang::DeclContext *current_decl_ctx, clang::VarDecl *TypeSystemClang::CreateVariableDeclaration( clang::DeclContext *decl_context, const char *name, clang::QualType type) { - if (decl_context != nullptr) { - clang::VarDecl *var_decl = clang::VarDecl::Create( - getASTContext(), decl_context, clang::SourceLocation(), - clang::SourceLocation(), - name && name[0] ? &getASTContext().Idents.getOwn(name) : nullptr, type, - nullptr, clang::SC_None); + if (decl_context) { + clang::VarDecl *var_decl = + clang::VarDecl::CreateDeserialized(getASTContext(), 0); + var_decl->setDeclContext(decl_context); + if (name && name[0]) + var_decl->setDeclName(&getASTContext().Idents.getOwn(name)); + var_decl->setType(type); var_decl->setAccess(clang::AS_public); decl_context->addDecl(var_decl); return var_decl; @@ -1873,11 +1887,15 @@ FunctionDecl *TypeSystemClang::CreateFunctionDeclaration( clang::DeclarationName declarationName = GetDeclarationName(name, function_clang_type); - func_decl = FunctionDecl::Create( - ast, decl_ctx, SourceLocation(), SourceLocation(), declarationName, - ClangUtil::GetQualType(function_clang_type), nullptr, - (clang::StorageClass)storage, is_inline, hasWrittenPrototype, - isConstexprSpecified ? CSK_constexpr : CSK_unspecified); + func_decl = FunctionDecl::CreateDeserialized(ast, 0); + func_decl->setDeclContext(decl_ctx); + func_decl->setDeclName(declarationName); + func_decl->setType(ClangUtil::GetQualType(function_clang_type)); + func_decl->setStorageClass(static_cast(storage)); + func_decl->setInlineSpecified(is_inline); + func_decl->setHasWrittenPrototype(hasWrittenPrototype); + func_decl->setConstexprKind(isConstexprSpecified ? CSK_constexpr + : CSK_unspecified); if (func_decl) decl_ctx->addDecl(func_decl); @@ -1931,11 +1949,12 @@ ParmVarDecl *TypeSystemClang::CreateParameterDeclaration( clang::DeclContext *decl_ctx, const char *name, const CompilerType ¶m_type, int storage, bool add_decl) { ASTContext &ast = getASTContext(); - auto *decl = - ParmVarDecl::Create(ast, decl_ctx, SourceLocation(), SourceLocation(), - name && name[0] ? &ast.Idents.get(name) : nullptr, - ClangUtil::GetQualType(param_type), nullptr, - (clang::StorageClass)storage, nullptr); + auto *decl = ParmVarDecl::CreateDeserialized(ast, 0); + decl->setDeclContext(decl_ctx); + if (name && name[0]) + decl->setDeclName(&ast.Idents.get(name)); + decl->setType(ClangUtil::GetQualType(param_type)); + decl->setStorageClass(static_cast(storage)); if (add_decl) decl_ctx->addDecl(decl); @@ -2034,7 +2053,6 @@ TypeSystemClang::CreateEnumerationType(const char *name, DeclContext *decl_ctx, // TODO: ask about these... // const bool IsFixed = false; - EnumDecl *enum_decl = EnumDecl::Create( ast, decl_ctx, SourceLocation(), SourceLocation(), name && name[0] ? &ast.Idents.get(name) : nullptr, nullptr, @@ -4243,10 +4261,11 @@ CompilerType TypeSystemClang::CreateTypedefType( if (decl_ctx == nullptr) decl_ctx = ast->getASTContext().getTranslationUnitDecl(); - clang::TypedefDecl *decl = clang::TypedefDecl::Create( - clang_ast, decl_ctx, clang::SourceLocation(), clang::SourceLocation(), - &clang_ast.Idents.get(typedef_name), - clang_ast.getTrivialTypeSourceInfo(qual_type)); + clang::TypedefDecl *decl = + clang::TypedefDecl::CreateDeserialized(clang_ast, 0); + decl->setDeclContext(decl_ctx); + decl->setDeclName(&clang_ast.Idents.get(typedef_name)); + decl->setTypeSourceInfo(clang_ast.getTrivialTypeSourceInfo(qual_type)); decl->setAccess(clang::AS_public); // TODO respect proper access specifier @@ -4349,10 +4368,11 @@ TypeSystemClang::CreateTypedef(lldb::opaque_compiler_type_t type, if (decl_ctx == nullptr) decl_ctx = getASTContext().getTranslationUnitDecl(); - clang::TypedefDecl *decl = clang::TypedefDecl::Create( - clang_ast, decl_ctx, clang::SourceLocation(), clang::SourceLocation(), - &clang_ast.Idents.get(typedef_name), - clang_ast.getTrivialTypeSourceInfo(qual_type)); + clang::TypedefDecl *decl = + clang::TypedefDecl::CreateDeserialized(clang_ast, 0); + decl->setDeclContext(decl_ctx); + decl->setDeclName(&clang_ast.Idents.get(typedef_name)); + decl->setTypeSourceInfo(clang_ast.getTrivialTypeSourceInfo(qual_type)); clang::TagDecl *tdecl = nullptr; if (!qual_type.isNull()) { @@ -6903,15 +6923,12 @@ clang::FieldDecl *TypeSystemClang::AddFieldToRecordType( clang::RecordDecl *record_decl = ast->GetAsRecordDecl(type); if (record_decl) { - field = clang::FieldDecl::Create( - clang_ast, record_decl, clang::SourceLocation(), - clang::SourceLocation(), - ident, // Identifier - ClangUtil::GetQualType(field_clang_type), // Field type - nullptr, // TInfo * - bit_width, // BitWidth - false, // Mutable - clang::ICIS_NoInit); // HasInit + field = clang::FieldDecl::CreateDeserialized(clang_ast, 0); + field->setDeclContext(record_decl); + field->setDeclName(ident); + field->setType(ClangUtil::GetQualType(field_clang_type)); + if (bit_width) + field->setBitWidth(bit_width); if (name.empty()) { // Determine whether this field corresponds to an anonymous struct or @@ -6946,14 +6963,15 @@ clang::FieldDecl *TypeSystemClang::AddFieldToRecordType( field_clang_type.GetCompleteType(); - field = clang::ObjCIvarDecl::Create( - clang_ast, class_interface_decl, clang::SourceLocation(), - clang::SourceLocation(), - ident, // Identifier - ClangUtil::GetQualType(field_clang_type), // Field type - nullptr, // TypeSourceInfo * - ConvertAccessTypeToObjCIvarAccessControl(access), bit_width, - is_synthesized); + auto ivar = clang::ObjCIvarDecl::CreateDeserialized(clang_ast, 0); + ivar->setDeclContext(class_interface_decl); + ivar->setDeclName(ident); + ivar->setType(ClangUtil::GetQualType(field_clang_type)); + ivar->setAccessControl(ConvertAccessTypeToObjCIvarAccessControl(access)); + if (bit_width) + ivar->setBitWidth(bit_width); + ivar->setSynthesize(is_synthesized); + field = ivar; if (field) { class_interface_decl->addDecl(field); @@ -7108,15 +7126,11 @@ clang::VarDecl *TypeSystemClang::AddVariableToRecordType( if (!name.empty()) ident = &ast->getASTContext().Idents.get(name); - var_decl = clang::VarDecl::Create( - ast->getASTContext(), // ASTContext & - record_decl, // DeclContext * - clang::SourceLocation(), // clang::SourceLocation StartLoc - clang::SourceLocation(), // clang::SourceLocation IdLoc - ident, // clang::IdentifierInfo * - ClangUtil::GetQualType(var_type), // Variable clang::QualType - nullptr, // TypeSourceInfo * - clang::SC_Static); // StorageClass + var_decl = clang::VarDecl::CreateDeserialized(ast->getASTContext(), 0); + var_decl->setDeclContext(record_decl); + var_decl->setDeclName(ident); + var_decl->setType(ClangUtil::GetQualType(var_type)); + var_decl->setStorageClass(clang::SC_Static); if (!var_decl) return nullptr; @@ -7174,29 +7188,34 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType( return nullptr; // skip everything artificial const clang::ExplicitSpecifier explicit_spec( - nullptr /*expr*/, is_explicit - ? clang::ExplicitSpecKind::ResolvedTrue - : clang::ExplicitSpecKind::ResolvedFalse); + nullptr /*expr*/, is_explicit ? clang::ExplicitSpecKind::ResolvedTrue + : clang::ExplicitSpecKind::ResolvedFalse); + if (name.startswith("~")) { - cxx_dtor_decl = clang::CXXDestructorDecl::Create( - getASTContext(), cxx_record_decl, clang::SourceLocation(), - clang::DeclarationNameInfo( - getASTContext().DeclarationNames.getCXXDestructorName( - getASTContext().getCanonicalType(record_qual_type)), - clang::SourceLocation()), - method_qual_type, nullptr, is_inline, is_artificial, - ConstexprSpecKind::CSK_unspecified); + cxx_dtor_decl = + clang::CXXDestructorDecl::CreateDeserialized(getASTContext(), 0); + cxx_dtor_decl->setDeclContext(cxx_record_decl); + cxx_dtor_decl->setDeclName( + getASTContext().DeclarationNames.getCXXDestructorName( + getASTContext().getCanonicalType(record_qual_type))); + cxx_dtor_decl->setType(method_qual_type); + cxx_dtor_decl->setImplicit(is_artificial); + cxx_dtor_decl->setInlineSpecified(is_inline); + cxx_dtor_decl->setConstexprKind(CSK_unspecified); cxx_method_decl = cxx_dtor_decl; } else if (decl_name == cxx_record_decl->getDeclName()) { - cxx_ctor_decl = clang::CXXConstructorDecl::Create( - getASTContext(), cxx_record_decl, clang::SourceLocation(), - clang::DeclarationNameInfo( - getASTContext().DeclarationNames.getCXXConstructorName( - getASTContext().getCanonicalType(record_qual_type)), - clang::SourceLocation()), - method_qual_type, - nullptr, // TypeSourceInfo * - explicit_spec, is_inline, is_artificial, CSK_unspecified); + cxx_ctor_decl = clang::CXXConstructorDecl::CreateDeserialized( + getASTContext(), 0, 0); + cxx_ctor_decl->setDeclContext(cxx_record_decl); + cxx_ctor_decl->setDeclName( + getASTContext().DeclarationNames.getCXXConstructorName( + getASTContext().getCanonicalType(record_qual_type))); + cxx_ctor_decl->setType(method_qual_type); + cxx_ctor_decl->setImplicit(is_artificial); + cxx_ctor_decl->setInlineSpecified(is_inline); + cxx_ctor_decl->setConstexprKind(CSK_unspecified); + cxx_ctor_decl->setNumCtorInitializers(0); + cxx_ctor_decl->setExplicitSpecifier(explicit_spec); cxx_method_decl = cxx_ctor_decl; } else { clang::StorageClass SC = is_static ? clang::SC_Static : clang::SC_None; @@ -7212,36 +7231,41 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType( if (!TypeSystemClang::CheckOverloadedOperatorKindParameterCount( is_method, op_kind, num_params)) return nullptr; - cxx_method_decl = clang::CXXMethodDecl::Create( - getASTContext(), cxx_record_decl, clang::SourceLocation(), - clang::DeclarationNameInfo( - getASTContext().DeclarationNames.getCXXOperatorName(op_kind), - clang::SourceLocation()), - method_qual_type, - nullptr, // TypeSourceInfo * - SC, is_inline, CSK_unspecified, clang::SourceLocation()); + cxx_method_decl = + clang::CXXMethodDecl::CreateDeserialized(getASTContext(), 0); + cxx_method_decl->setDeclContext(cxx_record_decl); + cxx_method_decl->setDeclName( + getASTContext().DeclarationNames.getCXXOperatorName(op_kind)); + cxx_method_decl->setType(method_qual_type); + cxx_method_decl->setStorageClass(SC); + cxx_method_decl->setInlineSpecified(is_inline); + cxx_method_decl->setConstexprKind(CSK_unspecified); } else if (num_params == 0) { // Conversion operators don't take params... - cxx_method_decl = clang::CXXConversionDecl::Create( - getASTContext(), cxx_record_decl, clang::SourceLocation(), - clang::DeclarationNameInfo( - getASTContext().DeclarationNames.getCXXConversionFunctionName( - getASTContext().getCanonicalType( - function_type->getReturnType())), - clang::SourceLocation()), - method_qual_type, - nullptr, // TypeSourceInfo * - is_inline, explicit_spec, CSK_unspecified, clang::SourceLocation()); + auto *cxx_conversion_decl = + clang::CXXConversionDecl::CreateDeserialized(getASTContext(), 0); + cxx_conversion_decl->setDeclContext(cxx_record_decl); + cxx_conversion_decl->setDeclName( + getASTContext().DeclarationNames.getCXXConversionFunctionName( + getASTContext().getCanonicalType( + function_type->getReturnType()))); + cxx_conversion_decl->setType(method_qual_type); + cxx_conversion_decl->setInlineSpecified(is_inline); + cxx_conversion_decl->setExplicitSpecifier(explicit_spec); + cxx_conversion_decl->setConstexprKind(CSK_unspecified); + cxx_method_decl = cxx_conversion_decl; } } if (cxx_method_decl == nullptr) { - cxx_method_decl = clang::CXXMethodDecl::Create( - getASTContext(), cxx_record_decl, clang::SourceLocation(), - clang::DeclarationNameInfo(decl_name, clang::SourceLocation()), - method_qual_type, - nullptr, // TypeSourceInfo * - SC, is_inline, CSK_unspecified, clang::SourceLocation()); + cxx_method_decl = + clang::CXXMethodDecl::CreateDeserialized(getASTContext(), 0); + cxx_method_decl->setDeclContext(cxx_record_decl); + cxx_method_decl->setDeclName(decl_name); + cxx_method_decl->setType(method_qual_type); + cxx_method_decl->setInlineSpecified(is_inline); + cxx_method_decl->setStorageClass(SC); + cxx_method_decl->setConstexprKind(CSK_unspecified); } } @@ -7412,15 +7436,14 @@ bool TypeSystemClang::AddObjCClassProperty( prop_type_source = clang_ast.getTrivialTypeSourceInfo( ClangUtil::GetQualType(property_clang_type)); - clang::ObjCPropertyDecl *property_decl = clang::ObjCPropertyDecl::Create( - clang_ast, class_interface_decl, - clang::SourceLocation(), // Source Location - &clang_ast.Idents.get(property_name), - clang::SourceLocation(), // Source Location for AT - clang::SourceLocation(), // Source location for ( - ivar_decl ? ivar_decl->getType() - : ClangUtil::GetQualType(property_clang_type), - prop_type_source); + clang::ObjCPropertyDecl *property_decl = + clang::ObjCPropertyDecl::CreateDeserialized(clang_ast, 0); + property_decl->setDeclContext(class_interface_decl); + property_decl->setDeclName(&clang_ast.Idents.get(property_name)); + property_decl->setType(ivar_decl + ? ivar_decl->getType() + : ClangUtil::GetQualType(property_clang_type), + prop_type_source); if (!property_decl) return false; @@ -7500,12 +7523,18 @@ bool TypeSystemClang::AddObjCClassProperty( clang::ObjCMethodDecl::None; const bool HasRelatedResultType = false; - getter = clang::ObjCMethodDecl::Create( - clang_ast, clang::SourceLocation(), clang::SourceLocation(), getter_sel, - ClangUtil::GetQualType(property_clang_type_to_access), nullptr, - class_interface_decl, isInstance, isVariadic, isPropertyAccessor, - isSynthesizedAccessorStub, isImplicitlyDeclared, isDefined, impControl, - HasRelatedResultType); + getter = clang::ObjCMethodDecl::CreateDeserialized(clang_ast, 0); + getter->setDeclName(getter_sel); + getter->setReturnType(ClangUtil::GetQualType(property_clang_type_to_access)); + getter->setDeclContext(class_interface_decl); + getter->setInstanceMethod(isInstance); + getter->setVariadic(isVariadic); + getter->setPropertyAccessor(isPropertyAccessor); + getter->setSynthesizedAccessorStub(isSynthesizedAccessorStub); + getter->setImplicit(isImplicitlyDeclared); + getter->setDefined(isDefined); + getter->setDeclImplementation(impControl); + getter->setRelatedResultType(HasRelatedResultType); if (getter) { if (metadata) @@ -7535,11 +7564,18 @@ bool TypeSystemClang::AddObjCClassProperty( clang::ObjCMethodDecl::None; const bool HasRelatedResultType = false; - setter = clang::ObjCMethodDecl::Create( - clang_ast, clang::SourceLocation(), clang::SourceLocation(), setter_sel, - result_type, nullptr, class_interface_decl, isInstance, isVariadic, - isPropertyAccessor, isSynthesizedAccessorStub, isImplicitlyDeclared, - isDefined, impControl, HasRelatedResultType); + setter = clang::ObjCMethodDecl::CreateDeserialized(clang_ast, 0); + setter->setDeclName(setter_sel); + setter->setReturnType(result_type); + setter->setDeclContext(class_interface_decl); + setter->setInstanceMethod(isInstance); + setter->setVariadic(isVariadic); + setter->setPropertyAccessor(isPropertyAccessor); + setter->setSynthesizedAccessorStub(isSynthesizedAccessorStub); + setter->setImplicit(isImplicitlyDeclared); + setter->setDefined(isDefined); + setter->setDeclImplementation(impControl); + setter->setRelatedResultType(HasRelatedResultType); if (setter) { if (metadata) @@ -7656,15 +7692,19 @@ clang::ObjCMethodDecl *TypeSystemClang::AddMethodToObjCObjectType( return nullptr; // some debug information is corrupt. We are not going to // deal with it. - clang::ObjCMethodDecl *objc_method_decl = clang::ObjCMethodDecl::Create( - ast, - clang::SourceLocation(), // beginLoc, - clang::SourceLocation(), // endLoc, - method_selector, method_function_prototype->getReturnType(), - nullptr, // TypeSourceInfo *ResultTInfo, - lldb_ast->GetDeclContextForType(ClangUtil::GetQualType(type)), isInstance, - isVariadic, isPropertyAccessor, isSynthesizedAccessorStub, - isImplicitlyDeclared, isDefined, impControl, HasRelatedResultType); + auto *objc_method_decl = clang::ObjCMethodDecl::CreateDeserialized(ast, 0); + objc_method_decl->setDeclName(method_selector); + objc_method_decl->setReturnType(method_function_prototype->getReturnType()); + objc_method_decl->setDeclContext( + lldb_ast->GetDeclContextForType(ClangUtil::GetQualType(type))); + objc_method_decl->setInstanceMethod(isInstance); + objc_method_decl->setVariadic(isVariadic); + objc_method_decl->setPropertyAccessor(isPropertyAccessor); + objc_method_decl->setSynthesizedAccessorStub(isSynthesizedAccessorStub); + objc_method_decl->setImplicit(isImplicitlyDeclared); + objc_method_decl->setDefined(isDefined); + objc_method_decl->setDeclImplementation(impControl); + objc_method_decl->setRelatedResultType(HasRelatedResultType); if (objc_method_decl == nullptr) return nullptr; @@ -7896,10 +7936,13 @@ clang::EnumConstantDecl *TypeSystemClang::AddEnumerationValueToEnumerationType( if (!enutype) return nullptr; - clang::EnumConstantDecl *enumerator_decl = clang::EnumConstantDecl::Create( - getASTContext(), enutype->getDecl(), clang::SourceLocation(), - name ? &getASTContext().Idents.get(name) : nullptr, // Identifier - clang::QualType(enutype, 0), nullptr, value); + clang::EnumConstantDecl *enumerator_decl = + clang::EnumConstantDecl::CreateDeserialized(getASTContext(), 0); + enumerator_decl->setDeclContext(enutype->getDecl()); + if (name && name[0]) + enumerator_decl->setDeclName(&getASTContext().Idents.get(name)); + enumerator_decl->setType(clang::QualType(enutype, 0)); + enumerator_decl->setInitVal(value); if (!enumerator_decl) return nullptr; From 689466fc2594e8c7819b50ff8ec74047e3c3c3d1 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Wed, 18 Mar 2020 13:14:07 -0700 Subject: [PATCH 202/286] Correctly initialize the DW_AT_comp_dir attribute of Clang module skeleton CUs Before this patch a Clang module skeleton CU would have a DW_AT_comp_dir pointing to the directory of the module map file, and this information was not used by anyone. Even worse, LLDB actually resolves relative DWO paths by appending it to DW_AT_comp_dir. This patch sets it to the same directory that is used as the main CU's compilation directory, which would make the LLDB code work. Differential Revision: https://reviews.llvm.org/D76377 (cherry picked from commit 079c6ddaf5344eb501652c2a874e3e4e8c466c2b) --- clang/lib/CodeGen/CGDebugInfo.cpp | 12 ++++++++---- clang/test/Modules/debug-info-moduleimport.m | 6 ++++-- clang/test/PCH/debug-info-pch-path.c | 8 ++++---- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 010ba496a628c..40a4693d6e586 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -2455,12 +2455,16 @@ CGDebugInfo::getOrCreateModuleRef(ExternalASTSource::ASTSourceDescriptor Mod, ? (uint64_t)Mod.getSignature()[1] << 32 | Mod.getSignature()[0] : ~1ULL; llvm::DIBuilder DIB(CGM.getModule()); + SmallString<0> PCM; + if (!llvm::sys::path::is_absolute(PCM)) + PCM = Mod.getPath(); + llvm::sys::path::append(PCM, Mod.getASTFile()); + StringRef CompDir = getCurrentDirname(); DIB.createCompileUnit(TheCU->getSourceLanguage(), // TODO: Support "Source" from external AST providers? - DIB.createFile(Mod.getModuleName(), Mod.getPath()), - TheCU->getProducer(), true, StringRef(), 0, - Mod.getASTFile(), llvm::DICompileUnit::FullDebug, - Signature); + DIB.createFile(Mod.getModuleName(), CompDir), + TheCU->getProducer(), true, StringRef(), 0, PCM, + llvm::DICompileUnit::FullDebug, Signature); DIB.finalize(); } diff --git a/clang/test/Modules/debug-info-moduleimport.m b/clang/test/Modules/debug-info-moduleimport.m index f07c6fce784d5..837459b0786c3 100644 --- a/clang/test/Modules/debug-info-moduleimport.m +++ b/clang/test/Modules/debug-info-moduleimport.m @@ -28,5 +28,7 @@ // RUN: -fmodule-format=obj -dwarf-ext-refs \ // RUN: %s -I %S/Inputs -isysroot /tmp/.. -I %t -emit-llvm -o - \ // RUN: | FileCheck %s --check-prefix=SKEL-CHECK -// SKEL-CHECK: distinct !DICompileUnit -// SKEL-CHECK: distinct !DICompileUnit{{.*}}dwoId +// SKEL-CHECK: distinct !DICompileUnit({{.*}}file: ![[CUFILE:[0-9]+]] +// SKEL-CHECK: ![[CUFILE]] = !DIFile({{.*}}directory: "[[COMP_DIR:.*]]" +// SKEL-CHECK: distinct !DICompileUnit({{.*}}file: ![[DWOFILE:[0-9]+]]{{.*}}dwoId +// SKEL-CHECK: ![[DWOFILE]] = !DIFile({{.*}}directory: "[[COMP_DIR]]" diff --git a/clang/test/PCH/debug-info-pch-path.c b/clang/test/PCH/debug-info-pch-path.c index dcf7ed41f50ef..32d1cbd44bdf4 100644 --- a/clang/test/PCH/debug-info-pch-path.c +++ b/clang/test/PCH/debug-info-pch-path.c @@ -23,7 +23,7 @@ // CHECK-REL-NODIR: ![[C]] = !DIFile({{.*}}directory: "[[DIR:.*]]" // CHECK-REL-NODIR: !DICompileUnit( // CHECK-REL-NODIR-SAME: file: ![[PCH:[0-9]+]] -// CHECK-REL-NODIR-SAME: splitDebugFilename: "prefix.pch" +// CHECK-REL-NODIR-SAME: splitDebugFilename: "{{.*}}PCH{{.*}}prefix.pch" // CHECK-REL-NODIR: ![[PCH]] = !DIFile({{.*}}directory: "[[DIR]] // --------------------------------------------------------------------- @@ -47,8 +47,8 @@ // CHECK-REL: ![[C]] = !DIFile({{.*}}directory: "[[DIR:.*]]" // CHECK-REL: !DICompileUnit( // CHECK-REL-SAME: file: ![[PCH:[0-9]+]] -// CHECK-REL-SAME: splitDebugFilename: "prefix.pch" -// CHECK-REL: ![[PCH]] = !DIFile({{.*}}directory: "[[DIR]]{{.*}}pchdir" +// CHECK-REL-SAME: splitDebugFilename: "[[DIR]]{{.*}}pchdir{{.*}}prefix.pch" +// CHECK-REL: ![[PCH]] = !DIFile({{.*}}directory: "[[DIR]]" // --------------------------------------------------------------------- // Absolute PCH. @@ -70,5 +70,5 @@ // CHECK-ABS: ![[C]] = !DIFile({{.*}}directory: "[[DIR:.*]]" // CHECK-ABS: !DICompileUnit( // CHECK-ABS-SAME: file: ![[PCH:[0-9]+]] -// CHECK-ABS-SAME: splitDebugFilename: "prefix.pch" +// CHECK-ABS-SAME: splitDebugFilename: "[[DIR]]{{.*}}prefix.pch" // CHECK-ABS: ![[PCH]] = !DIFile({{.*}}directory: "[[DIR]] From cff98e90bd1265d21e65be43ece170a24f74f873 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Fri, 20 Mar 2020 14:17:32 -0700 Subject: [PATCH 203/286] Don't set the isOptimized flag in module skeleton DICompileUnits. It's not used for anything. (cherry picked from commit 97f490d87b226b1deade74ec93b4378fb28d26cc) --- clang/lib/CodeGen/CGDebugInfo.cpp | 2 +- clang/test/Modules/ExtDebugInfo.m | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 40a4693d6e586..e346feb02b53d 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -2463,7 +2463,7 @@ CGDebugInfo::getOrCreateModuleRef(ExternalASTSource::ASTSourceDescriptor Mod, DIB.createCompileUnit(TheCU->getSourceLanguage(), // TODO: Support "Source" from external AST providers? DIB.createFile(Mod.getModuleName(), CompDir), - TheCU->getProducer(), true, StringRef(), 0, PCM, + TheCU->getProducer(), false, StringRef(), 0, PCM, llvm::DICompileUnit::FullDebug, Signature); DIB.finalize(); } diff --git a/clang/test/Modules/ExtDebugInfo.m b/clang/test/Modules/ExtDebugInfo.m index 41247b00a49f8..380bc4c9bb983 100644 --- a/clang/test/Modules/ExtDebugInfo.m +++ b/clang/test/Modules/ExtDebugInfo.m @@ -6,13 +6,16 @@ // RUN: -fmodule-format=obj -fimplicit-module-maps -DMODULES \ // RUN: -fmodules-cache-path=%t %s -I %S/Inputs -I %t -emit-llvm -o %t-mod.ll // RUN: cat %t-mod.ll | FileCheck %s +// RUN: cat %t-mod.ll | FileCheck %s --check-prefix=DWOID // PCH: // RUN: %clang_cc1 -x objective-c -fmodule-format=obj -emit-pch -I%S/Inputs \ // RUN: -o %t.pch %S/Inputs/DebugObjC.h -// RUN: %clang_cc1 -x objective-c -debug-info-kind=limited -dwarf-ext-refs -fmodule-format=obj \ +// RUN: %clang_cc1 -x objective-c -debug-info-kind=limited -dwarf-ext-refs \ +// RUN: -fmodule-format=obj \ // RUN: -include-pch %t.pch %s -emit-llvm -o %t-pch.ll %s // RUN: cat %t-pch.ll | FileCheck %s +// RUN: cat %t-pch.ll | FileCheck %s --check-prefix=DWOID #ifdef MODULES @import DebugObjC; @@ -34,6 +37,8 @@ int foo(ObjCClass *c) { return [c property]; } +// DWOID: !DICompileUnit(language: DW_LANG_ObjC,{{.*}}isOptimized: false,{{.*}}dwoId: + // CHECK: ![[MOD:.*]] = !DIModule(scope: null, name: "DebugObjC // CHECK: !DIGlobalVariable(name: "GlobalUnion", From 2e1899c7722a1ae94f1820dc40ce796a58b27498 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Wed, 18 Mar 2020 13:15:14 -0700 Subject: [PATCH 204/286] Allow remapping Clang module skeleton CU references with -fdebug-prefix-map Differential Revision: https://reviews.llvm.org/D76383 (cherry picked from commit 43580a5c5afc3cd935e4e3d67f285fe81dd7e8c5) --- clang/lib/CodeGen/CGDebugInfo.cpp | 10 ++++++--- clang/test/Modules/debug-info-moduleimport.m | 23 ++++++++++++++------ clang/test/PCH/debug-info-pch-path.c | 6 ++--- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index e346feb02b53d..cce7bb37b1ab9 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -2456,14 +2456,18 @@ CGDebugInfo::getOrCreateModuleRef(ExternalASTSource::ASTSourceDescriptor Mod, : ~1ULL; llvm::DIBuilder DIB(CGM.getModule()); SmallString<0> PCM; - if (!llvm::sys::path::is_absolute(PCM)) + if (!llvm::sys::path::is_absolute(Mod.getASTFile())) PCM = Mod.getPath(); llvm::sys::path::append(PCM, Mod.getASTFile()); - StringRef CompDir = getCurrentDirname(); + std::string RemappedPCM = remapDIPath(PCM); + StringRef RelativePCM(RemappedPCM); + StringRef CompDir = TheCU->getDirectory(); + if (RelativePCM.consume_front(CompDir)) + RelativePCM.consume_front(llvm::sys::path::get_separator()); DIB.createCompileUnit(TheCU->getSourceLanguage(), // TODO: Support "Source" from external AST providers? DIB.createFile(Mod.getModuleName(), CompDir), - TheCU->getProducer(), false, StringRef(), 0, PCM, + TheCU->getProducer(), false, StringRef(), 0, RelativePCM, llvm::DICompileUnit::FullDebug, Signature); DIB.finalize(); } diff --git a/clang/test/Modules/debug-info-moduleimport.m b/clang/test/Modules/debug-info-moduleimport.m index 837459b0786c3..9dee9964b538e 100644 --- a/clang/test/Modules/debug-info-moduleimport.m +++ b/clang/test/Modules/debug-info-moduleimport.m @@ -1,11 +1,19 @@ // RUN: rm -rf %t -// RUN: %clang_cc1 -debug-info-kind=limited -fmodules -DGREETING="Hello World" -UNDEBUG -fimplicit-module-maps -fmodules-cache-path=%t %s -I %S/Inputs -isysroot /tmp/.. -I %t -emit-llvm -o - | FileCheck %s --check-prefix=NOIMPORT +// RUN: %clang_cc1 -debug-info-kind=limited -fmodules \ +// RUN: -DGREETING="Hello World" -UNDEBUG \ +// RUN: -fimplicit-module-maps -fmodules-cache-path=%t %s \ +// RUN: -I %S/Inputs -isysroot /tmp/.. -I %t -emit-llvm -o - \ +// RUN: | FileCheck %s --check-prefix=NOIMPORT // NOIMPORT-NOT: !DIImportedEntity // NOIMPORT-NOT: !DIModule // RUN: rm -rf %t -// RUN: %clang_cc1 -debug-info-kind=limited -fmodules -DGREETING="Hello World" -UNDEBUG -fimplicit-module-maps -fmodules-cache-path=%t %s -I %S/Inputs -isysroot /tmp/.. -I %t -emit-llvm -debugger-tuning=lldb -o - | FileCheck %s +// RUN: %clang_cc1 -debug-info-kind=limited -fmodules \ +// RUN: -DGREETING="Hello World" -UNDEBUG \ +// RUN: -fimplicit-module-maps -fmodules-cache-path=%t %s \ +// RUN: -I %S/Inputs -isysroot /tmp/.. -I %t -emit-llvm \ +// RUN: -debugger-tuning=lldb -o - | FileCheck %s // CHECK: ![[CU:.*]] = distinct !DICompileUnit // CHECK-SAME: sysroot: "/tmp/..") @@ -18,17 +26,18 @@ // CHECK-SAME: includePath: "{{.*}}test{{.*}}Modules{{.*}}Inputs" // CHECK: ![[F]] = !DIFile(filename: {{.*}}debug-info-moduleimport.m -// RUN: %clang_cc1 -debug-info-kind=limited -fmodules -fimplicit-module-maps -fmodules-cache-path=%t \ -// RUN: %s -I %S/Inputs -isysroot /tmp/.. -I %t -emit-llvm -o - \ -// RUN: | FileCheck %s --check-prefix=NO-SKEL-CHECK +// RUN: %clang_cc1 -debug-info-kind=limited -fmodules -fimplicit-module-maps \ +// RUN: -fmodules-cache-path=%t %s -I %S/Inputs -isysroot /tmp/.. -I %t \ +// RUN: -emit-llvm -o - | FileCheck %s --check-prefix=NO-SKEL-CHECK // NO-SKEL-CHECK: distinct !DICompileUnit // NO-SKEL-CHECK-NOT: distinct !DICompileUnit -// RUN: %clang_cc1 -debug-info-kind=limited -fmodules -fimplicit-module-maps -fmodules-cache-path=%t \ +// RUN: %clang_cc1 -debug-info-kind=limited -fmodules -fimplicit-module-maps \ +// RUN: -fmodules-cache-path=%t -fdebug-prefix-map=%t=/MODULE-CACHE \ // RUN: -fmodule-format=obj -dwarf-ext-refs \ // RUN: %s -I %S/Inputs -isysroot /tmp/.. -I %t -emit-llvm -o - \ // RUN: | FileCheck %s --check-prefix=SKEL-CHECK // SKEL-CHECK: distinct !DICompileUnit({{.*}}file: ![[CUFILE:[0-9]+]] // SKEL-CHECK: ![[CUFILE]] = !DIFile({{.*}}directory: "[[COMP_DIR:.*]]" -// SKEL-CHECK: distinct !DICompileUnit({{.*}}file: ![[DWOFILE:[0-9]+]]{{.*}}dwoId +// SKEL-CHECK: distinct !DICompileUnit({{.*}}file: ![[DWOFILE:[0-9]+]]{{.*}}splitDebugFilename: "/MODULE-CACHE{{.*}}dwoId // SKEL-CHECK: ![[DWOFILE]] = !DIFile({{.*}}directory: "[[COMP_DIR]]" diff --git a/clang/test/PCH/debug-info-pch-path.c b/clang/test/PCH/debug-info-pch-path.c index 32d1cbd44bdf4..272d9ac1ab7cf 100644 --- a/clang/test/PCH/debug-info-pch-path.c +++ b/clang/test/PCH/debug-info-pch-path.c @@ -23,7 +23,7 @@ // CHECK-REL-NODIR: ![[C]] = !DIFile({{.*}}directory: "[[DIR:.*]]" // CHECK-REL-NODIR: !DICompileUnit( // CHECK-REL-NODIR-SAME: file: ![[PCH:[0-9]+]] -// CHECK-REL-NODIR-SAME: splitDebugFilename: "{{.*}}PCH{{.*}}prefix.pch" +// CHECK-REL-NODIR-SAME: splitDebugFilename: "prefix.pch" // CHECK-REL-NODIR: ![[PCH]] = !DIFile({{.*}}directory: "[[DIR]] // --------------------------------------------------------------------- @@ -47,7 +47,7 @@ // CHECK-REL: ![[C]] = !DIFile({{.*}}directory: "[[DIR:.*]]" // CHECK-REL: !DICompileUnit( // CHECK-REL-SAME: file: ![[PCH:[0-9]+]] -// CHECK-REL-SAME: splitDebugFilename: "[[DIR]]{{.*}}pchdir{{.*}}prefix.pch" +// CHECK-REL-SAME: splitDebugFilename: "pchdir{{.*}}prefix.pch" // CHECK-REL: ![[PCH]] = !DIFile({{.*}}directory: "[[DIR]]" // --------------------------------------------------------------------- @@ -70,5 +70,5 @@ // CHECK-ABS: ![[C]] = !DIFile({{.*}}directory: "[[DIR:.*]]" // CHECK-ABS: !DICompileUnit( // CHECK-ABS-SAME: file: ![[PCH:[0-9]+]] -// CHECK-ABS-SAME: splitDebugFilename: "[[DIR]]{{.*}}prefix.pch" +// CHECK-ABS-SAME: splitDebugFilename: "prefix.pch" // CHECK-ABS: ![[PCH]] = !DIFile({{.*}}directory: "[[DIR]] From ac0c72283d471f4b6161f562f8277ee98493d3ef Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Wed, 18 Mar 2020 15:48:23 -0700 Subject: [PATCH 205/286] Allow remapping the sysroot with -fdebug-prefix-map. Differential Revision: https://reviews.llvm.org/D76393 (cherry picked from commit ceae47143b1d2c5622e0318255e6663264d61299) --- clang/lib/CodeGen/CGDebugInfo.cpp | 2 +- clang/test/CodeGen/debug-prefix-map.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index cce7bb37b1ab9..fb6ed7ffe24ef 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -629,7 +629,7 @@ void CGDebugInfo::CreateCompileUnit() { ? llvm::DICompileUnit::DebugNameTableKind::None : static_cast( CGOpts.DebugNameTable), - CGOpts.DebugRangesBaseAddress, Sysroot, SDK); + CGOpts.DebugRangesBaseAddress, remapDIPath(Sysroot), SDK); } llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) { diff --git a/clang/test/CodeGen/debug-prefix-map.c b/clang/test/CodeGen/debug-prefix-map.c index 5366e19447ae2..354110d1b0da7 100644 --- a/clang/test/CodeGen/debug-prefix-map.c +++ b/clang/test/CodeGen/debug-prefix-map.c @@ -2,6 +2,7 @@ // RUN: %clang_cc1 -debug-info-kind=standalone -fdebug-prefix-map=%p=/UNLIKELY_PATH=empty %s -emit-llvm -o - | FileCheck %s -check-prefix CHECK-EVIL // RUN: %clang_cc1 -debug-info-kind=standalone -fdebug-prefix-map=%p=/UNLIKELY_PATH/empty %s -emit-llvm -o - -main-file-name debug-prefix-map.c | FileCheck %s // RUN: %clang_cc1 -debug-info-kind=standalone -fdebug-prefix-map=%p=/UNLIKELY_PATH/empty %s -emit-llvm -o - -fdebug-compilation-dir %p | FileCheck %s -check-prefix CHECK-COMPILATION-DIR +// RUN: %clang_cc1 -debug-info-kind=standalone -fdebug-prefix-map=%p=/UNLIKELY_PATH/empty %s -emit-llvm -o - -isysroot %p -debugger-tuning=lldb | FileCheck %s -check-prefix CHECK-SYSROOT // RUN: %clang -g -fdebug-prefix-map=%p=/UNLIKELY_PATH/empty -S -c %s -emit-llvm -o - | FileCheck %s // RUN: %clang -g -ffile-prefix-map=%p=/UNLIKELY_PATH/empty -S -c %s -emit-llvm -o - | FileCheck %s @@ -40,3 +41,4 @@ void test_rewrite_includes() { // CHECK-COMPILATION-DIR: !DIFile(filename: "{{.*}}", directory: "/UNLIKELY_PATH/empty") // CHECK-COMPILATION-DIR: !DIFile(filename: "{{.*}}Inputs/stdio.h", directory: "/UNLIKELY_PATH/empty") // CHECK-COMPILATION-DIR-NOT: !DIFile(filename: +// CHECK-SYSROOT: !DICompileUnit({{.*}}sysroot: "/UNLIKELY_PATH/empty" From 32c673ebdc8257383375a0400b969c88a7b6dea3 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Fri, 20 Mar 2020 16:40:57 -0700 Subject: [PATCH 206/286] Driver: Improve performance of getSDKName() The ".sdk" component is usually the last one in the -isysroot, so it makes more sense to scan from the back. Also, technically, someone could install Xcode into a directory ending with .sdk, which would break this heuristic. Differential Revision: https://reviews.llvm.org/D76097 (cherry picked from commit 0e916bf9f5e4a51af621fd72ccf4b00b7e6f86fa) --- clang/lib/Driver/ToolChains/Darwin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp index 3a86821d33e53..24750b79521aa 100644 --- a/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/clang/lib/Driver/ToolChains/Darwin.cpp @@ -1134,8 +1134,8 @@ StringRef Darwin::getPlatformFamily() const { StringRef Darwin::getSDKName(StringRef isysroot) { // Assume SDK has path: SOME_PATH/SDKs/PlatformXX.YY.sdk - auto BeginSDK = llvm::sys::path::begin(isysroot); - auto EndSDK = llvm::sys::path::end(isysroot); + auto BeginSDK = llvm::sys::path::rbegin(isysroot); + auto EndSDK = llvm::sys::path::rend(isysroot); for (auto IT = BeginSDK; IT != EndSDK; ++IT) { StringRef SDK = *IT; if (SDK.endswith(".sdk")) From 6fd3d2ba6366ee016565922f00350cd9a8d4a5cd Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Wed, 18 Mar 2020 15:31:39 -0700 Subject: [PATCH 207/286] Add an -object-path-prefix option to dsymutil to remap object file paths (but no source paths) before processing. This is meant to be used for Clang objects where the module cache location was remapped using ``-fdebug-prefix-map``; to help dsymutil find the Clang module cache. Differential Revision: https://reviews.llvm.org/D76391 (cherry picked from commit ed8ad6ec1562a980d8d6a8fea29703030acc125b) Conflicts: llvm/include/llvm/DWARFLinker/DWARFLinker.h llvm/tools/dsymutil/DwarfLinker.cpp llvm/tools/dsymutil/DwarfLinkerForBinary.cpp --- llvm/docs/CommandGuide/dsymutil.rst | 6 ++++++ llvm/test/tools/dsymutil/X86/object-prefix-path.test | 11 +++++++++++ llvm/test/tools/dsymutil/cmdline.test | 1 + llvm/tools/dsymutil/DwarfLinker.cpp | 12 ++++++++++++ llvm/tools/dsymutil/DwarfLinker.h | 8 ++++++++ llvm/tools/dsymutil/LinkUtils.h | 3 +++ llvm/tools/dsymutil/Options.td | 9 +++++++++ llvm/tools/dsymutil/dsymutil.cpp | 6 ++++++ 8 files changed, 56 insertions(+) create mode 100644 llvm/test/tools/dsymutil/X86/object-prefix-path.test diff --git a/llvm/docs/CommandGuide/dsymutil.rst b/llvm/docs/CommandGuide/dsymutil.rst index 4aa9c1c7c49dd..2f638daf2ae3f 100644 --- a/llvm/docs/CommandGuide/dsymutil.rst +++ b/llvm/docs/CommandGuide/dsymutil.rst @@ -71,6 +71,12 @@ OPTIONS Specifies a ``path`` to prepend to all debug symbol object file paths. +.. option:: --object-prefix-map= + + Remap object file paths (but no source paths) before processing. Use + this for Clang objects where the module cache location was remapped using + ``-fdebug-prefix-map``; to help dsymutil find the Clang module cache. + .. option:: --papertrail When running dsymutil as part of your build system, it can be desirable for diff --git a/llvm/test/tools/dsymutil/X86/object-prefix-path.test b/llvm/test/tools/dsymutil/X86/object-prefix-path.test new file mode 100644 index 0000000000000..16956e0f94521 --- /dev/null +++ b/llvm/test/tools/dsymutil/X86/object-prefix-path.test @@ -0,0 +1,11 @@ +RUN: rm -rf %t.dir && mkdir %t.dir && mkdir %t.dir/ModuleCacheRenamed +RUN: cp %p/../Inputs/module-warnings/1.o %t.dir +RUN: cp %p/../Inputs/module-warnings/Foo.pcm %t.dir/ModuleCacheRenamed + +RUN: dsymutil -verify -f -oso-prepend-path=%t.dir -y \ +RUN: %p/dummy-debug-map.map -o %t \ +RUN: -object-prefix-map=/ModuleCache=/ModuleCacheRenamed \ +RUN: 2>&1 | FileCheck %s + +CHECK: warning: {{.*}}Bar.pcm: +CHECK-NOT: warning: {{.*}}Foo.pcm: diff --git a/llvm/test/tools/dsymutil/cmdline.test b/llvm/test/tools/dsymutil/cmdline.test index fc3f00b369fde..701de29637dd8 100644 --- a/llvm/test/tools/dsymutil/cmdline.test +++ b/llvm/test/tools/dsymutil/cmdline.test @@ -12,6 +12,7 @@ HELP: -no-odr HELP: -no-output HELP: -no-swiftmodule-timestamp HELP: -num-threads +HELP: -object-prefix-map HELP: -oso-prepend-path HELP: -o HELP: -papertrail diff --git a/llvm/tools/dsymutil/DwarfLinker.cpp b/llvm/tools/dsymutil/DwarfLinker.cpp index 7c0eeb9dd35cc..14bff4f706953 100644 --- a/llvm/tools/dsymutil/DwarfLinker.cpp +++ b/llvm/tools/dsymutil/DwarfLinker.cpp @@ -2328,6 +2328,14 @@ static uint64_t getDwoId(const DWARFDie &CUDie, const DWARFUnit &Unit) { return 0; } +static std::string remapPath(StringRef Path, + const objectPrefixMap &ObjectPrefixMap) { + for (const auto &Entry : ObjectPrefixMap) + if (Path.startswith(Entry.first)) + return (Twine(Entry.second) + Path.substr(Entry.first.size())).str(); + return Path.str(); +} + bool DwarfLinker::registerModuleReference( DWARFDie CUDie, const DWARFUnit &Unit, DebugMap &ModuleMap, const DebugMapObject &DMO, RangesTy &Ranges, OffsetsStringPool &StringPool, @@ -2338,6 +2346,8 @@ bool DwarfLinker::registerModuleReference( CUDie.find({dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}), ""); if (PCMfile.empty()) return false; + if (ObjectPrefixMap) + PCMfile = remapPath(PCMfile, *ObjectPrefixMap); // Clang module DWARF skeleton CUs abuse this for the path to the module. uint64_t DwoId = getDwoId(CUDie, Unit); @@ -2752,6 +2762,8 @@ bool DwarfLinker::link(const DebugMap &Map) { if (!createStreamer(Map.getTriple(), OutFile)) return false; + setObjectPrefixMap(&Options.ObjectPrefixMap); + // Size of the DIEs (and headers) generated for the linked output. OutputDebugInfoSize = 0; // A unique ID that identifies each compile unit. diff --git a/llvm/tools/dsymutil/DwarfLinker.h b/llvm/tools/dsymutil/DwarfLinker.h index eeb533fd55b76..ba7ed721b1540 100644 --- a/llvm/tools/dsymutil/DwarfLinker.h +++ b/llvm/tools/dsymutil/DwarfLinker.h @@ -38,6 +38,7 @@ struct DebugMapObjectRange { /// Map LowPC to DebugMapObjectRange. using RangesTy = std::map; using UnitListTy = std::vector>; +typedef std::map objectPrefixMap; /// The core of the Dwarf linking logic. /// @@ -184,6 +185,11 @@ class DwarfLinker { /// Called at the end of a debug object link. void endDebugObject(LinkContext &Context); + /// Set prefix map for objects. + void setObjectPrefixMap(objectPrefixMap *Map) { + ObjectPrefixMap = Map; + } + /// \defgroup FindRootDIEs Find DIEs corresponding to debug map entries. /// /// @{ @@ -505,6 +511,8 @@ class DwarfLinker { /// be uniqued and sorted and there are only few entries expected /// per compile unit, which is why this is a std::map. std::map ParseableSwiftInterfaces; + /// A list of remappings to apply to file paths. + objectPrefixMap *ObjectPrefixMap = nullptr; bool ModuleCacheHintDisplayed = false; bool ArchiveHintDisplayed = false; diff --git a/llvm/tools/dsymutil/LinkUtils.h b/llvm/tools/dsymutil/LinkUtils.h index 0f31334cd317a..0d99fa73f74d6 100644 --- a/llvm/tools/dsymutil/LinkUtils.h +++ b/llvm/tools/dsymutil/LinkUtils.h @@ -63,6 +63,9 @@ struct LinkOptions { /// -oso-prepend-path std::string PrependPath; + /// The -object-prefix-map. + std::map ObjectPrefixMap; + /// The Resources directory in the .dSYM bundle. Optional ResourceDir; diff --git a/llvm/tools/dsymutil/Options.td b/llvm/tools/dsymutil/Options.td index eb86c2f3ae1b3..5360bf09ac751 100644 --- a/llvm/tools/dsymutil/Options.td +++ b/llvm/tools/dsymutil/Options.td @@ -110,6 +110,15 @@ def oso_prepend_path: Separate<["--", "-"], "oso-prepend-path">, Group; def: Joined<["--", "-"], "oso-prepend-path=">, Alias; +def object_prefix_map: Separate<["--", "-"], "object-prefix-map">, + MetaVarName<"">, + HelpText<"Remap object file paths (but no source paths) before processing." + "Use this for Clang objects where the module cache location was" + "remapped using -fdebug-prefix-map; to help dsymutil" + "find the Clang module cache.">, + Group; +def: Joined<["--", "-"], "object-prefix-map=">, Alias; + def symbolmap: Separate<["--", "-"], "symbol-map">, MetaVarName<"">, HelpText<"Updates the existing dSYMs inplace using symbol map specified.">, diff --git a/llvm/tools/dsymutil/dsymutil.cpp b/llvm/tools/dsymutil/dsymutil.cpp index 2801178c605f2..15f34e509c7a8 100644 --- a/llvm/tools/dsymutil/dsymutil.cpp +++ b/llvm/tools/dsymutil/dsymutil.cpp @@ -246,6 +246,12 @@ static Expected getOptions(opt::InputArgList &Args) { if (opt::Arg *OsoPrependPath = Args.getLastArg(OPT_oso_prepend_path)) Options.LinkOpts.PrependPath = OsoPrependPath->getValue(); + for (const auto &Arg : Args.getAllArgValues(OPT_object_prefix_map)) { + auto Split = StringRef(Arg).split('='); + Options.LinkOpts.ObjectPrefixMap.insert( + {std::string(Split.first), std::string(Split.second)}); + } + if (opt::Arg *OutputFile = Args.getLastArg(OPT_output)) Options.OutputFile = OutputFile->getValue(); From 7cd386498a109579da71ea294f2380e317bc250c Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Wed, 18 Mar 2020 15:30:20 -0700 Subject: [PATCH 208/286] Allow remapping Clang module include paths rdar://problem/55685132 Differential Revision: https://reviews.llvm.org/D76385 (cherry picked from commit dca920a904c27f4c86e909ef2e4e343d48168cca) Conflicts: clang/lib/CodeGen/CGDebugInfo.cpp --- clang/lib/CodeGen/CGDebugInfo.cpp | 30 +++++++++++++------- clang/test/Modules/debug-info-moduleimport.m | 2 ++ 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index fb6ed7ffe24ef..a965528e471dd 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -2446,6 +2446,17 @@ CGDebugInfo::getOrCreateModuleRef(ExternalASTSource::ASTSourceDescriptor Mod, assert(StringRef(M->Name).startswith(CGM.getLangOpts().ModuleName) && "clang module without ASTFile must be specified by -fmodule-name"); + // Return a StringRef to the remapped Path. + auto RemapPath = [this](StringRef Path) -> std::string { + std::string Remapped = remapDIPath(Path); + StringRef Relative(Remapped); + StringRef CompDir = TheCU->getDirectory(); + if (Relative.consume_front(CompDir)) + Relative.consume_front(llvm::sys::path::get_separator()); + + return Relative.str(); + }; + if (CreateSkeletonCU && IsRootModule && !Mod.getASTFile().empty()) { // PCH files don't have a signature field in the control block, // but LLVM detects skeleton CUs by looking for a non-zero DWO id. @@ -2459,16 +2470,12 @@ CGDebugInfo::getOrCreateModuleRef(ExternalASTSource::ASTSourceDescriptor Mod, if (!llvm::sys::path::is_absolute(Mod.getASTFile())) PCM = Mod.getPath(); llvm::sys::path::append(PCM, Mod.getASTFile()); - std::string RemappedPCM = remapDIPath(PCM); - StringRef RelativePCM(RemappedPCM); - StringRef CompDir = TheCU->getDirectory(); - if (RelativePCM.consume_front(CompDir)) - RelativePCM.consume_front(llvm::sys::path::get_separator()); - DIB.createCompileUnit(TheCU->getSourceLanguage(), - // TODO: Support "Source" from external AST providers? - DIB.createFile(Mod.getModuleName(), CompDir), - TheCU->getProducer(), false, StringRef(), 0, RelativePCM, - llvm::DICompileUnit::FullDebug, Signature); + DIB.createCompileUnit( + TheCU->getSourceLanguage(), + // TODO: Support "Source" from external AST providers? + DIB.createFile(Mod.getModuleName(), TheCU->getDirectory()), + TheCU->getProducer(), false, StringRef(), 0, RemapPath(PCM), + llvm::DICompileUnit::FullDebug, Signature); DIB.finalize(); } @@ -2477,9 +2484,10 @@ CGDebugInfo::getOrCreateModuleRef(ExternalASTSource::ASTSourceDescriptor Mod, : getOrCreateModuleRef( ExternalASTSource::ASTSourceDescriptor(*M->Parent), CreateSkeletonCU); + std::string IncludePath = Mod.getPath().str(); llvm::DIModule *DIMod = DBuilder.createModule(Parent, Mod.getModuleName(), ConfigMacros, - Mod.getPath(), M ? M->APINotesFile : ""); + RemapPath(IncludePath), M ? M->APINotesFile : ""); ModuleCache[M].reset(DIMod); return DIMod; } diff --git a/clang/test/Modules/debug-info-moduleimport.m b/clang/test/Modules/debug-info-moduleimport.m index 9dee9964b538e..5787ffe227513 100644 --- a/clang/test/Modules/debug-info-moduleimport.m +++ b/clang/test/Modules/debug-info-moduleimport.m @@ -34,9 +34,11 @@ // RUN: %clang_cc1 -debug-info-kind=limited -fmodules -fimplicit-module-maps \ // RUN: -fmodules-cache-path=%t -fdebug-prefix-map=%t=/MODULE-CACHE \ +// RUN: -fdebug-prefix-map=%S=/SRCDIR \ // RUN: -fmodule-format=obj -dwarf-ext-refs \ // RUN: %s -I %S/Inputs -isysroot /tmp/.. -I %t -emit-llvm -o - \ // RUN: | FileCheck %s --check-prefix=SKEL-CHECK +// SKEL-CHECK: includePath: "/SRCDIR/Inputs" // SKEL-CHECK: distinct !DICompileUnit({{.*}}file: ![[CUFILE:[0-9]+]] // SKEL-CHECK: ![[CUFILE]] = !DIFile({{.*}}directory: "[[COMP_DIR:.*]]" // SKEL-CHECK: distinct !DICompileUnit({{.*}}file: ![[DWOFILE:[0-9]+]]{{.*}}splitDebugFilename: "/MODULE-CACHE{{.*}}dwoId From a324394725e6fbb630b3b88013deb949da1f2550 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Fri, 27 Mar 2020 14:22:02 -0700 Subject: [PATCH 209/286] Unbreak LLDB tests after 96023917e6f by teaching LLDB to apply DW_AT_comp_dir to the DW_AT_LLVM_include path. (cherry picked from commit 974fbd9b8145d351b7359e34e415581eda6e0b4d) --- .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 1bd5030033128..d2af13ebebafe 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -684,6 +684,22 @@ DWARFDebugRanges *SymbolFileDWARF::GetDebugRanges() { return m_ranges.get(); } +/// Make an absolute path out of \p file_spec and remap it using the +/// module's source remapping dictionary. +static void MakeAbsoluteAndRemap(FileSpec &file_spec, DWARFUnit &dwarf_cu, + const ModuleSP &module_sp) { + if (!file_spec) + return; + // If we have a full path to the compile unit, we don't need to + // resolve the file. This can be expensive e.g. when the source + // files are NFS mounted. + file_spec.MakeAbsolute(dwarf_cu.GetCompilationDirectory()); + + std::string remapped_file; + if (module_sp->RemapSourceFile(file_spec.GetPath(), remapped_file)) + file_spec.SetFile(remapped_file, FileSpec::Style::native); +} + lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) { CompUnitSP cu_sp; CompileUnit *comp_unit = (CompileUnit *)dwarf_cu.GetUserData(); @@ -703,17 +719,7 @@ lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) { const DWARFDIE cu_die = dwarf_cu.DIE(); if (cu_die) { FileSpec cu_file_spec(cu_die.GetName(), dwarf_cu.GetPathStyle()); - if (cu_file_spec) { - // If we have a full path to the compile unit, we don't need to - // resolve the file. This can be expensive e.g. when the source - // files are NFS mounted. - cu_file_spec.MakeAbsolute(dwarf_cu.GetCompilationDirectory()); - - std::string remapped_file; - if (module_sp->RemapSourceFile(cu_file_spec.GetPath(), - remapped_file)) - cu_file_spec.SetFile(remapped_file, FileSpec::Style::native); - } + MakeAbsoluteAndRemap(cu_file_spec, dwarf_cu, module_sp); LanguageType cu_language = DWARFUnit::LanguageTypeFromDWARF( cu_die.GetAttributeValueAsUnsigned(DW_AT_language, 0)); @@ -983,8 +989,11 @@ bool SymbolFileDWARF::ParseImportedModules( } std::reverse(module.path.begin(), module.path.end()); if (const char *include_path = module_die.GetAttributeValueAsString( - DW_AT_LLVM_include_path, nullptr)) - module.search_path = ConstString(include_path); + DW_AT_LLVM_include_path, nullptr)) { + FileSpec include_spec(include_path, dwarf_cu->GetPathStyle()); + MakeAbsoluteAndRemap(include_spec, *dwarf_cu, m_objfile_sp->GetModule()); + module.search_path = ConstString(include_spec.GetPath()); + } if (const char *sysroot = dwarf_cu->DIE().GetAttributeValueAsString( DW_AT_LLVM_sysroot, nullptr)) module.sysroot = ConstString(sysroot); From f166c198abe4bb84b5024ef66004295f7dfd5070 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Tue, 3 Mar 2020 13:01:51 -0800 Subject: [PATCH 210/286] Add an opque payload field to lldb::Type (NFC). Differential Revision: https://reviews.llvm.org/D75562 (cherry picked from commit 7b06cb4523083206ad79776c80a564cd26bd8326) Conflicts: lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h --- lldb/include/lldb/Symbol/Type.h | 14 ++++---- .../ObjC/ObjCLanguageRuntime.cpp | 2 +- .../SymbolFile/DWARF/DWARFASTParserClang.cpp | 11 +++--- .../TypeSystem/Clang/TypeSystemClang.cpp | 4 +++ .../TypeSystem/Clang/TypeSystemClang.h | 35 +++++++++++++++++++ lldb/source/Symbol/Type.cpp | 9 +++-- 6 files changed, 56 insertions(+), 19 deletions(-) diff --git a/lldb/include/lldb/Symbol/Type.h b/lldb/include/lldb/Symbol/Type.h index 95a3bc497517e..531a027054b25 100644 --- a/lldb/include/lldb/Symbol/Type.h +++ b/lldb/include/lldb/Symbol/Type.h @@ -97,7 +97,7 @@ class Type : public std::enable_shared_from_this, public UserID { llvm::Optional byte_size, SymbolContextScope *context, lldb::user_id_t encoding_uid, EncodingDataType encoding_uid_type, const Declaration &decl, const CompilerType &compiler_qual_type, - ResolveState compiler_type_resolve_state); + ResolveState compiler_type_resolve_state, uint32_t opaque_payload = 0); // This makes an invalid type. Used for functions that return a Type when // they get an error. @@ -196,11 +196,10 @@ class Type : public std::enable_shared_from_this, public UserID { uint32_t GetEncodingMask(); - bool IsCompleteObjCClass() { return m_is_complete_objc_class; } - - void SetIsCompleteObjCClass(bool is_complete_objc_class) { - m_is_complete_objc_class = is_complete_objc_class; - } + /// Return the language-specific payload. + uint32_t GetPayload() { return m_payload; } + /// Return the language-specific payload. + void SetPayload(uint32_t opaque_payload) { m_payload = opaque_payload; } protected: ConstString m_name; @@ -215,7 +214,8 @@ class Type : public std::enable_shared_from_this, public UserID { Declaration m_decl; CompilerType m_compiler_type; ResolveState m_compiler_type_resolve_state; - bool m_is_complete_objc_class; + /// Language-specific flags. + uint32_t m_payload; Type *GetEncodingType(); diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp index 1b2286ae19d1c..4c2230944537c 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp @@ -129,7 +129,7 @@ ObjCLanguageRuntime::LookupInCompleteClassCache(ConstString &name) { if (TypeSystemClang::IsObjCObjectOrInterfaceType( type_sp->GetForwardCompilerType())) { - if (type_sp->IsCompleteObjCClass()) { + if (TypePayloadClang(type_sp->GetPayload()).IsCompleteObjCClass()) { m_complete_class_cache[name] = type_sp; return type_sp; } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index 59604a25fad6f..f3077c4cdfade 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -1637,12 +1637,11 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, // parameters in any class methods need it for the clang types for // function prototypes. LinkDeclContextToDIE(m_ast.GetDeclContextForType(clang_type), die); - type_sp = std::make_shared(die.GetID(), dwarf, attrs.name, - attrs.byte_size, nullptr, LLDB_INVALID_UID, - Type::eEncodingIsUID, &attrs.decl, - clang_type, Type::ResolveState::Forward); - - type_sp->SetIsCompleteObjCClass(attrs.is_complete_objc_class); + type_sp = std::make_shared( + die.GetID(), dwarf, attrs.name, attrs.byte_size, nullptr, + LLDB_INVALID_UID, Type::eEncodingIsUID, &attrs.decl, clang_type, + Type::ResolveState::Forward, + TypePayloadClang(attrs.is_complete_objc_class)); // Add our type to the unique type map so we don't end up creating many // copies of the same type over and over in the ASTContext for our diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index fa12ef13f86d9..7b6a39756e3c7 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -312,6 +312,10 @@ static ClangASTMap &GetASTMap() { return *g_map_ptr; } +TypePayloadClang::TypePayloadClang(bool is_complete_objc_class) { + SetIsCompleteObjCClass(is_complete_objc_class); +} + char TypeSystemClang::ID; bool TypeSystemClang::IsOperator(llvm::StringRef name, diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index c38f6f7347f9e..f8d51b8c1e77c 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -31,6 +31,7 @@ #include "lldb/Symbol/TypeSystem.h" #include "lldb/Target/Target.h" #include "lldb/Utility/ConstString.h" +#include "lldb/Utility/Flags.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/Logging.h" #include "lldb/lldb-enumerations.h" @@ -38,10 +39,44 @@ class DWARFASTParserClang; class PDBASTParser; +namespace clang { +class FileManager; +class HeaderSearch; +class ModuleMap; +} // namespace clang + namespace lldb_private { class Declaration; +/// The implementation of lldb::Type's m_payload field for TypeSystemClang. +class TypePayloadClang { + /// Layout: bit 31 ... IsCompleteObjCClass. + uint32_t m_payload = 0; +public: + TypePayloadClang() = default; + explicit TypePayloadClang(bool is_complete_objc_class); + explicit TypePayloadClang(uint32_t opaque_payload) : m_payload(opaque_payload) {} + operator uint32_t() { return m_payload; } + + static constexpr unsigned ObjCClassBit = 1 << 31; + bool IsCompleteObjCClass() { return Flags(m_payload).Test(ObjCClassBit); } + void SetIsCompleteObjCClass(bool is_complete_objc_class) { + m_payload = is_complete_objc_class ? Flags(m_payload).Set(ObjCClassBit) + : Flags(m_payload).Clear(ObjCClassBit); + } +}; + +/// A TypeSystem implementation based on Clang. +/// +/// This class uses a single clang::ASTContext as the backend for storing +/// its types and declarations. Every clang::ASTContext should also just have +/// a single associated TypeSystemClang instance that manages it. +/// +/// The clang::ASTContext instance can either be created by TypeSystemClang +/// itself or it can adopt an existing clang::ASTContext (for example, when +/// it is necessary to provide a TypeSystem interface for an existing +/// clang::ASTContext that was created by clang::CompilerInstance). class TypeSystemClang : public TypeSystem { // LLVM RTTI support static char ID; diff --git a/lldb/source/Symbol/Type.cpp b/lldb/source/Symbol/Type.cpp index c95e4bb3c695d..b3dbbfba4a7f8 100644 --- a/lldb/source/Symbol/Type.cpp +++ b/lldb/source/Symbol/Type.cpp @@ -143,15 +143,14 @@ Type::Type(lldb::user_id_t uid, SymbolFile *symbol_file, ConstString name, llvm::Optional byte_size, SymbolContextScope *context, user_id_t encoding_uid, EncodingDataType encoding_uid_type, const Declaration &decl, const CompilerType &compiler_type, - ResolveState compiler_type_resolve_state) + ResolveState compiler_type_resolve_state, uint32_t opaque_payload) : std::enable_shared_from_this(), UserID(uid), m_name(name), m_symbol_file(symbol_file), m_context(context), m_encoding_type(nullptr), m_encoding_uid(encoding_uid), m_encoding_uid_type(encoding_uid_type), m_decl(decl), m_compiler_type(compiler_type), - m_compiler_type_resolve_state( - compiler_type ? compiler_type_resolve_state - : ResolveState::Unresolved), - m_is_complete_objc_class(false) { + m_compiler_type_resolve_state(compiler_type ? compiler_type_resolve_state + : ResolveState::Unresolved), + m_payload(opaque_payload) { if (byte_size) { m_byte_size = *byte_size; m_byte_size_has_value = true; From 1b880fe0723cf14e131cdb0ed7eda18115891ec3 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Tue, 31 Mar 2020 14:12:11 -0700 Subject: [PATCH 211/286] Add a Type::Payload typedef. (NFC) This addresses review feedback from Raphael that I missed before landing the change that introduced the payload field. (cherry picked from commit 00efcd6fffa533e5a4aa5646e678d57df0f9aca8) --- lldb/include/lldb/Symbol/Type.h | 7 ++++--- lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lldb/include/lldb/Symbol/Type.h b/lldb/include/lldb/Symbol/Type.h index 531a027054b25..942f691697de3 100644 --- a/lldb/include/lldb/Symbol/Type.h +++ b/lldb/include/lldb/Symbol/Type.h @@ -196,10 +196,11 @@ class Type : public std::enable_shared_from_this, public UserID { uint32_t GetEncodingMask(); + typedef uint32_t Payload; /// Return the language-specific payload. - uint32_t GetPayload() { return m_payload; } + Payload GetPayload() { return m_payload; } /// Return the language-specific payload. - void SetPayload(uint32_t opaque_payload) { m_payload = opaque_payload; } + void SetPayload(Payload opaque_payload) { m_payload = opaque_payload; } protected: ConstString m_name; @@ -215,7 +216,7 @@ class Type : public std::enable_shared_from_this, public UserID { CompilerType m_compiler_type; ResolveState m_compiler_type_resolve_state; /// Language-specific flags. - uint32_t m_payload; + Payload m_payload; Type *GetEncodingType(); diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index f8d51b8c1e77c..92332d43d052a 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -52,7 +52,7 @@ class Declaration; /// The implementation of lldb::Type's m_payload field for TypeSystemClang. class TypePayloadClang { /// Layout: bit 31 ... IsCompleteObjCClass. - uint32_t m_payload = 0; + Type::Payload m_payload = 0; public: TypePayloadClang() = default; explicit TypePayloadClang(bool is_complete_objc_class); From 84c0e3395c88a1822e6dde29e5effaddb7723ac2 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Tue, 31 Mar 2020 14:58:25 -0700 Subject: [PATCH 212/286] Replace uint32_t with typedef (NFC) (cherry picked from commit ec11c5615a7c153a68d098903edebbb92719f5f9) --- lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index 92332d43d052a..0bfdd5bd53106 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -57,7 +57,7 @@ class TypePayloadClang { TypePayloadClang() = default; explicit TypePayloadClang(bool is_complete_objc_class); explicit TypePayloadClang(uint32_t opaque_payload) : m_payload(opaque_payload) {} - operator uint32_t() { return m_payload; } + operator Type::Payload() { return m_payload; } static constexpr unsigned ObjCClassBit = 1 << 31; bool IsCompleteObjCClass() { return Flags(m_payload).Test(ObjCClassBit); } From bd2ac39991a032b9622845bd50d9a1304a6ad1b2 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Thu, 9 Apr 2020 17:19:42 -0700 Subject: [PATCH 213/286] Add a unit test for TypeSystemSwiftTypeRef::IsFunctionType() and fix a bug in its implementation. --- lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp | 10 +++++- .../Symbol/TestTypeSystemSwiftTypeRef.cpp | 33 +++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp index f487f7d6c345f..836273cf039b2 100644 --- a/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp +++ b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp @@ -404,7 +404,15 @@ bool TypeSystemSwiftTypeRef::IsFunctionType(void *type, bool *is_variadic_ptr) { node->getKind() != Node::Kind::Global) return false; node = node->getFirstChild(); - if (node->getNumChildren() != 1 || node->getKind() != Node::Kind::Function) + if (node->getNumChildren() != 1 || + node->getKind() != Node::Kind::TypeMangling) + return false; + node = node->getFirstChild(); + if (node->getNumChildren() != 1 || node->getKind() != Node::Kind::Type) + return false; + node = node->getFirstChild(); + if (node->getKind() != Node::Kind::FunctionType && + node->getKind() != Node::Kind::ImplFunctionType) return false; return true; }; diff --git a/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp b/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp index 4b80bb38a2824..59a748ede86a7 100644 --- a/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp +++ b/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp @@ -82,3 +82,36 @@ TEST_F(TestTypeSystemSwiftTypeRef, Array) { CompilerType int_array = GetCompilerType(b.Mangle(n)); ASSERT_TRUE(int_array.IsArrayType(nullptr, nullptr, nullptr)); } + +TEST_F(TestTypeSystemSwiftTypeRef, Function) { + using namespace swift::Demangle; + Demangler dem; + NodeBuilder b(dem); + { + NodePointer n = b.Node( + Node::Kind::Global, + b.Node(Node::Kind::TypeMangling, + b.Node(Node::Kind::Type, + b.Node(Node::Kind::FunctionType, + b.Node(Node::Kind::ArgumentTuple, + b.Node(Node::Kind::Type, + b.Node(Node::Kind::Tuple))), + b.Node(Node::Kind::ReturnType, + b.Node(Node::Kind::Type, + b.Node(Node::Kind::Tuple))))))); + CompilerType void_void = GetCompilerType(b.Mangle(n)); + ASSERT_TRUE(void_void.IsFunctionType(nullptr)); + } + { + NodePointer n = + b.Node(Node::Kind::Global, + b.Node(Node::Kind::TypeMangling, + b.Node(Node::Kind::Type, + b.Node(Node::Kind::ImplFunctionType, + b.Node(Node::Kind::ImplEscaping), + b.Node(Node::Kind::ImplConvention, + "@callee_guaranteed"))))); + CompilerType opaque = GetCompilerType(b.Mangle(n)); + ASSERT_TRUE(opaque.IsFunctionType(nullptr)); + } +} From e771f60ed5d843726f63969f9f527a09d7da00d5 Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Thu, 9 Apr 2020 16:30:03 -0700 Subject: [PATCH 214/286] Fix the master-next build after merging in the ThreadPlanStack changes. Merging the ThreadPlanStack changes onto master-next revealed a header dependency cycle caused by the fact that Target.h was including SwiftASTContext.h which brings in a whole raft of other headers (including ValueObject.h). A generic header file like Target.h should not have been including SwiftASTContext.h anyway, so I removed that and forward-declared the few swift types it referred to. That uncovered a bunch of other places which were getting various types (including Value.h in one place!) from SwiftASTContext.h. I fixed all those. There was also one bit of swift specific code in Thread.cpp that was directly referring to the thread plan stacks that were moved out of Thread.h. I fixed that as well. --- .../lldb/Core/UserSettingsController.h | 1 + .../lldb/Target/SwiftLanguageRuntime.h | 1 + lldb/include/lldb/Target/Target.h | 9 ++++++--- lldb/include/lldb/Target/ThreadPlanStack.h | 4 ++-- lldb/source/Core/ValueObjectDynamicValue.cpp | 1 + lldb/source/Core/ValueObjectVariable.cpp | 1 + lldb/source/Expression/Materializer.cpp | 1 + lldb/source/Expression/UserExpression.cpp | 1 + .../Swift/SwiftExpressionSourceCode.cpp | 1 + lldb/source/Target/ABI.cpp | 1 + lldb/source/Target/Target.cpp | 3 +++ lldb/source/Target/Thread.cpp | 19 +++++++------------ lldb/source/Target/ThreadPlanCallFunction.cpp | 4 +++- lldb/source/Target/ThreadPlanStack.cpp | 7 +++++-- lldb/source/Target/ThreadPlanStepOut.cpp | 8 +++++++- 15 files changed, 41 insertions(+), 21 deletions(-) diff --git a/lldb/include/lldb/Core/UserSettingsController.h b/lldb/include/lldb/Core/UserSettingsController.h index 6ae3bdec16650..5374137a8d639 100644 --- a/lldb/include/lldb/Core/UserSettingsController.h +++ b/lldb/include/lldb/Core/UserSettingsController.h @@ -9,6 +9,7 @@ #ifndef liblldb_UserSettingsController_h_ #define liblldb_UserSettingsController_h_ +#include "lldb/Core/Value.h" #include "lldb/Utility/Status.h" #include "lldb/lldb-forward.h" #include "lldb/lldb-private-enumerations.h" diff --git a/lldb/include/lldb/Target/SwiftLanguageRuntime.h b/lldb/include/lldb/Target/SwiftLanguageRuntime.h index 7124386fc3ace..f659b8586d7f1 100644 --- a/lldb/include/lldb/Target/SwiftLanguageRuntime.h +++ b/lldb/include/lldb/Target/SwiftLanguageRuntime.h @@ -23,6 +23,7 @@ #include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h" #include "lldb/Breakpoint/BreakpointPrecondition.h" #include "lldb/Core/PluginInterface.h" +#include "lldb/Symbol/SwiftASTContext.h" #include "lldb/Target/LanguageRuntime.h" #include "lldb/lldb-private.h" diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index 16c0a98a97578..d83493f946e8d 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -16,8 +16,6 @@ #include #include -#include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h" -#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h" #include "lldb/Breakpoint/BreakpointList.h" #include "lldb/Breakpoint/BreakpointName.h" #include "lldb/Breakpoint/WatchpointList.h" @@ -25,12 +23,12 @@ #include "lldb/Core/Disassembler.h" #include "lldb/Core/ModuleList.h" #include "lldb/Core/UserSettingsController.h" +#include "lldb/Core/SwiftASTContextReader.h" #include "lldb/Expression/Expression.h" #include "lldb/Host/ProcessLaunchInfo.h" #include "lldb/Interpreter/OptionValueBoolean.h" #include "lldb/Interpreter/OptionValueEnumeration.h" #include "lldb/Interpreter/OptionValueFileSpec.h" -#include "lldb/Symbol/SwiftASTContext.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/TypeSystem.h" #include "lldb/Target/ABI.h" @@ -46,6 +44,11 @@ namespace lldb_private { +class ClangModulesDeclVendor; +class SwiftPersistentExpressionState; +class SharedMutex; +class SwiftASTContextForExpressions; + OptionEnumValues GetDynamicValueTypes(); enum InlineStrategy { diff --git a/lldb/include/lldb/Target/ThreadPlanStack.h b/lldb/include/lldb/Target/ThreadPlanStack.h index de52ee3ee198a..6018f2d8925fe 100644 --- a/lldb/include/lldb/Target/ThreadPlanStack.h +++ b/lldb/include/lldb/Target/ThreadPlanStack.h @@ -75,8 +75,8 @@ class ThreadPlanStack { lldb::ThreadPlanSP GetPlanByIndex(uint32_t plan_idx, bool skip_private = true) const; - lldb::ValueObjectSP GetReturnValueObject() const; - + lldb::ValueObjectSP GetReturnValueObject(bool &is_error) const; + lldb::ExpressionVariableSP GetExpressionVariable() const; bool AnyPlans() const; diff --git a/lldb/source/Core/ValueObjectDynamicValue.cpp b/lldb/source/Core/ValueObjectDynamicValue.cpp index a0abbf54e7c45..1b1d6163325e3 100644 --- a/lldb/source/Core/ValueObjectDynamicValue.cpp +++ b/lldb/source/Core/ValueObjectDynamicValue.cpp @@ -10,6 +10,7 @@ #include "lldb/Core/Value.h" #include "lldb/Core/ValueObject.h" #include "lldb/Symbol/CompilerType.h" +#include "lldb/Symbol/SwiftASTContext.h" #include "lldb/Symbol/Type.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/LanguageRuntime.h" diff --git a/lldb/source/Core/ValueObjectVariable.cpp b/lldb/source/Core/ValueObjectVariable.cpp index 027b891bd59c6..2e1d43774724b 100644 --- a/lldb/source/Core/ValueObjectVariable.cpp +++ b/lldb/source/Core/ValueObjectVariable.cpp @@ -16,6 +16,7 @@ #include "lldb/Symbol/Declaration.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SwiftASTContext.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/SymbolContextScope.h" #include "lldb/Symbol/Type.h" diff --git a/lldb/source/Expression/Materializer.cpp b/lldb/source/Expression/Materializer.cpp index 808d1b4ca723f..8780cd45ec80a 100644 --- a/lldb/source/Expression/Materializer.cpp +++ b/lldb/source/Expression/Materializer.cpp @@ -12,6 +12,7 @@ #include "lldb/Core/ValueObjectVariable.h" #include "lldb/Expression/ExpressionVariable.h" #include "lldb/Symbol/Symbol.h" +#include "lldb/Symbol/SwiftASTContext.h" #include "lldb/Symbol/Type.h" #include "lldb/Symbol/Variable.h" #include "lldb/Target/ExecutionContext.h" diff --git a/lldb/source/Expression/UserExpression.cpp b/lldb/source/Expression/UserExpression.cpp index 1a1c595a129da..2b327ee867aac 100644 --- a/lldb/source/Expression/UserExpression.cpp +++ b/lldb/source/Expression/UserExpression.cpp @@ -30,6 +30,7 @@ #include "lldb/Symbol/Block.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SwiftASTContext.h" #include "lldb/Symbol/SymbolVendor.h" #include "lldb/Symbol/Type.h" #include "lldb/Symbol/TypeSystem.h" diff --git a/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionSourceCode.cpp b/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionSourceCode.cpp index 8e08cdf50b6f2..7aa65aaf88da0 100644 --- a/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionSourceCode.cpp +++ b/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionSourceCode.cpp @@ -9,6 +9,7 @@ #include "SwiftExpressionSourceCode.h" #include "Plugins/ExpressionParser/Swift/SwiftASTManipulator.h" +#include "lldb/Symbol/SwiftASTContext.h" #include "lldb/Target/Language.h" #include "lldb/Target/Platform.h" #include "lldb/Target/Target.h" diff --git a/lldb/source/Target/ABI.cpp b/lldb/source/Target/ABI.cpp index 127d8f858460e..d7a1dfa67d215 100644 --- a/lldb/source/Target/ABI.cpp +++ b/lldb/source/Target/ABI.cpp @@ -13,6 +13,7 @@ #include "lldb/Expression/ExpressionVariable.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Symbol/TypeSystem.h" +#include "lldb/Symbol/SwiftASTContext.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/Log.h" diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index 8df8c35bb5e07..035f15b3a01f0 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -8,6 +8,8 @@ #include "lldb/Target/Target.h" #include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h" +#include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h" +#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h" #include "lldb/Breakpoint/BreakpointIDList.h" #include "lldb/Breakpoint/BreakpointPrecondition.h" #include "lldb/Breakpoint/BreakpointResolver.h" @@ -41,6 +43,7 @@ #include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SwiftASTContext.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/SymbolVendor.h" diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp index cb46a3e854637..9043f16c9b795 100644 --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -1115,18 +1115,13 @@ ThreadPlan *Thread::GetCurrentPlan() const { ValueObjectSP Thread::GetReturnValueObject(bool *is_swift_error_value) { if (is_swift_error_value) *is_swift_error_value = false; - - if (!m_completed_plan_stack.empty()) { - for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--) { - ValueObjectSP return_valobj_sp; - return_valobj_sp = m_completed_plan_stack[i]->GetReturnValueObject(); - if (return_valobj_sp) { - if (is_swift_error_value) - *is_swift_error_value = - m_completed_plan_stack[i]->IsReturnValueSwiftErrorValue(); - return return_valobj_sp; - } - } + + bool is_error; + ValueObjectSP return_valobj_sp = GetPlans().GetReturnValueObject(is_error); + if (return_valobj_sp) { + if (is_swift_error_value) + *is_swift_error_value = is_error; + return return_valobj_sp; } return ValueObjectSP(); } diff --git a/lldb/source/Target/ThreadPlanCallFunction.cpp b/lldb/source/Target/ThreadPlanCallFunction.cpp index ffb9e094d2c2a..8ba4b68f9513f 100644 --- a/lldb/source/Target/ThreadPlanCallFunction.cpp +++ b/lldb/source/Target/ThreadPlanCallFunction.cpp @@ -13,6 +13,7 @@ #include "lldb/Core/DumpRegisterValue.h" #include "lldb/Core/Module.h" #include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SwiftASTContext.h" #include "lldb/Target/ABI.h" #include "lldb/Target/LanguageRuntime.h" #include "lldb/Target/Process.h" @@ -417,7 +418,8 @@ void ThreadPlanCallFunction::SetBreakpoints() { } } if (GetExpressionLanguage() == eLanguageTypeSwift) { - auto *swift_runtime = SwiftLanguageRuntime::Get(process_sp); + auto *swift_runtime + = SwiftLanguageRuntime::Get(m_process.shared_from_this()); if (swift_runtime) { llvm::StringRef backstop_name = swift_runtime->GetErrorBackstopName(); if (!backstop_name.empty()) { diff --git a/lldb/source/Target/ThreadPlanStack.cpp b/lldb/source/Target/ThreadPlanStack.cpp index 11102650c1092..ec9ee6c3fc5d2 100644 --- a/lldb/source/Target/ThreadPlanStack.cpp +++ b/lldb/source/Target/ThreadPlanStack.cpp @@ -282,15 +282,18 @@ lldb::ThreadPlanSP ThreadPlanStack::GetPlanByIndex(uint32_t plan_idx, return {}; } -lldb::ValueObjectSP ThreadPlanStack::GetReturnValueObject() const { +lldb::ValueObjectSP +ThreadPlanStack::GetReturnValueObject(bool &is_error) const { if (m_completed_plans.empty()) return {}; for (int i = m_completed_plans.size() - 1; i >= 0; i--) { lldb::ValueObjectSP return_valobj_sp; return_valobj_sp = m_completed_plans[i]->GetReturnValueObject(); - if (return_valobj_sp) + if (return_valobj_sp) { + is_error = m_completed_plans[i]->IsReturnValueSwiftErrorValue(); return return_valobj_sp; + } } return {}; } diff --git a/lldb/source/Target/ThreadPlanStepOut.cpp b/lldb/source/Target/ThreadPlanStepOut.cpp index 9991ab2a2cd23..81f5853171514 100644 --- a/lldb/source/Target/ThreadPlanStepOut.cpp +++ b/lldb/source/Target/ThreadPlanStepOut.cpp @@ -13,6 +13,7 @@ #include "lldb/Symbol/Block.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Function.h" +#include "lldb/Symbol/SwiftASTContext.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Symbol/Type.h" #include "lldb/Symbol/VariableList.h" @@ -176,7 +177,8 @@ ThreadPlanStepOut::ThreadPlanStepOut( if (frame_idx == 0) { StackFrameSP frame_sp = m_thread.GetStackFrameAtIndex(0); if (frame_sp->GuessLanguage() == eLanguageTypeSwift) { - auto *swift_runtime = SwiftLanguageRuntime::Get(m_thread.GetProcess()); + auto *swift_runtime + = SwiftLanguageRuntime::Get(m_process.shared_from_this()); if (swift_runtime) { m_swift_error_return = swift_runtime->GetErrorReturnLocationBeforeReturn( @@ -544,7 +546,11 @@ void ThreadPlanStepOut::CalculateReturnValue() { return; // First check if we have an error return address, and if that pointer // contains a valid error return, grab it. +<<<<<<< HEAD auto *swift_runtime = SwiftLanguageRuntime::Get(m_thread.GetProcess()); +======= + auto *swift_runtime = SwiftLanguageRuntime::Get(m_process.shared_from_this()); +>>>>>>> 57e01f5b22ad... Fix the master-next build after merging in the ThreadPlanStack changes. if (swift_runtime) { // In some ABI's the error is in a memory location in the caller's frame // and we need to fetch that location from the frame before we leave the From 210d46743addf7e5fc7989551c479c8362018015 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Thu, 9 Apr 2020 18:24:15 -0700 Subject: [PATCH 215/286] Fix a linker error on Linux --- lldb/source/Symbol/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/source/Symbol/CMakeLists.txt b/lldb/source/Symbol/CMakeLists.txt index 9b2acf695ba68..e0101858b10b7 100644 --- a/lldb/source/Symbol/CMakeLists.txt +++ b/lldb/source/Symbol/CMakeLists.txt @@ -55,6 +55,7 @@ add_lldb_library(lldbSymbol lldbTarget lldbUtility lldbPluginObjCLanguage + lldbPluginPlatformMacOSX LINK_COMPONENTS Support From dfad7bb4a2ad7af385a7fc64a5be3363dcdb5954 Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Thu, 9 Apr 2020 20:05:25 -0700 Subject: [PATCH 216/286] Fix the places where master depended on Target.h including SwiftASTContext.h Also fixed a few uses of m_thread, and "not uses of m_process" that were specific to master. --- lldb/source/Core/ValueObject.cpp | 1 + .../MainThreadCheckerRuntime.cpp | 1 + lldb/source/Target/SwiftLanguageRuntime.cpp | 2 + lldb/source/Target/ThreadPlanCallFunction.cpp | 75 +++++++++---------- lldb/source/Target/ThreadPlanStepInRange.cpp | 2 +- lldb/source/Target/ThreadPlanStepOut.cpp | 10 +-- lldb/source/Target/ThreadPlanStepRange.cpp | 2 +- 7 files changed, 45 insertions(+), 48 deletions(-) diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index 2e275fc8d3214..222b5f78fdcf6 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -51,6 +51,7 @@ #include "lldb/Utility/StreamString.h" #include "lldb/lldb-private-types.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" +#include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h" // BEGIN SWIFT #include "lldb/Symbol/SwiftASTContext.h" diff --git a/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp b/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp index 454d4a16d7640..52e04794919ff 100644 --- a/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp +++ b/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.cpp @@ -11,6 +11,7 @@ #include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" +#include "lldb/Symbol/SwiftASTContext.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/Variable.h" diff --git a/lldb/source/Target/SwiftLanguageRuntime.cpp b/lldb/source/Target/SwiftLanguageRuntime.cpp index b1c380aabff11..a2f4cb4818379 100644 --- a/lldb/source/Target/SwiftLanguageRuntime.cpp +++ b/lldb/source/Target/SwiftLanguageRuntime.cpp @@ -19,6 +19,7 @@ #include "lldb/Core/Section.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/StringPrinter.h" +#include "lldb/Expression/ExpressionVariable.h" #include "lldb/Host/OptionParser.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandObject.h" @@ -46,6 +47,7 @@ // FIXME: we should not need this #include "Plugins/Language/Swift/SwiftFormatters.h" #include "Plugins/Language/Swift/SwiftRuntimeFailureRecognizer.h" +#include "Plugins/ExpressionParser/Clang/ClangExpressionVariable.h" using namespace lldb; using namespace lldb_private; diff --git a/lldb/source/Target/ThreadPlanCallFunction.cpp b/lldb/source/Target/ThreadPlanCallFunction.cpp index 8ba4b68f9513f..49d4ed9ee9c70 100644 --- a/lldb/source/Target/ThreadPlanCallFunction.cpp +++ b/lldb/source/Target/ThreadPlanCallFunction.cpp @@ -429,7 +429,7 @@ void ThreadPlanCallFunction::SetBreakpoints() { const LazyBool skip_prologue = eLazyBoolNo; const bool is_internal = true; const bool is_hardware = false; - m_error_backstop_bp_sp = process_sp->GetTarget().CreateBreakpoint( + m_error_backstop_bp_sp = m_process.GetTarget().CreateBreakpoint( &stdlib_module_list, NULL, backstop_name.str().c_str(), eFunctionNameTypeFull, eLanguageTypeUnknown, 0, skip_prologue, is_internal, is_hardware); @@ -477,45 +477,42 @@ bool ThreadPlanCallFunction::BreakpointsExplainStop() { } } if (m_error_backstop_bp_sp) { - ProcessSP process_sp(m_thread.CalculateProcess()); - if (process_sp) { - uint64_t break_site_id = stop_info_sp->GetValue(); - if (process_sp->GetBreakpointSiteList().BreakpointSiteContainsBreakpoint( - break_site_id, m_error_backstop_bp_sp->GetID())) { - // Our expression threw an uncaught exception. That will happen in REPL - // & Playground, though not in - // the regular expression parser. In that case, we should fetch the - // actual return value from the - // argument passed to this function, and set that as the return value. - SetPlanComplete(true); - StackFrameSP frame_sp = m_thread.GetStackFrameAtIndex(0); - PersistentExpressionState *persistent_state = - GetTarget().GetPersistentExpressionStateForLanguage( - eLanguageTypeSwift); - const bool is_error = true; - auto prefix = persistent_state->GetPersistentVariablePrefix(is_error); - ConstString persistent_variable_name( - persistent_state->GetNextPersistentVariableName(GetTarget(), - prefix)); - if (m_return_valobj_sp = SwiftLanguageRuntime::CalculateErrorValue( - frame_sp, persistent_variable_name)) { - - DataExtractor data; - Status data_error; - uint64_t data_size = - m_return_valobj_sp->GetStaticValue()->GetData(data, data_error); - - if (data_size == data.GetAddressByteSize()) { - lldb::offset_t offset = 0; - lldb::addr_t addr = data.GetAddress(&offset); - - SwiftLanguageRuntime::RegisterGlobalError( - GetTarget(), persistent_variable_name, addr); - } - - m_hit_error_backstop = true; - return true; + uint64_t break_site_id = stop_info_sp->GetValue(); + if (m_process.GetBreakpointSiteList().BreakpointSiteContainsBreakpoint( + break_site_id, m_error_backstop_bp_sp->GetID())) { + // Our expression threw an uncaught exception. That will happen in REPL + // & Playground, though not in + // the regular expression parser. In that case, we should fetch the + // actual return value from the + // argument passed to this function, and set that as the return value. + SetPlanComplete(true); + StackFrameSP frame_sp = GetThread().GetStackFrameAtIndex(0); + PersistentExpressionState *persistent_state = + GetTarget().GetPersistentExpressionStateForLanguage( + eLanguageTypeSwift); + const bool is_error = true; + auto prefix = persistent_state->GetPersistentVariablePrefix(is_error); + ConstString persistent_variable_name( + persistent_state->GetNextPersistentVariableName(GetTarget(), + prefix)); + if (m_return_valobj_sp = SwiftLanguageRuntime::CalculateErrorValue( + frame_sp, persistent_variable_name)) { + + DataExtractor data; + Status data_error; + uint64_t data_size = + m_return_valobj_sp->GetStaticValue()->GetData(data, data_error); + + if (data_size == data.GetAddressByteSize()) { + lldb::offset_t offset = 0; + lldb::addr_t addr = data.GetAddress(&offset); + + SwiftLanguageRuntime::RegisterGlobalError( + GetTarget(), persistent_variable_name, addr); } + + m_hit_error_backstop = true; + return true; } } } diff --git a/lldb/source/Target/ThreadPlanStepInRange.cpp b/lldb/source/Target/ThreadPlanStepInRange.cpp index df5e00fecb081..0e45faca57eb3 100644 --- a/lldb/source/Target/ThreadPlanStepInRange.cpp +++ b/lldb/source/Target/ThreadPlanStepInRange.cpp @@ -339,7 +339,7 @@ bool ThreadPlanStepInRange::StepInDeepBreakpointExplainsStop( break_id_t bp_site_id = stop_info_sp->GetValue(); BreakpointSiteSP bp_site_sp = - m_thread.GetProcess()->GetBreakpointSiteList().FindByID(bp_site_id); + m_process.GetBreakpointSiteList().FindByID(bp_site_id); if (!bp_site_sp) return false; diff --git a/lldb/source/Target/ThreadPlanStepOut.cpp b/lldb/source/Target/ThreadPlanStepOut.cpp index 81f5853171514..ecd5722c5e17b 100644 --- a/lldb/source/Target/ThreadPlanStepOut.cpp +++ b/lldb/source/Target/ThreadPlanStepOut.cpp @@ -131,7 +131,7 @@ ThreadPlanStepOut::ThreadPlanStepOut( // Perform some additional validation on the return address. uint32_t permissions = 0; - if (!m_process->GetLoadAddressPermissions(m_return_addr, + if (!m_process.GetLoadAddressPermissions(m_return_addr, permissions)) { LLDB_LOGF(log, "ThreadPlanStepOut(%p): Return address (0x%" PRIx64 ") permissions not found.", static_cast(this), @@ -175,7 +175,7 @@ ThreadPlanStepOut::ThreadPlanStepOut( // step out. That's more than I have time to do right now. if (frame_idx == 0) { - StackFrameSP frame_sp = m_thread.GetStackFrameAtIndex(0); + StackFrameSP frame_sp = GetThread().GetStackFrameAtIndex(0); if (frame_sp->GuessLanguage() == eLanguageTypeSwift) { auto *swift_runtime = SwiftLanguageRuntime::Get(m_process.shared_from_this()); @@ -546,11 +546,7 @@ void ThreadPlanStepOut::CalculateReturnValue() { return; // First check if we have an error return address, and if that pointer // contains a valid error return, grab it. -<<<<<<< HEAD - auto *swift_runtime = SwiftLanguageRuntime::Get(m_thread.GetProcess()); -======= auto *swift_runtime = SwiftLanguageRuntime::Get(m_process.shared_from_this()); ->>>>>>> 57e01f5b22ad... Fix the master-next build after merging in the ThreadPlanStack changes. if (swift_runtime) { // In some ABI's the error is in a memory location in the caller's frame // and we need to fetch that location from the frame before we leave the @@ -558,7 +554,7 @@ void ThreadPlanStepOut::CalculateReturnValue() { // so we need to fetch the value of the address AFTER leaving the frame. if (m_swift_error_check_after_return) { - StackFrameSP frame_sp = m_thread.GetStackFrameAtIndex(0); + StackFrameSP frame_sp = GetThread().GetStackFrameAtIndex(0); if (!frame_sp) return; diff --git a/lldb/source/Target/ThreadPlanStepRange.cpp b/lldb/source/Target/ThreadPlanStepRange.cpp index 2495d5e98a08e..3a0e1eb686c4e 100644 --- a/lldb/source/Target/ThreadPlanStepRange.cpp +++ b/lldb/source/Target/ThreadPlanStepRange.cpp @@ -263,7 +263,7 @@ InstructionList *ThreadPlanStepRange::GetInstructionsForAddress( if (!m_instruction_ranges[i]) { // Disassemble the address range given: - ExecutionContext exe_ctx(m_thread.GetProcess()); + ExecutionContext exe_ctx(&m_process); const char *plugin_name = nullptr; const char *flavor = nullptr; const bool prefer_file_cache = true; From 004fc3921deecb6be6c10ad023f43debeedb4a4d Mon Sep 17 00:00:00 2001 From: Raphael Isemann Date: Fri, 10 Apr 2020 14:44:42 +0200 Subject: [PATCH 217/286] [lldb][swift] Make sure we have a StackFrame in GetDynamicTypeAndAddress We got a report of getting a bad weak ptr abort from the stack frame here. This just makes sure that we have a valid shared_ptr when we call DoArchetypeBindingForType as this might later call get_shared_from_this() (via SwiftLanguageRuntime::GetConcreteType -> StackFrame::CalculateStackFrame). (Potentially) Fixes rdar://problem/61384698 --- .../Target/SwiftLanguageRuntimeDynamicTypeResolution.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lldb/source/Target/SwiftLanguageRuntimeDynamicTypeResolution.cpp b/lldb/source/Target/SwiftLanguageRuntimeDynamicTypeResolution.cpp index c9edb184c8890..faa5416cabbb6 100644 --- a/lldb/source/Target/SwiftLanguageRuntimeDynamicTypeResolution.cpp +++ b/lldb/source/Target/SwiftLanguageRuntimeDynamicTypeResolution.cpp @@ -1518,11 +1518,11 @@ bool SwiftLanguageRuntimeImpl::GetDynamicTypeAndAddress( class_type_or_name, address); else { // Perform archetype binding in the scratch context. - auto *frame = in_value.GetExecutionContextRef().GetFrameSP().get(); + StackFrameSP frame = in_value.GetExecutionContextRef().GetFrameSP(); if (!frame) return false; - CompilerType bound_type = DoArchetypeBindingForType(*frame, val_type); + CompilerType bound_type = DoArchetypeBindingForType(*frame.get(), val_type); if (!bound_type) return false; From 5e64ad7e9d28c144d906cad0c5b070eef34015f6 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Tue, 17 Mar 2020 12:51:58 -0700 Subject: [PATCH 218/286] Remove const qualifier from Modules returned by ExternalASTSource. (NFC) This API is used by LLDB to attach owning module information to Declarations deserialized from DWARF. Differential Revision: https://reviews.llvm.org/D75561 (cherry picked from commit f4754ea0ed7ddc35042bacbc47d661bfe660f132) Conflicts: clang/include/clang/Basic/Module.h clang/lib/Basic/Module.cpp clang/lib/Serialization/ASTReader.cpp --- clang/include/clang/AST/ExternalASTSource.h | 6 +++--- clang/lib/AST/ExternalASTSource.cpp | 2 +- clang/lib/Serialization/ASTReader.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/clang/include/clang/AST/ExternalASTSource.h b/clang/include/clang/AST/ExternalASTSource.h index 899ac3f669371..68888fb02b3dd 100644 --- a/clang/include/clang/AST/ExternalASTSource.h +++ b/clang/include/clang/AST/ExternalASTSource.h @@ -173,7 +173,7 @@ class ExternalASTSource : public RefCountedBase { StringRef Path; StringRef ASTFile; ASTFileSignature Signature; - const Module *ClangModule = nullptr; + Module *ClangModule = nullptr; public: ASTSourceDescriptor() = default; @@ -181,13 +181,13 @@ class ExternalASTSource : public RefCountedBase { ASTFileSignature Signature) : PCHModuleName(std::move(Name)), Path(std::move(Path)), ASTFile(std::move(ASTFile)), Signature(Signature) {} - ASTSourceDescriptor(const Module &M); + ASTSourceDescriptor(Module &M); std::string getModuleName() const; StringRef getPath() const { return Path; } StringRef getASTFile() const { return ASTFile; } ASTFileSignature getSignature() const { return Signature; } - const Module *getModuleOrNull() const { return ClangModule; } + Module *getModuleOrNull() const { return ClangModule; } }; /// Return a descriptor for the corresponding module, if one exists. diff --git a/clang/lib/AST/ExternalASTSource.cpp b/clang/lib/AST/ExternalASTSource.cpp index 837be5527fce3..656d22e6d5aa2 100644 --- a/clang/lib/AST/ExternalASTSource.cpp +++ b/clang/lib/AST/ExternalASTSource.cpp @@ -38,7 +38,7 @@ ExternalASTSource::hasExternalDefinitions(const Decl *D) { return EK_ReplyHazy; } -ExternalASTSource::ASTSourceDescriptor::ASTSourceDescriptor(const Module &M) +ExternalASTSource::ASTSourceDescriptor::ASTSourceDescriptor(Module &M) : Signature(M.Signature), ClangModule(&M) { if (M.Directory) Path = M.Directory->getName(); diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 00d2e7e882a99..97c6990f4be0c 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -8488,7 +8488,7 @@ unsigned ASTReader::getModuleFileID(ModuleFile *F) { llvm::Optional ASTReader::getSourceDescriptor(unsigned ID) { - if (const Module *M = getSubmodule(ID)) + if (Module *M = getSubmodule(ID)) return ExternalASTSource::ASTSourceDescriptor(*M); // If there is only a single PCH, return it instead. From b74718abde9eb868638cf15fddb393968b284418 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Tue, 17 Mar 2020 12:51:58 -0700 Subject: [PATCH 219/286] Remove const qualifier from Modules returned by ExternalASTSource. (NFC) This API is used by LLDB to attach owning module information to Declarations deserialized from DWARF. Differential Revision: https://reviews.llvm.org/D75561 (cherry picked from commit f4754ea0ed7ddc35042bacbc47d661bfe660f132) Conflicts: clang/include/clang/Basic/Module.h clang/lib/Basic/Module.cpp clang/lib/Serialization/ASTReader.cpp --- clang/include/clang/AST/ExternalASTSource.h | 6 +++--- clang/lib/AST/ExternalASTSource.cpp | 2 +- clang/lib/Serialization/ASTReader.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/clang/include/clang/AST/ExternalASTSource.h b/clang/include/clang/AST/ExternalASTSource.h index 899ac3f669371..68888fb02b3dd 100644 --- a/clang/include/clang/AST/ExternalASTSource.h +++ b/clang/include/clang/AST/ExternalASTSource.h @@ -173,7 +173,7 @@ class ExternalASTSource : public RefCountedBase { StringRef Path; StringRef ASTFile; ASTFileSignature Signature; - const Module *ClangModule = nullptr; + Module *ClangModule = nullptr; public: ASTSourceDescriptor() = default; @@ -181,13 +181,13 @@ class ExternalASTSource : public RefCountedBase { ASTFileSignature Signature) : PCHModuleName(std::move(Name)), Path(std::move(Path)), ASTFile(std::move(ASTFile)), Signature(Signature) {} - ASTSourceDescriptor(const Module &M); + ASTSourceDescriptor(Module &M); std::string getModuleName() const; StringRef getPath() const { return Path; } StringRef getASTFile() const { return ASTFile; } ASTFileSignature getSignature() const { return Signature; } - const Module *getModuleOrNull() const { return ClangModule; } + Module *getModuleOrNull() const { return ClangModule; } }; /// Return a descriptor for the corresponding module, if one exists. diff --git a/clang/lib/AST/ExternalASTSource.cpp b/clang/lib/AST/ExternalASTSource.cpp index 837be5527fce3..656d22e6d5aa2 100644 --- a/clang/lib/AST/ExternalASTSource.cpp +++ b/clang/lib/AST/ExternalASTSource.cpp @@ -38,7 +38,7 @@ ExternalASTSource::hasExternalDefinitions(const Decl *D) { return EK_ReplyHazy; } -ExternalASTSource::ASTSourceDescriptor::ASTSourceDescriptor(const Module &M) +ExternalASTSource::ASTSourceDescriptor::ASTSourceDescriptor(Module &M) : Signature(M.Signature), ClangModule(&M) { if (M.Directory) Path = M.Directory->getName(); diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 00d2e7e882a99..97c6990f4be0c 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -8488,7 +8488,7 @@ unsigned ASTReader::getModuleFileID(ModuleFile *F) { llvm::Optional ASTReader::getSourceDescriptor(unsigned ID) { - if (const Module *M = getSubmodule(ID)) + if (Module *M = getSubmodule(ID)) return ExternalASTSource::ASTSourceDescriptor(*M); // If there is only a single PCH, return it instead. From 524c6935b79460eae3a1b13801edaa934627b11e Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Fri, 10 Apr 2020 14:50:04 -0700 Subject: [PATCH 220/286] Implement TypeSystemSwiftTypeRef::GetNumberOfFunctionArguments() (NFC) --- lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp | 70 +++++++++++---- .../Symbol/TestTypeSystemSwiftTypeRef.cpp | 86 +++++++++++++++---- 2 files changed, 119 insertions(+), 37 deletions(-) diff --git a/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp index 836273cf039b2..b06458a7cab7e 100644 --- a/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp +++ b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp @@ -394,34 +394,68 @@ bool TypeSystemSwiftTypeRef::IsFloatingPointType(void *type, uint32_t &count, return m_swift_ast_context->IsFloatingPointType(ReconstructType(type), count, is_complex); } + +/// Drill into a function type. +static NodePointer GetFunctionTypeNode(NodePointer node) { + using namespace swift::Demangle; + if (!node || node->getNumChildren() != 1 || + node->getKind() != Node::Kind::Global) + return nullptr; + node = node->getFirstChild(); + if (node->getNumChildren() != 1 || + node->getKind() != Node::Kind::TypeMangling) + return nullptr; + node = node->getFirstChild(); + if (node->getNumChildren() != 1 || node->getKind() != Node::Kind::Type) + return nullptr; + node = node->getFirstChild(); + if (node->getKind() != Node::Kind::FunctionType && + node->getKind() != Node::Kind::ImplFunctionType) + return nullptr; + return node; +} + bool TypeSystemSwiftTypeRef::IsFunctionType(void *type, bool *is_variadic_ptr) { - auto impl = [&]() { + auto impl = [&]() -> bool { using namespace swift::Demangle; Demangler Dem; NodePointer node = GetCanonicalDemangleTree(GetModule(), Dem, AsMangledName(type)); - if (!node || node->getNumChildren() != 1 || - node->getKind() != Node::Kind::Global) - return false; - node = node->getFirstChild(); - if (node->getNumChildren() != 1 || - node->getKind() != Node::Kind::TypeMangling) - return false; - node = node->getFirstChild(); - if (node->getNumChildren() != 1 || node->getKind() != Node::Kind::Type) - return false; - node = node->getFirstChild(); - if (node->getKind() != Node::Kind::FunctionType && - node->getKind() != Node::Kind::ImplFunctionType) - return false; - return true; + return GetFunctionTypeNode(node); }; VALIDATE_AND_RETURN(impl, m_swift_ast_context->IsFunctionType( ReconstructType(type), nullptr)); } size_t TypeSystemSwiftTypeRef::GetNumberOfFunctionArguments(void *type) { - return m_swift_ast_context->GetNumberOfFunctionArguments( - ReconstructType(type)); + auto impl = [&]() -> size_t { + using namespace swift::Demangle; + Demangler Dem; + NodePointer node = + GetCanonicalDemangleTree(GetModule(), Dem, AsMangledName(type)); + if (!node) + return 0; + node = GetFunctionTypeNode(node); + if (!node) + return 0; + unsigned num_args = 0; + for (NodePointer child : *node) { + if (child->getKind() == Node::Kind::ImplParameter) + ++num_args; + if (child->getKind() == Node::Kind::ArgumentTuple && + child->getNumChildren() == 1) { + NodePointer node = child->getFirstChild(); + if (node->getNumChildren() != 1 || + node->getKind() != Node::Kind::Type) + break; + node = node->getFirstChild(); + if (node->getKind() == Node::Kind::Tuple) + return node->getNumChildren(); + } + } + return num_args; + }; + VALIDATE_AND_RETURN(impl, m_swift_ast_context->GetNumberOfFunctionArguments( + ReconstructType(type))); } CompilerType TypeSystemSwiftTypeRef::GetFunctionArgumentAtIndex(void *type, diff --git a/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp b/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp index 59a748ede86a7..7cb778533a6a5 100644 --- a/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp +++ b/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp @@ -42,15 +42,28 @@ class NodeBuilder { return m_dem.createNode(kind, text); } NodePointer Node(Kind kind, NodePointer child0 = nullptr, - NodePointer child1 = nullptr) { + NodePointer child1 = nullptr, + NodePointer child2 = nullptr, + NodePointer child3 = nullptr) { NodePointer node = m_dem.createNode(kind); if (child0) node->addChild(child0, m_dem); if (child1) node->addChild(child1, m_dem); + if (child2) + node->addChild(child2, m_dem); + if (child3) + node->addChild(child3, m_dem); return node; } + NodePointer IntType() { + return Node( + Node::Kind::Type, + Node(Node::Kind::Structure, + Node(Node::Kind::Module, swift::STDLIB_NAME), + Node(Node::Kind::Identifier, swift::BUILTIN_TYPE_NAME_INT))); + } std::string Mangle(NodePointer node) { return mangleNode(node); } }; @@ -63,22 +76,14 @@ TEST_F(TestTypeSystemSwiftTypeRef, Array) { Node::Kind::Global, b.Node( Node::Kind::TypeMangling, - b.Node( - Node::Kind::Type, - b.Node( - Node::Kind::BoundGenericStructure, - b.Node(Node::Kind::Type, - b.Node(Node::Kind::Structure, - b.Node(Node::Kind::Module, swift::STDLIB_NAME), - b.Node(Node::Kind::Identifier, "Array"))), - b.Node( - Node::Kind::TypeList, - b.Node( - Node::Kind::Type, - b.Node(Node::Kind::Structure, - b.Node(Node::Kind::Module, swift::STDLIB_NAME), - b.Node(Node::Kind::Identifier, - swift::BUILTIN_TYPE_NAME_INT)))))))); + b.Node(Node::Kind::Type, + b.Node(Node::Kind::BoundGenericStructure, + b.Node(Node::Kind::Type, + b.Node(Node::Kind::Structure, + b.Node(Node::Kind::Module, + swift::STDLIB_NAME), + b.Node(Node::Kind::Identifier, "Array"))), + b.Node(Node::Kind::TypeList, b.IntType()))))); CompilerType int_array = GetCompilerType(b.Mangle(n)); ASSERT_TRUE(int_array.IsArrayType(nullptr, nullptr, nullptr)); } @@ -101,6 +106,7 @@ TEST_F(TestTypeSystemSwiftTypeRef, Function) { b.Node(Node::Kind::Tuple))))))); CompilerType void_void = GetCompilerType(b.Mangle(n)); ASSERT_TRUE(void_void.IsFunctionType(nullptr)); + ASSERT_EQ(void_void.GetNumberOfFunctionArguments(), 0); } { NodePointer n = @@ -111,7 +117,49 @@ TEST_F(TestTypeSystemSwiftTypeRef, Function) { b.Node(Node::Kind::ImplEscaping), b.Node(Node::Kind::ImplConvention, "@callee_guaranteed"))))); - CompilerType opaque = GetCompilerType(b.Mangle(n)); - ASSERT_TRUE(opaque.IsFunctionType(nullptr)); + CompilerType impl_void_void = GetCompilerType(b.Mangle(n)); + ASSERT_TRUE(impl_void_void.IsFunctionType(nullptr)); + ASSERT_EQ(impl_void_void.GetNumberOfFunctionArguments(), 0); + } + { + NodePointer n = b.Node( + Node::Kind::Global, + b.Node( + Node::Kind::TypeMangling, + b.Node( + Node::Kind::Type, + b.Node(Node::Kind::ImplFunctionType, + b.Node(Node::Kind::ImplEscaping), + b.Node(Node::Kind::ImplConvention, "@callee_guaranteed"), + b.Node(Node::Kind::ImplParameter, + b.Node(Node::Kind::ImplConvention, "@unowned"), + b.IntType()), + b.Node(Node::Kind::ImplParameter, + b.Node(Node::Kind::ImplConvention, "@unowned"), + b.IntType()))))); + CompilerType impl_two_args = GetCompilerType(b.Mangle(n)); + ASSERT_TRUE(impl_two_args.IsFunctionType(nullptr)); + ASSERT_EQ(impl_two_args.GetNumberOfFunctionArguments(), 2); + } + { + NodePointer n = b.Node( + Node::Kind::Global, + b.Node( + Node::Kind::TypeMangling, + b.Node(Node::Kind::Type, + b.Node(Node::Kind::FunctionType, + b.Node(Node::Kind::ArgumentTuple, + b.Node(Node::Kind::Type, + b.Node(Node::Kind::Tuple, + b.Node(Node::Kind::TupleElement, + b.IntType()), + b.Node(Node::Kind::TupleElement, + b.IntType())))), + b.Node(Node::Kind::ReturnType, + b.Node(Node::Kind::Type, + b.Node(Node::Kind::Tuple))))))); + CompilerType two_args = GetCompilerType(b.Mangle(n)); + ASSERT_TRUE(two_args.IsFunctionType(nullptr)); + ASSERT_EQ(two_args.GetNumberOfFunctionArguments(), 2); } } From 346b941f25f42cc753b279314c3ad10c5c3ee388 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Thu, 2 Apr 2020 16:05:45 -0700 Subject: [PATCH 221/286] Teach the stripNonLineTableDebugInfo pass about the llvm.dbg.addr intrinsic. This patch also strips llvm.dbg.addr intrinsics when downgrading debug info to linetables-only. Differential Revision: https://reviews.llvm.org/D77343 (cherry picked from commit c024f3ebdcfc9910d7d8f711a76d9dc669c9e97c) --- llvm/lib/IR/DebugInfo.cpp | 1 + .../Util/strip-nonlinetable-debuginfo-localvars.ll | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/llvm/lib/IR/DebugInfo.cpp b/llvm/lib/IR/DebugInfo.cpp index 7ac26986c662a..4b4dac5373659 100644 --- a/llvm/lib/IR/DebugInfo.cpp +++ b/llvm/lib/IR/DebugInfo.cpp @@ -623,6 +623,7 @@ bool llvm::stripNonLineTableDebugInfo(Module &M) { Changed = true; } }; + RemoveUses("llvm.dbg.addr"); RemoveUses("llvm.dbg.declare"); RemoveUses("llvm.dbg.value"); diff --git a/llvm/test/Transforms/Util/strip-nonlinetable-debuginfo-localvars.ll b/llvm/test/Transforms/Util/strip-nonlinetable-debuginfo-localvars.ll index c2cb87acb2a0b..c2642c312ccdc 100644 --- a/llvm/test/Transforms/Util/strip-nonlinetable-debuginfo-localvars.ll +++ b/llvm/test/Transforms/Util/strip-nonlinetable-debuginfo-localvars.ll @@ -3,14 +3,18 @@ define void @f() !dbg !4 { entry: %i = alloca i32, align 4 - ; CHECK-NOT: llvm.dbg.declare + ; CHECK-NOT: llvm.dbg.{{addr|declare|value}} call void @llvm.dbg.declare(metadata i32* %i, metadata !11, metadata !13), !dbg !14 + call void @llvm.dbg.addr(metadata i32* %i, metadata !16, metadata !13), !dbg !14 store i32 42, i32* %i, align 4, !dbg !14 + call void @llvm.dbg.value(metadata i32 0, metadata !16, metadata !13), !dbg !15 ret void, !dbg !15 } ; Function Attrs: nounwind readnone +declare void @llvm.dbg.addr(metadata, metadata, metadata) declare void @llvm.dbg.declare(metadata, metadata, metadata) +declare void @llvm.dbg.value(metadata, metadata, metadata) !llvm.dbg.cu = !{!0} !llvm.module.flags = !{!7, !8, !9} @@ -22,6 +26,7 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata) ; CHECK: ![[F]] = distinct !DISubprogram(name: "f" ; CHECK-NOT: retainedNodes: ; CHECK-NOT: distinct !DISubprogram(name: "f" +; CHECK-NOT: DILocalVariable !4 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 1, type: !5, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: false, unit: !0, retainedNodes: !2) !5 = !DISubroutineType(types: !6) !6 = !{null} @@ -34,3 +39,4 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata) !13 = !DIExpression() !14 = !DILocation(line: 1, column: 16, scope: !4) !15 = !DILocation(line: 1, column: 24, scope: !4) +!16 = !DILocalVariable(name: "j", scope: !4, file: !1, line: 1, type: !12) From e9e4035903f425b08b42ede0e435bd1b9c88a526 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Thu, 2 Apr 2020 16:11:49 -0700 Subject: [PATCH 222/286] Teach the stripNonLineTableDebugInfo pass about the llvm.dbg.label intrinsic. Debug info for labels is not generated at -gline-tables-only, so this pass should remove them. Differential Revision: https://reviews.llvm.org/D77345 (cherry picked from commit 93fe58c9cf532d8ddb166d8d00667707bc017ed7) --- llvm/lib/IR/DebugInfo.cpp | 1 + .../strip-nonlinetable-debuginfo-labels.ll | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 llvm/test/Transforms/Util/strip-nonlinetable-debuginfo-labels.ll diff --git a/llvm/lib/IR/DebugInfo.cpp b/llvm/lib/IR/DebugInfo.cpp index 4b4dac5373659..2175ffe77cfd8 100644 --- a/llvm/lib/IR/DebugInfo.cpp +++ b/llvm/lib/IR/DebugInfo.cpp @@ -625,6 +625,7 @@ bool llvm::stripNonLineTableDebugInfo(Module &M) { }; RemoveUses("llvm.dbg.addr"); RemoveUses("llvm.dbg.declare"); + RemoveUses("llvm.dbg.label"); RemoveUses("llvm.dbg.value"); // Delete non-CU debug info named metadata nodes. diff --git a/llvm/test/Transforms/Util/strip-nonlinetable-debuginfo-labels.ll b/llvm/test/Transforms/Util/strip-nonlinetable-debuginfo-labels.ll new file mode 100644 index 0000000000000..ed48add3b115a --- /dev/null +++ b/llvm/test/Transforms/Util/strip-nonlinetable-debuginfo-labels.ll @@ -0,0 +1,28 @@ +; RUN: opt -S -strip-nonlinetable-debuginfo %s -o - | FileCheck %s +; CHECK: define void @f() +define void @f() !dbg !4 { +entry: +; CHECK-NOT: llvm.dbg.label + call void @llvm.dbg.label(metadata !12), !dbg !11 + ret void, !dbg !11 +} + +declare void @llvm.dbg.label(metadata) + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!7, !8, !9} +!llvm.ident = !{!10} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "LLVM", isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2) +!1 = !DIFile(filename: "f.c", directory: "/") +!2 = !{} +!4 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 1, type: !5, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: false, unit: !0, retainedNodes: !2) +!5 = !DISubroutineType(types: !6) +!6 = !{null} +!7 = !{i32 2, !"Dwarf Version", i32 2} +!8 = !{i32 2, !"Debug Info Version", i32 3} +!9 = !{i32 1, !"PIC Level", i32 2} +!10 = !{!"LLVM"} +!11 = !DILocation(line: 1, column: 24, scope: !4) +; CHECK-NOT: DILabel +!12 = !DILabel(scope: !4, name: "entry", file: !1, line: 1) From bf07502b6db73f085f95c541cfe4aa06577e8936 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Thu, 19 Mar 2020 18:51:36 -0700 Subject: [PATCH 223/286] Remap the target (Xcode) SDK directory to the host SDK directory. This is mostly useful for Swift support; it allows LLDB to substitute a matching SDK it shipped with instead of the sysroot path that was used at compile time. The goal of this is to make the Xcode SDK something that behaves more like the compiler's resource directory, as in that it ships with LLDB rather than with the debugged program. This important primarily for importing Swift and Clang modules in the expression evaluator, and getting at the APINotes from the SDK in Swift. For a cross-debugging scenario, this means you have to have an SDK for your target installed alongside LLDB. In Xcode this will always be the case. rdar://problem/60640017 Differential Revision: https://reviews.llvm.org/D76471 (cherry picked from commit 1e05d7b3d3c6d29ff6f9493cc478a36244cc32bd) Conflicts: lldb/include/lldb/Core/Module.h --- lldb/include/lldb/Core/Module.h | 11 ++ lldb/include/lldb/Host/HostInfoBase.h | 4 + .../include/lldb/Host/macosx/HostInfoMacOSX.h | 4 + lldb/include/lldb/Target/Platform.h | 4 + lldb/include/lldb/Utility/XcodeSDK.h | 63 +++++++ lldb/source/Core/Module.cpp | 18 ++ .../Host/macosx/objcxx/HostInfoMacOSX.mm | 37 ++++ .../MacOSX/PlatformAppleTVSimulator.h | 2 +- .../MacOSX/PlatformAppleWatchSimulator.h | 2 +- .../Platform/MacOSX/PlatformDarwin.cpp | 146 +++------------- .../Plugins/Platform/MacOSX/PlatformDarwin.h | 41 ++--- .../Platform/MacOSX/PlatformMacOSX.cpp | 3 +- .../Plugins/Platform/MacOSX/PlatformMacOSX.h | 2 +- .../MacOSX/PlatformRemoteDarwinDevice.h | 2 +- .../Platform/MacOSX/PlatformiOSSimulator.h | 2 +- .../Plugins/SymbolFile/DWARF/DWARFUnit.h | 1 + .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 6 + lldb/source/Utility/CMakeLists.txt | 1 + lldb/source/Utility/XcodeSDK.cpp | 163 ++++++++++++++++++ .../unittests/Platform/PlatformDarwinTest.cpp | 45 ----- lldb/unittests/Utility/CMakeLists.txt | 1 + lldb/unittests/Utility/XcodeSDKTest.cpp | 86 +++++++++ 22 files changed, 440 insertions(+), 204 deletions(-) create mode 100644 lldb/include/lldb/Utility/XcodeSDK.h create mode 100644 lldb/source/Utility/XcodeSDK.cpp create mode 100644 lldb/unittests/Utility/XcodeSDKTest.cpp diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h index 2af18c83f23a3..df9a271df0866 100644 --- a/lldb/include/lldb/Core/Module.h +++ b/lldb/include/lldb/Core/Module.h @@ -19,6 +19,7 @@ #include "lldb/Utility/ConstString.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/Status.h" +#include "lldb/Utility/XcodeSDK.h" #include "lldb/Utility/UUID.h" #include "lldb/lldb-defines.h" #include "lldb/lldb-enumerations.h" @@ -508,6 +509,12 @@ class Module : public std::enable_shared_from_this, m_mod_time = mod_time; } + /// This callback will be called by SymbolFile implementations when + /// parsing a compile unit that contains SDK information. + /// \param sdk will be merged with \p m_sdk. + /// \param sysroot will be added to the path remapping dictionary. + void RegisterXcodeSDK(llvm::StringRef sdk, llvm::StringRef sysroot); + /// Tells whether this module is capable of being the main executable for a /// process. /// @@ -970,6 +977,10 @@ class Module : public std::enable_shared_from_this, ///when you have debug info for a module ///that doesn't match where the sources ///currently are + + /// The (Xcode) SDK this module was compiled with. + XcodeSDK m_xcode_sdk; + lldb::SectionListUP m_sections_up; ///< Unified section list for module that /// is used by the ObjectFile and and /// ObjectFile instances for the debug info diff --git a/lldb/include/lldb/Host/HostInfoBase.h b/lldb/include/lldb/Host/HostInfoBase.h index c59050cb34e97..ff328783d4b7e 100644 --- a/lldb/include/lldb/Host/HostInfoBase.h +++ b/lldb/include/lldb/Host/HostInfoBase.h @@ -12,6 +12,7 @@ #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/UserIDResolver.h" +#include "lldb/Utility/XcodeSDK.h" #include "lldb/lldb-enumerations.h" #include "llvm/ADT/StringRef.h" @@ -91,6 +92,9 @@ class HostInfoBase { static bool ComputePathRelativeToLibrary(FileSpec &file_spec, llvm::StringRef dir); + /// Return the directory containing a specific Xcode SDK. + static std::string GetXcodeSDK(XcodeSDK sdk) { return {}; } + protected: static bool ComputeSharedLibraryDirectory(FileSpec &file_spec); static bool ComputeSupportExeDirectory(FileSpec &file_spec); diff --git a/lldb/include/lldb/Host/macosx/HostInfoMacOSX.h b/lldb/include/lldb/Host/macosx/HostInfoMacOSX.h index 217ca5bf1fce9..b21de371a3973 100644 --- a/lldb/include/lldb/Host/macosx/HostInfoMacOSX.h +++ b/lldb/include/lldb/Host/macosx/HostInfoMacOSX.h @@ -11,6 +11,7 @@ #include "lldb/Host/posix/HostInfoPosix.h" #include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/XcodeSDK.h" #include "llvm/Support/VersionTuple.h" namespace lldb_private { @@ -31,7 +32,10 @@ class HostInfoMacOSX : public HostInfoPosix { static bool GetOSBuildString(std::string &s); static bool GetOSKernelDescription(std::string &s); static FileSpec GetProgramFileSpec(); + static std::string FindXcodeContentsDirectoryInPath(llvm::StringRef path); + /// Query xcrun to find an Xcode SDK directory. + static std::string GetXcodeSDK(XcodeSDK sdk); protected: static bool ComputeSupportExeDirectory(FileSpec &file_spec); static void ComputeHostArchitectureSupport(ArchSpec &arch_32, diff --git a/lldb/include/lldb/Target/Platform.h b/lldb/include/lldb/Target/Platform.h index 46d5974e3c30b..0e37e36498df3 100644 --- a/lldb/include/lldb/Target/Platform.h +++ b/lldb/include/lldb/Target/Platform.h @@ -431,6 +431,10 @@ class Platform : public PluginInterface { return lldb_private::ConstString(); } + virtual llvm::StringRef GetSDKPath(lldb_private::XcodeSDK sdk) { + return {}; + } + const std::string &GetRemoteURL() const { return m_remote_url; } bool IsHost() const { diff --git a/lldb/include/lldb/Utility/XcodeSDK.h b/lldb/include/lldb/Utility/XcodeSDK.h new file mode 100644 index 0000000000000..9b9f1d226bf09 --- /dev/null +++ b/lldb/include/lldb/Utility/XcodeSDK.h @@ -0,0 +1,63 @@ +//===-- XcodeSDK.h ----------------------------------------------*- 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 LLDB_UTILITY_SDK_H +#define LLDB_UTILITY_SDK_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/VersionTuple.h" +#include + +namespace lldb_private { + +/// An abstraction for Xcode-style SDKs that works like \ref ArchSpec. +class XcodeSDK { + std::string m_name; + +public: + XcodeSDK() = default; + XcodeSDK(std::string &&name) : m_name(std::move(name)) {} + static XcodeSDK GetAnyMacOS() { return XcodeSDK("MacOSX.sdk"); } + + enum Type : int { + MacOSX = 0, + iPhoneSimulator, + iPhoneOS, + AppleTVSimulator, + AppleTVOS, + WatchSimulator, + watchOS, + bridgeOS, + Linux, + numSDKTypes, + unknown = -1 + }; + static llvm::StringRef GetNameForType(Type type); + + /// The merge function follows a strict order to maintain monotonicity: + /// 1. SDK with the higher SDKType wins. + /// 2. The newer SDK wins. + void Merge(XcodeSDK other); + + XcodeSDK &operator=(XcodeSDK other); + bool operator==(XcodeSDK other); + + /// Return parsed SDK number, and SDK version number. + std::tuple Parse() const; + llvm::VersionTuple GetVersion() const; + Type GetType() const; + llvm::StringRef GetString() const; + + static bool SDKSupportsModules(Type type, llvm::VersionTuple version); + static bool SDKSupportsModules(Type desired_type, const FileSpec &sdk_path); + static llvm::StringRef GetSDKNameForType(Type type); +}; + +} // namespace lldb_private + +#endif diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp index 031892abdd247..00b260b3277bd 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -1591,6 +1591,24 @@ bool Module::RemapSourceFile(llvm::StringRef path, return m_source_mappings.RemapPath(path, new_path); } +void Module::RegisterXcodeSDK(llvm::StringRef sdk_name, llvm::StringRef sysroot) { + XcodeSDK sdk(sdk_name.str()); + if (m_xcode_sdk == sdk) + return; + m_xcode_sdk.Merge(sdk); + PlatformSP module_platform = + Platform::GetPlatformForArchitecture(GetArchitecture(), nullptr); + ConstString sdk_path(module_platform->GetSDKPath(sdk)); + if (!sdk_path) + return; + // If merged SDK changed for a previously registered source path, update it. + // This could happend with -fdebug-prefix-map, otherwise it's unlikely. + ConstString sysroot_cs(sysroot); + if (!m_source_mappings.Replace(sysroot_cs, sdk_path, true)) + // In the general case, however, append it to the list. + m_source_mappings.Append(sysroot_cs, sdk_path, false); +} + bool Module::MergeArchitecture(const ArchSpec &arch_spec) { if (!arch_spec.IsValid()) return false; diff --git a/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm b/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm index e73d2ffe9b9ab..c09339e8c6731 100644 --- a/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm +++ b/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm @@ -8,6 +8,7 @@ #include "lldb/Host/macosx/HostInfoMacOSX.h" #include "lldb/Host/FileSystem.h" +#include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" #include "lldb/Utility/Args.h" #include "lldb/Utility/Log.h" @@ -295,3 +296,39 @@ static void ParseOSVersion(llvm::VersionTuple &version, NSString *Key) { } } } + +std::string HostInfoMacOSX::GetXcodeSDK(XcodeSDK sdk) { + std::string xcrun_cmd = "xcrun --show-sdk-path --sdk " + + XcodeSDK::GetSDKNameForType(sdk.GetType()).str(); + llvm::VersionTuple version = sdk.GetVersion(); + if (!version.empty()) + xcrun_cmd += version.getAsString(); + + int status = 0; + int signo = 0; + std::string output_str; + lldb_private::Status error = + Host::RunShellCommand(xcrun_cmd.c_str(), FileSpec(), &status, &signo, + &output_str, std::chrono::seconds(15)); + + // Check that xcrun return something useful. + if (status != 0 || output_str.empty()) + return {}; + + // Convert to a StringRef so we can manipulate the string without modifying + // the underlying data. + llvm::StringRef output(output_str); + + // Remove any trailing newline characters. + output = output.rtrim(); + + // Strip any leading newline characters and everything before them. + const size_t last_newline = output.rfind('\n'); + if (last_newline != llvm::StringRef::npos) + output = output.substr(last_newline + 1); + + // Whatever is left in output should be a valid path. + if (!FileSystem::Instance().Exists(output)) + return {}; + return output.str(); +} diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.h b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.h index 0005eab4e6710..fc377ef04a6d4 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.h @@ -69,7 +69,7 @@ class PlatformAppleTVSimulator : public PlatformDarwin { AddClangModuleCompilationOptions(lldb_private::Target *target, std::vector &options) override { return PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( - target, options, PlatformDarwin::SDKType::iPhoneSimulator); + target, options, lldb_private::XcodeSDK::Type::iPhoneSimulator); } protected: diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.h b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.h index d8ffa05343a73..cf6b2436b2969 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.h @@ -69,7 +69,7 @@ class PlatformAppleWatchSimulator : public PlatformDarwin { AddClangModuleCompilationOptions(lldb_private::Target *target, std::vector &options) override { return PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( - target, options, PlatformDarwin::SDKType::iPhoneSimulator); + target, options, lldb_private::XcodeSDK::Type::iPhoneSimulator); } protected: diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp index a734bfc39d1ea..0c70bafdfdb51 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp @@ -1220,56 +1220,12 @@ static FileSpec GetCommandLineToolsLibraryPath() { return g_command_line_tools_filespec; } -bool PlatformDarwin::SDKSupportsModules(SDKType sdk_type, - llvm::VersionTuple version) { - switch (sdk_type) { - case SDKType::MacOSX: - return version >= llvm::VersionTuple(10, 10); - case SDKType::iPhoneOS: - case SDKType::iPhoneSimulator: - case SDKType::AppleTVOS: - case SDKType::AppleTVSimulator: - return version >= llvm::VersionTuple(8); - case SDKType::watchOS: - case SDKType::WatchSimulator: - return version >= llvm::VersionTuple(6); - default: - return false; - } - - return false; -} - -bool PlatformDarwin::SDKSupportsModules(SDKType desired_type, - const FileSpec &sdk_path) { - ConstString last_path_component = sdk_path.GetLastPathComponent(); - - if (last_path_component) { - const llvm::StringRef sdk_name = last_path_component.GetStringRef(); - - const std::string sdk_name_lower = sdk_name.lower(); - const llvm::StringRef sdk_string = GetSDKNameForType(desired_type); - if (!llvm::StringRef(sdk_name_lower).startswith(sdk_string)) - return false; - - auto version_part = sdk_name.drop_front(sdk_string.size()); - version_part.consume_back(".sdk"); - - llvm::VersionTuple version; - if (version.tryParse(version_part)) - return false; - return SDKSupportsModules(desired_type, version); - } - - return false; -} - FileSystem::EnumerateDirectoryResult PlatformDarwin::DirectoryEnumerator( void *baton, llvm::sys::fs::file_type file_type, llvm::StringRef path) { SDKEnumeratorInfo *enumerator_info = static_cast(baton); FileSpec spec(path); - if (SDKSupportsModules(enumerator_info->sdk_type, spec)) { + if (XcodeSDK::SDKSupportsModules(enumerator_info->sdk_type, spec)) { enumerator_info->found_path = spec; return FileSystem::EnumerateDirectoryResult::eEnumerateDirectoryResultNext; } @@ -1277,7 +1233,7 @@ FileSystem::EnumerateDirectoryResult PlatformDarwin::DirectoryEnumerator( return FileSystem::EnumerateDirectoryResult::eEnumerateDirectoryResultNext; } -FileSpec PlatformDarwin::FindSDKInXcodeForModules(SDKType sdk_type, +FileSpec PlatformDarwin::FindSDKInXcodeForModules(XcodeSDK::Type sdk_type, const FileSpec &sdks_spec) { // Look inside Xcode for the required installed iOS SDK version @@ -1303,19 +1259,19 @@ FileSpec PlatformDarwin::FindSDKInXcodeForModules(SDKType sdk_type, return FileSpec(); } -FileSpec PlatformDarwin::GetSDKDirectoryForModules(SDKType sdk_type) { +FileSpec PlatformDarwin::GetSDKDirectoryForModules(XcodeSDK::Type sdk_type) { FileSpec sdks_spec = GetXcodeContentsDirectory(); sdks_spec.AppendPathComponent("Developer"); sdks_spec.AppendPathComponent("Platforms"); switch (sdk_type) { - case SDKType::MacOSX: + case XcodeSDK::Type::MacOSX: sdks_spec.AppendPathComponent("MacOSX.platform"); break; - case SDKType::iPhoneSimulator: + case XcodeSDK::Type::iPhoneSimulator: sdks_spec.AppendPathComponent("iPhoneSimulator.platform"); break; - case SDKType::iPhoneOS: + case XcodeSDK::Type::iPhoneOS: sdks_spec.AppendPathComponent("iPhoneOS.platform"); break; default: @@ -1325,11 +1281,11 @@ FileSpec PlatformDarwin::GetSDKDirectoryForModules(SDKType sdk_type) { sdks_spec.AppendPathComponent("Developer"); sdks_spec.AppendPathComponent("SDKs"); - if (sdk_type == SDKType::MacOSX) { + if (sdk_type == XcodeSDK::Type::MacOSX) { llvm::VersionTuple version = HostInfo::GetOSVersion(); if (!version.empty()) { - if (SDKSupportsModules(SDKType::MacOSX, version)) { + if (XcodeSDK::SDKSupportsModules(XcodeSDK::Type::MacOSX, version)) { // If the Xcode SDKs are not available then try to use the // Command Line Tools one which is only for MacOSX. if (!FileSystem::Instance().Exists(sdks_spec)) { @@ -1498,7 +1454,7 @@ PlatformDarwin::ExtractCrashInfoAnnotations(Process &process) { } void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( - Target *target, std::vector &options, SDKType sdk_type) { + Target *target, std::vector &options, XcodeSDK::Type sdk_type) { const std::vector apple_arguments = { "-x", "objective-c++", "-fobjc-arc", "-fblocks", "-D_ISO646_H", "-D__ISO646_H", @@ -1509,7 +1465,7 @@ void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( StreamString minimum_version_option; bool use_current_os_version = false; switch (sdk_type) { - case SDKType::iPhoneOS: + case XcodeSDK::Type::iPhoneOS: #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) use_current_os_version = true; #else @@ -1517,11 +1473,11 @@ void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( #endif break; - case SDKType::iPhoneSimulator: + case XcodeSDK::Type::iPhoneSimulator: use_current_os_version = false; break; - case SDKType::MacOSX: + case XcodeSDK::Type::MacOSX: #if defined(__i386__) || defined(__x86_64__) use_current_os_version = true; #else @@ -1548,15 +1504,15 @@ void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( // Only add the version-min options if we got a version from somewhere if (!version.empty()) { switch (sdk_type) { - case SDKType::iPhoneOS: + case XcodeSDK::Type::iPhoneOS: minimum_version_option.PutCString("-mios-version-min="); minimum_version_option.PutCString(version.getAsString()); break; - case SDKType::iPhoneSimulator: + case XcodeSDK::Type::iPhoneSimulator: minimum_version_option.PutCString("-mios-simulator-version-min="); minimum_version_option.PutCString(version.getAsString()); break; - case SDKType::MacOSX: + case XcodeSDK::Type::MacOSX: minimum_version_option.PutCString("-mmacosx-version-min="); minimum_version_option.PutCString(version.getAsString()); break; @@ -1805,70 +1761,11 @@ PlatformDarwin::FindXcodeContentsDirectoryInPath(llvm::StringRef path) { return {}; } -llvm::StringRef PlatformDarwin::GetSDKNameForType(SDKType type) { - switch (type) { - case MacOSX: - return "macosx"; - case iPhoneSimulator: - return "iphonesimulator"; - case iPhoneOS: - return "iphoneos"; - case AppleTVSimulator: - return "appletvsimulator"; - case AppleTVOS: - return "appletvos"; - case WatchSimulator: - return "watchsimulator"; - case watchOS: - return "watchos"; - case bridgeOS: - return "bridgeos"; - case Linux: - return "linux"; - case numSDKTypes: - case unknown: - return ""; - } - llvm_unreachable("unhandled switch case"); -} - -FileSpec PlatformDarwin::GetXcodeSDK(SDKType type) { - std::string xcrun_cmd = - "xcrun --show-sdk-path --sdk " + GetSDKNameForType(type).str(); - - int status = 0; - int signo = 0; - std::string output_str; - lldb_private::Status error = - Host::RunShellCommand(xcrun_cmd.c_str(), FileSpec(), &status, &signo, - &output_str, std::chrono::seconds(15)); - - // Check that xcrun return something useful. - if (status != 0 || output_str.empty()) - return {}; - - // Convert to a StringRef so we can manipulate the string without modifying - // the underlying data. - llvm::StringRef output(output_str); - - // Remove any trailing newline characters. - output = output.rtrim(); - - // Strip any leading newline characters and everything before them. - const size_t last_newline = output.rfind('\n'); - if (last_newline != llvm::StringRef::npos) - output = output.substr(last_newline + 1); - - // Whatever is left in output should be a valid path. - if (!FileSystem::Instance().Exists(output)) - return {}; - - // Find the contents dir in the xcrun provided path. - std::string xcode_contents_dir = FindXcodeContentsDirectoryInPath(output); - if (xcode_contents_dir.empty()) - return {}; - - return FileSpec(xcode_contents_dir); +llvm::StringRef PlatformDarwin::GetSDKPath(XcodeSDK sdk) { + std::string &path = m_sdk_path[sdk.GetString()]; + if (path.empty()) + path = HostInfo::GetXcodeSDK(sdk); + return path; } FileSpec PlatformDarwin::GetXcodeContentsDirectory() { @@ -1899,7 +1796,8 @@ FileSpec PlatformDarwin::GetXcodeContentsDirectory() { } } - if (FileSpec fspec = GetXcodeSDK(SDKType::MacOSX)) { + FileSpec fspec(HostInfo::GetXcodeSDK(XcodeSDK::GetAnyMacOS())); + if (fspec) { if (FileSystem::Instance().Exists(fspec)) { std::string xcode_contents_dir = FindXcodeContentsDirectoryInPath(fspec.GetPath()); diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h index d1b960d2d5535..91301d40e567f 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h @@ -12,8 +12,10 @@ #include "Plugins/Platform/POSIX/PlatformPOSIX.h" #include "lldb/Host/FileSystem.h" +#include "lldb/Utility/ConstString.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/StructuredData.h" +#include "lldb/Utility/XcodeSDK.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/FileSystem.h" @@ -85,25 +87,11 @@ class PlatformDarwin : public PlatformPOSIX { static std::tuple ParseVersionBuildDir(llvm::StringRef str); - enum SDKType : int { - MacOSX = 0, - iPhoneSimulator, - iPhoneOS, - AppleTVSimulator, - AppleTVOS, - WatchSimulator, - watchOS, - bridgeOS, - Linux, - numSDKTypes, - unknown = -1 - }; - llvm::Expected FetchExtendedCrashInformation(lldb_private::Process &process) override; - static llvm::StringRef GetSDKNameForType(SDKType type); - static lldb_private::FileSpec GetXcodeSDK(SDKType type); + llvm::StringRef GetSDKPath(lldb_private::XcodeSDK sdk) override; + static lldb_private::FileSpec GetXcodeContentsDirectory(); static lldb_private::FileSpec GetXcodeDeveloperDirectory(); @@ -152,14 +140,9 @@ class PlatformDarwin : public PlatformPOSIX { const lldb_private::FileSpecList *module_search_paths_ptr, lldb::ModuleSP *old_module_sp_ptr, bool *did_create_ptr); - static bool SDKSupportsModules(SDKType sdk_type, llvm::VersionTuple version); - - static bool SDKSupportsModules(SDKType desired_type, - const lldb_private::FileSpec &sdk_path); - struct SDKEnumeratorInfo { lldb_private::FileSpec found_path; - SDKType sdk_type; + lldb_private::XcodeSDK::Type sdk_type; }; static lldb_private::FileSystem::EnumerateDirectoryResult @@ -167,17 +150,15 @@ class PlatformDarwin : public PlatformPOSIX { llvm::StringRef path); static lldb_private::FileSpec - FindSDKInXcodeForModules(SDKType sdk_type, + FindSDKInXcodeForModules(lldb_private::XcodeSDK::Type sdk_type, const lldb_private::FileSpec &sdks_spec); static lldb_private::FileSpec - GetSDKDirectoryForModules(PlatformDarwin::SDKType sdk_type); - - void - AddClangModuleCompilationOptionsForSDKType(lldb_private::Target *target, - std::vector &options, - SDKType sdk_type); + GetSDKDirectoryForModules(lldb_private::XcodeSDK::Type sdk_type); + void AddClangModuleCompilationOptionsForSDKType( + lldb_private::Target *target, std::vector &options, + lldb_private::XcodeSDK::Type sdk_type); lldb_private::Status FindBundleBinaryInExecSearchPaths( const lldb_private::ModuleSpec &module_spec, @@ -189,6 +170,8 @@ class PlatformDarwin : public PlatformPOSIX { llvm::StringRef component); static std::string FindXcodeContentsDirectoryInPath(llvm::StringRef path); + std::string m_developer_directory; + llvm::StringMap m_sdk_path; private: DISALLOW_COPY_AND_ASSIGN(PlatformDarwin); diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp index a5cb449bcbd6e..0de249eb0bb85 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp @@ -178,7 +178,8 @@ ConstString PlatformMacOSX::GetSDKDirectory(lldb_private::Target &target) { } // Use the default SDK as a fallback. - if (FileSpec fspec = GetXcodeSDK(SDKType::MacOSX)) { + FileSpec fspec(HostInfo::GetXcodeSDK(lldb_private::XcodeSDK::GetAnyMacOS())); + if (fspec) { if (FileSystem::Instance().Exists(fspec)) return ConstString(fspec.GetPath()); } diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h index 5e942f090c943..a4baf9274a8e1 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h @@ -73,7 +73,7 @@ class PlatformMacOSX : public PlatformDarwin { AddClangModuleCompilationOptions(lldb_private::Target *target, std::vector &options) override { return PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( - target, options, PlatformDarwin::SDKType::MacOSX); + target, options, lldb_private::XcodeSDK::Type::MacOSX); } private: diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h index 5e0b7d92bbd4d..5b2bb55b6585a 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h @@ -45,7 +45,7 @@ class PlatformRemoteDarwinDevice : public PlatformDarwin { AddClangModuleCompilationOptions(lldb_private::Target *target, std::vector &options) override { return PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( - target, options, PlatformDarwin::SDKType::iPhoneOS); + target, options, lldb_private::XcodeSDK::Type::iPhoneOS); } protected: diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h b/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h index d766929b2b891..948488a2853cd 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h @@ -71,7 +71,7 @@ class PlatformiOSSimulator : public PlatformAppleSimulator { AddClangModuleCompilationOptions(lldb_private::Target *target, std::vector &options) override { return PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( - target, options, PlatformDarwin::SDKType::iPhoneSimulator); + target, options, lldb_private::XcodeSDK::Type::iPhoneSimulator); } protected: diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h index d53ed756fe05d..1ac286a8a52d5 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -12,6 +12,7 @@ #include "DWARFDIE.h" #include "DWARFDebugInfoEntry.h" #include "lldb/lldb-enumerations.h" +#include "lldb/Utility/XcodeSDK.h" #include "llvm/Support/RWMutex.h" #include diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index d2af13ebebafe..10a41d02aa139 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -718,6 +718,12 @@ lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) { if (module_sp) { const DWARFDIE cu_die = dwarf_cu.DIE(); if (cu_die) { + if (const char *sdk = + cu_die.GetAttributeValueAsString(DW_AT_APPLE_sdk, nullptr)) { + const char *sysroot = + cu_die.GetAttributeValueAsString(DW_AT_LLVM_sysroot, ""); + module_sp->RegisterXcodeSDK(sdk, sysroot); + } FileSpec cu_file_spec(cu_die.GetName(), dwarf_cu.GetPathStyle()); MakeAbsoluteAndRemap(cu_file_spec, dwarf_cu, module_sp); diff --git a/lldb/source/Utility/CMakeLists.txt b/lldb/source/Utility/CMakeLists.txt index df486e2c0a4ca..0d82640019a27 100644 --- a/lldb/source/Utility/CMakeLists.txt +++ b/lldb/source/Utility/CMakeLists.txt @@ -58,6 +58,7 @@ add_lldb_library(lldbUtility UserIDResolver.cpp VASprintf.cpp VMRange.cpp + XcodeSDK.cpp LINK_LIBS ${LLDB_SYSTEM_LIBS} diff --git a/lldb/source/Utility/XcodeSDK.cpp b/lldb/source/Utility/XcodeSDK.cpp new file mode 100644 index 0000000000000..f2403f10de553 --- /dev/null +++ b/lldb/source/Utility/XcodeSDK.cpp @@ -0,0 +1,163 @@ +//===-- XcodeSDK.cpp ------------------------------------------------------===// +// +// 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 "lldb/Utility/FileSpec.h" +#include "lldb/Utility/XcodeSDK.h" + +#include "lldb/lldb-types.h" + +using namespace lldb; +using namespace lldb_private; + +XcodeSDK &XcodeSDK::operator=(XcodeSDK other) { + m_name = other.m_name; + return *this; +} + +bool XcodeSDK::operator==(XcodeSDK other) { + return m_name == other.m_name; +} + +static XcodeSDK::Type ParseSDKName(llvm::StringRef &name) { + if (name.consume_front("MacOSX")) + return XcodeSDK::MacOSX; + if (name.consume_front("iPhoneSimulator")) + return XcodeSDK::iPhoneSimulator; + if (name.consume_front("iPhoneOS")) + return XcodeSDK::iPhoneOS; + if (name.consume_front("AppleTVSimulator")) + return XcodeSDK::AppleTVSimulator; + if (name.consume_front("AppleTVOS")) + return XcodeSDK::AppleTVOS; + if (name.consume_front("WatchSimulator")) + return XcodeSDK::WatchSimulator; + if (name.consume_front("WatchOS")) + return XcodeSDK::watchOS; + if (name.consume_front("bridgeOS")) + return XcodeSDK::bridgeOS; + if (name.consume_front("Linux")) + return XcodeSDK::Linux; + static_assert(XcodeSDK::Linux == XcodeSDK::numSDKTypes - 1, + "New SDK type was added, update this list!"); + return XcodeSDK::unknown; +} + +static llvm::VersionTuple ParseSDKVersion(llvm::StringRef &name) { + unsigned i = 0; + while (i < name.size() && name[i] >= '0' && name[i] <= '9') + ++i; + if (i == name.size() || name[i++] != '.') + return {}; + while (i < name.size() && name[i] >= '0' && name[i] <= '9') + ++i; + if (i == name.size() || name[i++] != '.') + return {}; + + llvm::VersionTuple version; + version.tryParse(name.slice(0, i - 1)); + name = name.drop_front(i); + return version; +} + + +std::tuple XcodeSDK::Parse() const { + llvm::StringRef input(m_name); + XcodeSDK::Type sdk = ParseSDKName(input); + llvm::VersionTuple version = ParseSDKVersion(input); + return {sdk, version}; +} + +llvm::VersionTuple XcodeSDK::GetVersion() const { + llvm::StringRef input(m_name); + ParseSDKName(input); + return ParseSDKVersion(input); +} + +XcodeSDK::Type XcodeSDK::GetType() const { + llvm::StringRef input(m_name); + return ParseSDKName(input); +} + +llvm::StringRef XcodeSDK::GetString() const { return m_name; } + +void XcodeSDK::Merge(XcodeSDK other) { + // The "bigger" SDK always wins. + if (Parse() < other.Parse()) + *this = other; +} + +llvm::StringRef XcodeSDK::GetSDKNameForType(XcodeSDK::Type type) { + switch (type) { + case MacOSX: + return "macosx"; + case iPhoneSimulator: + return "iphonesimulator"; + case iPhoneOS: + return "iphoneos"; + case AppleTVSimulator: + return "appletvsimulator"; + case AppleTVOS: + return "appletvos"; + case WatchSimulator: + return "watchsimulator"; + case watchOS: + return "watchos"; + case bridgeOS: + return "bridgeos"; + case Linux: + return "linux"; + case numSDKTypes: + case unknown: + return ""; + } + llvm_unreachable("unhandled switch case"); +} + +bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type sdk_type, + llvm::VersionTuple version) { + switch (sdk_type) { + case Type::MacOSX: + return version >= llvm::VersionTuple(10, 10); + case Type::iPhoneOS: + case Type::iPhoneSimulator: + case Type::AppleTVOS: + case Type::AppleTVSimulator: + return version >= llvm::VersionTuple(8); + case Type::watchOS: + case Type::WatchSimulator: + return version >= llvm::VersionTuple(6); + default: + return false; + } + + return false; +} + +bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type desired_type, + const FileSpec &sdk_path) { + ConstString last_path_component = sdk_path.GetLastPathComponent(); + + if (last_path_component) { + const llvm::StringRef sdk_name = last_path_component.GetStringRef(); + + const std::string sdk_name_lower = sdk_name.lower(); + const llvm::StringRef sdk_string = GetSDKNameForType(desired_type); + if (!llvm::StringRef(sdk_name_lower).startswith(sdk_string)) + return false; + + auto version_part = sdk_name.drop_front(sdk_string.size()); + version_part.consume_back(".sdk"); + + llvm::VersionTuple version; + if (version.tryParse(version_part)) + return false; + return SDKSupportsModules(desired_type, version); + } + + return false; +} diff --git a/lldb/unittests/Platform/PlatformDarwinTest.cpp b/lldb/unittests/Platform/PlatformDarwinTest.cpp index 0aea200fe967e..74ad2318ecffd 100644 --- a/lldb/unittests/Platform/PlatformDarwinTest.cpp +++ b/lldb/unittests/Platform/PlatformDarwinTest.cpp @@ -21,10 +21,6 @@ struct PlatformDarwinTester : public PlatformDarwin { public: using PlatformDarwin::FindComponentInPath; using PlatformDarwin::FindXcodeContentsDirectoryInPath; - static bool SDKSupportsModules(SDKType desired_type, - const lldb_private::FileSpec &sdk_path) { - return PlatformDarwin::SDKSupportsModules(desired_type, sdk_path); - } }; TEST(PlatformDarwinTest, TestParseVersionBuildDir) { @@ -53,24 +49,6 @@ TEST(PlatformDarwinTest, TestParseVersionBuildDir) { std::tie(V, D) = PlatformDarwin::ParseVersionBuildDir("3.4.5"); EXPECT_EQ(llvm::VersionTuple(3, 4, 5), V); - - std::string base = "/Applications/Xcode.app/Contents/Developer/Platforms/"; - EXPECT_TRUE(PlatformDarwinTester::SDKSupportsModules( - PlatformDarwin::SDKType::iPhoneSimulator, - FileSpec( - base + - "iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator12.0.sdk"))); - EXPECT_FALSE(PlatformDarwinTester::SDKSupportsModules( - PlatformDarwin::SDKType::iPhoneSimulator, - FileSpec( - base + - "iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator7.2.sdk"))); - EXPECT_TRUE(PlatformDarwinTester::SDKSupportsModules( - PlatformDarwin::SDKType::MacOSX, - FileSpec(base + "MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk"))); - EXPECT_FALSE(PlatformDarwinTester::SDKSupportsModules( - PlatformDarwin::SDKType::MacOSX, - FileSpec(base + "MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk"))); } TEST(PlatformDarwinTest, FindXcodeContentsDirectoryInPath) { @@ -111,29 +89,6 @@ TEST(PlatformDarwinTest, FindXcodeContentsDirectoryInPath) { no_capitalization)); } -TEST(PlatformDarwinTest, GetSDKNameForType) { - EXPECT_EQ("macosx", - PlatformDarwin::GetSDKNameForType(PlatformDarwin::SDKType::MacOSX)); - EXPECT_EQ("iphonesimulator", PlatformDarwin::GetSDKNameForType( - PlatformDarwin::SDKType::iPhoneSimulator)); - EXPECT_EQ("iphoneos", PlatformDarwin::GetSDKNameForType( - PlatformDarwin::SDKType::iPhoneOS)); - EXPECT_EQ("appletvsimulator", PlatformDarwin::GetSDKNameForType( - PlatformDarwin::SDKType::AppleTVSimulator)); - EXPECT_EQ("appletvos", PlatformDarwin::GetSDKNameForType( - PlatformDarwin::SDKType::AppleTVOS)); - EXPECT_EQ("watchsimulator", PlatformDarwin::GetSDKNameForType( - PlatformDarwin::SDKType::WatchSimulator)); - EXPECT_EQ("watchos", PlatformDarwin::GetSDKNameForType( - PlatformDarwin::SDKType::watchOS)); - EXPECT_EQ("linux", - PlatformDarwin::GetSDKNameForType(PlatformDarwin::SDKType::Linux)); - EXPECT_EQ("", PlatformDarwin::GetSDKNameForType( - PlatformDarwin::SDKType::numSDKTypes)); - EXPECT_EQ( - "", PlatformDarwin::GetSDKNameForType(PlatformDarwin::SDKType::unknown)); -} - TEST(PlatformDarwinTest, FindComponentInPath) { EXPECT_EQ("/path/to/foo", PlatformDarwinTester::FindComponentInPath("/path/to/foo/", "foo")); diff --git a/lldb/unittests/Utility/CMakeLists.txt b/lldb/unittests/Utility/CMakeLists.txt index 8dc13327b9b0e..876fb9268c3e4 100644 --- a/lldb/unittests/Utility/CMakeLists.txt +++ b/lldb/unittests/Utility/CMakeLists.txt @@ -41,6 +41,7 @@ add_lldb_unittest(UtilityTests UUIDTest.cpp VASprintfTest.cpp VMRangeTest.cpp + XcodeSDKTest.cpp LINK_LIBS lldbUtility diff --git a/lldb/unittests/Utility/XcodeSDKTest.cpp b/lldb/unittests/Utility/XcodeSDKTest.cpp new file mode 100644 index 0000000000000..a316516a16758 --- /dev/null +++ b/lldb/unittests/Utility/XcodeSDKTest.cpp @@ -0,0 +1,86 @@ +//===-- XcodeSDKTest.cpp --------------------------------------------------===// +// +// 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 "gtest/gtest.h" + +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/XcodeSDK.h" + +#include "llvm/ADT/StringRef.h" + +#include + +using namespace lldb_private; + +TEST(XcodeSDKTest, ParseTest) { + EXPECT_EQ(XcodeSDK::GetAnyMacOS().GetType(), XcodeSDK::MacOSX); + EXPECT_EQ(XcodeSDK("MacOSX.sdk").GetType(), XcodeSDK::MacOSX); + EXPECT_EQ(XcodeSDK("iPhoneSimulator.sdk").GetType(), XcodeSDK::iPhoneSimulator); + EXPECT_EQ(XcodeSDK("iPhoneOS.sdk").GetType(), XcodeSDK::iPhoneOS); + EXPECT_EQ(XcodeSDK("AppleTVSimulator.sdk").GetType(), XcodeSDK::AppleTVSimulator); + EXPECT_EQ(XcodeSDK("AppleTVOS.sdk").GetType(), XcodeSDK::AppleTVOS); + EXPECT_EQ(XcodeSDK("WatchSimulator.sdk").GetType(), XcodeSDK::WatchSimulator); + EXPECT_EQ(XcodeSDK("WatchOS.sdk").GetType(), XcodeSDK::watchOS); + EXPECT_EQ(XcodeSDK("Linux.sdk").GetType(), XcodeSDK::Linux); + EXPECT_EQ(XcodeSDK("MacOSX.sdk").GetVersion(), llvm::VersionTuple()); + EXPECT_EQ(XcodeSDK("MacOSX10.9.sdk").GetVersion(), llvm::VersionTuple(10, 9)); + EXPECT_EQ(XcodeSDK("MacOSX10.15.4.sdk").GetVersion(), llvm::VersionTuple(10, 15)); + EXPECT_EQ(XcodeSDK().GetType(), XcodeSDK::unknown); + EXPECT_EQ(XcodeSDK().GetVersion(), llvm::VersionTuple()); +} + +TEST(XcodeSDKTest, MergeTest) { + XcodeSDK sdk("MacOSX.sdk"); + sdk.Merge(XcodeSDK("WatchOS.sdk")); + // This doesn't make any particular sense and shouldn't happen in practice, we + // just want to guarantee a well-defined behavior when choosing one + // SDK to fit all CUs in an lldb::Module. + // -> The higher number wins. + EXPECT_EQ(sdk.GetType(), XcodeSDK::watchOS); + sdk.Merge(XcodeSDK("WatchOS1.1.sdk")); + EXPECT_EQ(sdk.GetVersion(), llvm::VersionTuple(1, 1)); + sdk.Merge(XcodeSDK("WatchOS2.0.sdk")); + EXPECT_EQ(sdk.GetVersion(), llvm::VersionTuple(2, 0)); +} + +TEST(XcodeSDKTest, SDKSupportsModules) { + std::string base = "/Applications/Xcode.app/Contents/Developer/Platforms/"; + EXPECT_TRUE(XcodeSDK::SDKSupportsModules( + XcodeSDK::Type::iPhoneSimulator, + FileSpec( + base + + "iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator12.0.sdk"))); + EXPECT_FALSE(XcodeSDK::SDKSupportsModules( + XcodeSDK::Type::iPhoneSimulator, + FileSpec( + base + + "iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator7.2.sdk"))); + EXPECT_TRUE(XcodeSDK::SDKSupportsModules( + XcodeSDK::Type::MacOSX, + FileSpec(base + "MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk"))); + EXPECT_FALSE(XcodeSDK::SDKSupportsModules( + XcodeSDK::Type::MacOSX, + FileSpec(base + "MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk"))); +} + +TEST(XcodeSDKTest, GetSDKNameForType) { + EXPECT_EQ("macosx", XcodeSDK::GetSDKNameForType(XcodeSDK::Type::MacOSX)); + EXPECT_EQ("iphonesimulator", + XcodeSDK::GetSDKNameForType(XcodeSDK::Type::iPhoneSimulator)); + EXPECT_EQ("iphoneos", XcodeSDK::GetSDKNameForType(XcodeSDK::Type::iPhoneOS)); + EXPECT_EQ("appletvsimulator", + XcodeSDK::GetSDKNameForType(XcodeSDK::Type::AppleTVSimulator)); + EXPECT_EQ("appletvos", + XcodeSDK::GetSDKNameForType(XcodeSDK::Type::AppleTVOS)); + EXPECT_EQ("watchsimulator", + XcodeSDK::GetSDKNameForType(XcodeSDK::Type::WatchSimulator)); + EXPECT_EQ("watchos", XcodeSDK::GetSDKNameForType(XcodeSDK::Type::watchOS)); + EXPECT_EQ("linux", XcodeSDK::GetSDKNameForType(XcodeSDK::Type::Linux)); + EXPECT_EQ("", XcodeSDK::GetSDKNameForType(XcodeSDK::Type::numSDKTypes)); + EXPECT_EQ("", XcodeSDK::GetSDKNameForType(XcodeSDK::Type::unknown)); +} From 44a52582e612e88307e4e31e2a24ff5310d7f7bc Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Mon, 6 Apr 2020 17:28:53 -0700 Subject: [PATCH 224/286] Add missing include (cherry picked from commit 469580a9677473f4ee19d80861f7a5da4e0f316d) --- lldb/include/lldb/Target/Platform.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/include/lldb/Target/Platform.h b/lldb/include/lldb/Target/Platform.h index 0e37e36498df3..521f7c8f4afe1 100644 --- a/lldb/include/lldb/Target/Platform.h +++ b/lldb/include/lldb/Target/Platform.h @@ -26,6 +26,7 @@ #include "lldb/Utility/StructuredData.h" #include "lldb/Utility/Timeout.h" #include "lldb/Utility/UserIDResolver.h" +#include "lldb/Utility/XcodeSDK.h" #include "lldb/lldb-private-forward.h" #include "lldb/lldb-public.h" #include "llvm/Support/VersionTuple.h" From 06f3f4bf159ba751f3696d0e61999ea4683de90d Mon Sep 17 00:00:00 2001 From: Eric Christopher Date: Fri, 3 Apr 2020 17:58:59 -0700 Subject: [PATCH 225/286] Fix unused variable, format, and format string warnings. NFC. (cherry picked from commit 3ccd454c102b069d2230a18cfe16b84a5f005fc8) --- lldb/include/lldb/Target/ThreadPlanStack.h | 2 +- lldb/source/Commands/CommandObjectThread.cpp | 1 - lldb/source/Target/ThreadPlan.cpp | 2 +- lldb/source/Target/ThreadPlanStack.cpp | 6 +----- lldb/source/Target/ThreadPlanStepRange.cpp | 1 - 5 files changed, 3 insertions(+), 9 deletions(-) diff --git a/lldb/include/lldb/Target/ThreadPlanStack.h b/lldb/include/lldb/Target/ThreadPlanStack.h index de52ee3ee198a..f1874136cad83 100644 --- a/lldb/include/lldb/Target/ThreadPlanStack.h +++ b/lldb/include/lldb/Target/ThreadPlanStack.h @@ -125,7 +125,7 @@ class ThreadPlanStackMap { void AddThread(Thread &thread) { lldb::tid_t tid = thread.GetID(); - auto result = m_plans_list.emplace(tid, thread); + m_plans_list.emplace(tid, thread); } bool RemoveTID(lldb::tid_t tid) { diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp index 0f64219a1dbef..a9c81176e1666 100644 --- a/lldb/source/Commands/CommandObjectThread.cpp +++ b/lldb/source/Commands/CommandObjectThread.cpp @@ -2061,7 +2061,6 @@ class CommandObjectThreadPlanPrune : public CommandObjectParsed { return true; } - bool success; const size_t num_args = args.GetArgumentCount(); std::lock_guard guard( diff --git a/lldb/source/Target/ThreadPlan.cpp b/lldb/source/Target/ThreadPlan.cpp index 9d393ff4fd843..48bba704d06e7 100644 --- a/lldb/source/Target/ThreadPlan.cpp +++ b/lldb/source/Target/ThreadPlan.cpp @@ -24,7 +24,7 @@ ThreadPlan::ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread, : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()), m_stop_vote(stop_vote), m_run_vote(run_vote), m_takes_iteration_count(false), m_could_not_resolve_hw_bp(false), - m_kind(kind), m_thread(&thread), m_name(name), m_plan_complete_mutex(), + m_thread(&thread), m_kind(kind), m_name(name), m_plan_complete_mutex(), m_cached_plan_explains_stop(eLazyBoolCalculate), m_plan_complete(false), m_plan_private(false), m_okay_to_discard(true), m_is_master_plan(false), m_plan_succeeded(true) { diff --git a/lldb/source/Target/ThreadPlanStack.cpp b/lldb/source/Target/ThreadPlanStack.cpp index 11102650c1092..c51946aae71c8 100644 --- a/lldb/source/Target/ThreadPlanStack.cpp +++ b/lldb/source/Target/ThreadPlanStack.cpp @@ -39,9 +39,6 @@ ThreadPlanStack::ThreadPlanStack(const Thread &thread, bool make_null) { void ThreadPlanStack::DumpThreadPlans(Stream &s, lldb::DescriptionLevel desc_level, bool include_internal) const { - - uint32_t stack_size; - s.IndentMore(); PrintOneStack(s, "Active plan stack", m_plans, desc_level, include_internal); PrintOneStack(s, "Completed plan stack", m_completed_plans, desc_level, @@ -73,7 +70,7 @@ void ThreadPlanStack::PrintOneStack(Stream &s, llvm::StringRef stack_name, if (include_internal || any_public) { int print_idx = 0; s.Indent(); - s.Printf("%s:\n", stack_name); + s << stack_name << ":\n"; for (auto plan : stack) { if (!include_internal && plan->GetPrivate()) continue; @@ -270,7 +267,6 @@ lldb::ThreadPlanSP ThreadPlanStack::GetCompletedPlan(bool skip_private) const { lldb::ThreadPlanSP ThreadPlanStack::GetPlanByIndex(uint32_t plan_idx, bool skip_private) const { uint32_t idx = 0; - ThreadPlan *up_to_plan_ptr = nullptr; for (lldb::ThreadPlanSP plan_sp : m_plans) { if (skip_private && plan_sp->GetPrivate()) diff --git a/lldb/source/Target/ThreadPlanStepRange.cpp b/lldb/source/Target/ThreadPlanStepRange.cpp index 548d9a78a35a3..e3b72a1bf63e6 100644 --- a/lldb/source/Target/ThreadPlanStepRange.cpp +++ b/lldb/source/Target/ThreadPlanStepRange.cpp @@ -86,7 +86,6 @@ void ThreadPlanStepRange::AddRange(const AddressRange &new_range) { } void ThreadPlanStepRange::DumpRanges(Stream *s) { - Thread &thread = GetThread(); size_t num_ranges = m_address_ranges.size(); if (num_ranges == 1) { m_address_ranges[0].Dump(s, &GetTarget(), Address::DumpStyleLoadAddress); From 3c58b0f0909004864366d18bbf58c5765fcfeaf9 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Wed, 4 Mar 2020 09:30:12 -0800 Subject: [PATCH 226/286] Preserve the owning module information from DWARF in the synthesized AST Types that came from a Clang module are nested in DW_TAG_module tags in DWARF. This patch recreates the Clang module hierarchy in LLDB and 1;95;0csets the owning module information accordingly. My primary motivation is to facilitate looking up per-module APINotes for individual declarations, but this likely also has other applications. This reapplies the previously reverted commit, but without support for ClassTemplateSpecializations, which I'm going to look into separately. rdar://problem/59634380 Differential Revision: https://reviews.llvm.org/D75488 (cherry picked from commit 143d507c9ff90db93e547f0e1131e92db06e2675) --- lldb/include/lldb/Symbol/CompilerType.h | 10 +- lldb/include/lldb/Symbol/TypeSystem.h | 5 +- .../Clang/ClangASTImporter.cpp | 30 +++ .../Clang/ClangExpressionDeclMap.cpp | 2 +- .../Clang/ClangExternalASTSourceCallbacks.cpp | 28 ++ .../Clang/ClangExternalASTSourceCallbacks.h | 23 +- .../Plugins/Language/ObjC/NSDictionary.cpp | 5 +- .../AppleObjCTypeEncodingParser.cpp | 3 +- .../SymbolFile/DWARF/DWARFASTParserClang.cpp | 92 ++++--- .../SymbolFile/DWARF/DWARFASTParserClang.h | 5 + .../SymbolFile/NativePDB/PdbAstBuilder.cpp | 26 +- .../Plugins/SymbolFile/PDB/PDBASTParser.cpp | 25 +- .../MacOSX/SystemRuntimeMacOSX.cpp | 5 +- .../TypeSystem/Clang/TypeSystemClang.cpp | 246 +++++++++++++----- .../TypeSystem/Clang/TypeSystemClang.h | 95 +++++-- lldb/source/Symbol/CompilerType.cpp | 8 +- lldb/source/Symbol/Type.cpp | 4 +- lldb/source/Symbol/TypeSystem.cpp | 3 +- .../DWARF/Inputs/ModuleOwnership/A.h | 29 +++ .../DWARF/Inputs/ModuleOwnership/B.h | 8 + .../Inputs/ModuleOwnership/module.modulemap | 6 + .../test/Shell/SymbolFile/DWARF/lit.local.cfg | 2 +- .../SymbolFile/DWARF/module-ownership.mm | 42 +++ lldb/unittests/Symbol/TestTypeSystemClang.cpp | 48 ++-- .../TestingSupport/Symbol/ClangTestUtils.h | 1 + 25 files changed, 576 insertions(+), 175 deletions(-) create mode 100644 lldb/test/Shell/SymbolFile/DWARF/Inputs/ModuleOwnership/A.h create mode 100644 lldb/test/Shell/SymbolFile/DWARF/Inputs/ModuleOwnership/B.h create mode 100644 lldb/test/Shell/SymbolFile/DWARF/Inputs/ModuleOwnership/module.modulemap create mode 100644 lldb/test/Shell/SymbolFile/DWARF/module-ownership.mm diff --git a/lldb/include/lldb/Symbol/CompilerType.h b/lldb/include/lldb/Symbol/CompilerType.h index 0f185e5013446..37ae382ed2128 100644 --- a/lldb/include/lldb/Symbol/CompilerType.h +++ b/lldb/include/lldb/Symbol/CompilerType.h @@ -237,11 +237,13 @@ class CompilerType { // an invalid type. CompilerType AddRestrictModifier() const; - // Create a typedef to this type using "name" as the name of the typedef this - // type is valid and the type system supports typedefs, else return an - // invalid type. + /// Create a typedef to this type using "name" as the name of the typedef this + /// type is valid and the type system supports typedefs, else return an + /// invalid type. + /// \param payload The typesystem-specific \p lldb::Type payload. CompilerType CreateTypedef(const char *name, - const CompilerDeclContext &decl_ctx) const; + const CompilerDeclContext &decl_ctx, + uint32_t payload) const; // If the current object represents a typedef type, get the underlying type CompilerType GetTypedefedType() const; diff --git a/lldb/include/lldb/Symbol/TypeSystem.h b/lldb/include/lldb/Symbol/TypeSystem.h index d16e772b1c6c4..96bdf3a1c5bf7 100644 --- a/lldb/include/lldb/Symbol/TypeSystem.h +++ b/lldb/include/lldb/Symbol/TypeSystem.h @@ -259,9 +259,12 @@ class TypeSystem : public PluginInterface { virtual CompilerType AddRestrictModifier(lldb::opaque_compiler_type_t type); + /// \param opaque_payload The m_payload field of Type, which may + /// carry TypeSystem-specific extra information. virtual CompilerType CreateTypedef(lldb::opaque_compiler_type_t type, const char *name, - const CompilerDeclContext &decl_ctx); + const CompilerDeclContext &decl_ctx, + uint32_t opaque_payload); // Exploring the type diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp index 61fe5e24492b7..85b6c42fa91f1 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp @@ -18,6 +18,7 @@ #include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" #include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h" +#include "Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h" #include "Plugins/ExpressionParser/Clang/ClangUtil.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" @@ -1005,6 +1006,21 @@ void ClangASTImporter::ASTImporterDelegate::ImportDefinitionTo( } } +/// Recreate a module with its parents in \p to_source and return its id. +static OptionalClangModuleID +RemapModule(OptionalClangModuleID from_id, + ClangExternalASTSourceCallbacks &from_source, + ClangExternalASTSourceCallbacks &to_source) { + if (!from_id.HasValue()) + return {}; + clang::Module *module = from_source.getModule(from_id.GetValue()); + OptionalClangModuleID parent = RemapModule( + from_source.GetIDForModule(module->Parent), from_source, to_source); + TypeSystemClang &to_ts = to_source.GetTypeSystem(); + return to_ts.GetOrCreateClangModule(module->Name, parent, module->IsFramework, + module->IsExplicit); +} + void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from, clang::Decl *to) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); @@ -1014,6 +1030,20 @@ void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from, if (m_decls_to_ignore.find(to) != m_decls_to_ignore.end()) return clang::ASTImporter::Imported(from, to); + // Transfer module ownership information. + auto *from_source = llvm::dyn_cast_or_null( + getFromContext().getExternalSource()); + // Can also be a ClangASTSourceProxy. + auto *to_source = llvm::dyn_cast_or_null( + getToContext().getExternalSource()); + if (from_source && to_source) { + OptionalClangModuleID from_id(from->getOwningModuleID()); + OptionalClangModuleID to_id = + RemapModule(from_id, *from_source, *to_source); + TypeSystemClang &to_ts = to_source->GetTypeSystem(); + to_ts.SetOwningModule(to, to_id); + } + lldb::user_id_t user_id = LLDB_INVALID_UID; ClangASTMetadata *metadata = m_master.GetDeclMetadata(from); if (metadata) diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp index 0a829f89f1942..fd66b6bde0908 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp @@ -1017,7 +1017,7 @@ void ClangExpressionDeclMap::LookupLocalVarNamespace( clang::NamespaceDecl *namespace_decl = m_clang_ast_context->GetUniqueNamespaceDeclaration( - g_lldb_local_vars_namespace_cstr, nullptr); + g_lldb_local_vars_namespace_cstr, nullptr, OptionalClangModuleID()); if (!namespace_decl) return; diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp index db9d265ba9a2c..4552bc5ccf8ef 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp @@ -13,6 +13,8 @@ using namespace lldb_private; +char ClangExternalASTSourceCallbacks::ID; + void ClangExternalASTSourceCallbacks::CompleteType(clang::TagDecl *tag_decl) { m_ast.CompleteTagDecl(tag_decl); } @@ -43,3 +45,29 @@ void ClangExternalASTSourceCallbacks::FindExternalLexicalDecls( CompleteType(tag_decl); } } + +OptionalClangModuleID +ClangExternalASTSourceCallbacks::RegisterModule(clang::Module *module) { + m_modules.push_back(module); + unsigned id = m_modules.size(); + m_ids.insert({module, id}); + return OptionalClangModuleID(id); +} + +llvm::Optional +ClangExternalASTSourceCallbacks::getSourceDescriptor(unsigned id) { + if (clang::Module *module = getModule(id)) + return {*module}; + return {}; +} + +clang::Module *ClangExternalASTSourceCallbacks::getModule(unsigned id) { + if (id && id <= m_modules.size()) + return m_modules[id - 1]; + return nullptr; +} + +OptionalClangModuleID +ClangExternalASTSourceCallbacks::GetIDForModule(clang::Module *module) { + return OptionalClangModuleID(m_ids[module]); +} diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h index 98e9f5adbdbf1..5be15bb3f5540 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h @@ -10,14 +10,19 @@ #define liblldb_ClangExternalASTSourceCallbacks_h_ #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" -#include "clang/AST/ExternalASTSource.h" +#include "clang/Basic/Module.h" namespace lldb_private { -class TypeSystemClang; - class ClangExternalASTSourceCallbacks : public clang::ExternalASTSource { + /// LLVM RTTI support. + static char ID; + public: + /// LLVM RTTI support. + bool isA(const void *ClassID) const override { return ClassID == &ID; } + static bool classof(const clang::ExternalASTSource *s) { return s->isA(&ID); } + ClangExternalASTSourceCallbacks(TypeSystemClang &ast) : m_ast(ast) {} void FindExternalLexicalDecls( @@ -37,8 +42,20 @@ class ClangExternalASTSourceCallbacks : public clang::ExternalASTSource { llvm::DenseMap &VirtualBaseOffsets) override; + TypeSystemClang &GetTypeSystem() const { return m_ast; } + + /// Module-related methods. + /// \{ + llvm::Optional + getSourceDescriptor(unsigned ID) override; + clang::Module *getModule(unsigned ID) override; + OptionalClangModuleID RegisterModule(clang::Module *module); + OptionalClangModuleID GetIDForModule(clang::Module *module); + /// \} private: TypeSystemClang &m_ast; + std::vector m_modules; + llvm::DenseMap m_ids; }; } // namespace lldb_private diff --git a/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp b/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp index d2cb3d19516ca..0e163d56dcec1 100644 --- a/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp @@ -76,8 +76,9 @@ static CompilerType GetLLDBNSPairType(TargetSP target_sp) { if (!compiler_type) { compiler_type = target_ast_context->CreateRecordType( - nullptr, lldb::eAccessPublic, g___lldb_autogen_nspair.GetCString(), - clang::TTK_Struct, lldb::eLanguageTypeC); + nullptr, OptionalClangModuleID(), lldb::eAccessPublic, + g___lldb_autogen_nspair.GetCString(), clang::TTK_Struct, + lldb::eLanguageTypeC); if (compiler_type) { TypeSystemClang::StartTagDeclarationDefinition(compiler_type); diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp index 2bc6cfd9a7fc9..a918c0a686472 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp @@ -123,7 +123,8 @@ clang::QualType AppleObjCTypeEncodingParser::BuildAggregate( return clang::QualType(); // This is where we bail out. Sorry! CompilerType union_type(ast_ctx.CreateRecordType( - nullptr, lldb::eAccessPublic, name, kind, lldb::eLanguageTypeC)); + nullptr, OptionalClangModuleID(), lldb::eAccessPublic, name, kind, + lldb::eLanguageTypeC)); if (union_type) { TypeSystemClang::StartTagDeclarationDefinition(union_type); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index f3077c4cdfade..25f18fe56e3bb 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -212,14 +212,15 @@ TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc, TypeSP type_sp(new Type( die.GetID(), dwarf, pcm_type_sp->GetName(), pcm_type_sp->GetByteSize(), nullptr, LLDB_INVALID_UID, Type::eEncodingInvalid, - &pcm_type_sp->GetDeclaration(), type, Type::ResolveState::Forward)); + &pcm_type_sp->GetDeclaration(), type, Type::ResolveState::Forward, + TypePayloadClang(GetOwningClangModule(die)))); dwarf->GetTypeList().Insert(type_sp); dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); clang::TagDecl *tag_decl = TypeSystemClang::GetAsTagDecl(type); - if (tag_decl) + if (tag_decl) { LinkDeclContextToDIE(tag_decl, die); - else { + } else { clang::DeclContext *defn_decl_ctx = GetCachedClangDeclContextForDIE(die); if (defn_decl_ctx) LinkDeclContextToDIE(defn_decl_ctx, die); @@ -708,7 +709,7 @@ DWARFASTParserClang::ParseTypeModifier(const SymbolContext &sc, type_sp = std::make_shared( die.GetID(), dwarf, attrs.name, attrs.byte_size, nullptr, dwarf->GetUID(attrs.type.Reference()), encoding_data_type, &attrs.decl, - clang_type, resolve_state); + clang_type, resolve_state, TypePayloadClang(GetOwningClangModule(die))); dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); return type_sp; @@ -791,7 +792,8 @@ TypeSP DWARFASTParserClang::ParseEnum(const SymbolContext &sc, clang_type = m_ast.CreateEnumerationType( attrs.name.GetCString(), GetClangDeclContextContainingDIE(die, nullptr), - attrs.decl, enumerator_clang_type, attrs.is_scoped_enum); + GetOwningClangModule(die), attrs.decl, enumerator_clang_type, + attrs.is_scoped_enum); } else { enumerator_clang_type = m_ast.GetEnumerationIntegerType(clang_type.GetOpaqueQualType()); @@ -802,7 +804,8 @@ TypeSP DWARFASTParserClang::ParseEnum(const SymbolContext &sc, type_sp = std::make_shared( die.GetID(), dwarf, attrs.name, attrs.byte_size, nullptr, dwarf->GetUID(attrs.type.Reference()), Type::eEncodingIsUID, &attrs.decl, - clang_type, Type::ResolveState::Forward); + clang_type, Type::ResolveState::Forward, + TypePayloadClang(GetOwningClangModule(die))); if (TypeSystemClang::StartTagDeclarationDefinition(clang_type)) { if (die.HasChildren()) { @@ -1186,7 +1189,8 @@ TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, function_decl = m_ast.CreateFunctionDeclaration( ignore_containing_context ? m_ast.GetTranslationUnitDecl() : containing_decl_ctx, - name, clang_type, attrs.storage, attrs.is_inline); + GetOwningClangModule(die), name, clang_type, attrs.storage, + attrs.is_inline); if (has_template_params) { TypeSystemClang::TemplateParameterInfos template_param_infos; @@ -1194,12 +1198,12 @@ TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, template_function_decl = m_ast.CreateFunctionDeclaration( ignore_containing_context ? m_ast.GetTranslationUnitDecl() : containing_decl_ctx, - name, clang_type, attrs.storage, attrs.is_inline); - + GetOwningClangModule(die), attrs.name.GetCString(), clang_type, + attrs.storage, attrs.is_inline); clang::FunctionTemplateDecl *func_template_decl = - m_ast.CreateFunctionTemplateDecl(containing_decl_ctx, - template_function_decl, name, - template_param_infos); + m_ast.CreateFunctionTemplateDecl( + containing_decl_ctx, GetOwningClangModule(die), + template_function_decl, name, template_param_infos); m_ast.CreateFunctionTemplateSpecializationInfo( template_function_decl, func_template_decl, template_param_infos); } @@ -1597,9 +1601,9 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, TypeSystemClang::TemplateParameterInfos template_param_infos; if (ParseTemplateParameterInfos(die, template_param_infos)) { clang::ClassTemplateDecl *class_template_decl = - m_ast.ParseClassTemplateDecl(decl_ctx, attrs.accessibility, - attrs.name.GetCString(), tag_decl_kind, - template_param_infos); + m_ast.ParseClassTemplateDecl( + decl_ctx, GetOwningClangModule(die), attrs.accessibility, + attrs.name.GetCString(), tag_decl_kind, template_param_infos); if (!class_template_decl) { if (log) { dwarf->GetObjectFile()->GetModule()->LogMessage( @@ -1614,8 +1618,8 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, clang::ClassTemplateSpecializationDecl *class_specialization_decl = m_ast.CreateClassTemplateSpecializationDecl( - decl_ctx, class_template_decl, tag_decl_kind, - template_param_infos); + decl_ctx, GetOwningClangModule(die), class_template_decl, + tag_decl_kind, template_param_infos); clang_type = m_ast.CreateClassTemplateSpecializationType( class_specialization_decl); clang_type_was_created = true; @@ -1628,8 +1632,9 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, if (!clang_type_was_created) { clang_type_was_created = true; clang_type = m_ast.CreateRecordType( - decl_ctx, attrs.accessibility, attrs.name.GetCString(), tag_decl_kind, - attrs.class_language, &metadata, attrs.exports_symbols); + decl_ctx, GetOwningClangModule(die), attrs.accessibility, + attrs.name.GetCString(), tag_decl_kind, attrs.class_language, + &metadata, attrs.exports_symbols); } } @@ -1641,7 +1646,7 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, die.GetID(), dwarf, attrs.name, attrs.byte_size, nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, &attrs.decl, clang_type, Type::ResolveState::Forward, - TypePayloadClang(attrs.is_complete_objc_class)); + TypePayloadClang(OptionalClangModuleID(), attrs.is_complete_objc_class)); // Add our type to the unique type map so we don't end up creating many // copies of the same type over and over in the ASTContext for our @@ -3134,9 +3139,9 @@ size_t DWARFASTParserClang::ParseChildParameters( function_param_types.push_back(type->GetForwardCompilerType()); clang::ParmVarDecl *param_var_decl = - m_ast.CreateParameterDeclaration(containing_decl_ctx, name, - type->GetForwardCompilerType(), - storage); + m_ast.CreateParameterDeclaration( + containing_decl_ctx, GetOwningClangModule(die), name, + type->GetForwardCompilerType(), storage); assert(param_var_decl); function_param_decls.push_back(param_var_decl); @@ -3334,7 +3339,7 @@ clang::Decl *DWARFASTParserClang::GetClangDeclForDIE(const DWARFDIE &die) { TypeSystemClang::DeclContextGetAsDeclContext( dwarf->GetDeclContextContainingUID(die.GetID())); decl = m_ast.CreateVariableDeclaration( - decl_context, name, + decl_context, GetOwningClangModule(die), name, ClangUtil::GetQualType(type->GetForwardCompilerType())); } break; @@ -3351,8 +3356,8 @@ clang::Decl *DWARFASTParserClang::GetClangDeclForDIE(const DWARFDIE &die) { if (clang::NamedDecl *clang_imported_decl = llvm::dyn_cast( (clang::Decl *)imported_decl.GetOpaqueDecl())) - decl = - m_ast.CreateUsingDeclaration(decl_context, clang_imported_decl); + decl = m_ast.CreateUsingDeclaration( + decl_context, OptionalClangModuleID(), clang_imported_decl); } } break; @@ -3370,7 +3375,8 @@ clang::Decl *DWARFASTParserClang::GetClangDeclForDIE(const DWARFDIE &die) { if (clang::NamespaceDecl *ns_decl = TypeSystemClang::DeclContextGetAsNamespaceDecl( imported_decl_ctx)) - decl = m_ast.CreateUsingDirectiveDeclaration(decl_context, ns_decl); + decl = m_ast.CreateUsingDirectiveDeclaration( + decl_context, OptionalClangModuleID(), ns_decl); } } break; @@ -3428,6 +3434,32 @@ DWARFASTParserClang::GetClangDeclContextForDIE(const DWARFDIE &die) { return nullptr; } +OptionalClangModuleID +DWARFASTParserClang::GetOwningClangModule(const DWARFDIE &die) { + if (!die.IsValid()) + return {}; + + for (DWARFDIE parent = die.GetParent(); parent.IsValid(); + parent = parent.GetParent()) { + const dw_tag_t tag = parent.Tag(); + if (tag == DW_TAG_module) { + DWARFDIE module_die = parent; + auto it = m_die_to_module.find(module_die.GetDIE()); + if (it != m_die_to_module.end()) + return it->second; + const char *name = module_die.GetAttributeValueAsString(DW_AT_name, 0); + if (!name) + return {}; + + OptionalClangModuleID id = + m_ast.GetOrCreateClangModule(name, GetOwningClangModule(module_die)); + m_die_to_module.insert({module_die.GetDIE(), id}); + return id; + } + } + return {}; +} + static bool IsSubroutine(const DWARFDIE &die) { switch (die.Tag()) { case DW_TAG_subprogram: @@ -3500,7 +3532,8 @@ clang::BlockDecl *DWARFASTParserClang::ResolveBlockDIE(const DWARFDIE &die) { DWARFDIE decl_context_die; clang::DeclContext *decl_context = GetClangDeclContextContainingDIE(die, &decl_context_die); - decl = m_ast.CreateBlockDeclaration(decl_context); + decl = + m_ast.CreateBlockDeclaration(decl_context, GetOwningClangModule(die)); if (decl) LinkDeclContextToDIE((clang::DeclContext *)decl, die); @@ -3528,7 +3561,8 @@ DWARFASTParserClang::ResolveNamespaceDIE(const DWARFDIE &die) { die.GetAttributeValueAsUnsigned(DW_AT_export_symbols, 0) != 0; namespace_decl = m_ast.GetUniqueNamespaceDeclaration( - namespace_name, containing_decl_ctx, is_inline); + namespace_name, containing_decl_ctx, GetOwningClangModule(die), + is_inline); Log *log = nullptr; // (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO)); if (log) { diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h index 9282131301f5d..c93789ee830ff 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h @@ -79,6 +79,9 @@ class DWARFASTParserClang : public DWARFASTParser { DIEToDeclContextMap; typedef std::multimap DeclContextToDIEMap; + typedef llvm::DenseMap + DIEToModuleMap; typedef llvm::DenseMap DIEToDeclMap; typedef llvm::DenseMap DeclToDIEMap; @@ -88,6 +91,7 @@ class DWARFASTParserClang : public DWARFASTParser { DeclToDIEMap m_decl_to_die; DIEToDeclContextMap m_die_to_decl_ctx; DeclContextToDIEMap m_decl_ctx_to_die; + DIEToModuleMap m_die_to_module; std::unique_ptr m_clang_ast_importer_up; /// @} @@ -141,6 +145,7 @@ class DWARFASTParserClang : public DWARFASTParser { clang::DeclContext *GetClangDeclContextContainingDIE(const DWARFDIE &die, DWARFDIE *decl_ctx_die); + lldb_private::OptionalClangModuleID GetOwningClangModule(const DWARFDIE &die); bool CopyUniqueClassMethodTypes(const DWARFDIE &src_class_die, const DWARFDIE &dst_class_die, diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp index 03cd8ffc53921..005205c52a841 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp @@ -776,8 +776,9 @@ clang::QualType PdbAstBuilder::CreateRecordType(PdbTypeSymId id, metadata.SetUserID(toOpaqueUid(id)); metadata.SetIsDynamicCXXType(false); - CompilerType ct = m_clang.CreateRecordType( - context, access, uname, ttk, lldb::eLanguageTypeC_plus_plus, &metadata); + CompilerType ct = + m_clang.CreateRecordType(context, OptionalClangModuleID(), access, uname, + ttk, lldb::eLanguageTypeC_plus_plus, &metadata); lldbassert(ct.IsValid()); @@ -804,7 +805,8 @@ clang::NamespaceDecl * PdbAstBuilder::GetOrCreateNamespaceDecl(const char *name, clang::DeclContext &context) { return m_clang.GetUniqueNamespaceDeclaration( - IsAnonymousNamespaceName(name) ? nullptr : name, &context); + IsAnonymousNamespaceName(name) ? nullptr : name, &context, + OptionalClangModuleID()); } clang::BlockDecl * @@ -814,7 +816,8 @@ PdbAstBuilder::GetOrCreateBlockDecl(PdbCompilandSymId block_id) { clang::DeclContext *scope = GetParentDeclContext(block_id); - clang::BlockDecl *block_decl = m_clang.CreateBlockDeclaration(scope); + clang::BlockDecl *block_decl = + m_clang.CreateBlockDeclaration(scope, OptionalClangModuleID()); m_uid_to_decl.insert({toOpaqueUid(block_id), block_decl}); DeclStatus status; @@ -831,7 +834,7 @@ clang::VarDecl *PdbAstBuilder::CreateVariableDecl(PdbSymUid uid, CVSymbol sym, clang::QualType qt = GetOrCreateType(var_info.type); clang::VarDecl *var_decl = m_clang.CreateVariableDeclaration( - &scope, var_info.name.str().c_str(), qt); + &scope, OptionalClangModuleID(), var_info.name.str().c_str(), qt); m_uid_to_decl[toOpaqueUid(uid)] = var_decl; DeclStatus status; @@ -879,7 +882,7 @@ PdbAstBuilder::GetOrCreateTypedefDecl(PdbGlobalSymId id) { std::string uname = DropNameScope(udt.Name); CompilerType ct = m_clang.CreateTypedefType(ToCompilerType(qt), uname.c_str(), - ToCompilerDeclContext(*scope)); + ToCompilerDeclContext(*scope), 0); clang::TypedefNameDecl *tnd = m_clang.GetAsTypedefDecl(ct); DeclStatus status; status.resolved = true; @@ -1012,7 +1015,8 @@ PdbAstBuilder::GetOrCreateFunctionDecl(PdbCompilandSymId func_id) { proc_name.consume_front("::"); clang::FunctionDecl *function_decl = m_clang.CreateFunctionDeclaration( - parent, proc_name.str().c_str(), func_ct, storage, false); + parent, OptionalClangModuleID(), proc_name.str().c_str(), func_ct, + storage, false); lldbassert(m_uid_to_decl.count(toOpaqueUid(func_id)) == 0); m_uid_to_decl[toOpaqueUid(func_id)] = function_decl; @@ -1080,8 +1084,8 @@ void PdbAstBuilder::CreateFunctionParameters(PdbCompilandSymId func_id, CompilerType param_type_ct = m_clang.GetType(qt); clang::ParmVarDecl *param = m_clang.CreateParameterDeclaration( - &function_decl, param_name.str().c_str(), param_type_ct, - clang::SC_None, true); + &function_decl, OptionalClangModuleID(), param_name.str().c_str(), + param_type_ct, clang::SC_None, true); lldbassert(m_uid_to_decl.count(toOpaqueUid(param_uid)) == 0); m_uid_to_decl[toOpaqueUid(param_uid)] = param; @@ -1102,8 +1106,8 @@ clang::QualType PdbAstBuilder::CreateEnumType(PdbTypeSymId id, Declaration declaration; CompilerType enum_ct = m_clang.CreateEnumerationType( - uname.c_str(), decl_context, declaration, ToCompilerType(underlying_type), - er.isScoped()); + uname.c_str(), decl_context, OptionalClangModuleID(), declaration, + ToCompilerType(underlying_type), er.isScoped()); TypeSystemClang::StartTagDeclarationDefinition(enum_ct); TypeSystemClang::SetHasExternalStorage(enum_ct.GetOpaqueQualType(), true); diff --git a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp index 8f1a40a82150e..47f097862c790 100644 --- a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp +++ b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp @@ -408,9 +408,9 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { metadata.SetUserID(type.getSymIndexId()); metadata.SetIsDynamicCXXType(false); - clang_type = - m_ast.CreateRecordType(decl_context, access, name, tag_type_kind, - lldb::eLanguageTypeC_plus_plus, &metadata); + clang_type = m_ast.CreateRecordType( + decl_context, OptionalClangModuleID(), access, name, tag_type_kind, + lldb::eLanguageTypeC_plus_plus, &metadata); assert(clang_type.IsValid()); auto record_decl = @@ -496,7 +496,8 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { // Class). Set it false for now. bool isScoped = false; - ast_enum = m_ast.CreateEnumerationType(name.c_str(), decl_context, decl, + ast_enum = m_ast.CreateEnumerationType(name.c_str(), decl_context, + OptionalClangModuleID(), decl, builtin_type, isScoped); auto enum_decl = TypeSystemClang::GetAsEnumDecl(ast_enum); @@ -549,7 +550,7 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { CompilerType target_ast_type = target_type->GetFullCompilerType(); ast_typedef = m_ast.CreateTypedefType( - target_ast_type, name.c_str(), m_ast.CreateDeclContext(decl_ctx)); + target_ast_type, name.c_str(), m_ast.CreateDeclContext(decl_ctx), 0); if (!ast_typedef) return nullptr; @@ -898,7 +899,7 @@ PDBASTParser::GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol) { return nullptr; decl = m_ast.CreateVariableDeclaration( - decl_context, name.c_str(), + decl_context, OptionalClangModuleID(), name.c_str(), ClangUtil::GetQualType(type->GetLayoutCompilerType())); } @@ -923,8 +924,8 @@ PDBASTParser::GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol) { : clang::StorageClass::SC_None; auto decl = m_ast.CreateFunctionDeclaration( - decl_context, name.c_str(), type->GetForwardCompilerType(), storage, - func->hasInlineAttribute()); + decl_context, OptionalClangModuleID(), name.c_str(), + type->GetForwardCompilerType(), storage, func->hasInlineAttribute()); std::vector params; if (std::unique_ptr sig = func->getSignature()) { @@ -937,8 +938,8 @@ PDBASTParser::GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol) { continue; clang::ParmVarDecl *param = m_ast.CreateParameterDeclaration( - decl, nullptr, arg_type->GetForwardCompilerType(), - clang::SC_None, true); + decl, OptionalClangModuleID(), nullptr, + arg_type->GetForwardCompilerType(), clang::SC_None, true); if (param) params.push_back(param); } @@ -1052,8 +1053,8 @@ clang::DeclContext *PDBASTParser::GetDeclContextContainingSymbol( IsAnonymousNamespaceName(namespace_name) ? nullptr : namespace_name.data(); clang::NamespaceDecl *namespace_decl = - m_ast.GetUniqueNamespaceDeclaration(namespace_name_c_str, - curr_context); + m_ast.GetUniqueNamespaceDeclaration( + namespace_name_c_str, curr_context, OptionalClangModuleID()); m_parent_to_namespaces[curr_context].insert(namespace_decl); m_namespaces.insert(namespace_decl); diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp index 41a7a525385b7..1778e4aafaa25 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp @@ -417,8 +417,9 @@ void SystemRuntimeMacOSX::ReadLibdispatchTSDIndexes() { CompilerType uint16 = ast_ctx->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 16); CompilerType dispatch_tsd_indexes_s = ast_ctx->CreateRecordType( - nullptr, lldb::eAccessPublic, "__lldb_dispatch_tsd_indexes_s", - clang::TTK_Struct, lldb::eLanguageTypeC); + nullptr, OptionalClangModuleID(), lldb::eAccessPublic, + "__lldb_dispatch_tsd_indexes_s", clang::TTK_Struct, + lldb::eLanguageTypeC); TypeSystemClang::StartTagDeclarationDefinition(dispatch_tsd_indexes_s); TypeSystemClang::AddFieldToRecordType(dispatch_tsd_indexes_s, diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 7b6a39756e3c7..d7fb89eafb657 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -34,6 +34,9 @@ #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TargetOptions.h" #include "clang/Frontend/FrontendOptions.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/HeaderSearchOptions.h" +#include "clang/Lex/ModuleMap.h" #include "clang/Sema/Sema.h" #include "llvm/Support/Signals.h" @@ -312,10 +315,33 @@ static ClangASTMap &GetASTMap() { return *g_map_ptr; } -TypePayloadClang::TypePayloadClang(bool is_complete_objc_class) { +TypePayloadClang::TypePayloadClang(OptionalClangModuleID owning_module, + bool is_complete_objc_class) + : m_payload(owning_module.GetValue()) { SetIsCompleteObjCClass(is_complete_objc_class); } +void TypePayloadClang::SetOwningModule(OptionalClangModuleID id) { + assert(id.GetValue() < ObjCClassBit); + bool is_complete = IsCompleteObjCClass(); + m_payload = id.GetValue(); + SetIsCompleteObjCClass(is_complete); +} + +static void SetMemberOwningModule(clang::Decl *member, + const clang::Decl *parent) { + if (!member || !parent) + return; + + OptionalClangModuleID id(parent->getOwningModuleID()); + if (!id.HasValue()) + return; + + member->setFromASTFile(); + member->setOwningModuleID(id.GetValue()); + member->setModuleOwnershipKind(clang::Decl::ModuleOwnershipKind::Visible); +} + char TypeSystemClang::ID; bool TypeSystemClang::IsOperator(llvm::StringRef name, @@ -501,6 +527,10 @@ static void ParseLangArgs(LangOptions &Opts, InputKind IK, const char *triple) { // // FIXME: This is affected by other options (-fno-inline). Opts.NoInlineDefine = !Opt; + + // This is needed to allocate the extra space for the owning module + // on each decl. + Opts.ModulesLocalVisibility = 1; } TypeSystemClang::TypeSystemClang(llvm::Triple target_triple) { @@ -1176,12 +1206,60 @@ CompilerType TypeSystemClang::GetTypeForDecl(ObjCInterfaceDecl *decl) { #pragma mark Structure, Unions, Classes -CompilerType TypeSystemClang::CreateRecordType(DeclContext *decl_ctx, - AccessType access_type, - llvm::StringRef name, int kind, - LanguageType language, - ClangASTMetadata *metadata, - bool exports_symbols) { +void TypeSystemClang::SetOwningModule(clang::Decl *decl, + OptionalClangModuleID owning_module) { + if (!decl || !owning_module.HasValue()) + return; + + decl->setFromASTFile(); + decl->setOwningModuleID(owning_module.GetValue()); + decl->setModuleOwnershipKind(clang::Decl::ModuleOwnershipKind::Visible); + if (auto *decl_ctx = llvm::dyn_cast(decl)) { + decl_ctx->setHasExternalVisibleStorage(); + if (auto *ns = llvm::dyn_cast(decl_ctx)) + ns->getPrimaryContext()->setMustBuildLookupTable(); + } +} + +OptionalClangModuleID +TypeSystemClang::GetOrCreateClangModule(llvm::StringRef name, + OptionalClangModuleID parent, + bool is_framework, bool is_explicit) { + // Get the external AST source which holds the modules. + auto *ast_source = llvm::dyn_cast_or_null( + getASTContext().getExternalSource()); + assert(ast_source && "external ast source was lost"); + if (!ast_source) + return {}; + + // Lazily initialize the module map. + if (!m_header_search_up) { + auto HSOpts = std::make_shared(); + m_header_search_up = std::make_unique( + HSOpts, *m_source_manager_up, *m_diagnostics_engine_up, + *m_language_options_up, m_target_info_up.get()); + m_module_map_up = std::make_unique( + *m_source_manager_up, *m_diagnostics_engine_up, *m_language_options_up, + m_target_info_up.get(), *m_header_search_up); + } + + // Get or create the module context. + bool created; + clang::Module *module; + auto parent_desc = ast_source->getSourceDescriptor(parent.GetValue()); + std::tie(module, created) = m_module_map_up->findOrCreateModule( + name, parent_desc ? parent_desc->getModuleOrNull() : nullptr, + is_framework, is_explicit); + if (!created) + return ast_source->GetIDForModule(module); + + return ast_source->RegisterModule(module); +} + +CompilerType TypeSystemClang::CreateRecordType( + clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, + AccessType access_type, llvm::StringRef name, int kind, + LanguageType language, ClangASTMetadata *metadata, bool exports_symbols) { ASTContext &ast = getASTContext(); if (decl_ctx == nullptr) @@ -1191,7 +1269,8 @@ CompilerType TypeSystemClang::CreateRecordType(DeclContext *decl_ctx, language == eLanguageTypeObjC_plus_plus) { bool isForwardDecl = true; bool isInternal = false; - return CreateObjCClass(name, decl_ctx, isForwardDecl, isInternal, metadata); + return CreateObjCClass(name, decl_ctx, owning_module, isForwardDecl, + isInternal, metadata); } // NOTE: Eventually CXXRecordDecl will be merged back into RecordDecl and @@ -1206,6 +1285,7 @@ CompilerType TypeSystemClang::CreateRecordType(DeclContext *decl_ctx, decl->setDeclContext(decl_ctx); if (has_name) decl->setDeclName(&ast.Idents.get(name)); + SetOwningModule(decl, owning_module); if (!has_name) { // In C++ a lambda is also represented as an unnamed class. This is @@ -1314,13 +1394,13 @@ static TemplateParameterList *CreateTemplateParameterList( } clang::FunctionTemplateDecl *TypeSystemClang::CreateFunctionTemplateDecl( - clang::DeclContext *decl_ctx, clang::FunctionDecl *func_decl, - const char *name, const TemplateParameterInfos &template_param_infos) { + clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, + clang::FunctionDecl *func_decl, const char *name, + const TemplateParameterInfos &template_param_infos) { // /// Create a function template node. ASTContext &ast = getASTContext(); llvm::SmallVector template_param_decls; - TemplateParameterList *template_param_list = CreateTemplateParameterList( ast, template_param_infos, template_param_decls); FunctionTemplateDecl *func_tmpl_decl = @@ -1329,6 +1409,7 @@ clang::FunctionTemplateDecl *TypeSystemClang::CreateFunctionTemplateDecl( func_tmpl_decl->setLocation(func_decl->getLocation()); func_tmpl_decl->setDeclName(func_decl->getDeclName()); func_tmpl_decl->init(func_decl, template_param_list); + SetOwningModule(func_tmpl_decl, owning_module); for (size_t i = 0, template_param_decl_count = template_param_decls.size(); i < template_param_decl_count; ++i) { @@ -1355,8 +1436,9 @@ void TypeSystemClang::CreateFunctionTemplateSpecializationInfo( } ClassTemplateDecl *TypeSystemClang::CreateClassTemplateDecl( - DeclContext *decl_ctx, lldb::AccessType access_type, const char *class_name, - int kind, const TemplateParameterInfos &template_param_infos) { + DeclContext *decl_ctx, OptionalClangModuleID owning_module, + lldb::AccessType access_type, const char *class_name, int kind, + const TemplateParameterInfos &template_param_infos) { ASTContext &ast = getASTContext(); ClassTemplateDecl *class_template_decl = nullptr; @@ -1384,6 +1466,7 @@ ClassTemplateDecl *TypeSystemClang::CreateClassTemplateDecl( // What decl context do we use here? TU? The actual decl context? template_cxx_decl->setDeclContext(decl_ctx); template_cxx_decl->setDeclName(decl_name); + SetOwningModule(template_cxx_decl, owning_module); for (size_t i = 0, template_param_decl_count = template_param_decls.size(); i < template_param_decl_count; ++i) { @@ -1401,6 +1484,7 @@ ClassTemplateDecl *TypeSystemClang::CreateClassTemplateDecl( class_template_decl->setDeclName(decl_name); class_template_decl->init(template_cxx_decl, template_param_list); template_cxx_decl->setDescribedClassTemplate(class_template_decl); + SetOwningModule(class_template_decl, owning_module); if (class_template_decl) { if (access_type != eAccessNone) @@ -1445,7 +1529,8 @@ TypeSystemClang::CreateTemplateTemplateParmDecl(const char *template_name) { ClassTemplateSpecializationDecl * TypeSystemClang::CreateClassTemplateSpecializationDecl( - DeclContext *decl_ctx, ClassTemplateDecl *class_template_decl, int kind, + DeclContext *decl_ctx, OptionalClangModuleID owning_module, + ClassTemplateDecl *class_template_decl, int kind, const TemplateParameterInfos &template_param_infos) { ASTContext &ast = getASTContext(); llvm::SmallVector args( @@ -1468,6 +1553,16 @@ TypeSystemClang::CreateClassTemplateSpecializationDecl( ast.getTypeDeclType(class_template_specialization_decl, nullptr); class_template_specialization_decl->setDeclName( class_template_decl->getDeclName()); + // FIXME: Turning this on breaks the libcxx data formatter tests. + // SetOwningModule marks the Decl as external, which prevents a + // LookupPtr from being built. Template instantiations can also not + // be found by ExternalASTSource::FindExternalVisibleDeclsByName(), + // nor can we lazily build a LookupPtr later, because template + // specializations are supposed to be hidden so + // makeDeclVisibleInContextWithFlags() is a noop, as well. + // + // SetOwningModule(class_template_specialization_decl, owning_module); + decl_ctx->addDecl(class_template_specialization_decl); class_template_specialization_decl->setSpecializationKind( TSK_ExplicitSpecialization); @@ -1586,14 +1681,13 @@ bool TypeSystemClang::RecordHasFields(const RecordDecl *record_decl) { #pragma mark Objective-C Classes -CompilerType TypeSystemClang::CreateObjCClass(llvm::StringRef name, - DeclContext *decl_ctx, - bool isForwardDecl, - bool isInternal, - ClangASTMetadata *metadata) { +CompilerType TypeSystemClang::CreateObjCClass( + llvm::StringRef name, clang::DeclContext *decl_ctx, + OptionalClangModuleID owning_module, bool isForwardDecl, bool isInternal, + ClangASTMetadata *metadata) { ASTContext &ast = getASTContext(); assert(!name.empty()); - if (decl_ctx == nullptr) + if (!decl_ctx) decl_ctx = ast.getTranslationUnitDecl(); ObjCInterfaceDecl *decl = ObjCInterfaceDecl::CreateDeserialized(ast, 0); @@ -1601,6 +1695,7 @@ CompilerType TypeSystemClang::CreateObjCClass(llvm::StringRef name, decl->setDeclName(&ast.Idents.get(name)); /*isForwardDecl,*/ decl->setImplicit(isInternal); + SetOwningModule(decl, owning_module); if (decl && metadata) SetMetadata(decl, *metadata); @@ -1638,11 +1733,12 @@ TypeSystemClang::GetNumBaseClasses(const CXXRecordDecl *cxx_record_decl, #pragma mark Namespace Declarations NamespaceDecl *TypeSystemClang::GetUniqueNamespaceDeclaration( - const char *name, clang::DeclContext *decl_ctx, bool is_inline) { + const char *name, clang::DeclContext *decl_ctx, + OptionalClangModuleID owning_module, bool is_inline) { NamespaceDecl *namespace_decl = nullptr; ASTContext &ast = getASTContext(); TranslationUnitDecl *translation_unit_decl = ast.getTranslationUnitDecl(); - if (decl_ctx == nullptr) + if (!decl_ctx) decl_ctx = translation_unit_decl; if (name) { @@ -1691,6 +1787,11 @@ NamespaceDecl *TypeSystemClang::GetUniqueNamespaceDeclaration( } } } + + // Note: namespaces can span multiple modules, so perhaps this isn't a good + // idea. + SetOwningModule(namespace_decl, owning_module); + #ifdef LLDB_CONFIGURATION_DEBUG VerifyDecl(namespace_decl); #endif @@ -1698,12 +1799,14 @@ NamespaceDecl *TypeSystemClang::GetUniqueNamespaceDeclaration( } clang::BlockDecl * -TypeSystemClang::CreateBlockDeclaration(clang::DeclContext *ctx) { +TypeSystemClang::CreateBlockDeclaration(clang::DeclContext *ctx, + OptionalClangModuleID owning_module) { if (ctx) { clang::BlockDecl *decl = clang::BlockDecl::CreateDeserialized(getASTContext(), 0); decl->setDeclContext(ctx); ctx->addDecl(decl); + SetOwningModule(decl, owning_module); return decl; } return nullptr; @@ -1727,7 +1830,8 @@ clang::DeclContext *FindLCABetweenDecls(clang::DeclContext *left, } clang::UsingDirectiveDecl *TypeSystemClang::CreateUsingDirectiveDeclaration( - clang::DeclContext *decl_ctx, clang::NamespaceDecl *ns_decl) { + clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, + clang::NamespaceDecl *ns_decl) { if (decl_ctx && ns_decl) { auto *translation_unit = getASTContext().getTranslationUnitDecl(); clang::UsingDirectiveDecl *using_decl = clang::UsingDirectiveDecl::Create( @@ -1737,6 +1841,7 @@ clang::UsingDirectiveDecl *TypeSystemClang::CreateUsingDirectiveDeclaration( FindLCABetweenDecls(decl_ctx, ns_decl, translation_unit)); decl_ctx->addDecl(using_decl); + SetOwningModule(using_decl, owning_module); return using_decl; } return nullptr; @@ -1744,14 +1849,17 @@ clang::UsingDirectiveDecl *TypeSystemClang::CreateUsingDirectiveDeclaration( clang::UsingDecl * TypeSystemClang::CreateUsingDeclaration(clang::DeclContext *current_decl_ctx, + OptionalClangModuleID owning_module, clang::NamedDecl *target) { - if (current_decl_ctx != nullptr && target != nullptr) { + if (current_decl_ctx && target) { clang::UsingDecl *using_decl = clang::UsingDecl::Create( getASTContext(), current_decl_ctx, clang::SourceLocation(), clang::NestedNameSpecifierLoc(), clang::DeclarationNameInfo(), false); + SetOwningModule(using_decl, owning_module); clang::UsingShadowDecl *shadow_decl = clang::UsingShadowDecl::Create( getASTContext(), current_decl_ctx, clang::SourceLocation(), using_decl, target); + SetOwningModule(shadow_decl, owning_module); using_decl->addShadowDecl(shadow_decl); current_decl_ctx->addDecl(using_decl); return using_decl; @@ -1760,7 +1868,8 @@ TypeSystemClang::CreateUsingDeclaration(clang::DeclContext *current_decl_ctx, } clang::VarDecl *TypeSystemClang::CreateVariableDeclaration( - clang::DeclContext *decl_context, const char *name, clang::QualType type) { + clang::DeclContext *decl_context, OptionalClangModuleID owning_module, + const char *name, clang::QualType type) { if (decl_context) { clang::VarDecl *var_decl = clang::VarDecl::CreateDeserialized(getASTContext(), 0); @@ -1768,6 +1877,7 @@ clang::VarDecl *TypeSystemClang::CreateVariableDeclaration( if (name && name[0]) var_decl->setDeclName(&getASTContext().Idents.getOwn(name)); var_decl->setType(type); + SetOwningModule(var_decl, owning_module); var_decl->setAccess(clang::AS_public); decl_context->addDecl(var_decl); return var_decl; @@ -1879,11 +1989,12 @@ TypeSystemClang::GetDeclarationName(const char *name, } FunctionDecl *TypeSystemClang::CreateFunctionDeclaration( - DeclContext *decl_ctx, const char *name, - const CompilerType &function_clang_type, int storage, bool is_inline) { + clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, + const char *name, const CompilerType &function_clang_type, int storage, + bool is_inline) { FunctionDecl *func_decl = nullptr; ASTContext &ast = getASTContext(); - if (decl_ctx == nullptr) + if (!decl_ctx) decl_ctx = ast.getTranslationUnitDecl(); const bool hasWrittenPrototype = true; @@ -1900,6 +2011,7 @@ FunctionDecl *TypeSystemClang::CreateFunctionDeclaration( func_decl->setHasWrittenPrototype(hasWrittenPrototype); func_decl->setConstexprKind(isConstexprSpecified ? CSK_constexpr : CSK_unspecified); + SetOwningModule(func_decl, owning_module); if (func_decl) decl_ctx->addDecl(func_decl); @@ -1950,8 +2062,9 @@ TypeSystemClang::CreateFunctionType(const CompilerType &result_type, } ParmVarDecl *TypeSystemClang::CreateParameterDeclaration( - clang::DeclContext *decl_ctx, const char *name, - const CompilerType ¶m_type, int storage, bool add_decl) { + clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, + const char *name, const CompilerType ¶m_type, int storage, + bool add_decl) { ASTContext &ast = getASTContext(); auto *decl = ParmVarDecl::CreateDeserialized(ast, 0); decl->setDeclContext(decl_ctx); @@ -1959,6 +2072,7 @@ ParmVarDecl *TypeSystemClang::CreateParameterDeclaration( decl->setDeclName(&ast.Idents.get(name)); decl->setType(ClangUtil::GetQualType(param_type)); decl->setStorageClass(static_cast(storage)); + SetOwningModule(decl, owning_module); if (add_decl) decl_ctx->addDecl(decl); @@ -2020,8 +2134,9 @@ CompilerType TypeSystemClang::CreateStructForIdentifier( return type; } - type = CreateRecordType(nullptr, lldb::eAccessPublic, type_name.GetCString(), - clang::TTK_Struct, lldb::eLanguageTypeC); + type = CreateRecordType(nullptr, OptionalClangModuleID(), lldb::eAccessPublic, + type_name.GetCString(), clang::TTK_Struct, + lldb::eLanguageTypeC); StartTagDeclarationDefinition(type); for (const auto &field : type_fields) AddFieldToRecordType(type, field.first, field.second, lldb::eAccessPublic, @@ -2046,24 +2161,24 @@ CompilerType TypeSystemClang::GetOrCreateStructForIdentifier( #pragma mark Enumeration Types -CompilerType -TypeSystemClang::CreateEnumerationType(const char *name, DeclContext *decl_ctx, - const Declaration &decl, - const CompilerType &integer_clang_type, - bool is_scoped) { +CompilerType TypeSystemClang::CreateEnumerationType( + const char *name, clang::DeclContext *decl_ctx, + OptionalClangModuleID owning_module, const Declaration &decl, + const CompilerType &integer_clang_type, bool is_scoped) { // TODO: Do something intelligent with the Declaration object passed in // like maybe filling in the SourceLocation with it... ASTContext &ast = getASTContext(); // TODO: ask about these... // const bool IsFixed = false; - EnumDecl *enum_decl = EnumDecl::Create( - ast, decl_ctx, SourceLocation(), SourceLocation(), - name && name[0] ? &ast.Idents.get(name) : nullptr, nullptr, - is_scoped, // IsScoped - is_scoped, // IsScopedUsingClassTag - false); // IsFixed - + EnumDecl *enum_decl = EnumDecl::CreateDeserialized(ast, 0); + enum_decl->setDeclContext(decl_ctx); + if (name && name[0]) + enum_decl->setDeclName(&ast.Idents.get(name)); + enum_decl->setScoped(is_scoped); + enum_decl->setScopedUsingClassTag(is_scoped); + enum_decl->setFixed(false); + SetOwningModule(enum_decl, owning_module); if (enum_decl) { if (decl_ctx) decl_ctx->addDecl(enum_decl); @@ -4251,7 +4366,7 @@ TypeSystemClang::GetNonReferenceType(lldb::opaque_compiler_type_t type) { CompilerType TypeSystemClang::CreateTypedefType( const CompilerType &type, const char *typedef_name, - const CompilerDeclContext &compiler_decl_ctx) { + const CompilerDeclContext &compiler_decl_ctx, uint32_t payload) { if (type && typedef_name && typedef_name[0]) { TypeSystemClang *ast = llvm::dyn_cast(type.GetTypeSystem()); @@ -4262,7 +4377,7 @@ CompilerType TypeSystemClang::CreateTypedefType( clang::DeclContext *decl_ctx = TypeSystemClang::DeclContextGetAsDeclContext(compiler_decl_ctx); - if (decl_ctx == nullptr) + if (!decl_ctx) decl_ctx = ast->getASTContext().getTranslationUnitDecl(); clang::TypedefDecl *decl = @@ -4271,6 +4386,7 @@ CompilerType TypeSystemClang::CreateTypedefType( decl->setDeclName(&clang_ast.Idents.get(typedef_name)); decl->setTypeSourceInfo(clang_ast.getTrivialTypeSourceInfo(qual_type)); + SetOwningModule(decl, TypePayloadClang(payload).GetOwningModule()); decl->setAccess(clang::AS_public); // TODO respect proper access specifier decl_ctx->addDecl(decl); @@ -4359,24 +4475,23 @@ TypeSystemClang::AddRestrictModifier(lldb::opaque_compiler_type_t type) { return CompilerType(); } -CompilerType -TypeSystemClang::CreateTypedef(lldb::opaque_compiler_type_t type, - const char *typedef_name, - const CompilerDeclContext &compiler_decl_ctx) { +CompilerType TypeSystemClang::CreateTypedef( + lldb::opaque_compiler_type_t type, const char *typedef_name, + const CompilerDeclContext &compiler_decl_ctx, uint32_t payload) { if (type) { clang::ASTContext &clang_ast = getASTContext(); clang::QualType qual_type(GetQualType(type)); clang::DeclContext *decl_ctx = TypeSystemClang::DeclContextGetAsDeclContext(compiler_decl_ctx); - if (decl_ctx == nullptr) + if (!decl_ctx) decl_ctx = getASTContext().getTranslationUnitDecl(); - clang::TypedefDecl *decl = - clang::TypedefDecl::CreateDeserialized(clang_ast, 0); - decl->setDeclContext(decl_ctx); - decl->setDeclName(&clang_ast.Idents.get(typedef_name)); - decl->setTypeSourceInfo(clang_ast.getTrivialTypeSourceInfo(qual_type)); + clang::TypedefDecl *decl = clang::TypedefDecl::Create( + clang_ast, decl_ctx, clang::SourceLocation(), clang::SourceLocation(), + &clang_ast.Idents.get(typedef_name), + clang_ast.getTrivialTypeSourceInfo(qual_type)); + SetOwningModule(decl, TypePayloadClang(payload).GetOwningModule()); clang::TagDecl *tdecl = nullptr; if (!qual_type.isNull()) { @@ -6933,6 +7048,7 @@ clang::FieldDecl *TypeSystemClang::AddFieldToRecordType( field->setType(ClangUtil::GetQualType(field_clang_type)); if (bit_width) field->setBitWidth(bit_width); + SetMemberOwningModule(field, record_decl); if (name.empty()) { // Determine whether this field corresponds to an anonymous struct or @@ -6976,6 +7092,7 @@ clang::FieldDecl *TypeSystemClang::AddFieldToRecordType( ivar->setBitWidth(bit_width); ivar->setSynthesize(is_synthesized); field = ivar; + SetMemberOwningModule(field, class_interface_decl); if (field) { class_interface_decl->addDecl(field); @@ -7039,6 +7156,7 @@ void TypeSystemClang::BuildIndirectFields(const CompilerType &type) { ast->getASTContext(), record_decl, clang::SourceLocation(), nested_field_decl->getIdentifier(), nested_field_decl->getType(), {chain, 2}); + SetMemberOwningModule(indirect_field, record_decl); indirect_field->setImplicit(); @@ -7069,6 +7187,7 @@ void TypeSystemClang::BuildIndirectFields(const CompilerType &type) { nested_indirect_field_decl->getIdentifier(), nested_indirect_field_decl->getType(), {chain, nested_chain_size + 1}); + SetMemberOwningModule(indirect_field, record_decl); indirect_field->setImplicit(); @@ -7135,6 +7254,7 @@ clang::VarDecl *TypeSystemClang::AddVariableToRecordType( var_decl->setDeclName(ident); var_decl->setType(ClangUtil::GetQualType(var_type)); var_decl->setStorageClass(clang::SC_Static); + SetMemberOwningModule(var_decl, record_decl); if (!var_decl) return nullptr; @@ -7272,6 +7392,7 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType( cxx_method_decl->setConstexprKind(CSK_unspecified); } } + SetMemberOwningModule(cxx_method_decl, cxx_record_decl); clang::AccessSpecifier access_specifier = TypeSystemClang::ConvertAccessTypeToAccessSpecifier(access); @@ -7448,6 +7569,7 @@ bool TypeSystemClang::AddObjCClassProperty( ? ivar_decl->getType() : ClangUtil::GetQualType(property_clang_type), prop_type_source); + SetMemberOwningModule(property_decl, class_interface_decl); if (!property_decl) return false; @@ -7539,6 +7661,7 @@ bool TypeSystemClang::AddObjCClassProperty( getter->setDefined(isDefined); getter->setDeclImplementation(impControl); getter->setRelatedResultType(HasRelatedResultType); + SetMemberOwningModule(getter, class_interface_decl); if (getter) { if (metadata) @@ -7580,6 +7703,7 @@ bool TypeSystemClang::AddObjCClassProperty( setter->setDefined(isDefined); setter->setDeclImplementation(impControl); setter->setRelatedResultType(HasRelatedResultType); + SetMemberOwningModule(setter, class_interface_decl); if (setter) { if (metadata) @@ -7709,6 +7833,7 @@ clang::ObjCMethodDecl *TypeSystemClang::AddMethodToObjCObjectType( objc_method_decl->setDefined(isDefined); objc_method_decl->setDeclImplementation(impControl); objc_method_decl->setRelatedResultType(HasRelatedResultType); + SetMemberOwningModule(objc_method_decl, class_interface_decl); if (objc_method_decl == nullptr) return nullptr; @@ -7947,6 +8072,7 @@ clang::EnumConstantDecl *TypeSystemClang::AddEnumerationValueToEnumerationType( enumerator_decl->setDeclName(&getASTContext().Idents.get(name)); enumerator_decl->setType(clang::QualType(enutype, 0)); enumerator_decl->setInitVal(value); + SetMemberOwningModule(enumerator_decl, enutype->getDecl()); if (!enumerator_decl) return nullptr; @@ -8851,14 +8977,14 @@ void TypeSystemClang::DumpTypeName(const CompilerType &type) { } clang::ClassTemplateDecl *TypeSystemClang::ParseClassTemplateDecl( - clang::DeclContext *decl_ctx, lldb::AccessType access_type, - const char *parent_name, int tag_decl_kind, + clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, + lldb::AccessType access_type, const char *parent_name, int tag_decl_kind, const TypeSystemClang::TemplateParameterInfos &template_param_infos) { if (template_param_infos.IsValid()) { std::string template_basename(parent_name); template_basename.erase(template_basename.find('<')); - return CreateClassTemplateDecl(decl_ctx, access_type, + return CreateClassTemplateDecl(decl_ctx, owning_module, access_type, template_basename.c_str(), tag_decl_kind, template_param_infos); } diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index 0bfdd5bd53106..4eab2bea18c05 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -49,13 +49,30 @@ namespace lldb_private { class Declaration; +/// A Clang module ID. +class OptionalClangModuleID { + unsigned m_id = 0; + +public: + OptionalClangModuleID() = default; + explicit OptionalClangModuleID(unsigned id) : m_id(id) {} + bool HasValue() const { return m_id != 0; } + unsigned GetValue() const { return m_id; } +}; + /// The implementation of lldb::Type's m_payload field for TypeSystemClang. class TypePayloadClang { - /// Layout: bit 31 ... IsCompleteObjCClass. + /// The Layout is as follows: + /// \verbatim + /// bit 0..30 ... Owning Module ID. + /// bit 31 ...... IsCompleteObjCClass. + /// \endverbatim Type::Payload m_payload = 0; + public: TypePayloadClang() = default; - explicit TypePayloadClang(bool is_complete_objc_class); + explicit TypePayloadClang(OptionalClangModuleID owning_module, + bool is_complete_objc_class = false); explicit TypePayloadClang(uint32_t opaque_payload) : m_payload(opaque_payload) {} operator Type::Payload() { return m_payload; } @@ -65,6 +82,11 @@ class TypePayloadClang { m_payload = is_complete_objc_class ? Flags(m_payload).Set(ObjCClassBit) : Flags(m_payload).Clear(ObjCClassBit); } + OptionalClangModuleID GetOwningModule() { + return OptionalClangModuleID(Flags(m_payload).Clear(ObjCClassBit)); + } + void SetOwningModule(OptionalClangModuleID id); + /// \} }; /// A TypeSystem implementation based on Clang. @@ -281,7 +303,14 @@ class TypeSystemClang : public TypeSystem { static uint32_t GetNumBaseClasses(const clang::CXXRecordDecl *cxx_record_decl, bool omit_empty_base_classes); + /// Synthesize a clang::Module and return its ID or a default-constructed ID. + OptionalClangModuleID GetOrCreateClangModule(llvm::StringRef name, + OptionalClangModuleID parent, + bool is_framework = false, + bool is_explicit = false); + CompilerType CreateRecordType(clang::DeclContext *decl_ctx, + OptionalClangModuleID owning_module, lldb::AccessType access_type, llvm::StringRef name, int kind, lldb::LanguageType language, @@ -307,6 +336,7 @@ class TypeSystemClang : public TypeSystem { clang::FunctionTemplateDecl * CreateFunctionTemplateDecl(clang::DeclContext *decl_ctx, + OptionalClangModuleID owning_module, clang::FunctionDecl *func_decl, const char *name, const TemplateParameterInfos &infos); @@ -316,6 +346,7 @@ class TypeSystemClang : public TypeSystem { clang::ClassTemplateDecl * CreateClassTemplateDecl(clang::DeclContext *decl_ctx, + OptionalClangModuleID owning_module, lldb::AccessType access_type, const char *class_name, int kind, const TemplateParameterInfos &infos); @@ -323,7 +354,7 @@ class TypeSystemClang : public TypeSystem { CreateTemplateTemplateParmDecl(const char *template_name); clang::ClassTemplateSpecializationDecl *CreateClassTemplateSpecializationDecl( - clang::DeclContext *decl_ctx, + clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, clang::ClassTemplateDecl *class_template_decl, int kind, const TemplateParameterInfos &infos); @@ -343,8 +374,9 @@ class TypeSystemClang : public TypeSystem { static bool RecordHasFields(const clang::RecordDecl *record_decl); CompilerType CreateObjCClass(llvm::StringRef name, - clang::DeclContext *decl_ctx, bool isForwardDecl, - bool isInternal, + clang::DeclContext *decl_ctx, + OptionalClangModuleID owning_module, + bool isForwardDecl, bool isInternal, ClangASTMetadata *metadata = nullptr); bool SetTagTypeKind(clang::QualType type, int kind) const; @@ -361,14 +393,16 @@ class TypeSystemClang : public TypeSystem { clang::NamespaceDecl * GetUniqueNamespaceDeclaration(const char *name, clang::DeclContext *decl_ctx, + OptionalClangModuleID owning_module, bool is_inline = false); // Function Types clang::FunctionDecl * - CreateFunctionDeclaration(clang::DeclContext *decl_ctx, const char *name, - const CompilerType &function_Type, int storage, - bool is_inline); + CreateFunctionDeclaration(clang::DeclContext *decl_ctx, + OptionalClangModuleID owning_module, + const char *name, const CompilerType &function_Type, + int storage, bool is_inline); CompilerType CreateFunctionType(const CompilerType &result_type, const CompilerType *args, unsigned num_args, @@ -382,11 +416,11 @@ class TypeSystemClang : public TypeSystem { type_quals, clang::CC_C); } - clang::ParmVarDecl *CreateParameterDeclaration(clang::DeclContext *decl_ctx, - const char *name, - const CompilerType ¶m_type, - int storage, - bool add_decl=false); + clang::ParmVarDecl * + CreateParameterDeclaration(clang::DeclContext *decl_ctx, + OptionalClangModuleID owning_module, + const char *name, const CompilerType ¶m_type, + int storage, bool add_decl = false); void SetFunctionParameters(clang::FunctionDecl *function_decl, clang::ParmVarDecl **params, unsigned num_params); @@ -401,6 +435,7 @@ class TypeSystemClang : public TypeSystem { // Enumeration Types CompilerType CreateEnumerationType(const char *name, clang::DeclContext *decl_ctx, + OptionalClangModuleID owning_module, const Declaration &decl, const CompilerType &integer_qual_type, bool is_scoped); @@ -457,6 +492,10 @@ class TypeSystemClang : public TypeSystem { /// TypeSystemClang. CompilerDeclContext CreateDeclContext(clang::DeclContext *ctx); + /// Set the owning module for \p decl. + static void SetOwningModule(clang::Decl *decl, + OptionalClangModuleID owning_module); + std::vector DeclContextFindDeclByName(void *opaque_decl_ctx, ConstString name, const bool ignore_using_decls) override; @@ -619,11 +658,13 @@ class TypeSystemClang : public TypeSystem { // Creating related types - // Using the current type, create a new typedef to that type using - // "typedef_name" as the name and "decl_ctx" as the decl context. + /// Using the current type, create a new typedef to that type using + /// "typedef_name" as the name and "decl_ctx" as the decl context. + /// \param payload is an opaque TypePayloadClang. static CompilerType CreateTypedefType(const CompilerType &type, const char *typedef_name, - const CompilerDeclContext &compiler_decl_ctx); + const CompilerDeclContext &compiler_decl_ctx, + uint32_t opaque_payload); CompilerType GetArrayElementType(lldb::opaque_compiler_type_t type, uint64_t *stride) override; @@ -674,7 +715,8 @@ class TypeSystemClang : public TypeSystem { CompilerType CreateTypedef(lldb::opaque_compiler_type_t type, const char *name, - const CompilerDeclContext &decl_ctx) override; + const CompilerDeclContext &decl_ctx, + uint32_t opaque_payload) override; // If the current object represents a typedef type, get the underlying type CompilerType GetTypedefedType(lldb::opaque_compiler_type_t type) override; @@ -930,20 +972,24 @@ class TypeSystemClang : public TypeSystem { GetAsObjCInterfaceDecl(const CompilerType &type); clang::ClassTemplateDecl *ParseClassTemplateDecl( - clang::DeclContext *decl_ctx, lldb::AccessType access_type, - const char *parent_name, int tag_decl_kind, + clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, + lldb::AccessType access_type, const char *parent_name, int tag_decl_kind, const TypeSystemClang::TemplateParameterInfos &template_param_infos); - clang::BlockDecl *CreateBlockDeclaration(clang::DeclContext *ctx); + clang::BlockDecl *CreateBlockDeclaration(clang::DeclContext *ctx, + OptionalClangModuleID owning_module); clang::UsingDirectiveDecl * CreateUsingDirectiveDeclaration(clang::DeclContext *decl_ctx, + OptionalClangModuleID owning_module, clang::NamespaceDecl *ns_decl); clang::UsingDecl *CreateUsingDeclaration(clang::DeclContext *current_decl_ctx, + OptionalClangModuleID owning_module, clang::NamedDecl *target); clang::VarDecl *CreateVariableDeclaration(clang::DeclContext *decl_context, + OptionalClangModuleID owning_module, const char *name, clang::QualType type); @@ -966,6 +1012,13 @@ class TypeSystemClang : public TypeSystem { clang::DeclarationName GetDeclarationName(const char *name, const CompilerType &function_clang_type); + clang::LangOptions *GetLangOpts() const { + return m_language_options_up.get(); + } + clang::SourceManager *GetSourceMgr() const { + return m_source_manager_up.get(); + } + private: const clang::ClassTemplateSpecializationDecl * GetAsTemplateSpecialization(lldb::opaque_compiler_type_t type); @@ -983,6 +1036,8 @@ class TypeSystemClang : public TypeSystem { std::unique_ptr m_identifier_table_up; std::unique_ptr m_selector_table_up; std::unique_ptr m_builtins_up; + std::unique_ptr m_header_search_up; + std::unique_ptr m_module_map_up; std::unique_ptr m_dwarf_ast_parser_up; std::unique_ptr m_pdb_ast_parser_up; std::unique_ptr m_mangle_ctx_up; diff --git a/lldb/source/Symbol/CompilerType.cpp b/lldb/source/Symbol/CompilerType.cpp index 0d56e86410585..79fadea36f66b 100644 --- a/lldb/source/Symbol/CompilerType.cpp +++ b/lldb/source/Symbol/CompilerType.cpp @@ -452,11 +452,11 @@ CompilerType CompilerType::AddRestrictModifier() const { return CompilerType(); } -CompilerType -CompilerType::CreateTypedef(const char *name, - const CompilerDeclContext &decl_ctx) const { +CompilerType CompilerType::CreateTypedef(const char *name, + const CompilerDeclContext &decl_ctx, + uint32_t payload) const { if (IsValid()) - return m_type_system->CreateTypedef(m_type, name, decl_ctx); + return m_type_system->CreateTypedef(m_type, name, decl_ctx, payload); else return CompilerType(); } diff --git a/lldb/source/Symbol/Type.cpp b/lldb/source/Symbol/Type.cpp index b3dbbfba4a7f8..45ce9c67092ae 100644 --- a/lldb/source/Symbol/Type.cpp +++ b/lldb/source/Symbol/Type.cpp @@ -505,7 +505,7 @@ bool Type::ResolveClangType(ResolveState compiler_type_resolve_state) { case eEncodingIsTypedefUID: m_compiler_type = encoding_type->GetForwardCompilerType().CreateTypedef( m_name.AsCString("__lldb_invalid_typedef_name"), - GetSymbolFile()->GetDeclContextContainingUID(GetID())); + GetSymbolFile()->GetDeclContextContainingUID(GetID()), m_payload); m_name.Clear(); break; @@ -563,7 +563,7 @@ bool Type::ResolveClangType(ResolveState compiler_type_resolve_state) { case eEncodingIsTypedefUID: m_compiler_type = void_compiler_type.CreateTypedef( m_name.AsCString("__lldb_invalid_typedef_name"), - GetSymbolFile()->GetDeclContextContainingUID(GetID())); + GetSymbolFile()->GetDeclContextContainingUID(GetID()), m_payload); break; case eEncodingIsPointerUID: diff --git a/lldb/source/Symbol/TypeSystem.cpp b/lldb/source/Symbol/TypeSystem.cpp index 049c42f1c785d..4b8fc9b9b3e8d 100644 --- a/lldb/source/Symbol/TypeSystem.cpp +++ b/lldb/source/Symbol/TypeSystem.cpp @@ -113,7 +113,8 @@ TypeSystem::AddRestrictModifier(lldb::opaque_compiler_type_t type) { CompilerType TypeSystem::CreateTypedef(lldb::opaque_compiler_type_t type, const char *name, - const CompilerDeclContext &decl_ctx) { + const CompilerDeclContext &decl_ctx, + uint32_t opaque_payload) { return CompilerType(); } diff --git a/lldb/test/Shell/SymbolFile/DWARF/Inputs/ModuleOwnership/A.h b/lldb/test/Shell/SymbolFile/DWARF/Inputs/ModuleOwnership/A.h new file mode 100644 index 0000000000000..4b223cafdcbaf --- /dev/null +++ b/lldb/test/Shell/SymbolFile/DWARF/Inputs/ModuleOwnership/A.h @@ -0,0 +1,29 @@ +#include "B.h" // -*- ObjC -*- + +typedef int Typedef; + +struct TopLevelStruct { + int a; +}; + +typedef struct Struct_s { + int a; +} Struct; + +struct Nested { + StructB fromb; +}; + +typedef enum Enum_e { a = 0 } Enum; + +@interface SomeClass { +} +@end + +template struct Template { T field; }; +extern template struct Template; + +namespace Namespace { +template struct InNamespace { T field; }; +extern template struct InNamespace; +} diff --git a/lldb/test/Shell/SymbolFile/DWARF/Inputs/ModuleOwnership/B.h b/lldb/test/Shell/SymbolFile/DWARF/Inputs/ModuleOwnership/B.h new file mode 100644 index 0000000000000..23d8347a23227 --- /dev/null +++ b/lldb/test/Shell/SymbolFile/DWARF/Inputs/ModuleOwnership/B.h @@ -0,0 +1,8 @@ +typedef struct { + int b; +} StructB; + +namespace Namespace { +template struct AlsoInNamespace { T field; }; +extern template struct AlsoInNamespace; +} // namespace Namespace diff --git a/lldb/test/Shell/SymbolFile/DWARF/Inputs/ModuleOwnership/module.modulemap b/lldb/test/Shell/SymbolFile/DWARF/Inputs/ModuleOwnership/module.modulemap new file mode 100644 index 0000000000000..b9940a8f53bfa --- /dev/null +++ b/lldb/test/Shell/SymbolFile/DWARF/Inputs/ModuleOwnership/module.modulemap @@ -0,0 +1,6 @@ +module A { + header "A.h" + module B { + header "B.h" + } +} diff --git a/lldb/test/Shell/SymbolFile/DWARF/lit.local.cfg b/lldb/test/Shell/SymbolFile/DWARF/lit.local.cfg index 8c4600c6922b4..84376e61665b9 100644 --- a/lldb/test/Shell/SymbolFile/DWARF/lit.local.cfg +++ b/lldb/test/Shell/SymbolFile/DWARF/lit.local.cfg @@ -1 +1 @@ -config.suffixes = ['.cpp', '.m', '.s', '.test', '.ll'] +config.suffixes = ['.cpp', '.m', '.mm', '.s', '.test', '.ll'] diff --git a/lldb/test/Shell/SymbolFile/DWARF/module-ownership.mm b/lldb/test/Shell/SymbolFile/DWARF/module-ownership.mm new file mode 100644 index 0000000000000..6a876d1ea5786 --- /dev/null +++ b/lldb/test/Shell/SymbolFile/DWARF/module-ownership.mm @@ -0,0 +1,42 @@ +// RUN: %clang --target=x86_64-apple-macosx -g -gmodules \ +// RUN: -fmodules -fmodules-cache-path=%t.cache \ +// RUN: -c -o %t.o %s -I%S/Inputs +// RUN: lldb-test symbols -dump-clang-ast %t.o | FileCheck %s +// Verify that the owning module information from DWARF is preserved in the AST. + +@import A; + +Typedef t1; +// CHECK-DAG: TypedefDecl {{.*}} imported in A Typedef + +TopLevelStruct s1; +// CHECK-DAG: CXXRecordDecl {{.*}} imported in A struct TopLevelStruct +// CHECK-DAG: -FieldDecl {{.*}} in A a 'int' + +Struct s2; +// CHECK-DAG: CXXRecordDecl {{.*}} imported in A struct + +StructB s3; +// CHECK-DAG: CXXRecordDecl {{.*}} imported in A.B struct +// CHECK-DAG: -FieldDecl {{.*}} in A.B b 'int' + +Nested s4; +// CHECK-DAG: CXXRecordDecl {{.*}} imported in A struct Nested +// CHECK-DAG: -FieldDecl {{.*}} in A fromb 'StructB' + +Enum e1; +// CHECK-DAG: EnumDecl {{.*}} imported in A {{.*}} Enum_e +// FIXME: -EnumConstantDecl {{.*}} imported in A a + +SomeClass *obj1; +// CHECK-DAG: ObjCInterfaceDecl {{.*}} imported in A {{.*}} SomeClass + +// Template specializations are not yet supported, so they lack the ownership info: +Template t2; +// CHECK-DAG: ClassTemplateSpecializationDecl {{.*}} struct Template + +Namespace::InNamespace t3; +// CHECK-DAG: ClassTemplateSpecializationDecl {{.*}} struct InNamespace + +Namespace::AlsoInNamespace t4; +// CHECK-DAG: ClassTemplateSpecializationDecl {{.*}} struct AlsoInNamespace diff --git a/lldb/unittests/Symbol/TestTypeSystemClang.cpp b/lldb/unittests/Symbol/TestTypeSystemClang.cpp index 8b716be955e80..3aef16788645d 100644 --- a/lldb/unittests/Symbol/TestTypeSystemClang.cpp +++ b/lldb/unittests/Symbol/TestTypeSystemClang.cpp @@ -14,6 +14,7 @@ #include "lldb/Host/HostInfo.h" #include "lldb/Symbol/Declaration.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" #include "clang/AST/ExprCXX.h" #include "gtest/gtest.h" @@ -226,8 +227,8 @@ TEST_F(TestTypeSystemClang, TestIsClangType) { TypeSystemClang::GetOpaqueCompilerType(&context, lldb::eBasicTypeBool); CompilerType bool_type(m_ast.get(), bool_ctype); CompilerType record_type = m_ast->CreateRecordType( - nullptr, lldb::eAccessPublic, "FooRecord", clang::TTK_Struct, - lldb::eLanguageTypeC_plus_plus, nullptr); + nullptr, OptionalClangModuleID(100), lldb::eAccessPublic, "FooRecord", + clang::TTK_Struct, lldb::eLanguageTypeC_plus_plus, nullptr); // Clang builtin type and record type should pass EXPECT_TRUE(ClangUtil::IsClangType(bool_type)); EXPECT_TRUE(ClangUtil::IsClangType(record_type)); @@ -238,8 +239,8 @@ TEST_F(TestTypeSystemClang, TestIsClangType) { TEST_F(TestTypeSystemClang, TestRemoveFastQualifiers) { CompilerType record_type = m_ast->CreateRecordType( - nullptr, lldb::eAccessPublic, "FooRecord", clang::TTK_Struct, - lldb::eLanguageTypeC_plus_plus, nullptr); + nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "FooRecord", + clang::TTK_Struct, lldb::eLanguageTypeC_plus_plus, nullptr); QualType qt; qt = ClangUtil::GetQualType(record_type); @@ -310,8 +311,8 @@ TEST_F(TestTypeSystemClang, TestRecordHasFields) { // Test that a record with no fields returns false CompilerType empty_base = m_ast->CreateRecordType( - nullptr, lldb::eAccessPublic, "EmptyBase", clang::TTK_Struct, - lldb::eLanguageTypeC_plus_plus, nullptr); + nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "EmptyBase", + clang::TTK_Struct, lldb::eLanguageTypeC_plus_plus, nullptr); TypeSystemClang::StartTagDeclarationDefinition(empty_base); TypeSystemClang::CompleteTagDeclarationDefinition(empty_base); @@ -321,8 +322,8 @@ TEST_F(TestTypeSystemClang, TestRecordHasFields) { // Test that a record with direct fields returns true CompilerType non_empty_base = m_ast->CreateRecordType( - nullptr, lldb::eAccessPublic, "NonEmptyBase", clang::TTK_Struct, - lldb::eLanguageTypeC_plus_plus, nullptr); + nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "NonEmptyBase", + clang::TTK_Struct, lldb::eLanguageTypeC_plus_plus, nullptr); TypeSystemClang::StartTagDeclarationDefinition(non_empty_base); FieldDecl *non_empty_base_field_decl = m_ast->AddFieldToRecordType( non_empty_base, "MyField", int_type, eAccessPublic, 0); @@ -337,8 +338,8 @@ TEST_F(TestTypeSystemClang, TestRecordHasFields) { // Test that a record with no direct fields, but fields in a base returns true CompilerType empty_derived = m_ast->CreateRecordType( - nullptr, lldb::eAccessPublic, "EmptyDerived", clang::TTK_Struct, - lldb::eLanguageTypeC_plus_plus, nullptr); + nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "EmptyDerived", + clang::TTK_Struct, lldb::eLanguageTypeC_plus_plus, nullptr); TypeSystemClang::StartTagDeclarationDefinition(empty_derived); std::unique_ptr non_empty_base_spec = m_ast->CreateBaseClassSpecifier(non_empty_base.GetOpaqueQualType(), @@ -360,8 +361,8 @@ TEST_F(TestTypeSystemClang, TestRecordHasFields) { // Test that a record with no direct fields, but fields in a virtual base // returns true CompilerType empty_derived2 = m_ast->CreateRecordType( - nullptr, lldb::eAccessPublic, "EmptyDerived2", clang::TTK_Struct, - lldb::eLanguageTypeC_plus_plus, nullptr); + nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "EmptyDerived2", + clang::TTK_Struct, lldb::eLanguageTypeC_plus_plus, nullptr); TypeSystemClang::StartTagDeclarationDefinition(empty_derived2); std::unique_ptr non_empty_vbase_spec = m_ast->CreateBaseClassSpecifier(non_empty_base.GetOpaqueQualType(), @@ -392,13 +393,15 @@ TEST_F(TestTypeSystemClang, TemplateArguments) { // template struct foo; ClassTemplateDecl *decl = m_ast->CreateClassTemplateDecl( - m_ast->GetTranslationUnitDecl(), eAccessPublic, "foo", TTK_Struct, infos); + m_ast->GetTranslationUnitDecl(), OptionalClangModuleID(), eAccessPublic, + "foo", TTK_Struct, infos); ASSERT_NE(decl, nullptr); // foo ClassTemplateSpecializationDecl *spec_decl = m_ast->CreateClassTemplateSpecializationDecl( - m_ast->GetTranslationUnitDecl(), decl, TTK_Struct, infos); + m_ast->GetTranslationUnitDecl(), OptionalClangModuleID(), decl, + TTK_Struct, infos); ASSERT_NE(spec_decl, nullptr); CompilerType type = m_ast->CreateClassTemplateSpecializationType(spec_decl); ASSERT_TRUE(type); @@ -407,7 +410,8 @@ TEST_F(TestTypeSystemClang, TemplateArguments) { // typedef foo foo_def; CompilerType typedef_type = m_ast->CreateTypedefType( - type, "foo_def", m_ast->CreateDeclContext(m_ast->GetTranslationUnitDecl())); + type, "foo_def", + m_ast->CreateDeclContext(m_ast->GetTranslationUnitDecl()), 0); CompilerType auto_type( m_ast.get(), @@ -481,13 +485,14 @@ TEST_F(TestTypeSystemClang, TestFunctionTemplateConstruction) { // Prepare the declarations/types we need for the template. CompilerType clang_type = m_ast->CreateFunctionType(int_type, nullptr, 0U, false, 0U); - FunctionDecl *func = - m_ast->CreateFunctionDeclaration(TU, "foo", clang_type, 0, false); + FunctionDecl *func = m_ast->CreateFunctionDeclaration( + TU, OptionalClangModuleID(), "foo", clang_type, 0, false); TypeSystemClang::TemplateParameterInfos empty_params; // Create the actual function template. clang::FunctionTemplateDecl *func_template = - m_ast->CreateFunctionTemplateDecl(TU, func, "foo", empty_params); + m_ast->CreateFunctionTemplateDecl(TU, OptionalClangModuleID(), func, + "foo", empty_params); EXPECT_EQ(TU, func_template->getDeclContext()); EXPECT_EQ("foo", func_template->getName()); @@ -511,13 +516,14 @@ TEST_F(TestTypeSystemClang, TestFunctionTemplateInRecordConstruction) { // We create the FunctionDecl for the template in the TU DeclContext because: // 1. FunctionDecls can't be in a Record (only CXXMethodDecls can). // 2. It is mirroring the behavior of DWARFASTParserClang::ParseSubroutine. - FunctionDecl *func = - m_ast->CreateFunctionDeclaration(TU, "foo", clang_type, 0, false); + FunctionDecl *func = m_ast->CreateFunctionDeclaration( + TU, OptionalClangModuleID(), "foo", clang_type, 0, false); TypeSystemClang::TemplateParameterInfos empty_params; // Create the actual function template. clang::FunctionTemplateDecl *func_template = - m_ast->CreateFunctionTemplateDecl(record, func, "foo", empty_params); + m_ast->CreateFunctionTemplateDecl(record, OptionalClangModuleID(), func, + "foo", empty_params); EXPECT_EQ(record, func_template->getDeclContext()); EXPECT_EQ("foo", func_template->getName()); diff --git a/lldb/unittests/TestingSupport/Symbol/ClangTestUtils.h b/lldb/unittests/TestingSupport/Symbol/ClangTestUtils.h index 896996512fcf7..1fc262746278b 100644 --- a/lldb/unittests/TestingSupport/Symbol/ClangTestUtils.h +++ b/lldb/unittests/TestingSupport/Symbol/ClangTestUtils.h @@ -27,6 +27,7 @@ inline std::unique_ptr createAST() { inline CompilerType createRecord(TypeSystemClang &ast, llvm::StringRef name) { return ast.CreateRecordType(ast.getASTContext().getTranslationUnitDecl(), + OptionalClangModuleID(), lldb::AccessType::eAccessPublic, name, 0, lldb::LanguageType::eLanguageTypeC); } From 11d62fc66341a02040af155be64c976976e72fc1 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Fri, 10 Apr 2020 10:34:08 -0700 Subject: [PATCH 227/286] Attempt to fix a compile error reported with older compilers and libstdc++ (cherry picked from commit f5be71b44500b18d636b1f540422dda4012ac192) --- lldb/source/Utility/XcodeSDK.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lldb/source/Utility/XcodeSDK.cpp b/lldb/source/Utility/XcodeSDK.cpp index f2403f10de553..7ad0090f85e2d 100644 --- a/lldb/source/Utility/XcodeSDK.cpp +++ b/lldb/source/Utility/XcodeSDK.cpp @@ -69,7 +69,8 @@ std::tuple XcodeSDK::Parse() const { llvm::StringRef input(m_name); XcodeSDK::Type sdk = ParseSDKName(input); llvm::VersionTuple version = ParseSDKVersion(input); - return {sdk, version}; + return std::make_tuple( + std::move(sdk), std::move(version)); } llvm::VersionTuple XcodeSDK::GetVersion() const { From 6deae69d73d3975e58d2d56410c971389f98273f Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Fri, 10 Apr 2020 16:27:11 -0700 Subject: [PATCH 228/286] Implement TypeSystemSwiftTypeRef::GetFunctionArgumentAtIndex() (NFC) --- lldb/include/lldb/Symbol/SwiftASTContext.h | 13 ++++ lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp | 72 ++++++++++++++++--- .../Symbol/TestTypeSystemSwiftTypeRef.cpp | 17 ++++- 3 files changed, 89 insertions(+), 13 deletions(-) diff --git a/lldb/include/lldb/Symbol/SwiftASTContext.h b/lldb/include/lldb/Symbol/SwiftASTContext.h index 9a673da795b7f..dc11cac892ff5 100644 --- a/lldb/include/lldb/Symbol/SwiftASTContext.h +++ b/lldb/include/lldb/Symbol/SwiftASTContext.h @@ -48,6 +48,11 @@ class ModuleDecl; class SourceFile; struct PrintOptions; class MemoryBufferSerializedModuleLoader; +namespace Demangle { +class Demangler; +class Node; +using NodePointer = Node *; +} // namespace Demangle namespace irgen { class FixedTypeInfo; class TypeInfo; @@ -406,9 +411,17 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift { bool print_extensions_if_available) override; private: + /// Helper that creates an AST type from \p type. void *ReconstructType(void *type); + /// Cast \p opaque_type as a mangled name. const char *AsMangledName(void *opaque_type); + /// Wrap \p node as \p Global(TypeMangling(node)), remangle the type + /// and create a CompilerType from it. + CompilerType RemangleAsType(swift::Demangle::Demangler &Dem, + swift::Demangle::NodePointer node); + + /// The sibling SwiftASTContext. SwiftASTContext *m_swift_ast_context = nullptr; }; diff --git a/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp index b06458a7cab7e..6d7310197c33f 100644 --- a/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp +++ b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp @@ -321,6 +321,22 @@ bool TypeSystemSwiftTypeRef::Verify(lldb::opaque_compiler_type_t type) { return result; \ } while (0) +CompilerType +TypeSystemSwiftTypeRef::RemangleAsType(swift::Demangle::Demangler &Dem, + swift::Demangle::NodePointer node) { + if (!node) + return {}; + assert(node->getKind() == Node::Kind::Type && "expected type node"); + + using namespace swift::Demangle; + auto global = Dem.createNode(Node::Kind::Global); + auto type_mangling = Dem.createNode(Node::Kind::TypeMangling); + global->addChild(type_mangling, Dem); + type_mangling->addChild(node, Dem); + ConstString mangled_element(mangleNode(global)); + return GetTypeFromMangledTypename(mangled_element); +} + bool TypeSystemSwiftTypeRef::IsArrayType(void *type, CompilerType *element_type, uint64_t *size, bool *is_incomplete) { auto impl = [&]() { @@ -363,15 +379,9 @@ bool TypeSystemSwiftTypeRef::IsArrayType(void *type, CompilerType *element_type, return false; elem_node = elem_node->getFirstChild(); - if (element_type) { - // Remangle the element type. - auto global = Dem.createNode(Node::Kind::Global); - auto type_mangling = Dem.createNode(Node::Kind::TypeMangling); - global->addChild(type_mangling, Dem); - type_mangling->addChild(elem_node, Dem); - ConstString mangled_element(mangleNode(global)); - *element_type = GetTypeFromMangledTypename(mangled_element); - } + if (element_type) + *element_type = RemangleAsType(Dem, elem_node); + if (is_incomplete) *is_incomplete = true; if (size) @@ -460,8 +470,48 @@ size_t TypeSystemSwiftTypeRef::GetNumberOfFunctionArguments(void *type) { CompilerType TypeSystemSwiftTypeRef::GetFunctionArgumentAtIndex(void *type, const size_t index) { - return m_swift_ast_context->GetFunctionArgumentAtIndex(ReconstructType(type), - index); + auto impl = [&]() -> CompilerType { + using namespace swift::Demangle; + Demangler Dem; + NodePointer node = + GetCanonicalDemangleTree(GetModule(), Dem, AsMangledName(type)); + if (!node) + return {}; + node = GetFunctionTypeNode(node); + if (!node) + return {}; + unsigned num_args = 0; + for (NodePointer child : *node) { + if (child->getKind() == Node::Kind::ImplParameter) { + if (num_args == index) + for (NodePointer type : *child) + if (type->getKind() == Node::Kind::Type) + return RemangleAsType(Dem, type); + ++num_args; + } + if (child->getKind() == Node::Kind::ArgumentTuple && + child->getNumChildren() == 1) { + NodePointer node = child->getFirstChild(); + if (node->getNumChildren() != 1 || + node->getKind() != Node::Kind::Type) + break; + node = node->getFirstChild(); + if (node->getKind() == Node::Kind::Tuple) + for (NodePointer child : *node) { + if (child->getNumChildren() == 1 && + child->getKind() == Node::Kind::TupleElement) { + NodePointer type = child->getFirstChild(); + if (num_args == index && type->getKind() == Node::Kind::Type) + return RemangleAsType(Dem, type); + ++num_args; + } + } + } + } + return {}; + }; + VALIDATE_AND_RETURN(impl, m_swift_ast_context->GetFunctionArgumentAtIndex( + ReconstructType(type), index)); } bool TypeSystemSwiftTypeRef::IsFunctionPointerType(void *type) { return m_swift_ast_context->IsFunctionPointerType(ReconstructType(type)); diff --git a/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp b/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp index 7cb778533a6a5..7bd52f9db6682 100644 --- a/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp +++ b/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp @@ -92,6 +92,15 @@ TEST_F(TestTypeSystemSwiftTypeRef, Function) { using namespace swift::Demangle; Demangler dem; NodeBuilder b(dem); + NodePointer int_node = + b.Node(Node::Kind::Global, b.Node(Node::Kind::TypeMangling, + b.Node(Node::Kind::Type, b.IntType()))); + CompilerType int_type = GetCompilerType(b.Mangle(int_node)); + NodePointer void_node = + b.Node(Node::Kind::Global, + b.Node(Node::Kind::TypeMangling, + b.Node(Node::Kind::Type, b.Node(Node::Kind::Tuple)))); + CompilerType void_type = GetCompilerType(b.Mangle(void_node)); { NodePointer n = b.Node( Node::Kind::Global, @@ -136,10 +145,12 @@ TEST_F(TestTypeSystemSwiftTypeRef, Function) { b.IntType()), b.Node(Node::Kind::ImplParameter, b.Node(Node::Kind::ImplConvention, "@unowned"), - b.IntType()))))); + b.Node(Node::Kind::Tuple)))))); CompilerType impl_two_args = GetCompilerType(b.Mangle(n)); ASSERT_TRUE(impl_two_args.IsFunctionType(nullptr)); ASSERT_EQ(impl_two_args.GetNumberOfFunctionArguments(), 2); + ASSERT_EQ(impl_two_args.GetFunctionArgumentAtIndex(0), int_type); + ASSERT_EQ(impl_two_args.GetFunctionArgumentAtIndex(1), void_type); } { NodePointer n = b.Node( @@ -154,12 +165,14 @@ TEST_F(TestTypeSystemSwiftTypeRef, Function) { b.Node(Node::Kind::TupleElement, b.IntType()), b.Node(Node::Kind::TupleElement, - b.IntType())))), + b.Node(Node::Kind::Tuple))))), b.Node(Node::Kind::ReturnType, b.Node(Node::Kind::Type, b.Node(Node::Kind::Tuple))))))); CompilerType two_args = GetCompilerType(b.Mangle(n)); ASSERT_TRUE(two_args.IsFunctionType(nullptr)); ASSERT_EQ(two_args.GetNumberOfFunctionArguments(), 2); + ASSERT_EQ(two_args.GetFunctionArgumentAtIndex(0), int_type); + ASSERT_EQ(two_args.GetFunctionArgumentAtIndex(1), void_type); } } From 129e448bf21fcec4072543026f27c8daeb0c9feb Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Fri, 13 Mar 2020 13:08:48 -0700 Subject: [PATCH 229/286] [Sema] Use the canonical type in function isVector This reapplies the following patch, which was reverted because it caused neon CodeGen tests to fail: https://reviews.llvm.org/rGa6150b48cea00ab31e9335cc73770327acc4cb3a I've added checks to detect half precision neon vectors and avoid promiting them to vectors of floats. See the discussion here: https://reviews.llvm.org/rG825235c140e7 Original commit message: This fixes an assertion in Sema::CreateBuiltinBinOp that fails when one of the vector operand's element type is a typedef of __fp16. rdar://problem/55983556 (cherry picked from commit 86bba6c6410c31e669b10f182c6d1a03f704555a) --- clang/lib/Sema/SemaExpr.cpp | 34 +++++++++++++++++++++++++--------- clang/test/CodeGen/fp16-ops.c | 13 +++++++++++++ 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index c9d9224d7e3ae..4898f279a44fb 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -8264,7 +8264,7 @@ Sema::CheckAssignmentConstraints(SourceLocation Loc, /// type ElementType. static bool isVector(QualType QT, QualType ElementType) { if (const VectorType *VT = QT->getAs()) - return VT->getElementType() == ElementType; + return VT->getElementType().getCanonicalType() == ElementType; return false; } @@ -12954,10 +12954,27 @@ CorrectDelayedTyposInBinOp(Sema &S, BinaryOperatorKind Opc, Expr *LHSExpr, /// Returns true if conversion between vectors of halfs and vectors of floats /// is needed. static bool needsConversionOfHalfVec(bool OpRequiresConversion, ASTContext &Ctx, - QualType SrcType) { - return OpRequiresConversion && !Ctx.getLangOpts().NativeHalfType && - !Ctx.getTargetInfo().useFP16ConversionIntrinsics() && - isVector(SrcType, Ctx.HalfTy); + Expr *E0, Expr *E1 = nullptr) { + if (!OpRequiresConversion || Ctx.getLangOpts().NativeHalfType || + Ctx.getTargetInfo().useFP16ConversionIntrinsics()) + return false; + + auto HasVectorOfHalfType = [&Ctx](Expr *E) { + QualType Ty = E->IgnoreImplicit()->getType(); + + // Don't promote half precision neon vectors like float16x4_t in arm_neon.h + // to vectors of floats. Although the element type of the vectors is __fp16, + // the vectors shouldn't be treated as storage-only types. See the + // discussion here: https://reviews.llvm.org/rG825235c140e7 + if (const VectorType *VT = Ty->getAs()) { + if (VT->getVectorKind() == VectorType::NeonVector) + return false; + return VT->getElementType().getCanonicalType() == Ctx.HalfTy; + } + return false; + }; + + return HasVectorOfHalfType(E0) && (!E1 || HasVectorOfHalfType(E1)); } /// CreateBuiltinBinOp - Creates a new built-in binary operation with @@ -13192,8 +13209,8 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, assert(isVector(RHS.get()->getType(), Context.HalfTy) == isVector(LHS.get()->getType(), Context.HalfTy) && "both sides are half vectors or neither sides are"); - ConvertHalfVec = needsConversionOfHalfVec(ConvertHalfVec, Context, - LHS.get()->getType()); + ConvertHalfVec = + needsConversionOfHalfVec(ConvertHalfVec, Context, LHS.get(), RHS.get()); // Check for array bounds violations for both sides of the BinaryOperator CheckArrayAccess(LHS.get()); @@ -13685,8 +13702,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, // float vector and truncating the result back to a half vector. For now, we // do this only when HalfArgsAndReturns is set (that is, when the target is // arm or arm64). - ConvertHalfVec = - needsConversionOfHalfVec(true, Context, Input.get()->getType()); + ConvertHalfVec = needsConversionOfHalfVec(true, Context, Input.get()); // If the operand is a half vector, promote it to a float vector. if (ConvertHalfVec) diff --git a/clang/test/CodeGen/fp16-ops.c b/clang/test/CodeGen/fp16-ops.c index f74552b85921c..6401dd125d2a5 100644 --- a/clang/test/CodeGen/fp16-ops.c +++ b/clang/test/CodeGen/fp16-ops.c @@ -11,6 +11,7 @@ // RUN: %clang_cc1 -emit-llvm -o - -x renderscript %s \ // RUN: | FileCheck %s --check-prefix=NATIVE-HALF typedef unsigned cond_t; +typedef __fp16 float16_t; volatile cond_t test; volatile int i0; @@ -541,3 +542,15 @@ void foo(void) { // NOTNATIVE: store volatile half [[TRUNC]], half* @h0 h0 = s0; } + +// CHECK-LABEL: define void @testTypeDef( +// CHECK: %[[CONV:.*]] = fpext <4 x half> %{{.*}} to <4 x float> +// CHECK: %[[CONV1:.*]] = fpext <4 x half> %{{.*}} to <4 x float> +// CHECK: %[[ADD:.*]] = fadd <4 x float> %[[CONV]], %[[CONV1]] +// CHECK: fptrunc <4 x float> %[[ADD]] to <4 x half> + +void testTypeDef() { + __fp16 t0 __attribute__((vector_size(8))); + float16_t t1 __attribute__((vector_size(8))); + t1 = t0 + t1; +} From de8b3c2750c692edbe693f3a8ba35976bd2463b2 Mon Sep 17 00:00:00 2001 From: Daniel Sanders Date: Fri, 3 Apr 2020 15:50:11 -0700 Subject: [PATCH 230/286] Add option to limit Debugify to locations (omitting variables) Summary: It can be helpful to test behaviour w.r.t locations without having DEBUG_VALUE around. In particular, because DEBUG_VALUE has the potential to change CodeGen behaviour (e.g. hasOneUse() vs hasOneNonDbgUse()) while locations generally don't. Reviewers: aprantl, bogner Subscribers: hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D77438 (cherry picked from commit 15f7bc78572543d75f56d1e7989801a2ac08c430) --- llvm/lib/Transforms/Utils/Debugify.cpp | 14 +++++++++++++ .../test/Transforms/Util/Debugify/loc-only.ll | 21 +++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 llvm/test/Transforms/Util/Debugify/loc-only.ll diff --git a/llvm/lib/Transforms/Utils/Debugify.cpp b/llvm/lib/Transforms/Utils/Debugify.cpp index b1274d948e882..a9cdf652b271b 100644 --- a/llvm/lib/Transforms/Utils/Debugify.cpp +++ b/llvm/lib/Transforms/Utils/Debugify.cpp @@ -30,6 +30,17 @@ namespace { cl::opt Quiet("debugify-quiet", cl::desc("Suppress verbose debugify output")); +enum class Level { + Locations, + LocationsAndVariables +}; +cl::opt DebugifyLevel( + "debugify-level", cl::desc("Kind of debug info to add"), + cl::values(clEnumValN(Level::Locations, "locations", "Locations only"), + clEnumValN(Level::LocationsAndVariables, "location+variables", + "Locations and Variables")), + cl::init(Level::LocationsAndVariables)); + raw_ostream &dbg() { return Quiet ? nulls() : errs(); } uint64_t getAllocSizeInBits(Module &M, Type *Ty) { @@ -100,6 +111,9 @@ bool applyDebugifyMetadata(Module &M, for (Instruction &I : BB) I.setDebugLoc(DILocation::get(Ctx, NextLine++, 1, SP)); + if (DebugifyLevel < Level::LocationsAndVariables) + continue; + // Inserting debug values into EH pads can break IR invariants. if (BB.isEHPad()) continue; diff --git a/llvm/test/Transforms/Util/Debugify/loc-only.ll b/llvm/test/Transforms/Util/Debugify/loc-only.ll new file mode 100644 index 0000000000000..250e72d28eb9f --- /dev/null +++ b/llvm/test/Transforms/Util/Debugify/loc-only.ll @@ -0,0 +1,21 @@ +; RUN: opt -debugify -S < %s | FileCheck --check-prefixes=ALL,VALUE %s +; RUN: opt -debugify -debugify-level=locations -S < %s | FileCheck --check-prefixes=ALL --implicit-check-not=dbg.value %s + +; ALL-LABEL: @test +define void @test() { + %add = add i32 1, 2 +; ALL-NEXT: %add = add i32 1, 2, !dbg [[L1:![0-9]+]] +; VALUE-NEXT: call void @llvm.dbg.value(metadata i32 %add, metadata [[add:![0-9]+]], metadata !DIExpression()), !dbg [[L1]] + %sub = sub i32 %add, 1 +; ALL-NEXT: %sub = sub i32 %add, 1, !dbg [[L2:![0-9]+]] +; VALUE-NEXT: call void @llvm.dbg.value(metadata i32 %sub, metadata [[sub:![0-9]+]], metadata !DIExpression()), !dbg [[L2]] +; ALL-NEXT: ret void, !dbg [[L3:![0-9]+]] + ret void +} + +; VALUE: [[add]] = !DILocalVariable +; VALUE: [[sub]] = !DILocalVariable + +; ALL: [[L1]] = !DILocation(line: 1, column: 1, scope: +; ALL: [[L2]] = !DILocation(line: 2, column: 1, scope: +; ALL: [[L3]] = !DILocation(line: 3, column: 1, scope: From df7160df7c762fd82491f7afc1bdbf71b5aacc80 Mon Sep 17 00:00:00 2001 From: Daniel Sanders Date: Fri, 3 Apr 2020 15:55:15 -0700 Subject: [PATCH 231/286] Allow MachineFunction to obtain non-const Function (to enable MIR-level debugify) Summary: To debugify MIR, we need to be able to create metadata and to do that, we need a non-const Module. However, MachineFunction only had a const reference to the Function preventing this. Reviewers: aprantl, bogner Subscribers: hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D77439 (cherry picked from commit 35b7b0851b1957d4f6f14f023eb3b4571cadc3d7) --- llvm/include/llvm/CodeGen/MachineFunction.h | 7 +++++-- llvm/include/llvm/CodeGen/MachineModuleInfo.h | 4 ++-- llvm/lib/CodeGen/MachineFunction.cpp | 3 +-- llvm/lib/CodeGen/MachineModuleInfo.cpp | 3 +-- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/llvm/include/llvm/CodeGen/MachineFunction.h b/llvm/include/llvm/CodeGen/MachineFunction.h index c396bf9cea573..972e9eddc5160 100644 --- a/llvm/include/llvm/CodeGen/MachineFunction.h +++ b/llvm/include/llvm/CodeGen/MachineFunction.h @@ -221,7 +221,7 @@ struct LandingPadInfo { }; class MachineFunction { - const Function &F; + Function &F; const LLVMTargetMachine &Target; const TargetSubtargetInfo *STI; MCContext &Ctx; @@ -414,7 +414,7 @@ class MachineFunction { using VariableDbgInfoMapTy = SmallVector; VariableDbgInfoMapTy VariableDbgInfos; - MachineFunction(const Function &F, const LLVMTargetMachine &Target, + MachineFunction(Function &F, const LLVMTargetMachine &Target, const TargetSubtargetInfo &STI, unsigned FunctionNum, MachineModuleInfo &MMI); MachineFunction(const MachineFunction &) = delete; @@ -452,6 +452,9 @@ class MachineFunction { /// Return the DataLayout attached to the Module associated to this MF. const DataLayout &getDataLayout() const; + /// Return the LLVM function that this machine code represents + Function &getFunction() { return F; } + /// Return the LLVM function that this machine code represents const Function &getFunction() const { return F; } diff --git a/llvm/include/llvm/CodeGen/MachineModuleInfo.h b/llvm/include/llvm/CodeGen/MachineModuleInfo.h index 6902dada2423a..4aa5f03960ce1 100644 --- a/llvm/include/llvm/CodeGen/MachineModuleInfo.h +++ b/llvm/include/llvm/CodeGen/MachineModuleInfo.h @@ -165,9 +165,9 @@ class MachineModuleInfo { /// Returns the MachineFunction constructed for the IR function \p F. /// Creates a new MachineFunction if none exists yet. - MachineFunction &getOrCreateMachineFunction(const Function &F); + MachineFunction &getOrCreateMachineFunction(Function &F); - /// \bried Returns the MachineFunction associated to IR function \p F if there + /// \brief Returns the MachineFunction associated to IR function \p F if there /// is one, otherwise nullptr. MachineFunction *getMachineFunction(const Function &F) const; diff --git a/llvm/lib/CodeGen/MachineFunction.cpp b/llvm/lib/CodeGen/MachineFunction.cpp index 1ef1939f9ba38..0db79d6ee8985 100644 --- a/llvm/lib/CodeGen/MachineFunction.cpp +++ b/llvm/lib/CodeGen/MachineFunction.cpp @@ -131,8 +131,7 @@ static inline unsigned getFnStackAlignment(const TargetSubtargetInfo *STI, return STI->getFrameLowering()->getStackAlignment(); } -MachineFunction::MachineFunction(const Function &F, - const LLVMTargetMachine &Target, +MachineFunction::MachineFunction(Function &F, const LLVMTargetMachine &Target, const TargetSubtargetInfo &STI, unsigned FunctionNum, MachineModuleInfo &mmi) : F(F), Target(Target), STI(&STI), Ctx(mmi.getContext()), MMI(mmi) { diff --git a/llvm/lib/CodeGen/MachineModuleInfo.cpp b/llvm/lib/CodeGen/MachineModuleInfo.cpp index 0094a923e0390..0fc9f2498a54c 100644 --- a/llvm/lib/CodeGen/MachineModuleInfo.cpp +++ b/llvm/lib/CodeGen/MachineModuleInfo.cpp @@ -279,8 +279,7 @@ MachineModuleInfo::getMachineFunction(const Function &F) const { return I != MachineFunctions.end() ? I->second.get() : nullptr; } -MachineFunction & -MachineModuleInfo::getOrCreateMachineFunction(const Function &F) { +MachineFunction &MachineModuleInfo::getOrCreateMachineFunction(Function &F) { // Shortcut for the common case where a sequence of MachineFunctionPasses // all query for the same Function. if (LastRequest == &F) From 8489015f3e9d297a12656184df1ca2ad4d7aa706 Mon Sep 17 00:00:00 2001 From: Daniel Sanders Date: Mon, 6 Apr 2020 10:57:21 -0700 Subject: [PATCH 232/286] Add way to omit debug-location from MIR output Summary: In lieu of a proper pass that strips debug info, add a way to omit debug-locations from the MIR output so that instructions with MMO's continue to match CHECK's when mir-debugify is used Reviewers: aprantl, bogner, vsk Subscribers: hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D77575 (cherry picked from commit f27cea721e5893c112edfe1136973ed77064580b) --- llvm/lib/CodeGen/MIRPrinter.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/llvm/lib/CodeGen/MIRPrinter.cpp b/llvm/lib/CodeGen/MIRPrinter.cpp index b06e34a809fca..2b81126e527d8 100644 --- a/llvm/lib/CodeGen/MIRPrinter.cpp +++ b/llvm/lib/CodeGen/MIRPrinter.cpp @@ -79,6 +79,9 @@ static cl::opt SimplifyMIR( "simplify-mir", cl::Hidden, cl::desc("Leave out unnecessary information when printing MIR")); +static cl::opt PrintLocations("mir-debug-loc", cl::Hidden, cl::init(true), + cl::desc("Print MIR debug-locations")); + namespace { /// This structure describes how to print out stack object references. @@ -792,11 +795,13 @@ void MIPrinter::print(const MachineInstr &MI) { NeedComma = true; } - if (const DebugLoc &DL = MI.getDebugLoc()) { - if (NeedComma) - OS << ','; - OS << " debug-location "; - DL->printAsOperand(OS, MST); + if (PrintLocations) { + if (const DebugLoc &DL = MI.getDebugLoc()) { + if (NeedComma) + OS << ','; + OS << " debug-location "; + DL->printAsOperand(OS, MST); + } } if (!MI.memoperands_empty()) { From 05493e9fa11ccab02257d2abe33a7de6ff1231a2 Mon Sep 17 00:00:00 2001 From: Jeremy Morse Date: Wed, 8 Apr 2020 12:24:13 +0100 Subject: [PATCH 233/286] [DebugInfo][NFC] Early-exit when analyzing for single-location variables This is a performance patch that hoists two conditions in DwarfDebug's validThroughout to avoid a linear-scan of all instructions in a block. We now exit early if validThrougout will never return true for the variable location. The first added clause filters for the two circumstances where validThroughout will return true. The second added clause should be identical to the one that's deleted from after the linear-scan. Differential Revision: https://reviews.llvm.org/D77639 (cherry picked from commit c77887e4d1beae537ebb43e75f119e9e3b4fbe9c) --- llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index 680b11ed8b77e..a5589d78c21d3 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -1469,11 +1469,24 @@ static bool validThroughout(LexicalScopes &LScopes, if (LSRange.size() == 0) return false; + // If this range is neither open ended nor a constant, then it is not a + // candidate for being validThroughout. + if (RangeEnd && !DbgValue->getOperand(0).isImm()) + return false; + // Determine if the DBG_VALUE is valid at the beginning of its lexical block. const MachineInstr *LScopeBegin = LSRange.front().first; // Early exit if the lexical scope begins outside of the current block. if (LScopeBegin->getParent() != MBB) return false; + + // If there are instructions belonging to our scope in another block, and + // we're not a constant (see DWARF2 comment below), then we can't be + // validThroughout. + const MachineInstr *LScopeEnd = LSRange.back().second; + if (RangeEnd && LScopeEnd->getParent() != MBB) + return false; + MachineBasicBlock::const_reverse_iterator Pred(DbgValue); for (++Pred; Pred != MBB->rend(); ++Pred) { if (Pred->getFlag(MachineInstr::FrameSetup)) @@ -1494,11 +1507,6 @@ static bool validThroughout(LexicalScopes &LScopes, if (!RangeEnd) return true; - // Fail if there are instructions belonging to our scope in another block. - const MachineInstr *LScopeEnd = LSRange.back().second; - if (LScopeEnd->getParent() != MBB) - return false; - // Single, constant DBG_VALUEs in the prologue are promoted to be live // throughout the function. This is a hack, presumably for DWARF v2 and not // necessarily correct. It would be much better to use a dbg.declare instead From b94ebc7727ba598603763450dd4702a2efcf5755 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Wed, 8 Apr 2020 11:35:58 -0700 Subject: [PATCH 234/286] MachineFunction: Copy call site info when duplicating insts Summary: Preserve call site info for duplicated instructions. We copy over the call site info in CloneMachineInstrBundle to avoid repeated calls to copyCallSiteInfo in CloneMachineInstr. (Alternatively, we could copy call site info higher up the stack, e.g. into TargetInstrInfo::duplicate, or even into individual backend passes. However, I don't see how that would be safer or more general than the current approach.) Reviewers: aprantl, djtodoro, dstenb Subscribers: hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D77685 --- llvm/lib/CodeGen/MachineFunction.cpp | 5 ++ .../test/CodeGen/X86/taildup-callsiteinfo.mir | 75 +++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 llvm/test/CodeGen/X86/taildup-callsiteinfo.mir diff --git a/llvm/lib/CodeGen/MachineFunction.cpp b/llvm/lib/CodeGen/MachineFunction.cpp index 0db79d6ee8985..f6e2089f1c1c9 100644 --- a/llvm/lib/CodeGen/MachineFunction.cpp +++ b/llvm/lib/CodeGen/MachineFunction.cpp @@ -369,6 +369,11 @@ MachineInstr &MachineFunction::CloneMachineInstrBundle(MachineBasicBlock &MBB, break; ++I; } + // Copy over call site info to the cloned instruction if needed. If Orig is in + // a bundle, copyCallSiteInfo takes care of finding the call instruction in + // the bundle. + if (Orig.shouldUpdateCallSiteInfo()) + copyCallSiteInfo(&Orig, FirstClone); return *FirstClone; } diff --git a/llvm/test/CodeGen/X86/taildup-callsiteinfo.mir b/llvm/test/CodeGen/X86/taildup-callsiteinfo.mir new file mode 100644 index 0000000000000..cecc58a419c4e --- /dev/null +++ b/llvm/test/CodeGen/X86/taildup-callsiteinfo.mir @@ -0,0 +1,75 @@ +# RUN: llc %s -run-pass=block-placement -tail-dup-placement-threshold=4 -o - | FileCheck %s +# +# Test case adapted from test/CodeGen/X86/taildup-heapallocsite.ll. + +# CHECK-LABEL: callSites: +# CHECK-NEXT: - { bb: 1, offset: 1, fwdArgRegs: +# CHECK-NEXT: - { arg: 0, reg: '$rcx' } } +# CHECK-NEXT: - { bb: 2, offset: 1, fwdArgRegs: +# CHECK-NEXT: - { arg: 0, reg: '$rcx' } } + +--- | + target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + target triple = "x86_64-pc-windows-msvc19.22.27905" + + define dso_local void @taildupit(i32* readonly %size_ptr) { + entry: + %tobool = icmp eq i32* %size_ptr, null + br i1 %tobool, label %cond.end, label %cond.true + + cond.true: ; preds = %entry + %0 = load i32, i32* %size_ptr, align 4 + br label %cond.end + + cond.end: ; preds = %cond.true, %entry + %cond = phi i32 [ %0, %cond.true ], [ 1, %entry ] + %call = tail call i8* @alloc(i32 %cond) + tail call void @f2() + ret void + } + + declare dso_local i8* @alloc(i32) + + declare dso_local void @f2() + +... +--- +name: taildupit +tracksRegLiveness: true +liveins: + - { reg: '$rcx', virtual-reg: '' } +callSites: + - { bb: 3, offset: 0, fwdArgRegs: + - { arg: 0, reg: '$rcx' } } +body: | + bb.0.entry: + successors: %bb.1(0x30000000), %bb.2(0x50000000) + liveins: $rcx + + $rsp = frame-setup SUB64ri8 $rsp, 40, implicit-def dead $eflags + frame-setup SEH_StackAlloc 40 + frame-setup SEH_EndPrologue + TEST64rr renamable $rcx, renamable $rcx, implicit-def $eflags + JCC_1 %bb.2, 5, implicit killed $eflags + + bb.1: + successors: %bb.3(0x80000000) + + renamable $ecx = MOV32ri 1 + JMP_1 %bb.3 + + bb.2.cond.true: + successors: %bb.3(0x80000000) + liveins: $rcx + + renamable $ecx = MOV32rm killed renamable $rcx, 1, $noreg, 0, $noreg :: (load 4 from %ir.size_ptr) + + bb.3.cond.end: + liveins: $ecx + + CALL64pcrel32 @alloc, csr_win64, implicit $rsp, implicit $ssp, implicit $ecx, implicit-def $rsp, implicit-def $ssp, implicit-def dead $rax + SEH_Epilogue + $rsp = frame-destroy ADD64ri8 $rsp, 40, implicit-def dead $eflags + TAILJMPd64 @f2, csr_win64, implicit $rsp, implicit $ssp, implicit $rsp, implicit $ssp + +... From 759d65ec3f4409aedbc18afa73732202b13c5653 Mon Sep 17 00:00:00 2001 From: Augusto Noronha Date: Fri, 3 Apr 2020 12:50:28 -0300 Subject: [PATCH 235/286] Check if objc runtime pointer is null before using it --- lldb/source/Core/ValueObject.cpp | 31 ++++++++++--------- .../Language/Swift/FoundationValueTypes.cpp | 7 +++-- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index f49bfc0262f0f..7a7333379b09f 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -362,23 +362,24 @@ CompilerType ValueObject::MaybeCalculateCompleteType() { } // then try the runtime - std::vector compiler_decls; - auto *objc_language_runtime = ObjCLanguageRuntime::Get(*process_sp); - if (auto runtime_vendor = objc_language_runtime->GetDeclVendor()) { - if (runtime_vendor->FindDecls(class_name, false, UINT32_MAX, - compiler_decls) > 0 && - compiler_decls.size() > 0) { - auto *ctx = llvm::dyn_cast(compiler_decls[0].GetTypeSystem()); - if (ctx) { - CompilerType runtime_type = - ctx->GetTypeForDecl(compiler_decls[0].GetOpaqueDecl()); - m_override_type = - is_pointer_type ? runtime_type.GetPointerType() : runtime_type; + if (auto *objc_language_runtime = ObjCLanguageRuntime::Get(*process_sp)) { + if (auto *runtime_vendor = objc_language_runtime->GetDeclVendor()) { + std::vector compiler_decls; + runtime_vendor->FindDecls(class_name, false, UINT32_MAX, compiler_decls); + if (!compiler_decls.empty()) { + auto *ctx = + llvm::dyn_cast(compiler_decls[0].GetTypeSystem()); + if (ctx) { + CompilerType runtime_type = + ctx->GetTypeForDecl(compiler_decls[0].GetOpaqueDecl()); + m_override_type = + is_pointer_type ? runtime_type.GetPointerType() : runtime_type; + } } - } - if (m_override_type.IsValid()) - return m_override_type; + if (m_override_type.IsValid()) + return m_override_type; + } } return compiler_type; } diff --git a/lldb/source/Plugins/Language/Swift/FoundationValueTypes.cpp b/lldb/source/Plugins/Language/Swift/FoundationValueTypes.cpp index acb3b9c2aa4c7..e2e472a003f2d 100644 --- a/lldb/source/Plugins/Language/Swift/FoundationValueTypes.cpp +++ b/lldb/source/Plugins/Language/Swift/FoundationValueTypes.cpp @@ -159,8 +159,11 @@ bool lldb_private::formatters::swift::Measurement_SummaryProvider( if (!process_sp) return false; - auto descriptor_sp( - ObjCLanguageRuntime::Get(*process_sp)->GetClassDescriptor(*unit_sp)); + ObjCLanguageRuntime *objc_runtime = ObjCLanguageRuntime::Get(*process_sp); + if (!objc_runtime) + return false; + + auto descriptor_sp(objc_runtime->GetClassDescriptor(*unit_sp)); if (!descriptor_sp) return false; From a27c7795066aebee40ee4890603e200586a8ec7d Mon Sep 17 00:00:00 2001 From: Augusto Noronha Date: Mon, 13 Apr 2020 14:38:33 -0300 Subject: [PATCH 236/286] Add contiguous array test --- .../swift/stdlib/ContiguousArray/Makefile | 3 ++ .../ContiguousArray/TestContiguousArray.py | 28 ++++++++++++++++++ .../lang/swift/stdlib/ContiguousArray/main | Bin 0 -> 16456 bytes .../swift/stdlib/ContiguousArray/main.swift | 11 +++++++ 4 files changed, 42 insertions(+) create mode 100644 lldb/test/API/lang/swift/stdlib/ContiguousArray/Makefile create mode 100644 lldb/test/API/lang/swift/stdlib/ContiguousArray/TestContiguousArray.py create mode 100755 lldb/test/API/lang/swift/stdlib/ContiguousArray/main create mode 100644 lldb/test/API/lang/swift/stdlib/ContiguousArray/main.swift diff --git a/lldb/test/API/lang/swift/stdlib/ContiguousArray/Makefile b/lldb/test/API/lang/swift/stdlib/ContiguousArray/Makefile new file mode 100644 index 0000000000000..2a69023633b34 --- /dev/null +++ b/lldb/test/API/lang/swift/stdlib/ContiguousArray/Makefile @@ -0,0 +1,3 @@ +SWIFT_SOURCES := main.swift + +include Makefile.rules diff --git a/lldb/test/API/lang/swift/stdlib/ContiguousArray/TestContiguousArray.py b/lldb/test/API/lang/swift/stdlib/ContiguousArray/TestContiguousArray.py new file mode 100644 index 0000000000000..a435dfbad1bff --- /dev/null +++ b/lldb/test/API/lang/swift/stdlib/ContiguousArray/TestContiguousArray.py @@ -0,0 +1,28 @@ +""" +Test that contiguous array prints correctly +""" +import lldb +from lldbsuite.test.decorators import * +import lldbsuite.test.lldbtest as lldbtest +import lldbsuite.test.lldbutil as lldbutil +import os +import unittest2 + + +class TestContiguousArray(lldbtest.TestBase): + + mydir = lldbtest.TestBase.compute_mydir(__file__) + + @swiftTest + def test_frame_contiguous_array(self): + """Test that contiguous array prints correctly""" + self.build() + lldbutil.run_to_source_breakpoint( + self, 'Set breakpoint here', lldb.SBFileSpec('main.swift')) + + self.expect("frame variable --dynamic-type run-target", + startstr="""(ContiguousArray) array = { + _buffer = { + _storage = 1 value { + [0] = 0x""") + diff --git a/lldb/test/API/lang/swift/stdlib/ContiguousArray/main b/lldb/test/API/lang/swift/stdlib/ContiguousArray/main new file mode 100755 index 0000000000000000000000000000000000000000..078d60a125bdeebab9001ed731c40328265cc906 GIT binary patch literal 16456 zcmeHO4RBo5b-pWGpn$!WsR03|UK^Q_0j*ZDBxHWI`ty@#B@0W!#Kk~-zhi~{kCP^%$M2ADK34b6}lLfw=}Jqe{Yb}?l#)HIYh18vm=C##wiQ5<7Z?Cm-C zp0j#-+6PIQ&U8Ay_SCN=F&Qq6im5Z`c4{Q)P45%lz^SaNRKJXVz>+RFu&h6P_>9nq~}zhJE+`D zxnAmG(V^zXx>&e27ENS#)b40$u5E7gW|H0pS$4FKWm?}mC|$y4AyYE#^n*H=m0+#` z%u@pIaKN`Y;5z|d1&=+L0F=u2n}9F13q$(P9q{it;I9H+%6>T%xD?*#fOk3IK?nRH z2mGJ|{+a{+HsFB%Vx=oG$ceB5DYI7>Llj2YU2yBpn%v zW{gOBpr<{SOhg8PL$QeBmFDQ79YHh@j74`wL}q(**wBOFaBpOLNB_p|cyJ^lsxxiL z&36Oo59W5P?;ptYgdmZrZ)#5_jOa)0s{eoQWHD3ejGhm9%)`?1P5CZMhQ zv#C@vZ9q#GneEAR1k-h+$#|qLm>tPxjAUI$a(g0{42Cmx(n4)V=iQxwjeR|xy#uxV zz5c#_ZR0>~gRj9?>uap_HPi-cvqRa0k*#m>`Wox9nKaI8N*7`bYJ!U zIplGPg{_}M3}01Oz|+?GPw)Ql=a23>IPt#wr}y8p{M3)%bI;Ct&aMb1-HZzvB9FdN7Y+OXQMu;AABaHR!bJZnW%S#W9+$@N%pYFdfcSa9o< z>a*b1sk6m`QlKulogI^V@E5Fh(gm&fC{U3 z!S5u5!fH&9qUQ8e0mAAurm^~_kIVEIFpW(+eMqKcip`YD;-gz0ij zPs;QLOk>qf@0IB`Ok*=lr)2sTOk)#HZkc_d&Y;SKa38_i5(Ow6S+)`UV0M z<(GghZDR3P%aPo^3p^`ao~Rb$^pX{@r~v3eFfgc1l;?nI>&|NCN#iQ0iY*|6Rk3($ zVQSdBWW|>t3n8{1S+b&4%%(x#k9reL=+~gO<~-3b#r_M$-mlnyS!9nZ_EU=ekYYbtWbab!2NnAP#m*Gjam5}|>=DHtD6;QU>~_Vz zN3olV?2U?Dt=Qd)eMOPo3c&P_KQ0uOtdPyAjlElG?*3RavorZ0K{M1Jg0WVqdKNaf zcC7O(Hc!BepADG#tw(0N+oa@!zEviF44V5z9OXa2aiW>W@>$4D8J*QF_7DGH->h`N zd@sKlq`S?(%j1NA!`{EO*sp#of6VMzaMEHQN~nQ{d9Vki1Ao2-k-wFl(0o}lJ5Oll z;PL#-e-#RW@i-(pUjg7yUWamM<2{Eo)1{3g);R;6Ho6izei&UdI}hgH!pOw#8Erg! zLK`1EsF{cJe+`C!nTKZz6k0(6q6hLg=Y#B&X1<*7m$r8w$UlL?V@EYCS((aetOD$NX3S8AqFU6H*+8}F#D z09!RjFjlD@KI_pw1g}8Cd{qnmr#6mSt`F<~(R@=g8>_(&ZG2g^HomAjf1ULCur@w` zHp|d##i{2e`?T@$s#W0j*jXsU!s_fADA0%pY5*7BFb%u~s|GC32fx8G!=Nmmmc?BJ zW*1g}-qKgp{5JM(i$i&QSRN>B083_6SE=$;L3vtac|4Z#c#7rmQF;6a3+NEkOJ%@3 z7Let~S_xnSzl3#AfnY^`3pok}h0J6@t4@85=Rf~u|J~i@PyB;^n5$Pm2ipfQ71w?r zXusb)*KM8&tT_p7QlT9_w;;dyBPjDjzcM`aZ?S&B{7t|-(_y~nFD!do8$06C*8Ow# z-?0<_!B+ph{;mG|{Q8l}*+KBZ5v*IV2NDp4iLp$`uMLQEn1QY$7ta9n39&a1X~f<* zS12@+5We8>z3rkjzN_)UG(L~PkiwT9z5{Q=g&qW#P%D6MKlyJPzUy~?bKy;{yKj2c zCD)#`4I*4SHwo8{O4l`uF0PmaLx|&^N(oek=%3fyDJ|qYhQfPW>6&l z0P!yeDwy9l%QuKGmu$?B&GPpH|2WuRW7Th;SP%pe%=3A8rhxBc{|(~Hbqw3@RQ6#? z6sO@q`_BO_`qwqFpzK>p2H_5PmP5HuK;1_WXmeNoNm-k_>W>$6x;+yM+uSvelxuF^ z!xw4pma&U_+^uPMi{I_@yKCCq9*_h1Hg|=r$1v6(yg;$-IG`W90I&M6P&j~~yRyq& zwPDGn+bi~pJFmX=hPBl&8dWtY}1--rU1;JRkPtu>Gzw))XCg~HR& z7YvYl2k4j17787}TL$fVFVIGyyMPV={RYteKwkiQ6zJPP-vRnD(9=MdgMKyCM+eaT zKpz2W$@W6@LJeG~feSTop$0D0z=ayPPy-ig;D4b8ct4i+UwOZkv%I@XktY0;e%M;-hPXxW>6macy9JKd408O=>X`DZ$j6;h(2wBx|3`kTGmDC zgH7R}PalQI}>eYW=X5tluDh`l5O^;xswEerJ{MF(aKFE_+gwPQ$ zTP1j$5iDYWmz6CNlQhm~n2Ozm^Z1aR2$UX`cHH7=^5-@(^c|8Pa}uwdC%+0ieA#@wOX9QRg6)S0=kdk(9*NJ^8{=Om zobOFB{;b3=D~?mfk2v5zmH6zqX89SykJ{?tB3$s4EfaS9S_gcs#4n#Gzrg|DCh;rg z$!~YSCnSF5Jo%>`@E=ILYM%V-4)`wtca^Oyu19%Xp9B0dm~UHc{d_TWV8lK2zPOPp zbQ$5tX}m-TuSR^qB5{a1IIrK<0PcaCSbfz0xm_9oUkZ~+ALWb9grQy9S8?m_AmEiH z>*1t65=#yRV|v&~rZajFZUMn^57v4{ zB<#Jpd0h)wE+Hf@o9RKk?*&(yjC4*6r{Nlv9?r(&IZ&~rOjExq*(`uf1eHh)0Zd-eL3j9Lk2 zI_2?IZK%0vxW3t&gga!7c%IcH53t&My6nKPi0KAg0h?Vy8|s3b-nGf!)2Vm%c0esc z!81vHG?)m(-8nM3Hk*m$ay#JS+1xz*?YWS=yk^ZvwR8 z&xpV!yHFas7T&+>N+;u%8+cINzl*qk2zp2`1lJx(&GKPHpE4qoiw`AZ(U1qqrDIs{ zvDU#XUot<5$Lb}DJy%T)L+U>rpYQeebhm?xc!`mQfV|u}7gBcu)vZri2TeMBV;RX% zGM2&e8Of9?q#eg=qBaE_JHyFz9Pc|iDbJU&7@9LKY`M?p*%YA>N~kbu5ysYn2DAxV zQH$_!G!hHP@!q7hDy*nQ818!}Lk7-4R$(h@5l%-^v0wN zAFrN52_Z+g1H2Jp;b=mKnGCB`imSdSWntE{NME>U{Qu>mvD!as(s?9!XXhm0#jE3L zeiB}J3)(x9Gz4z^;4N)|DQ_wU5xCAAR597Ryl|134bM(lpExCX!#RApvlb6|Z)B7f z4Wr>SWSGc$X&Tod8HKyq>6Gwd*F+z@=_L6A*5*hHZvxf|QXjXMYK!jzykFg<^8l1y z3m>E^}R7@K4w{_PV!4Y;DXF;6OsF*xVizR?6q(zsmmK7w((+VYd z{z6xR@n{IV7=?-f6^Jp-#br93l()xK*_5+bakh;>_Gs=jEh~*#$_Ls zNs#qfj_G%Sk9+!@=6!vp9@6LX+w1Rj;3LNRe9ppjFBO>cXaBkWI!V8c^5JtFrZa@2 zKDLuxeA$&ybr+iK2{`Z*WUs-=Fj@P&&AZHE@iFQ7eAx^ zJ2w9h(8oPfyTA7Iq%D8mFJo%;72{Y|Yxs&Sf7WAaZ!dfPXb&H*Ki&spYRwDd_Wb|Q zmOtw;{WSf;XVoX4{-^$L`i%MGokaNWSbz5VM_FsYzvHv&pP>H3^bMN=&mU~#Nr+hW zo&J85}=lPA#UHR`r?fG$ z^ha5cs9pafP`2vx{%D^^DeU_c{V&?|`5f>B>D$zc?;pn7KSlrdS&%4?Glq|XKCWN5 z{(1kN{|>s21&Lx=tzi%nSSPH{=ZvdYDyb<&iof>yTMHbtX>TXipDb#s20;~ z4+klK`}&Rh5z9XhhU|5Myc4AFqZi-}fZPL+4cV$;+UJ3 literal 0 HcmV?d00001 diff --git a/lldb/test/API/lang/swift/stdlib/ContiguousArray/main.swift b/lldb/test/API/lang/swift/stdlib/ContiguousArray/main.swift new file mode 100644 index 0000000000000..316cfa8a36d71 --- /dev/null +++ b/lldb/test/API/lang/swift/stdlib/ContiguousArray/main.swift @@ -0,0 +1,11 @@ +class Class {} + +func use(_ t: T) {} + +func main() { + let array = ContiguousArray([Class()]) + use(array)// Set breakpoint here +} + +main() + From 46a0ba9e0102efc7512f03b9e77b502ac68a3c85 Mon Sep 17 00:00:00 2001 From: Daniel Sanders Date: Fri, 3 Apr 2020 16:18:45 -0700 Subject: [PATCH 237/286] Add MIR-level debugify with only locations support for now Summary: Re-used the IR-level debugify for the most part. The MIR-level code then adds locations to the MachineInstrs afterwards based on the LLVM-IR debug info. It's worth mentioning that the resulting locations make little sense as the range of line numbers used in a Function at the MIR level exceeds that of the equivelent IR level function. As such, MachineInstrs can appear to originate from outside the subprogram scope (and from other subprogram scopes). However, it doesn't seem worth worrying about as the source is imaginary anyway. There's a few high level goals this pass works towards: * We should be able to debugify our .ll/.mir in the lit tests without changing the checks and still pass them. I.e. Debug info should not change codegen. Combining this with a strip-debug pass should enable this. The main issue I ran into without the strip-debug pass was instructions with MMO's and checks on both the instruction and the MMO as the debug-location is between them. I currently have a simple hack in the MIRPrinter to resolve that but the more general solution is a proper strip-debug pass. * We should be able to test that GlobalISel does not lose debug info. I recently found that the legalizer can be unexpectedly lossy in seemingly simple cases (e.g. expanding one instr into many). I have a verifier (will be posted separately) that can be integrated with passes that use the observer interface and will catch location loss (it does not verify correctness, just that there's zero lossage). It is a little conservative as the line-0 locations that arise from conflicts do not track the conflicting locations but it can still catch a fair bit. Depends on D77439, D77438 Reviewers: aprantl, bogner, vsk Subscribers: mgorny, hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D77446 (cherry picked from commit 1adeeabb79afbe966a45050f07e0bd6f446f8aa6) --- llvm/include/llvm/CodeGen/Passes.h | 2 + llvm/include/llvm/InitializePasses.h | 1 + llvm/include/llvm/Transforms/Utils/Debugify.h | 16 ++++ llvm/lib/CodeGen/CMakeLists.txt | 1 + llvm/lib/CodeGen/CodeGen.cpp | 1 + llvm/lib/CodeGen/MachineDebugify.cpp | 84 +++++++++++++++++++ llvm/lib/Transforms/Utils/Debugify.cpp | 18 ++-- .../CodeGen/Generic/MIRDebugify/locations.mir | 37 ++++++++ 8 files changed, 154 insertions(+), 6 deletions(-) create mode 100644 llvm/lib/CodeGen/MachineDebugify.cpp create mode 100644 llvm/test/CodeGen/Generic/MIRDebugify/locations.mir diff --git a/llvm/include/llvm/CodeGen/Passes.h b/llvm/include/llvm/CodeGen/Passes.h index 4e3451d80572b..ca7290890406a 100644 --- a/llvm/include/llvm/CodeGen/Passes.h +++ b/llvm/include/llvm/CodeGen/Passes.h @@ -466,6 +466,8 @@ namespace llvm { /// Create IR Type Promotion pass. \see TypePromotion.cpp FunctionPass *createTypePromotionPass(); + /// Creates MIR Debugify pass. \see MachineDebugify.cpp + ModulePass *createDebugifyMachineModulePass(); } // End llvm namespace #endif diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h index b3c6abab97a0d..8f8f0fb93503e 100644 --- a/llvm/include/llvm/InitializePasses.h +++ b/llvm/include/llvm/InitializePasses.h @@ -118,6 +118,7 @@ void initializeDSELegacyPassPass(PassRegistry&); void initializeDataFlowSanitizerPass(PassRegistry&); void initializeDeadInstEliminationPass(PassRegistry&); void initializeDeadMachineInstructionElimPass(PassRegistry&); +void initializeDebugifyMachineModulePass(PassRegistry &); void initializeDelinearizationPass(PassRegistry&); void initializeDemandedBitsWrapperPassPass(PassRegistry&); void initializeDependenceAnalysisPass(PassRegistry&); diff --git a/llvm/include/llvm/Transforms/Utils/Debugify.h b/llvm/include/llvm/Transforms/Utils/Debugify.h index 0b5ec738750db..aed6fb5e6da2c 100644 --- a/llvm/include/llvm/Transforms/Utils/Debugify.h +++ b/llvm/include/llvm/Transforms/Utils/Debugify.h @@ -17,6 +17,22 @@ #include "llvm/ADT/MapVector.h" #include "llvm/IR/PassManager.h" +namespace llvm { +class DIBuilder; + +/// Add synthesized debug information to a module. +/// +/// \param M The module to add debug information to. +/// \param Functions A range of functions to add debug information to. +/// \param Banner A prefix string to add to debug/error messages. +/// \param ApplyToMF A call back that will add debug information to the +/// MachineFunction for a Function. If nullptr, then the +/// MachineFunction (if any) will not be modified. +bool applyDebugifyMetadata( + Module &M, iterator_range Functions, StringRef Banner, + std::function ApplyToMF); +} // namespace llvm + llvm::ModulePass *createDebugifyModulePass(); llvm::FunctionPass *createDebugifyFunctionPass(); diff --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt index 470b027e38c81..d870ff3a75596 100644 --- a/llvm/lib/CodeGen/CMakeLists.txt +++ b/llvm/lib/CodeGen/CMakeLists.txt @@ -71,6 +71,7 @@ add_llvm_component_library(LLVMCodeGen MachineCombiner.cpp MachineCopyPropagation.cpp MachineCSE.cpp + MachineDebugify.cpp MachineDominanceFrontier.cpp MachineDominators.cpp MachineFrameInfo.cpp diff --git a/llvm/lib/CodeGen/CodeGen.cpp b/llvm/lib/CodeGen/CodeGen.cpp index 20fc67cc66ae7..51a8cd518c5f8 100644 --- a/llvm/lib/CodeGen/CodeGen.cpp +++ b/llvm/lib/CodeGen/CodeGen.cpp @@ -26,6 +26,7 @@ void llvm::initializeCodeGen(PassRegistry &Registry) { initializeCFIInstrInserterPass(Registry); initializeCodeGenPreparePass(Registry); initializeDeadMachineInstructionElimPass(Registry); + initializeDebugifyMachineModulePass(Registry); initializeDetectDeadLanesPass(Registry); initializeDwarfEHPreparePass(Registry); initializeEarlyIfConverterPass(Registry); diff --git a/llvm/lib/CodeGen/MachineDebugify.cpp b/llvm/lib/CodeGen/MachineDebugify.cpp new file mode 100644 index 0000000000000..86834dbc53d51 --- /dev/null +++ b/llvm/lib/CodeGen/MachineDebugify.cpp @@ -0,0 +1,84 @@ +//===- MachineDebugify.cpp - Attach synthetic debug info to everything ----===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file This pass attaches synthetic debug info to everything. It can be used +/// to create targeted tests for debug info preservation. +/// +/// This isn't intended to have feature parity with Debugify. +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/IR/DIBuilder.h" +#include "llvm/IR/DebugInfo.h" +#include "llvm/InitializePasses.h" +#include "llvm/Transforms/Utils/Debugify.h" + +#define DEBUG_TYPE "mir-debugify" + +using namespace llvm; + +namespace { +bool applyDebugifyMetadataToMachineFunction(MachineModuleInfo &MMI, + DIBuilder &DIB, Function &F) { + MachineFunction &MF = MMI.getOrCreateMachineFunction(F); + + DISubprogram *SP = F.getSubprogram(); + assert(SP && "IR Debugify just created it?"); + + LLVMContext &Ctx = F.getParent()->getContext(); + unsigned NextLine = SP->getLine(); + + for (MachineBasicBlock &MBB : MF) { + for (MachineInstr &MI : MBB) { + // This will likely emit line numbers beyond the end of the imagined + // source function and into subsequent ones. We don't do anything about + // that as it doesn't really matter to the compiler where the line is in + // the imaginary source code. + MI.setDebugLoc(DILocation::get(Ctx, NextLine++, 1, SP)); + } + } + + return true; +} + +/// ModulePass for attaching synthetic debug info to everything, used with the +/// legacy module pass manager. +struct DebugifyMachineModule : public ModulePass { + bool runOnModule(Module &M) override { + MachineModuleInfo &MMI = + getAnalysis().getMMI(); + return applyDebugifyMetadata( + M, M.functions(), + "ModuleDebugify: ", [&](DIBuilder &DIB, Function &F) -> bool { + return applyDebugifyMetadataToMachineFunction(MMI, DIB, F); + }); + } + + DebugifyMachineModule() : ModulePass(ID) {} + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired(); + AU.addPreserved(); + } + + static char ID; // Pass identification. +}; +char DebugifyMachineModule::ID = 0; + +} // end anonymous namespace + +INITIALIZE_PASS_BEGIN(DebugifyMachineModule, DEBUG_TYPE, + "Machine Debugify Module", false, false) +INITIALIZE_PASS_END(DebugifyMachineModule, DEBUG_TYPE, + "Machine Debugify Module", false, false) + +ModulePass *createDebugifyMachineModulePass() { + return new DebugifyMachineModule(); +} diff --git a/llvm/lib/Transforms/Utils/Debugify.cpp b/llvm/lib/Transforms/Utils/Debugify.cpp index a9cdf652b271b..f32cdbc80e093 100644 --- a/llvm/lib/Transforms/Utils/Debugify.cpp +++ b/llvm/lib/Transforms/Utils/Debugify.cpp @@ -62,10 +62,11 @@ Instruction *findTerminatingInstruction(BasicBlock &BB) { return I; return BB.getTerminator(); } +} // end anonymous namespace -bool applyDebugifyMetadata(Module &M, - iterator_range Functions, - StringRef Banner) { +bool llvm::applyDebugifyMetadata( + Module &M, iterator_range Functions, StringRef Banner, + std::function ApplyToMF) { // Skip modules with debug info. if (M.getNamedMetadata("llvm.dbg.cu")) { dbg() << Banner << "Skipping module with debug info\n"; @@ -149,6 +150,8 @@ bool applyDebugifyMetadata(Module &M, InsertBefore); } } + if (ApplyToMF) + ApplyToMF(DIB, F); DIB.finalizeSubprogram(SP); } DIB.finalize(); @@ -173,6 +176,7 @@ bool applyDebugifyMetadata(Module &M, return true; } +namespace { /// Return true if a mis-sized diagnostic is issued for \p DVI. bool diagnoseMisSizedDbgValue(Module &M, DbgValueInst *DVI) { // The size of a dbg.value's value operand should match the size of the @@ -315,7 +319,8 @@ bool checkDebugifyMetadata(Module &M, /// legacy module pass manager. struct DebugifyModulePass : public ModulePass { bool runOnModule(Module &M) override { - return applyDebugifyMetadata(M, M.functions(), "ModuleDebugify: "); + return applyDebugifyMetadata(M, M.functions(), + "ModuleDebugify: ", /*ApplyToMF*/ nullptr); } DebugifyModulePass() : ModulePass(ID) {} @@ -334,7 +339,7 @@ struct DebugifyFunctionPass : public FunctionPass { Module &M = *F.getParent(); auto FuncIt = F.getIterator(); return applyDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)), - "FunctionDebugify: "); + "FunctionDebugify: ", /*ApplyToMF*/ nullptr); } DebugifyFunctionPass() : FunctionPass(ID) {} @@ -409,7 +414,8 @@ FunctionPass *createDebugifyFunctionPass() { } PreservedAnalyses NewPMDebugifyPass::run(Module &M, ModuleAnalysisManager &) { - applyDebugifyMetadata(M, M.functions(), "ModuleDebugify: "); + applyDebugifyMetadata(M, M.functions(), + "ModuleDebugify: ", /*ApplyToMF*/ nullptr); return PreservedAnalyses::all(); } diff --git a/llvm/test/CodeGen/Generic/MIRDebugify/locations.mir b/llvm/test/CodeGen/Generic/MIRDebugify/locations.mir new file mode 100644 index 0000000000000..17aab12a6fef2 --- /dev/null +++ b/llvm/test/CodeGen/Generic/MIRDebugify/locations.mir @@ -0,0 +1,37 @@ +# RUN: llc -run-pass=mir-debugify -o - %s | FileCheck --check-prefixes=ALL,VALUE %s +# RUN: llc -run-pass=mir-debugify -debugify-level=locations -o - %s | FileCheck --check-prefixes=ALL --implicit-check-not=dbg.value %s +--- | + ; ModuleID = 'loc-only.ll' + source_filename = "loc-only.ll" + + ; ALL-LABEL: @test + define i32 @test(i32 %a, i32 %b) { + %add = add i32 %a, 2 + ; ALL-NEXT: %add = add i32 %a, 2, !dbg [[L1:![0-9]+]] + ; VALUE-NEXT: call void @llvm.dbg.value(metadata i32 %add, metadata [[add:![0-9]+]], metadata !DIExpression()), !dbg [[L1]] + %sub = sub i32 %add, %b + ; ALL-NEXT: %sub = sub i32 %add, %b, !dbg [[L2:![0-9]+]] + ; VALUE-NEXT: call void @llvm.dbg.value(metadata i32 %sub, metadata [[sub:![0-9]+]], metadata !DIExpression()), !dbg [[L2]] + ; ALL-NEXT: ret i32 %sub, !dbg [[L3:![0-9]+]] + ret i32 %sub + } + +... +--- +name: test +body: | + bb.1 (%ir-block.0): + %0:_(s32) = IMPLICIT_DEF + %1:_(s32) = IMPLICIT_DEF + %2:_(s32) = G_CONSTANT i32 2 + %3:_(s32) = G_ADD %0, %2 + %4:_(s32) = G_SUB %3, %1 + ; There's no attempt to have the locations make sense as it's an imaginary + ; source file anyway. These first three coincide with IR-level information + ; and therefore use metadata references. + ; ALL: %0:_(s32) = IMPLICIT_DEF debug-location [[L1]] + ; ALL: %1:_(s32) = IMPLICIT_DEF debug-location [[L2]] + ; ALL: %2:_(s32) = G_CONSTANT i32 2, debug-location [[L3]] + ; ALL: %3:_(s32) = G_ADD %0, %2, debug-location !DILocation(line: 4, column: 1, scope: !6) + ; ALL: %4:_(s32) = G_SUB %3, %1, debug-location !DILocation(line: 5, column: 1, scope: !6) +... From 34e0cf295c151d99cf2c5d13fd7d2396f16a9677 Mon Sep 17 00:00:00 2001 From: Daniel Sanders Date: Wed, 8 Apr 2020 10:27:17 -0700 Subject: [PATCH 238/286] Add pass to strip debug info from MIR Summary: Removes: * All LLVM-IR level debug info using StripDebugInfo() * All debugify metadata * 'Debug Info Version' module flag * All (valid*) DEBUG_VALUE MachineInstrs * All DebugLocs from MachineInstrs This is a more complete solution than the previous MIRPrinter option that just causes it to neglect to print debug-locations. * The qualifier 'valid' is used here because AArch64 emits an invalid one and tests depend on it Reviewers: vsk, aprantl, bogner Subscribers: mgorny, hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D77747 (cherry picked from commit a79b2fc44bfd5b5c856ce7b62f40c991afd9a532) --- llvm/include/llvm/CodeGen/Passes.h | 3 + llvm/include/llvm/InitializePasses.h | 1 + llvm/lib/CodeGen/CMakeLists.txt | 1 + llvm/lib/CodeGen/CodeGen.cpp | 1 + llvm/lib/CodeGen/MachineStripDebug.cpp | 112 ++++++++++++++++++ .../CodeGen/Generic/MIRDebugify/locations.mir | 7 ++ .../CodeGen/Generic/MIRStripDebug/all.mir | 73 ++++++++++++ .../MIRStripDebug/multiple-moduleflags.mir | 75 ++++++++++++ 8 files changed, 273 insertions(+) create mode 100644 llvm/lib/CodeGen/MachineStripDebug.cpp create mode 100644 llvm/test/CodeGen/Generic/MIRStripDebug/all.mir create mode 100644 llvm/test/CodeGen/Generic/MIRStripDebug/multiple-moduleflags.mir diff --git a/llvm/include/llvm/CodeGen/Passes.h b/llvm/include/llvm/CodeGen/Passes.h index ca7290890406a..9f2b8c5860dbc 100644 --- a/llvm/include/llvm/CodeGen/Passes.h +++ b/llvm/include/llvm/CodeGen/Passes.h @@ -468,6 +468,9 @@ namespace llvm { /// Creates MIR Debugify pass. \see MachineDebugify.cpp ModulePass *createDebugifyMachineModulePass(); + + /// Creates MIR Strip Debug pass. \see MachineStripDebug.cpp + ModulePass *createStripDebugMachineModulePass(); } // End llvm namespace #endif diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h index 8f8f0fb93503e..79459bdff959b 100644 --- a/llvm/include/llvm/InitializePasses.h +++ b/llvm/include/llvm/InitializePasses.h @@ -399,6 +399,7 @@ void initializeStraightLineStrengthReducePass(PassRegistry&); void initializeStripDeadDebugInfoPass(PassRegistry&); void initializeStripDeadPrototypesLegacyPassPass(PassRegistry&); void initializeStripDebugDeclarePass(PassRegistry&); +void initializeStripDebugMachineModulePass(PassRegistry &); void initializeStripGCRelocatesPass(PassRegistry&); void initializeStripNonDebugSymbolsPass(PassRegistry&); void initializeStripNonLineTableDebugInfoPass(PassRegistry&); diff --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt index d870ff3a75596..da2fa1b520af7 100644 --- a/llvm/lib/CodeGen/CMakeLists.txt +++ b/llvm/lib/CodeGen/CMakeLists.txt @@ -96,6 +96,7 @@ add_llvm_component_library(LLVMCodeGen MachineSink.cpp MachineSizeOpts.cpp MachineSSAUpdater.cpp + MachineStripDebug.cpp MachineTraceMetrics.cpp MachineVerifier.cpp ModuloSchedule.cpp diff --git a/llvm/lib/CodeGen/CodeGen.cpp b/llvm/lib/CodeGen/CodeGen.cpp index 51a8cd518c5f8..838142c062159 100644 --- a/llvm/lib/CodeGen/CodeGen.cpp +++ b/llvm/lib/CodeGen/CodeGen.cpp @@ -103,6 +103,7 @@ void llvm::initializeCodeGen(PassRegistry &Registry) { initializeStackMapLivenessPass(Registry); initializeStackProtectorPass(Registry); initializeStackSlotColoringPass(Registry); + initializeStripDebugMachineModulePass(Registry); initializeTailDuplicatePass(Registry); initializeTargetPassConfigPass(Registry); initializeTwoAddressInstructionPassPass(Registry); diff --git a/llvm/lib/CodeGen/MachineStripDebug.cpp b/llvm/lib/CodeGen/MachineStripDebug.cpp new file mode 100644 index 0000000000000..012971874cb51 --- /dev/null +++ b/llvm/lib/CodeGen/MachineStripDebug.cpp @@ -0,0 +1,112 @@ +//===- MachineStripDebug.cpp - Strip debug info ---------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file This removes debug info from everything. It can be used to ensure +/// tests can be debugified without affecting the output MIR. +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/IR/DebugInfo.h" +#include "llvm/InitializePasses.h" + +#define DEBUG_TYPE "mir-strip-debug" + +using namespace llvm; + +namespace { + +struct StripDebugMachineModule : public ModulePass { + bool runOnModule(Module &M) override { + MachineModuleInfo &MMI = + getAnalysis().getMMI(); + + bool Changed = false; + for (Function &F : M.functions()) { + MachineFunction &MF = MMI.getOrCreateMachineFunction(F); + for (MachineBasicBlock &MBB : MF) { + for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); + I != E;) { + if (I->isDebugInstr()) { + // FIXME: We should remove all of them. However, AArch64 emits an + // invalid `DBG_VALUE $lr` with only one operand instead of + // the usual three and has a test that depends on it's + // preservation. Preserve it for now. + if (I->getNumOperands() > 1) { + LLVM_DEBUG(dbgs() << "Removing debug instruction " << *I); + I = MBB.erase(I); + Changed |= true; + continue; + } + } + if (I->getDebugLoc()) { + LLVM_DEBUG(dbgs() << "Removing location " << *I); + I->setDebugLoc(DebugLoc()); + Changed |= true; + ++I; + continue; + } + LLVM_DEBUG(dbgs() << "Keeping " << *I); + ++I; + } + } + } + + Changed |= StripDebugInfo(M); + + NamedMDNode *NMD = M.getNamedMetadata("llvm.debugify"); + if (NMD) { + NMD->eraseFromParent(); + Changed |= true; + } + + NMD = M.getModuleFlagsMetadata(); + if (NMD) { + // There must be an easier way to remove an operand from a NamedMDNode. + SmallVector Flags; + for (MDNode *Flag : NMD->operands()) + Flags.push_back(Flag); + NMD->clearOperands(); + for (MDNode *Flag : Flags) { + MDString *Key = dyn_cast_or_null(Flag->getOperand(1)); + if (Key->getString() == "Debug Info Version") { + Changed |= true; + continue; + } + NMD->addOperand(Flag); + } + // If we left it empty we might as well remove it. + if (NMD->getNumOperands() == 0) + NMD->eraseFromParent(); + } + + return Changed; + } + + StripDebugMachineModule() : ModulePass(ID) {} + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired(); + AU.addPreserved(); + } + + static char ID; // Pass identification. +}; +char StripDebugMachineModule::ID = 0; + +} // end anonymous namespace + +INITIALIZE_PASS_BEGIN(StripDebugMachineModule, DEBUG_TYPE, + "Machine Strip Debug Module", false, false) +INITIALIZE_PASS_END(StripDebugMachineModule, DEBUG_TYPE, + "Machine Strip Debug Module", false, false) + +ModulePass *createStripDebugMachineModulePass() { + return new StripDebugMachineModule(); +} diff --git a/llvm/test/CodeGen/Generic/MIRDebugify/locations.mir b/llvm/test/CodeGen/Generic/MIRDebugify/locations.mir index 17aab12a6fef2..cd51432ad96bf 100644 --- a/llvm/test/CodeGen/Generic/MIRDebugify/locations.mir +++ b/llvm/test/CodeGen/Generic/MIRDebugify/locations.mir @@ -1,5 +1,6 @@ # RUN: llc -run-pass=mir-debugify -o - %s | FileCheck --check-prefixes=ALL,VALUE %s # RUN: llc -run-pass=mir-debugify -debugify-level=locations -o - %s | FileCheck --check-prefixes=ALL --implicit-check-not=dbg.value %s +# RUN: llc -run-pass=mir-debugify,mir-strip-debug,mir-debugify -o - %s | FileCheck --check-prefixes=ALL,VALUE %s --- | ; ModuleID = 'loc-only.ll' source_filename = "loc-only.ll" @@ -16,6 +17,12 @@ ret i32 %sub } + ; CHECK: !llvm.dbg.cu = !{!0} + ; CHECK: !llvm.debugify = + ; CHECK: !llvm.module.flags = !{![[VERSION:[0-9]+]]} + ; CHECK: !0 = distinct !DICompileUnit( + ; CHECK: ![[VERSION]] = !{i32 2, !"Debug Info Version", i32 3} + ... --- name: test diff --git a/llvm/test/CodeGen/Generic/MIRStripDebug/all.mir b/llvm/test/CodeGen/Generic/MIRStripDebug/all.mir new file mode 100644 index 0000000000000..7eaf609537956 --- /dev/null +++ b/llvm/test/CodeGen/Generic/MIRStripDebug/all.mir @@ -0,0 +1,73 @@ +# RUN: llc -run-pass=mir-strip-debug -o - %s | FileCheck %s +# RUN: llc -run-pass=mir-strip-debug,mir-debugify,mir-strip-debug -o - %s | FileCheck %s +--- | + ; ModuleID = 'loc-only.ll' + source_filename = "loc-only.ll" + + define i32 @test(i32 %a, i32 %b) !dbg !6 { + %add = add i32 %a, 2, !dbg !12 + call void @llvm.dbg.value(metadata i32 %add, metadata !9, metadata !DIExpression()), !dbg !12 + %sub = sub i32 %add, %b, !dbg !13 + call void @llvm.dbg.value(metadata i32 %sub, metadata !11, metadata !DIExpression()), !dbg !13 + ret i32 %sub, !dbg !14 + } + ; CHECK-LABEL: define i32 @test(i32 %a, i32 %b) { + ; CHECK-NEXT: %add = add i32 %a, 2 + ; CHECK-NEXT: %sub = sub i32 %add, %b + ; CHECK-NEXT: ret i32 %sub + ; CHECK-NEXT: } + + ; Function Attrs: nounwind readnone speculatable willreturn + declare void @llvm.dbg.value(metadata, metadata, metadata) #0 + + ; Function Attrs: nounwind + declare void @llvm.stackprotector(i8*, i8**) #1 + + attributes #0 = { nounwind readnone speculatable willreturn } + attributes #1 = { nounwind } + + !llvm.dbg.cu = !{!0} + ; CHECK-NOT: !llvm.dbg.cu + !llvm.debugify = !{!3, !4} + ; CHECK-NOT: !llvm.debugify + !llvm.module.flags = !{!5} + ; CHECK-NOT: !llvm.module.flags + + ; CHECK-NOT: !DI + !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) + !1 = !DIFile(filename: "", directory: "/") + !2 = !{} + !3 = !{i32 3} + !4 = !{i32 2} + !5 = !{i32 2, !"Debug Info Version", i32 3} + !6 = distinct !DISubprogram(name: "test", linkageName: "test", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8) + !7 = !DISubroutineType(types: !2) + !8 = !{!9, !11} + !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10) + !10 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_unsigned) + !11 = !DILocalVariable(name: "2", scope: !6, file: !1, line: 2, type: !10) + !12 = !DILocation(line: 1, column: 1, scope: !6) + !13 = !DILocation(line: 2, column: 1, scope: !6) + !14 = !DILocation(line: 3, column: 1, scope: !6) + +... +--- +name: test +body: | + bb.1 (%ir-block.0): + %0:_(s32) = G_IMPLICIT_DEF + %1:_(s32) = G_IMPLICIT_DEF + %2:_(s32) = G_CONSTANT i32 2, debug-location !DILocation(line: 0, scope: !6) + %3:_(s32) = G_ADD %0, %2, debug-location !12 + DBG_VALUE %3(s32), $noreg, !9, !DIExpression(), debug-location !12 + %4:_(s32) = G_SUB %3, %1, debug-location !13 + DBG_VALUE %4(s32), $noreg, !11, !DIExpression(), debug-location !13 + + ; CHECK-LABEL: body: + ; CHECK-NEXT: bb + ; CHECK-NEXT: %0:_(s32) = G_IMPLICIT_DEF{{$}} + ; CHECK-NEXT: %1:_(s32) = G_IMPLICIT_DEF{{$}} + ; CHECK-NEXT: %2:_(s32) = G_CONSTANT i32 2{{$}} + ; CHECK-NEXT: %3:_(s32) = G_ADD %0, %2{{$}} + ; CHECK-NEXT: %4:_(s32) = G_SUB %3, %1{{$}} +... diff --git a/llvm/test/CodeGen/Generic/MIRStripDebug/multiple-moduleflags.mir b/llvm/test/CodeGen/Generic/MIRStripDebug/multiple-moduleflags.mir new file mode 100644 index 0000000000000..2a62cd4bb8770 --- /dev/null +++ b/llvm/test/CodeGen/Generic/MIRStripDebug/multiple-moduleflags.mir @@ -0,0 +1,75 @@ +# RUN: llc -run-pass=mir-strip-debug -o - %s | FileCheck %s +# RUN: llc -run-pass=mir-strip-debug,mir-debugify,mir-strip-debug -o - %s | FileCheck %s +--- | + ; ModuleID = 'loc-only.ll' + source_filename = "loc-only.ll" + + define i32 @test(i32 %a, i32 %b) !dbg !6 { + %add = add i32 %a, 2, !dbg !12 + call void @llvm.dbg.value(metadata i32 %add, metadata !9, metadata !DIExpression()), !dbg !12 + %sub = sub i32 %add, %b, !dbg !13 + call void @llvm.dbg.value(metadata i32 %sub, metadata !11, metadata !DIExpression()), !dbg !13 + ret i32 %sub, !dbg !14 + } + ; CHECK-LABEL: define i32 @test(i32 %a, i32 %b) { + ; CHECK-NEXT: %add = add i32 %a, 2 + ; CHECK-NEXT: %sub = sub i32 %add, %b + ; CHECK-NEXT: ret i32 %sub + ; CHECK-NEXT: } + + ; Function Attrs: nounwind readnone speculatable willreturn + declare void @llvm.dbg.value(metadata, metadata, metadata) #0 + + ; Function Attrs: nounwind + declare void @llvm.stackprotector(i8*, i8**) #1 + + attributes #0 = { nounwind readnone speculatable willreturn } + attributes #1 = { nounwind } + + !llvm.dbg.cu = !{!0} + ; CHECK-NOT: !llvm.dbg.cu + !llvm.debugify = !{!3, !4} + ; CHECK-NOT: !llvm.debugify + !llvm.module.flags = !{!5, !15} + ; CHECK: !llvm.module.flags = !{!0} + ; CHECK: !0 = !{i32 2, !"Another Flag", i32 3} + + ; CHECK-NOT: !DI + !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) + !1 = !DIFile(filename: "", directory: "/") + !2 = !{} + !3 = !{i32 3} + !4 = !{i32 2} + !5 = !{i32 2, !"Debug Info Version", i32 3} + !6 = distinct !DISubprogram(name: "test", linkageName: "test", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8) + !7 = !DISubroutineType(types: !2) + !8 = !{!9, !11} + !9 = !DILocalVariable(name: "1", scope: !6, file: !1, line: 1, type: !10) + !10 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_unsigned) + !11 = !DILocalVariable(name: "2", scope: !6, file: !1, line: 2, type: !10) + !12 = !DILocation(line: 1, column: 1, scope: !6) + !13 = !DILocation(line: 2, column: 1, scope: !6) + !14 = !DILocation(line: 3, column: 1, scope: !6) + !15 = !{i32 2, !"Another Flag", i32 3} + +... +--- +name: test +body: | + bb.1 (%ir-block.0): + %0:_(s32) = G_IMPLICIT_DEF + %1:_(s32) = G_IMPLICIT_DEF + %2:_(s32) = G_CONSTANT i32 2, debug-location !DILocation(line: 0, scope: !6) + %3:_(s32) = G_ADD %0, %2, debug-location !12 + DBG_VALUE %3(s32), $noreg, !9, !DIExpression(), debug-location !12 + %4:_(s32) = G_SUB %3, %1, debug-location !13 + DBG_VALUE %4(s32), $noreg, !11, !DIExpression(), debug-location !13 + + ; CHECK-LABEL: body: + ; CHECK-NEXT: bb + ; CHECK-NEXT: %0:_(s32) = G_IMPLICIT_DEF{{$}} + ; CHECK-NEXT: %1:_(s32) = G_IMPLICIT_DEF{{$}} + ; CHECK-NEXT: %2:_(s32) = G_CONSTANT i32 2{{$}} + ; CHECK-NEXT: %3:_(s32) = G_ADD %0, %2{{$}} + ; CHECK-NEXT: %4:_(s32) = G_SUB %3, %1{{$}} +... From 81fc2b2f3d46deff7eac56420db33e398cdc74a1 Mon Sep 17 00:00:00 2001 From: Daniel Sanders Date: Wed, 8 Apr 2020 13:43:46 -0700 Subject: [PATCH 239/286] Make TargetPassConfig and llc add pre/post passes the same way. NFC Summary: At the moment, any changes we make to the passes that can be injected before/after others (e.g. -verify-machineinstrs and -print-after-all) have to be duplicated in both TargetPassConfig (for normal execution, -start-before/ -stop-before/etc) and llc (for -run-pass). Unify this pass injection into addMachinePrePass/addMachinePostPass that both TargetPassConfig and llc can use. Reviewers: vsk, aprantl, bogner Subscribers: hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D77887 (cherry picked from commit c162bc2aedbe7412a56063cd2284d1c7b1858f05) --- llvm/include/llvm/CodeGen/TargetPassConfig.h | 9 +++++++++ llvm/lib/CodeGen/TargetPassConfig.cpp | 21 ++++++++++++++------ llvm/tools/llc/llc.cpp | 3 ++- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/llvm/include/llvm/CodeGen/TargetPassConfig.h b/llvm/include/llvm/CodeGen/TargetPassConfig.h index d48fc664c1c3d..f84e85c5c8f98 100644 --- a/llvm/include/llvm/CodeGen/TargetPassConfig.h +++ b/llvm/include/llvm/CodeGen/TargetPassConfig.h @@ -306,6 +306,15 @@ class TargetPassConfig : public ImmutablePass { /// verification is enabled. void addVerifyPass(const std::string &Banner); + /// Add standard passes before a pass that's about to be added. For example, + /// the DebugifyMachineModulePass if it is enabled. + void addMachinePrePasses(); + + /// Add standard passes after a pass that has just been added. For example, + /// the MachineVerifier if it is enabled. + void addMachinePostPasses(const std::string &Banner, bool AllowPrint = true, + bool AllowVerify = true); + /// Check whether or not GlobalISel should abort on error. /// When this is disabled, GlobalISel will fall back on SDISel instead of /// erroring out. diff --git a/llvm/lib/CodeGen/TargetPassConfig.cpp b/llvm/lib/CodeGen/TargetPassConfig.cpp index 41cb511ad9b47..5b466f6b0eb23 100644 --- a/llvm/lib/CodeGen/TargetPassConfig.cpp +++ b/llvm/lib/CodeGen/TargetPassConfig.cpp @@ -530,17 +530,16 @@ void TargetPassConfig::addPass(Pass *P, bool verifyAfter, bool printAfter) { if (StopBefore == PassID && StopBeforeCount++ == StopBeforeInstanceNum) Stopped = true; if (Started && !Stopped) { + if (AddingMachinePasses) + addMachinePrePasses(); std::string Banner; // Construct banner message before PM->add() as that may delete the pass. if (AddingMachinePasses && (printAfter || verifyAfter)) Banner = std::string("After ") + std::string(P->getPassName()); PM->add(P); - if (AddingMachinePasses) { - if (printAfter) - addPrintPass(Banner); - if (verifyAfter) - addVerifyPass(Banner); - } + if (AddingMachinePasses) + addMachinePostPasses(Banner, /*AllowPrint*/ printAfter, + /*AllowVerify*/ verifyAfter); // Add the passes after the pass P if there is any. for (auto IP : Impl->InsertedPasses) { @@ -606,6 +605,16 @@ void TargetPassConfig::addVerifyPass(const std::string &Banner) { PM->add(createMachineVerifierPass(Banner)); } +void TargetPassConfig::addMachinePrePasses() {} + +void TargetPassConfig::addMachinePostPasses(const std::string &Banner, + bool AllowPrint, bool AllowVerify) { + if (AllowPrint) + addPrintPass(Banner); + if (AllowVerify) + addVerifyPass(Banner); +} + /// Add common target configurable passes that perform LLVM IR to IR transforms /// following machine independent optimization. void TargetPassConfig::addIRPasses() { diff --git a/llvm/tools/llc/llc.cpp b/llvm/tools/llc/llc.cpp index 9e5da83250728..4a1b2de388986 100644 --- a/llvm/tools/llc/llc.cpp +++ b/llvm/tools/llc/llc.cpp @@ -383,8 +383,9 @@ static bool addPass(PassManagerBase &PM, const char *argv0, return true; } std::string Banner = std::string("After ") + std::string(P->getPassName()); + TPC.addMachinePrePasses(); PM.add(P); - TPC.printAndVerify(Banner); + TPC.addMachinePostPasses(Banner); return false; } From 04b138afcb5d3c9f8d792aa5e6d66c64e6524c1f Mon Sep 17 00:00:00 2001 From: Daniel Sanders Date: Thu, 9 Apr 2020 10:36:50 -0700 Subject: [PATCH 240/286] [mir-strip-debug] Optionally preserve debug info that wasn't from debugify/mir-debugify Summary: A few tests start out with debug info and expect it to reach the output. For these tests we shouldn't strip the debug info Reviewers: aprantl, vsk, bogner Subscribers: hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D77886 (cherry picked from commit dfca98d6a83c725db38a20c06df92f1b2b9ce16b) --- llvm/include/llvm/CodeGen/Passes.h | 5 +- llvm/lib/CodeGen/MachineStripDebug.cpp | 26 +++++- .../dont-strip-real-debug-info.mir | 86 +++++++++++++++++++ 3 files changed, 113 insertions(+), 4 deletions(-) create mode 100644 llvm/test/CodeGen/Generic/MIRStripDebug/dont-strip-real-debug-info.mir diff --git a/llvm/include/llvm/CodeGen/Passes.h b/llvm/include/llvm/CodeGen/Passes.h index 9f2b8c5860dbc..9819543ec0d19 100644 --- a/llvm/include/llvm/CodeGen/Passes.h +++ b/llvm/include/llvm/CodeGen/Passes.h @@ -470,7 +470,10 @@ namespace llvm { ModulePass *createDebugifyMachineModulePass(); /// Creates MIR Strip Debug pass. \see MachineStripDebug.cpp - ModulePass *createStripDebugMachineModulePass(); + /// If OnlyDebugified is true then it will only strip debug info if it was + /// added by a Debugify pass. The module will be left unchanged if the debug + /// info was generated by another source such as clang. + ModulePass *createStripDebugMachineModulePass(bool OnlyDebugified); } // End llvm namespace #endif diff --git a/llvm/lib/CodeGen/MachineStripDebug.cpp b/llvm/lib/CodeGen/MachineStripDebug.cpp index 012971874cb51..aeb2789c28c11 100644 --- a/llvm/lib/CodeGen/MachineStripDebug.cpp +++ b/llvm/lib/CodeGen/MachineStripDebug.cpp @@ -15,15 +15,30 @@ #include "llvm/CodeGen/Passes.h" #include "llvm/IR/DebugInfo.h" #include "llvm/InitializePasses.h" +#include "llvm/Support/CommandLine.h" #define DEBUG_TYPE "mir-strip-debug" using namespace llvm; namespace { +cl::opt + OnlyDebugifiedDefault("mir-strip-debugify-only", + cl::desc("Should mir-strip-debug only strip debug " + "info from debugified modules by default"), + cl::init(true)); struct StripDebugMachineModule : public ModulePass { bool runOnModule(Module &M) override { + if (OnlyDebugified) { + NamedMDNode *DebugifyMD = M.getNamedMetadata("llvm.debugify"); + if (!DebugifyMD) { + LLVM_DEBUG(dbgs() << "Not stripping debug info" + " (debugify metadata not found)?\n"); + return false; + } + } + MachineModuleInfo &MMI = getAnalysis().getMMI(); @@ -89,7 +104,9 @@ struct StripDebugMachineModule : public ModulePass { return Changed; } - StripDebugMachineModule() : ModulePass(ID) {} + StripDebugMachineModule() : StripDebugMachineModule(OnlyDebugifiedDefault) {} + StripDebugMachineModule(bool OnlyDebugified) + : ModulePass(ID), OnlyDebugified(OnlyDebugified) {} void getAnalysisUsage(AnalysisUsage &AU) const override { AU.addRequired(); @@ -97,6 +114,9 @@ struct StripDebugMachineModule : public ModulePass { } static char ID; // Pass identification. + +protected: + bool OnlyDebugified; }; char StripDebugMachineModule::ID = 0; @@ -107,6 +127,6 @@ INITIALIZE_PASS_BEGIN(StripDebugMachineModule, DEBUG_TYPE, INITIALIZE_PASS_END(StripDebugMachineModule, DEBUG_TYPE, "Machine Strip Debug Module", false, false) -ModulePass *createStripDebugMachineModulePass() { - return new StripDebugMachineModule(); +ModulePass *createStripDebugMachineModulePass(bool OnlyDebugified) { + return new StripDebugMachineModule(OnlyDebugified); } diff --git a/llvm/test/CodeGen/Generic/MIRStripDebug/dont-strip-real-debug-info.mir b/llvm/test/CodeGen/Generic/MIRStripDebug/dont-strip-real-debug-info.mir new file mode 100644 index 0000000000000..860cb9731ae80 --- /dev/null +++ b/llvm/test/CodeGen/Generic/MIRStripDebug/dont-strip-real-debug-info.mir @@ -0,0 +1,86 @@ +# RUN: llc -run-pass=mir-strip-debug -o - %s | FileCheck %s +# RUN: llc -run-pass=mir-strip-debug,mir-debugify,mir-strip-debug -o - %s | FileCheck %s +--- | + ; ModuleID = 'loc-only.ll' + source_filename = "loc-only.ll" + + define i32 @test(i32 %a, i32 %b) !dbg !4 { + %add = add i32 %a, 2, !dbg !10 + call void @llvm.dbg.value(metadata i32 %add, metadata !7, metadata !DIExpression()), !dbg !10 + %sub = sub i32 %add, %b, !dbg !11 + call void @llvm.dbg.value(metadata i32 %sub, metadata !9, metadata !DIExpression()), !dbg !11 + ret i32 %sub, !dbg !12 + } + ; CHECK-LABEL: define i32 @test(i32 %a, i32 %b) !dbg !4 { + ; CHECK-NEXT: %add = add i32 %a, 2, !dbg !10 + ; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 %add, metadata !7, metadata !DIExpression()), !dbg !10 + ; CHECK-NEXT: %sub = sub i32 %add, %b, !dbg !11 + ; CHECK-NEXT: call void @llvm.dbg.value(metadata i32 %sub, metadata !9, metadata !DIExpression()), !dbg !11 + ; CHECK-NEXT: ret i32 %sub, !dbg !12 + ; CHECK-NEXT: } + + ; Function Attrs: nounwind readnone speculatable willreturn + declare void @llvm.dbg.value(metadata, metadata, metadata) #0 + + ; Function Attrs: nounwind + declare void @llvm.stackprotector(i8*, i8**) #1 + + attributes #0 = { nounwind readnone speculatable willreturn } + attributes #1 = { nounwind } + + !llvm.dbg.cu = !{!0} + ; CHECK: !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!3} + ; CHECK: !llvm.module.flags = !{!3} + + !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) + !1 = !DIFile(filename: "", directory: "/") + !2 = !{} + !3 = !{i32 2, !"Debug Info Version", i32 3} + !4 = distinct !DISubprogram(name: "test", linkageName: "test", scope: null, file: !1, line: 1, type: !5, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !6) + !5 = !DISubroutineType(types: !2) + !6 = !{!7, !9} + !7 = !DILocalVariable(name: "1", scope: !4, file: !1, line: 1, type: !8) + !8 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_unsigned) + !9 = !DILocalVariable(name: "2", scope: !4, file: !1, line: 2, type: !8) + !10 = !DILocation(line: 1, column: 1, scope: !4) + !11 = !DILocation(line: 2, column: 1, scope: !4) + !12 = !DILocation(line: 3, column: 1, scope: !4) + + ; CHECK: !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) + ; CHECK: !1 = !DIFile(filename: "", directory: "/") + ; CHECK: !2 = !{} + ; CHECK: !3 = !{i32 2, !"Debug Info Version", i32 3} + ; CHECK: !4 = distinct !DISubprogram(name: "test", linkageName: "test", scope: null, file: !1, line: 1, type: !5, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !6) + ; CHECK: !5 = !DISubroutineType(types: !2) + ; CHECK: !6 = !{!7, !9} + ; CHECK: !7 = !DILocalVariable(name: "1", scope: !4, file: !1, line: 1, type: !8) + ; CHECK: !8 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_unsigned) + ; CHECK: !9 = !DILocalVariable(name: "2", scope: !4, file: !1, line: 2, type: !8) + ; CHECK: !10 = !DILocation(line: 1, column: 1, scope: !4) + ; CHECK: !11 = !DILocation(line: 2, column: 1, scope: !4) + ; CHECK: !12 = !DILocation(line: 3, column: 1, scope: !4) + +... +--- +name: test +body: | + bb.1 (%ir-block.0): + %0:_(s32) = G_IMPLICIT_DEF + %1:_(s32) = G_IMPLICIT_DEF + %2:_(s32) = G_CONSTANT i32 2, debug-location !DILocation(line: 0, scope: !4) + %3:_(s32) = G_ADD %0, %2, debug-location !10 + DBG_VALUE %3(s32), $noreg, !7, !DIExpression(), debug-location !10 + %4:_(s32) = G_SUB %3, %1, debug-location !11 + DBG_VALUE %4(s32), $noreg, !9, !DIExpression(), debug-location !11 + + ; CHECK-LABEL: body: + ; CHECK-NEXT: bb + ; CHECK-NEXT: %0:_(s32) = G_IMPLICIT_DEF{{$}} + ; CHECK-NEXT: %1:_(s32) = G_IMPLICIT_DEF{{$}} + ; CHECK-NEXT: %2:_(s32) = G_CONSTANT i32 2, debug-location !DILocation(line: 0, scope: !4) + ; CHECK-NEXT: %3:_(s32) = G_ADD %0, %2, debug-location !10 + ; CHECK-NEXT: DBG_VALUE %3(s32), $noreg, !7, !DIExpression(), debug-location !10 + ; CHECK-NEXT: %4:_(s32) = G_SUB %3, %1, debug-location !11 + ; CHECK-NEXT: DBG_VALUE %4(s32), $noreg, !9, !DIExpression(), debug-location !11 +... From 718de63d90f5a5149c1778a5c4c2c8d592317217 Mon Sep 17 00:00:00 2001 From: Daniel Sanders Date: Wed, 8 Apr 2020 13:48:40 -0700 Subject: [PATCH 241/286] Add -debugify-and-strip-all to add debug info before a pass and remove it after Summary: This allows us to test each backend pass under the presence of debug info using pre-existing tests. The tests should not fail as a result of this so long as it's true that debug info does not affect CodeGen. In practice, a few tests are sensitive to this: * Tests that check the pass structure (e.g. O0-pipeline.ll) * Tests that check --debug output. Specifically instruction dumps containing MMO's (e.g. prelegalizercombiner-extends.ll) * Tests that contain debugify metadata as mir-strip-debug will remove it (e.g. fastisel-debugvalue-undef.ll) * Tests with partial debug info (e.g. patchable-function-entry-empty.mir had debug info but no !llvm.dbg.cu) * Tests that check optimization remarks overly strictly (e.g. prologue-epilogue-remarks.mir) * Tests that would inject the pass in an unsafe region (e.g. seqpairspill.mir would inject between register alloc and virt reg rewriter) In all cases, the checks can either be updated or --debugify-and-strip-all-safe=0 can be used to avoid being affected by something like llvm-lit -Dllc='llc --debugify-and-strip-all-safe' I tested this without the lost debug locations verifier to confirm that AArch64 behaviour is unaffected (with the fixes in this patch) and with it to confirm it finds the problems without the additional RUN lines we had before. Depends on D77886, D77887, D77747 Reviewers: aprantl, vsk, bogner Subscribers: qcolombet, kristof.beyls, hiraditya, danielkiss, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D77888 (cherry picked from commit f71350f05ae125b8b343b3a3a441537e353af039) --- llvm/include/llvm/CodeGen/TargetPassConfig.h | 11 ++++- llvm/lib/CodeGen/MachineDebugify.cpp | 3 +- llvm/lib/CodeGen/MachineStripDebug.cpp | 3 +- llvm/lib/CodeGen/TargetPassConfig.cpp | 43 ++++++++++++++++++- .../GlobalISel/gisel-commandline-option.ll | 11 +++++ ...ercombiner-extending-loads-cornercases.mir | 12 +++--- llvm/test/CodeGen/AArch64/O0-pipeline.ll | 3 +- llvm/test/CodeGen/AArch64/O3-pipeline.ll | 3 +- .../AArch64/arm64-opt-remarks-lazy-bfi.ll | 2 + .../AArch64/fastisel-debugvalue-undef.ll | 3 -- .../AArch64/prologue-epilogue-remarks.mir | 12 +++--- llvm/test/CodeGen/AArch64/seqpairspill.mir | 2 +- .../AArch64/stp-opt-with-renaming-debug.mir | 3 ++ 13 files changed, 87 insertions(+), 24 deletions(-) diff --git a/llvm/include/llvm/CodeGen/TargetPassConfig.h b/llvm/include/llvm/CodeGen/TargetPassConfig.h index f84e85c5c8f98..3a4c09163f325 100644 --- a/llvm/include/llvm/CodeGen/TargetPassConfig.h +++ b/llvm/include/llvm/CodeGen/TargetPassConfig.h @@ -103,6 +103,7 @@ class TargetPassConfig : public ImmutablePass { bool Started = true; bool Stopped = false; bool AddingMachinePasses = false; + bool DebugifyIsSafe = true; /// Set the StartAfter, StartBefore and StopAfter passes to allow running only /// a portion of the normal code-gen pass sequence. @@ -306,14 +307,20 @@ class TargetPassConfig : public ImmutablePass { /// verification is enabled. void addVerifyPass(const std::string &Banner); + /// Add a pass to add synthesized debug info to the MIR. + void addDebugifyPass(); + + /// Add a pass to remove debug info from the MIR. + void addStripDebugPass(); + /// Add standard passes before a pass that's about to be added. For example, /// the DebugifyMachineModulePass if it is enabled. - void addMachinePrePasses(); + void addMachinePrePasses(bool AllowDebugify = true); /// Add standard passes after a pass that has just been added. For example, /// the MachineVerifier if it is enabled. void addMachinePostPasses(const std::string &Banner, bool AllowPrint = true, - bool AllowVerify = true); + bool AllowVerify = true, bool AllowStrip = true); /// Check whether or not GlobalISel should abort on error. /// When this is disabled, GlobalISel will fall back on SDISel instead of diff --git a/llvm/lib/CodeGen/MachineDebugify.cpp b/llvm/lib/CodeGen/MachineDebugify.cpp index 86834dbc53d51..bee9b63467571 100644 --- a/llvm/lib/CodeGen/MachineDebugify.cpp +++ b/llvm/lib/CodeGen/MachineDebugify.cpp @@ -66,6 +66,7 @@ struct DebugifyMachineModule : public ModulePass { void getAnalysisUsage(AnalysisUsage &AU) const override { AU.addRequired(); AU.addPreserved(); + AU.setPreservesCFG(); } static char ID; // Pass identification. @@ -79,6 +80,6 @@ INITIALIZE_PASS_BEGIN(DebugifyMachineModule, DEBUG_TYPE, INITIALIZE_PASS_END(DebugifyMachineModule, DEBUG_TYPE, "Machine Debugify Module", false, false) -ModulePass *createDebugifyMachineModulePass() { +ModulePass *llvm::createDebugifyMachineModulePass() { return new DebugifyMachineModule(); } diff --git a/llvm/lib/CodeGen/MachineStripDebug.cpp b/llvm/lib/CodeGen/MachineStripDebug.cpp index aeb2789c28c11..240d657b6b2d5 100644 --- a/llvm/lib/CodeGen/MachineStripDebug.cpp +++ b/llvm/lib/CodeGen/MachineStripDebug.cpp @@ -111,6 +111,7 @@ struct StripDebugMachineModule : public ModulePass { void getAnalysisUsage(AnalysisUsage &AU) const override { AU.addRequired(); AU.addPreserved(); + AU.setPreservesCFG(); } static char ID; // Pass identification. @@ -127,6 +128,6 @@ INITIALIZE_PASS_BEGIN(StripDebugMachineModule, DEBUG_TYPE, INITIALIZE_PASS_END(StripDebugMachineModule, DEBUG_TYPE, "Machine Strip Debug Module", false, false) -ModulePass *createStripDebugMachineModulePass(bool OnlyDebugified) { +ModulePass *llvm::createStripDebugMachineModulePass(bool OnlyDebugified) { return new StripDebugMachineModule(OnlyDebugified); } diff --git a/llvm/lib/CodeGen/TargetPassConfig.cpp b/llvm/lib/CodeGen/TargetPassConfig.cpp index 5b466f6b0eb23..984d858be7d1f 100644 --- a/llvm/lib/CodeGen/TargetPassConfig.cpp +++ b/llvm/lib/CodeGen/TargetPassConfig.cpp @@ -114,6 +114,12 @@ static cl::opt VerifyMachineCode("verify-machineinstrs", cl::Hidden, cl::desc("Verify generated machine code"), cl::ZeroOrMore); +static cl::opt DebugifyAndStripAll( + "debugify-and-strip-all-safe", cl::Hidden, + cl::desc( + "Debugify MIR before and Strip debug after " + "each pass except those known to be unsafe when debug info is present"), + cl::ZeroOrMore); enum RunOutliner { AlwaysOutline, NeverOutline, TargetDefault }; // Enable or disable the MachineOutliner. static cl::opt EnableMachineOutliner( @@ -605,10 +611,24 @@ void TargetPassConfig::addVerifyPass(const std::string &Banner) { PM->add(createMachineVerifierPass(Banner)); } -void TargetPassConfig::addMachinePrePasses() {} +void TargetPassConfig::addDebugifyPass() { + PM->add(createDebugifyMachineModulePass()); +} + +void TargetPassConfig::addStripDebugPass() { + PM->add(createStripDebugMachineModulePass(/*OnlyDebugified=*/true)); +} + +void TargetPassConfig::addMachinePrePasses(bool AllowDebugify) { + if (AllowDebugify && DebugifyAndStripAll == cl::BOU_TRUE && DebugifyIsSafe) + addDebugifyPass(); +} void TargetPassConfig::addMachinePostPasses(const std::string &Banner, - bool AllowPrint, bool AllowVerify) { + bool AllowPrint, bool AllowVerify, + bool AllowStrip) { + if (DebugifyAndStripAll == cl::BOU_TRUE && DebugifyIsSafe) + addStripDebugPass(); if (AllowPrint) addPrintPass(Banner); if (AllowVerify) @@ -794,6 +814,19 @@ bool TargetPassConfig::addCoreISelPasses() { TM->setGlobalISel(true); } + // FIXME: Injecting into the DAGISel pipeline seems to cause issues with + // analyses needing to be re-run. This can result in being unable to + // schedule passes (particularly with 'Function Alias Analysis + // Results'). It's not entirely clear why but AFAICT this seems to be + // due to one FunctionPassManager not being able to use analyses from a + // previous one. As we're injecting a ModulePass we break the usual + // pass manager into two. GlobalISel with the fallback path disabled + // and -run-pass seem to be unaffected. The majority of GlobalISel + // testing uses -run-pass so this probably isn't too bad. + SaveAndRestore SavedDebugifyIsSafe(DebugifyIsSafe); + if (Selector != SelectorType::GlobalISel || !isGlobalISelAbortEnabled()) + DebugifyIsSafe = false; + // Add instruction selector passes. if (Selector == SelectorType::GlobalISel) { SaveAndRestore SavedAddingMachinePasses(AddingMachinePasses, true); @@ -910,6 +943,11 @@ void TargetPassConfig::addMachinePasses() { // Run pre-ra passes. addPreRegAlloc(); + // Debugifying the register allocator passes seems to provoke some + // non-determinism that affects CodeGen and there doesn't seem to be a point + // where it becomes safe again so stop debugifying here. + DebugifyIsSafe = false; + // Run register allocation and passes that are tightly coupled with it, // including phi elimination and scheduling. if (getOptimizeRegAlloc()) @@ -1119,6 +1157,7 @@ bool TargetPassConfig::addRegAssignmentOptimized() { // Finally rewrite virtual registers. addPass(&VirtRegRewriterID); + // Perform stack slot coloring and post-ra machine LICM. // // FIXME: Re-enable coloring with register when it's capable of adding diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/gisel-commandline-option.ll b/llvm/test/CodeGen/AArch64/GlobalISel/gisel-commandline-option.ll index f7cc409ea9d73..fba596d4e056c 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/gisel-commandline-option.ll +++ b/llvm/test/CodeGen/AArch64/GlobalISel/gisel-commandline-option.ll @@ -1,43 +1,54 @@ ; RUN: llc -mtriple=aarch64-- -debug-pass=Structure %s -o /dev/null 2>&1 \ +; RUN: --debugify-and-strip-all-safe=0 \ ; RUN: -verify-machineinstrs=0 -O0 \ ; RUN: | FileCheck %s --check-prefixes=ENABLED,ENABLED-O0,FALLBACK ; RUN: llc -mtriple=aarch64-- -debug-pass=Structure %s -o /dev/null 2>&1 \ +; RUN: --debugify-and-strip-all-safe=0 \ ; RUN: -verify-machineinstrs -O0 \ ; RUN: | FileCheck %s --check-prefixes=ENABLED,ENABLED-O0,FALLBACK,VERIFY,VERIFY-O0 ; RUN: llc -mtriple=aarch64-- -debug-pass=Structure %s -o /dev/null 2>&1 \ +; RUN: --debugify-and-strip-all-safe=0 \ ; RUN: -verify-machineinstrs=0 -O0 -aarch64-enable-global-isel-at-O=0 -global-isel-abort=1 \ ; RUN: | FileCheck %s --check-prefix ENABLED --check-prefix ENABLED-O0 --check-prefix NOFALLBACK ; RUN: llc -mtriple=aarch64-- -debug-pass=Structure %s -o /dev/null 2>&1 \ +; RUN: --debugify-and-strip-all-safe=0 \ ; RUN: -verify-machineinstrs=0 -O0 -aarch64-enable-global-isel-at-O=0 -global-isel-abort=2 \ ; RUN: | FileCheck %s --check-prefix ENABLED --check-prefix ENABLED-O0 --check-prefix FALLBACK ; RUN: llc -mtriple=aarch64-- -debug-pass=Structure %s -o /dev/null 2>&1 \ +; RUN: --debugify-and-strip-all-safe=0 \ ; RUN: -verify-machineinstrs=0 -global-isel \ ; RUN: | FileCheck %s --check-prefix ENABLED --check-prefix NOFALLBACK --check-prefix ENABLED-O1 ; RUN: llc -mtriple=aarch64-- -debug-pass=Structure %s -o /dev/null 2>&1 \ +; RUN: --debugify-and-strip-all-safe=0 \ ; RUN: -verify-machineinstrs=0 -global-isel -global-isel-abort=2 \ ; RUN: | FileCheck %s --check-prefix ENABLED --check-prefix FALLBACK --check-prefix ENABLED-O1 ; RUN: llc -mtriple=aarch64-- -debug-pass=Structure %s -o /dev/null 2>&1 \ +; RUN: --debugify-and-strip-all-safe=0 \ ; RUN: -verify-machineinstrs=0 -O1 -aarch64-enable-global-isel-at-O=3 \ ; RUN: | FileCheck %s --check-prefix ENABLED --check-prefix ENABLED-O1 ; RUN: llc -mtriple=aarch64-- -debug-pass=Structure %s -o /dev/null 2>&1 \ +; RUN: --debugify-and-strip-all-safe=0 \ ; RUN: -verify-machineinstrs=0 -O1 -aarch64-enable-global-isel-at-O=0 \ ; RUN: | FileCheck %s --check-prefix DISABLED ; RUN: llc -mtriple=aarch64-- -debug-pass=Structure %s -o /dev/null 2>&1 \ +; RUN: --debugify-and-strip-all-safe=0 \ ; RUN: -verify-machineinstrs=0 -aarch64-enable-global-isel-at-O=-1 \ ; RUN: | FileCheck %s --check-prefix DISABLED ; RUN: llc -mtriple=aarch64-- -debug-pass=Structure %s -o /dev/null 2>&1 \ +; RUN: --debugify-and-strip-all-safe=0 \ ; RUN: -verify-machineinstrs=0 | FileCheck %s --check-prefix DISABLED ; RUN: llc -mtriple=aarch64-- -fast-isel=0 -global-isel=false \ +; RUN: --debugify-and-strip-all-safe=0 \ ; RUN: -debug-pass=Structure %s -o /dev/null 2>&1 -verify-machineinstrs=0 \ ; RUN: | FileCheck %s --check-prefix DISABLED diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-extending-loads-cornercases.mir b/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-extending-loads-cornercases.mir index 9128cb88c6b6e..63e80af680d6d 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-extending-loads-cornercases.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-extending-loads-cornercases.mir @@ -112,15 +112,15 @@ body: | # a test of the debug output and a test. # # CHECK-WORKLIST-LABEL: Generic MI Combiner for: multiple_copies -# CHECK-WORKLIST: Try combining [[IN0:%[0-9]+]]:_(s8) = G_LOAD [[IN1:%[0-9]+]]:_(p0) :: (load 1 from %ir.addr) +# CHECK-WORKLIST: Try combining [[IN0:%[0-9]+]]:_(s8) = G_LOAD [[IN1:%[0-9]+]]:_(p0){{.*}} :: (load 1 from %ir.addr) # CHECK-WORKLIST: Preferred use is: [[IN2:%[0-9]+]]:_(s32) = G_SEXT [[IN0]]:_(s8) -# CHECK-WORKLIST-DAG: Changing: [[IN0]]:_(s8) = G_LOAD [[IN1]]:_(p0) :: (load 1 from %ir.addr) +# CHECK-WORKLIST-DAG: Changing: [[IN0]]:_(s8) = G_LOAD [[IN1]]:_(p0){{.*}} :: (load 1 from %ir.addr) # CHECK-WORKLIST-DAG: Changing: [[IN3:%[0-9]+]]:_(s8) = G_ADD [[IN0]]:_, [[IN4:%[0-9]+]]:_ # CHECK-WORKLIST-DAG: Changed: [[IN3]]:_(s8) = G_ADD [[NEW1:%[0-9]+]]:_, [[IN4]]:_ # CHECK-WORKLIST-DAG: Changing: [[IN5:%[0-9]+]]:_(s8) = G_SUB [[IN0]]:_, [[IN6:%[0-9]+]]:_ # CHECK-WORKLIST-DAG: Changed: [[IN5]]:_(s8) = G_SUB [[NEW2:%[0-9]+]]:_, [[IN6]]:_ # CHECK-WORKLIST-DAG: Erasing: [[IN2]]:_(s32) = G_SEXT [[IN0]]:_(s8) -# CHECK-WORKLIST-DAG: Changed: [[IN2]]:_(s32) = G_SEXTLOAD [[IN1]]:_(p0) :: (load 1 from %ir.addr) +# CHECK-WORKLIST-DAG: Changed: [[IN2]]:_(s32) = G_SEXTLOAD [[IN1]]:_(p0){{.*}} :: (load 1 from %ir.addr) # CHECK-WORKLIST-DAG: Created: [[NEW1]]:_(s8) = G_TRUNC [[IN2]]:_(s32) # CHECK-WORKLIST-DAG: Created: [[NEW2]]:_(s8) = G_TRUNC [[IN2]]:_(s32) # CHECK-WORKLIST: Try combining @@ -211,9 +211,9 @@ body: | $w0 = COPY %10 $w1 = COPY %11 # CHECK-WORKLIST-LABEL: Generic MI Combiner for: sink_to_phi_nondominating -# CHECK-WORKLIST: Try combining [[IN0:%[0-9]+]]:_(s8) = G_LOAD [[IN1:%[0-9]+]]:_(p0) :: (load 1 from %ir.addr) +# CHECK-WORKLIST: Try combining [[IN0:%[0-9]+]]:_(s8) = G_LOAD [[IN1:%[0-9]+]]:_(p0){{.*}} :: (load 1 from %ir.addr) # CHECK-WORKLIST: Preferred use is: [[IN2:%[0-9]+]]:_(s32) = G_SEXT [[IN0]]:_(s8) -# CHECK-WORKLIST-DAG: Changing: [[IN0]]:_(s8) = G_LOAD [[IN1]]:_(p0) :: (load 1 from %ir.addr) +# CHECK-WORKLIST-DAG: Changing: [[IN0]]:_(s8) = G_LOAD [[IN1]]:_(p0){{.*}} :: (load 1 from %ir.addr) # CHECK-WORKLIST-DAG: Creating: G_TRUNC # CHECK-WORKLIST-DAG: Changing: [[IN3:%[0-9]+]]:_(s8) = G_ADD [[IN0]]:_, [[IN4:%[0-9]+]]:_ # CHECK-WORKLIST-DAG: Changed: [[IN3]]:_(s8) = G_ADD [[OUT1:%[0-9]+]]:_, [[IN4]]:_ @@ -221,7 +221,7 @@ body: | # CHECK-WORKLIST-DAG: Changing: [[IN5:%[0-9]+]]:_(s8) = G_SUB [[IN0]]:_, [[IN6:%[0-9]+]]:_ # CHECK-WORKLIST-DAG: Changed: [[IN5]]:_(s8) = G_SUB [[OUT2:%[0-9]+]]:_, [[IN6]]:_ # CHECK-WORKLIST-DAG: Erasing: [[IN2]]:_(s32) = G_SEXT [[IN0]]:_(s8) -# CHECK-WORKLIST-DAG: Changed: [[IN2]]:_(s32) = G_SEXTLOAD [[IN1]]:_(p0) :: (load 1 from %ir.addr) +# CHECK-WORKLIST-DAG: Changed: [[IN2]]:_(s32) = G_SEXTLOAD [[IN1]]:_(p0){{.*}} :: (load 1 from %ir.addr) # CHECK-WORKLIST-DAG: Created: [[OUT1]]:_(s8) = G_TRUNC [[IN2]]:_(s32) # CHECK-WORKLIST-DAG: Created: [[OUT2]]:_(s8) = G_TRUNC [[IN2]]:_(s32) # CHECK-WORKLIST: Try combining diff --git a/llvm/test/CodeGen/AArch64/O0-pipeline.ll b/llvm/test/CodeGen/AArch64/O0-pipeline.ll index 489cc4316891d..383723389a2fb 100644 --- a/llvm/test/CodeGen/AArch64/O0-pipeline.ll +++ b/llvm/test/CodeGen/AArch64/O0-pipeline.ll @@ -1,4 +1,5 @@ -; RUN: llc -mtriple=arm64-- -O0 -debug-pass=Structure < %s -o /dev/null 2>&1 | grep -v "Verify generated machine code" | FileCheck %s +; RUN: llc --debugify-and-strip-all-safe=0 -mtriple=arm64-- -O0 -debug-pass=Structure < %s -o /dev/null 2>&1 | \ +; RUN: grep -v "Verify generated machine code" | FileCheck %s ; REQUIRES: asserts diff --git a/llvm/test/CodeGen/AArch64/O3-pipeline.ll b/llvm/test/CodeGen/AArch64/O3-pipeline.ll index 9aa5cb54bedf6..85e08cfd3e3d2 100644 --- a/llvm/test/CodeGen/AArch64/O3-pipeline.ll +++ b/llvm/test/CodeGen/AArch64/O3-pipeline.ll @@ -1,4 +1,5 @@ -; RUN: llc -mtriple=arm64-- -O3 -debug-pass=Structure < %s -o /dev/null 2>&1 | grep -v "Verify generated machine code" | FileCheck %s +; RUN: llc --debugify-and-strip-all-safe=0 -mtriple=arm64-- -O3 -debug-pass=Structure < %s -o /dev/null 2>&1 | \ +; RUN: grep -v "Verify generated machine code" | FileCheck %s ; REQUIRES: asserts diff --git a/llvm/test/CodeGen/AArch64/arm64-opt-remarks-lazy-bfi.ll b/llvm/test/CodeGen/AArch64/arm64-opt-remarks-lazy-bfi.ll index 79cf990084336..e12fb7478d647 100644 --- a/llvm/test/CodeGen/AArch64/arm64-opt-remarks-lazy-bfi.ll +++ b/llvm/test/CodeGen/AArch64/arm64-opt-remarks-lazy-bfi.ll @@ -1,10 +1,12 @@ ; RUN: llc < %s -mtriple=arm64-apple-ios7.0 -pass-remarks-analysis=asm-printer \ +; RUN: --debugify-and-strip-all-safe=0 \ ; RUN: -verify-machineinstrs \ ; RUN: -pass-remarks-with-hotness=1 -asm-verbose=0 \ ; RUN: -debug-only=lazy-machine-block-freq,block-freq \ ; RUN: -debug-pass=Executions 2>&1 | FileCheck %s -check-prefix=HOTNESS ; RUN: llc < %s -mtriple=arm64-apple-ios7.0 -pass-remarks-analysis=asm-printer \ +; RUN: --debugify-and-strip-all-safe=0 \ ; RUN: -verify-machineinstrs \ ; RUN: -pass-remarks-with-hotness=0 -asm-verbose=0 \ ; RUN: -debug-only=lazy-machine-block-freq,block-freq \ diff --git a/llvm/test/CodeGen/AArch64/fastisel-debugvalue-undef.ll b/llvm/test/CodeGen/AArch64/fastisel-debugvalue-undef.ll index 86aa7d15edbba..aceb85f4dd7f0 100644 --- a/llvm/test/CodeGen/AArch64/fastisel-debugvalue-undef.ll +++ b/llvm/test/CodeGen/AArch64/fastisel-debugvalue-undef.ll @@ -12,14 +12,11 @@ define void @foo() !dbg !6 { declare void @llvm.dbg.value(metadata, metadata, metadata) !llvm.dbg.cu = !{!0} -!llvm.debugify = !{!3, !4} !llvm.module.flags = !{!5} !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) !1 = !DIFile(filename: "t.ll", directory: "/") !2 = !{} -!3 = !{i32 2} -!4 = !{i32 1} !5 = !{i32 2, !"Debug Info Version", i32 3} !6 = distinct !DISubprogram(name: "foo", linkageName: "foo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8) !7 = !DISubroutineType(types: !2) diff --git a/llvm/test/CodeGen/AArch64/prologue-epilogue-remarks.mir b/llvm/test/CodeGen/AArch64/prologue-epilogue-remarks.mir index ed139875d26ac..4bc1b968d1708 100644 --- a/llvm/test/CodeGen/AArch64/prologue-epilogue-remarks.mir +++ b/llvm/test/CodeGen/AArch64/prologue-epilogue-remarks.mir @@ -5,10 +5,10 @@ name: fun0 stack: - { id: 0, type: default, offset: 0, size: 8, alignment: 4 } -# CHECK: --- !Analysis +# CHECK-LABEL: --- !Analysis # CHECK-NEXT: Pass: prologepilog # CHECK-NEXT: Name: StackSize -# CHECK-NEXT: Function: fun0 +# CHECK: Function: fun0 # CHECK-NEXT: Args: # CHECK-NEXT: - NumStackBytes: '16' # CHECK-NEXT: - String: ' stack bytes in function' @@ -23,10 +23,10 @@ body: | name: fun1 stack: - { id: 0, type: default, offset: 0, size: 19, alignment: 4 } -# CHECK: --- !Analysis +# CHECK-LABEL: --- !Analysis # CHECK-NEXT: Pass: prologepilog # CHECK-NEXT: Name: StackSize -# CHECK-NEXT: Function: fun1 +# CHECK: Function: fun1 # CHECK-NEXT: Args: # CHECK-NEXT: - NumStackBytes: '32' # CHECK-NEXT: - String: ' stack bytes in function' @@ -41,10 +41,10 @@ body: | name: fun2 stack: - { id: 0, type: default, offset: 0, size: 1024, alignment: 4 } -# --- !Analysis +# CHECK-LABEL: --- !Analysis # CHECK: Pass: prologepilog # CHECK-NEXT: Name: StackSize -# CHECK-NEXT: Function: fun2 +# CHECK: Function: fun2 # CHECK-NEXT: Args: # CHECK-NEXT: - NumStackBytes: '1040' # CHECK-NEXT: - String: ' stack bytes in function' diff --git a/llvm/test/CodeGen/AArch64/seqpairspill.mir b/llvm/test/CodeGen/AArch64/seqpairspill.mir index 225e10ecfdb5a..fdcb3dc611817 100644 --- a/llvm/test/CodeGen/AArch64/seqpairspill.mir +++ b/llvm/test/CodeGen/AArch64/seqpairspill.mir @@ -1,4 +1,4 @@ -# RUN: llc -o - %s -mtriple=aarch64-- -mattr=+v8.1a -run-pass=greedy,virtregrewriter | FileCheck %s +# RUN: llc --debugify-and-strip-all-safe=0 -o - %s -mtriple=aarch64-- -mattr=+v8.1a -run-pass=greedy,virtregrewriter | FileCheck %s # Make sure spills/reloads from xseqpairs and wseqpairs work correctly. --- # CHECK-LABEL: name: spill_reload_xseqpairs diff --git a/llvm/test/CodeGen/AArch64/stp-opt-with-renaming-debug.mir b/llvm/test/CodeGen/AArch64/stp-opt-with-renaming-debug.mir index 17a9c47a588a2..e89c778c53669 100644 --- a/llvm/test/CodeGen/AArch64/stp-opt-with-renaming-debug.mir +++ b/llvm/test/CodeGen/AArch64/stp-opt-with-renaming-debug.mir @@ -11,6 +11,9 @@ !7 = !DILocalVariable(name: "x", arg: 1, scope: !5, file: !1, line: 1, type: !8) !8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !9 = !DILocation(line: 1, column: 1, scope: !5) + !10 = !{i32 2, !"Debug Info Version", i32 3} + !llvm.dbg.cu = !{!0} + !llvm.module.flags = !{!10} --- # Check we do not crash when checking $noreg debug operands. # From 6588fe6b5e01d46f887b227789bc9e1fda22ef09 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Fri, 10 Apr 2020 14:58:13 -0700 Subject: [PATCH 242/286] [Debugify] Strip added metadata in the -debugify-each pipeline Summary: Share logic to strip debugify metadata between the IR and MIR level debugify passes. This makes it simpler to hunt for bugs by diffing IR with vs. without -debugify-each turned on. As a drive-by, fix an issue causing CallGraphNodes to become invalid when a dead llvm.dbg.value prototype is deleted. Reviewers: dsanders, aprantl Subscribers: hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D77915 (cherry picked from commit 122a6bfb07eb1ec7332ad1ee2e1a2136cc54a9c6) --- llvm/include/llvm/IR/IntrinsicInst.h | 22 +++++--- llvm/include/llvm/Transforms/Utils/Debugify.h | 6 ++ llvm/lib/Analysis/CallGraph.cpp | 6 +- llvm/lib/CodeGen/MachineStripDebug.cpp | 29 +--------- llvm/lib/Transforms/Utils/Debugify.cpp | 55 +++++++++++++++++-- llvm/test/DebugInfo/debugify-each.ll | 14 ++--- 6 files changed, 79 insertions(+), 53 deletions(-) diff --git a/llvm/include/llvm/IR/IntrinsicInst.h b/llvm/include/llvm/IR/IntrinsicInst.h index 42a5564a44880..90c3fbfc3655b 100644 --- a/llvm/include/llvm/IR/IntrinsicInst.h +++ b/llvm/include/llvm/IR/IntrinsicInst.h @@ -63,20 +63,26 @@ namespace llvm { } }; + /// Check if \p ID corresponds to a debug info intrinsic. + static inline bool isDbgInfoIntrinsic(Intrinsic::ID ID) { + switch (ID) { + case Intrinsic::dbg_declare: + case Intrinsic::dbg_value: + case Intrinsic::dbg_addr: + case Intrinsic::dbg_label: + return true; + default: + return false; + } + } + /// This is the common base class for debug info intrinsics. class DbgInfoIntrinsic : public IntrinsicInst { public: /// \name Casting methods /// @{ static bool classof(const IntrinsicInst *I) { - switch (I->getIntrinsicID()) { - case Intrinsic::dbg_declare: - case Intrinsic::dbg_value: - case Intrinsic::dbg_addr: - case Intrinsic::dbg_label: - return true; - default: return false; - } + return isDbgInfoIntrinsic(I->getIntrinsicID()); } static bool classof(const Value *V) { return isa(V) && classof(cast(V)); diff --git a/llvm/include/llvm/Transforms/Utils/Debugify.h b/llvm/include/llvm/Transforms/Utils/Debugify.h index aed6fb5e6da2c..6f11d0a7d0624 100644 --- a/llvm/include/llvm/Transforms/Utils/Debugify.h +++ b/llvm/include/llvm/Transforms/Utils/Debugify.h @@ -31,6 +31,12 @@ class DIBuilder; bool applyDebugifyMetadata( Module &M, iterator_range Functions, StringRef Banner, std::function ApplyToMF); + +/// Strip out all of the metadata and debug info inserted by debugify. If no +/// llvm.debugify module-level named metadata is present, this is a no-op. +/// Returns true if any change was made. +bool stripDebugifyMetadata(Module &M); + } // namespace llvm llvm::ModulePass *createDebugifyModulePass(); diff --git a/llvm/lib/Analysis/CallGraph.cpp b/llvm/lib/Analysis/CallGraph.cpp index 8e8a50178518d..3d4c9930920c6 100644 --- a/llvm/lib/Analysis/CallGraph.cpp +++ b/llvm/lib/Analysis/CallGraph.cpp @@ -11,6 +11,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/Config/llvm-config.h" #include "llvm/IR/Function.h" +#include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/Module.h" #include "llvm/IR/PassManager.h" @@ -31,9 +32,10 @@ using namespace llvm; CallGraph::CallGraph(Module &M) : M(M), ExternalCallingNode(getOrInsertFunction(nullptr)), CallsExternalNode(std::make_unique(nullptr)) { - // Add every function to the call graph. + // Add every interesting function to the call graph. for (Function &F : M) - addToCallGraph(&F); + if (!isDbgInfoIntrinsic(F.getIntrinsicID())) + addToCallGraph(&F); } CallGraph::CallGraph(CallGraph &&Arg) diff --git a/llvm/lib/CodeGen/MachineStripDebug.cpp b/llvm/lib/CodeGen/MachineStripDebug.cpp index 240d657b6b2d5..48b50ceb092a5 100644 --- a/llvm/lib/CodeGen/MachineStripDebug.cpp +++ b/llvm/lib/CodeGen/MachineStripDebug.cpp @@ -16,6 +16,7 @@ #include "llvm/IR/DebugInfo.h" #include "llvm/InitializePasses.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Transforms/Utils/Debugify.h" #define DEBUG_TYPE "mir-strip-debug" @@ -73,33 +74,7 @@ struct StripDebugMachineModule : public ModulePass { } } - Changed |= StripDebugInfo(M); - - NamedMDNode *NMD = M.getNamedMetadata("llvm.debugify"); - if (NMD) { - NMD->eraseFromParent(); - Changed |= true; - } - - NMD = M.getModuleFlagsMetadata(); - if (NMD) { - // There must be an easier way to remove an operand from a NamedMDNode. - SmallVector Flags; - for (MDNode *Flag : NMD->operands()) - Flags.push_back(Flag); - NMD->clearOperands(); - for (MDNode *Flag : Flags) { - MDString *Key = dyn_cast_or_null(Flag->getOperand(1)); - if (Key->getString() == "Debug Info Version") { - Changed |= true; - continue; - } - NMD->addOperand(Flag); - } - // If we left it empty we might as well remove it. - if (NMD->getNumOperands() == 0) - NMD->eraseFromParent(); - } + Changed |= stripDebugifyMetadata(M); return Changed; } diff --git a/llvm/lib/Transforms/Utils/Debugify.cpp b/llvm/lib/Transforms/Utils/Debugify.cpp index f32cdbc80e093..57f1740bc21b3 100644 --- a/llvm/lib/Transforms/Utils/Debugify.cpp +++ b/llvm/lib/Transforms/Utils/Debugify.cpp @@ -176,6 +176,52 @@ bool llvm::applyDebugifyMetadata( return true; } +bool llvm::stripDebugifyMetadata(Module &M) { + bool Changed = false; + + // Remove the llvm.debugify module-level named metadata. + NamedMDNode *DebugifyMD = M.getNamedMetadata("llvm.debugify"); + if (DebugifyMD) { + M.eraseNamedMetadata(DebugifyMD); + Changed = true; + } + + // Strip out all debug intrinsics and supporting metadata (subprograms, types, + // variables, etc). + Changed |= StripDebugInfo(M); + + // Strip out the dead dbg.value prototype. + Function *DbgValF = M.getFunction("llvm.dbg.value"); + if (DbgValF) { + assert(DbgValF->isDeclaration() && DbgValF->use_empty() && + "Not all debug info stripped?"); + DbgValF->eraseFromParent(); + Changed = true; + } + + // Strip out the module-level Debug Info Version metadata. + // FIXME: There must be an easier way to remove an operand from a NamedMDNode. + NamedMDNode *NMD = M.getModuleFlagsMetadata(); + assert(NMD && "debugify metadata present without Debug Info Version set?"); + SmallVector Flags; + for (MDNode *Flag : NMD->operands()) + Flags.push_back(Flag); + NMD->clearOperands(); + for (MDNode *Flag : Flags) { + MDString *Key = dyn_cast_or_null(Flag->getOperand(1)); + if (Key->getString() == "Debug Info Version") { + Changed = true; + continue; + } + NMD->addOperand(Flag); + } + // If we left it empty we might as well remove it. + if (NMD->getNumOperands() == 0) + NMD->eraseFromParent(); + + return Changed; +} + namespace { /// Return true if a mis-sized diagnostic is issued for \p DVI. bool diagnoseMisSizedDbgValue(Module &M, DbgValueInst *DVI) { @@ -305,12 +351,9 @@ bool checkDebugifyMetadata(Module &M, dbg() << " [" << NameOfWrappedPass << "]"; dbg() << ": " << (HasErrors ? "FAIL" : "PASS") << '\n'; - // Strip the Debugify Metadata if required. - if (Strip) { - StripDebugInfo(M); - M.eraseNamedMetadata(NMD); - return true; - } + // Strip debugify metadata if required. + if (Strip) + return stripDebugifyMetadata(M); return false; } diff --git a/llvm/test/DebugInfo/debugify-each.ll b/llvm/test/DebugInfo/debugify-each.ll index e290b948cc76d..3fbb66d7d517b 100644 --- a/llvm/test/DebugInfo/debugify-each.ll +++ b/llvm/test/DebugInfo/debugify-each.ll @@ -18,19 +18,13 @@ ; Check that stripped textual IR compares equal before and after applying ; debugify. -; RUN: opt -O1 < %s -S -o - | \ -; RUN: opt -strip -strip-dead-prototypes -strip-named-metadata -S -o %t.before -; RUN: opt -O1 -debugify-each < %s -S -o - | \ -; RUN: opt -strip -strip-dead-prototypes -strip-named-metadata -S -o %t.after +; RUN: opt -O1 < %s -S -o %t.before +; RUN: opt -O1 -debugify-each < %s -S -o %t.after ; RUN: diff %t.before %t.after ; Check that stripped IR compares equal before and after applying debugify. -; RUN: opt -O1 < %s | \ -; RUN: opt -strip -strip-dead-prototypes -strip-named-metadata | \ -; RUN: llvm-dis -o %t.before -; RUN: opt -O1 -debugify-each < %s | \ -; RUN: opt -strip -strip-dead-prototypes -strip-named-metadata | \ -; RUN: llvm-dis -o %t.after +; RUN: opt -O1 < %s | llvm-dis -o %t.before +; RUN: opt -O1 -debugify-each < %s | llvm-dis -o %t.after ; RUN: diff %t.before %t.after define void @foo(i32 %arg) { From 2d683e3b71e66c9c84fb6d567acc8b94d7185676 Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Fri, 10 Apr 2020 16:47:09 -0700 Subject: [PATCH 243/286] [InstCombine] Fix debug variance issue in tryToMoveFreeBeforeNullTest Fix an issue where the presence of debug info could disable an optimization in tryToMoveFreeBeforeNullTest. (cherry picked from commit 4831f4b7bdeb22e405248c45b3ea607a6b28b991) --- .../InstCombine/InstructionCombining.cpp | 2 +- .../malloc-free-delete-dbginvar.ll | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 llvm/test/Transforms/InstCombine/malloc-free-delete-dbginvar.ll diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp index e31023607e807..8901f3f2f5645 100644 --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -2517,7 +2517,7 @@ static Instruction *tryToMoveFreeBeforeNullTest(CallInst &FI, // If there are more than 2 instructions, check that they are noops // i.e., they won't hurt the performance of the generated code. if (FreeInstrBB->size() != 2) { - for (const Instruction &Inst : *FreeInstrBB) { + for (const Instruction &Inst : FreeInstrBB->instructionsWithoutDebug()) { if (&Inst == &FI || &Inst == FreeInstrBBTerminator) continue; auto *Cast = dyn_cast(&Inst); diff --git a/llvm/test/Transforms/InstCombine/malloc-free-delete-dbginvar.ll b/llvm/test/Transforms/InstCombine/malloc-free-delete-dbginvar.ll new file mode 100644 index 0000000000000..a3c4f47fd45e7 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/malloc-free-delete-dbginvar.ll @@ -0,0 +1,22 @@ +; Check that the instcombine result is the same with/without debug info. +; This is a regression test for a function taken from malloc-free-delete.ll. + +; RUN: opt < %s -instcombine -S > %t.no_dbg.ll +; RUN: opt < %s -debugify-each -instcombine -S > %t.ll +; RUN: diff %t.no_dbg.ll %t.ll + +declare void @free(i8*) + +define void @test12(i32* %foo) minsize { +entry: + %tobool = icmp eq i32* %foo, null + br i1 %tobool, label %if.end, label %if.then + +if.then: ; preds = %entry + %bitcast = bitcast i32* %foo to i8* + tail call void @free(i8* %bitcast) + br label %if.end + +if.end: ; preds = %entry, %if.then + ret void +} From e7d9f4c9418fbb15ad7e9eb8e95c6b6bc28ffe4b Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Thu, 19 Mar 2020 18:51:36 -0700 Subject: [PATCH 244/286] Remap the target (Xcode) SDK directory to the host SDK directory. This is mostly useful for Swift support; it allows LLDB to substitute a matching SDK it shipped with instead of the sysroot path that was used at compile time. The goal of this is to make the Xcode SDK something that behaves more like the compiler's resource directory, as in that it ships with LLDB rather than with the debugged program. This important primarily for importing Swift and Clang modules in the expression evaluator, and getting at the APINotes from the SDK in Swift. For a cross-debugging scenario, this means you have to have an SDK for your target installed alongside LLDB. In Xcode this will always be the case. rdar://problem/60640017 Differential Revision: https://reviews.llvm.org/D76471 (cherry picked from commit 1e05d7b3d3c6d29ff6f9493cc478a36244cc32bd) Conflicts: lldb/include/lldb/Core/Module.h --- lldb/include/lldb/Core/Module.h | 11 ++ lldb/include/lldb/Host/HostInfoBase.h | 4 + .../include/lldb/Host/macosx/HostInfoMacOSX.h | 4 + lldb/include/lldb/Target/Platform.h | 4 + lldb/include/lldb/Utility/XcodeSDK.h | 63 +++++++ lldb/source/Core/Module.cpp | 18 ++ .../Host/macosx/objcxx/HostInfoMacOSX.mm | 37 ++++ .../MacOSX/PlatformAppleTVSimulator.h | 2 +- .../MacOSX/PlatformAppleWatchSimulator.h | 2 +- .../Platform/MacOSX/PlatformDarwin.cpp | 146 +++------------- .../Plugins/Platform/MacOSX/PlatformDarwin.h | 41 ++--- .../Platform/MacOSX/PlatformMacOSX.cpp | 3 +- .../Plugins/Platform/MacOSX/PlatformMacOSX.h | 2 +- .../MacOSX/PlatformRemoteDarwinDevice.h | 2 +- .../Platform/MacOSX/PlatformiOSSimulator.h | 2 +- .../Plugins/SymbolFile/DWARF/DWARFUnit.h | 1 + .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 6 + lldb/source/Utility/CMakeLists.txt | 1 + lldb/source/Utility/XcodeSDK.cpp | 163 ++++++++++++++++++ .../unittests/Platform/PlatformDarwinTest.cpp | 45 ----- lldb/unittests/Utility/CMakeLists.txt | 1 + lldb/unittests/Utility/XcodeSDKTest.cpp | 86 +++++++++ 22 files changed, 440 insertions(+), 204 deletions(-) create mode 100644 lldb/include/lldb/Utility/XcodeSDK.h create mode 100644 lldb/source/Utility/XcodeSDK.cpp create mode 100644 lldb/unittests/Utility/XcodeSDKTest.cpp diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h index cad95afcee243..8cde45ad6c784 100644 --- a/lldb/include/lldb/Core/Module.h +++ b/lldb/include/lldb/Core/Module.h @@ -19,6 +19,7 @@ #include "lldb/Utility/ConstString.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/Status.h" +#include "lldb/Utility/XcodeSDK.h" #include "lldb/Utility/UUID.h" #include "lldb/lldb-defines.h" #include "lldb/lldb-enumerations.h" @@ -508,6 +509,12 @@ class Module : public std::enable_shared_from_this, m_mod_time = mod_time; } + /// This callback will be called by SymbolFile implementations when + /// parsing a compile unit that contains SDK information. + /// \param sdk will be merged with \p m_sdk. + /// \param sysroot will be added to the path remapping dictionary. + void RegisterXcodeSDK(llvm::StringRef sdk, llvm::StringRef sysroot); + /// Tells whether this module is capable of being the main executable for a /// process. /// @@ -982,6 +989,10 @@ class Module : public std::enable_shared_from_this, ///when you have debug info for a module ///that doesn't match where the sources ///currently are + + /// The (Xcode) SDK this module was compiled with. + XcodeSDK m_xcode_sdk; + lldb::SectionListUP m_sections_up; ///< Unified section list for module that /// is used by the ObjectFile and and /// ObjectFile instances for the debug info diff --git a/lldb/include/lldb/Host/HostInfoBase.h b/lldb/include/lldb/Host/HostInfoBase.h index c59050cb34e97..ff328783d4b7e 100644 --- a/lldb/include/lldb/Host/HostInfoBase.h +++ b/lldb/include/lldb/Host/HostInfoBase.h @@ -12,6 +12,7 @@ #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/UserIDResolver.h" +#include "lldb/Utility/XcodeSDK.h" #include "lldb/lldb-enumerations.h" #include "llvm/ADT/StringRef.h" @@ -91,6 +92,9 @@ class HostInfoBase { static bool ComputePathRelativeToLibrary(FileSpec &file_spec, llvm::StringRef dir); + /// Return the directory containing a specific Xcode SDK. + static std::string GetXcodeSDK(XcodeSDK sdk) { return {}; } + protected: static bool ComputeSharedLibraryDirectory(FileSpec &file_spec); static bool ComputeSupportExeDirectory(FileSpec &file_spec); diff --git a/lldb/include/lldb/Host/macosx/HostInfoMacOSX.h b/lldb/include/lldb/Host/macosx/HostInfoMacOSX.h index 217ca5bf1fce9..b21de371a3973 100644 --- a/lldb/include/lldb/Host/macosx/HostInfoMacOSX.h +++ b/lldb/include/lldb/Host/macosx/HostInfoMacOSX.h @@ -11,6 +11,7 @@ #include "lldb/Host/posix/HostInfoPosix.h" #include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/XcodeSDK.h" #include "llvm/Support/VersionTuple.h" namespace lldb_private { @@ -31,7 +32,10 @@ class HostInfoMacOSX : public HostInfoPosix { static bool GetOSBuildString(std::string &s); static bool GetOSKernelDescription(std::string &s); static FileSpec GetProgramFileSpec(); + static std::string FindXcodeContentsDirectoryInPath(llvm::StringRef path); + /// Query xcrun to find an Xcode SDK directory. + static std::string GetXcodeSDK(XcodeSDK sdk); protected: static bool ComputeSupportExeDirectory(FileSpec &file_spec); static void ComputeHostArchitectureSupport(ArchSpec &arch_32, diff --git a/lldb/include/lldb/Target/Platform.h b/lldb/include/lldb/Target/Platform.h index 46d5974e3c30b..0e37e36498df3 100644 --- a/lldb/include/lldb/Target/Platform.h +++ b/lldb/include/lldb/Target/Platform.h @@ -431,6 +431,10 @@ class Platform : public PluginInterface { return lldb_private::ConstString(); } + virtual llvm::StringRef GetSDKPath(lldb_private::XcodeSDK sdk) { + return {}; + } + const std::string &GetRemoteURL() const { return m_remote_url; } bool IsHost() const { diff --git a/lldb/include/lldb/Utility/XcodeSDK.h b/lldb/include/lldb/Utility/XcodeSDK.h new file mode 100644 index 0000000000000..9b9f1d226bf09 --- /dev/null +++ b/lldb/include/lldb/Utility/XcodeSDK.h @@ -0,0 +1,63 @@ +//===-- XcodeSDK.h ----------------------------------------------*- 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 LLDB_UTILITY_SDK_H +#define LLDB_UTILITY_SDK_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/VersionTuple.h" +#include + +namespace lldb_private { + +/// An abstraction for Xcode-style SDKs that works like \ref ArchSpec. +class XcodeSDK { + std::string m_name; + +public: + XcodeSDK() = default; + XcodeSDK(std::string &&name) : m_name(std::move(name)) {} + static XcodeSDK GetAnyMacOS() { return XcodeSDK("MacOSX.sdk"); } + + enum Type : int { + MacOSX = 0, + iPhoneSimulator, + iPhoneOS, + AppleTVSimulator, + AppleTVOS, + WatchSimulator, + watchOS, + bridgeOS, + Linux, + numSDKTypes, + unknown = -1 + }; + static llvm::StringRef GetNameForType(Type type); + + /// The merge function follows a strict order to maintain monotonicity: + /// 1. SDK with the higher SDKType wins. + /// 2. The newer SDK wins. + void Merge(XcodeSDK other); + + XcodeSDK &operator=(XcodeSDK other); + bool operator==(XcodeSDK other); + + /// Return parsed SDK number, and SDK version number. + std::tuple Parse() const; + llvm::VersionTuple GetVersion() const; + Type GetType() const; + llvm::StringRef GetString() const; + + static bool SDKSupportsModules(Type type, llvm::VersionTuple version); + static bool SDKSupportsModules(Type desired_type, const FileSpec &sdk_path); + static llvm::StringRef GetSDKNameForType(Type type); +}; + +} // namespace lldb_private + +#endif diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp index 4dff53583eae3..4d18edd66f625 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -1631,6 +1631,24 @@ bool Module::RemapSourceFile(llvm::StringRef path, return m_source_mappings.RemapPath(path, new_path); } +void Module::RegisterXcodeSDK(llvm::StringRef sdk_name, llvm::StringRef sysroot) { + XcodeSDK sdk(sdk_name.str()); + if (m_xcode_sdk == sdk) + return; + m_xcode_sdk.Merge(sdk); + PlatformSP module_platform = + Platform::GetPlatformForArchitecture(GetArchitecture(), nullptr); + ConstString sdk_path(module_platform->GetSDKPath(sdk)); + if (!sdk_path) + return; + // If merged SDK changed for a previously registered source path, update it. + // This could happend with -fdebug-prefix-map, otherwise it's unlikely. + ConstString sysroot_cs(sysroot); + if (!m_source_mappings.Replace(sysroot_cs, sdk_path, true)) + // In the general case, however, append it to the list. + m_source_mappings.Append(sysroot_cs, sdk_path, false); +} + bool Module::MergeArchitecture(const ArchSpec &arch_spec) { if (!arch_spec.IsValid()) return false; diff --git a/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm b/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm index e73d2ffe9b9ab..c09339e8c6731 100644 --- a/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm +++ b/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm @@ -8,6 +8,7 @@ #include "lldb/Host/macosx/HostInfoMacOSX.h" #include "lldb/Host/FileSystem.h" +#include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" #include "lldb/Utility/Args.h" #include "lldb/Utility/Log.h" @@ -295,3 +296,39 @@ static void ParseOSVersion(llvm::VersionTuple &version, NSString *Key) { } } } + +std::string HostInfoMacOSX::GetXcodeSDK(XcodeSDK sdk) { + std::string xcrun_cmd = "xcrun --show-sdk-path --sdk " + + XcodeSDK::GetSDKNameForType(sdk.GetType()).str(); + llvm::VersionTuple version = sdk.GetVersion(); + if (!version.empty()) + xcrun_cmd += version.getAsString(); + + int status = 0; + int signo = 0; + std::string output_str; + lldb_private::Status error = + Host::RunShellCommand(xcrun_cmd.c_str(), FileSpec(), &status, &signo, + &output_str, std::chrono::seconds(15)); + + // Check that xcrun return something useful. + if (status != 0 || output_str.empty()) + return {}; + + // Convert to a StringRef so we can manipulate the string without modifying + // the underlying data. + llvm::StringRef output(output_str); + + // Remove any trailing newline characters. + output = output.rtrim(); + + // Strip any leading newline characters and everything before them. + const size_t last_newline = output.rfind('\n'); + if (last_newline != llvm::StringRef::npos) + output = output.substr(last_newline + 1); + + // Whatever is left in output should be a valid path. + if (!FileSystem::Instance().Exists(output)) + return {}; + return output.str(); +} diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.h b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.h index 0005eab4e6710..fc377ef04a6d4 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleTVSimulator.h @@ -69,7 +69,7 @@ class PlatformAppleTVSimulator : public PlatformDarwin { AddClangModuleCompilationOptions(lldb_private::Target *target, std::vector &options) override { return PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( - target, options, PlatformDarwin::SDKType::iPhoneSimulator); + target, options, lldb_private::XcodeSDK::Type::iPhoneSimulator); } protected: diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.h b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.h index d8ffa05343a73..cf6b2436b2969 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformAppleWatchSimulator.h @@ -69,7 +69,7 @@ class PlatformAppleWatchSimulator : public PlatformDarwin { AddClangModuleCompilationOptions(lldb_private::Target *target, std::vector &options) override { return PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( - target, options, PlatformDarwin::SDKType::iPhoneSimulator); + target, options, lldb_private::XcodeSDK::Type::iPhoneSimulator); } protected: diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp index a734bfc39d1ea..0c70bafdfdb51 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp @@ -1220,56 +1220,12 @@ static FileSpec GetCommandLineToolsLibraryPath() { return g_command_line_tools_filespec; } -bool PlatformDarwin::SDKSupportsModules(SDKType sdk_type, - llvm::VersionTuple version) { - switch (sdk_type) { - case SDKType::MacOSX: - return version >= llvm::VersionTuple(10, 10); - case SDKType::iPhoneOS: - case SDKType::iPhoneSimulator: - case SDKType::AppleTVOS: - case SDKType::AppleTVSimulator: - return version >= llvm::VersionTuple(8); - case SDKType::watchOS: - case SDKType::WatchSimulator: - return version >= llvm::VersionTuple(6); - default: - return false; - } - - return false; -} - -bool PlatformDarwin::SDKSupportsModules(SDKType desired_type, - const FileSpec &sdk_path) { - ConstString last_path_component = sdk_path.GetLastPathComponent(); - - if (last_path_component) { - const llvm::StringRef sdk_name = last_path_component.GetStringRef(); - - const std::string sdk_name_lower = sdk_name.lower(); - const llvm::StringRef sdk_string = GetSDKNameForType(desired_type); - if (!llvm::StringRef(sdk_name_lower).startswith(sdk_string)) - return false; - - auto version_part = sdk_name.drop_front(sdk_string.size()); - version_part.consume_back(".sdk"); - - llvm::VersionTuple version; - if (version.tryParse(version_part)) - return false; - return SDKSupportsModules(desired_type, version); - } - - return false; -} - FileSystem::EnumerateDirectoryResult PlatformDarwin::DirectoryEnumerator( void *baton, llvm::sys::fs::file_type file_type, llvm::StringRef path) { SDKEnumeratorInfo *enumerator_info = static_cast(baton); FileSpec spec(path); - if (SDKSupportsModules(enumerator_info->sdk_type, spec)) { + if (XcodeSDK::SDKSupportsModules(enumerator_info->sdk_type, spec)) { enumerator_info->found_path = spec; return FileSystem::EnumerateDirectoryResult::eEnumerateDirectoryResultNext; } @@ -1277,7 +1233,7 @@ FileSystem::EnumerateDirectoryResult PlatformDarwin::DirectoryEnumerator( return FileSystem::EnumerateDirectoryResult::eEnumerateDirectoryResultNext; } -FileSpec PlatformDarwin::FindSDKInXcodeForModules(SDKType sdk_type, +FileSpec PlatformDarwin::FindSDKInXcodeForModules(XcodeSDK::Type sdk_type, const FileSpec &sdks_spec) { // Look inside Xcode for the required installed iOS SDK version @@ -1303,19 +1259,19 @@ FileSpec PlatformDarwin::FindSDKInXcodeForModules(SDKType sdk_type, return FileSpec(); } -FileSpec PlatformDarwin::GetSDKDirectoryForModules(SDKType sdk_type) { +FileSpec PlatformDarwin::GetSDKDirectoryForModules(XcodeSDK::Type sdk_type) { FileSpec sdks_spec = GetXcodeContentsDirectory(); sdks_spec.AppendPathComponent("Developer"); sdks_spec.AppendPathComponent("Platforms"); switch (sdk_type) { - case SDKType::MacOSX: + case XcodeSDK::Type::MacOSX: sdks_spec.AppendPathComponent("MacOSX.platform"); break; - case SDKType::iPhoneSimulator: + case XcodeSDK::Type::iPhoneSimulator: sdks_spec.AppendPathComponent("iPhoneSimulator.platform"); break; - case SDKType::iPhoneOS: + case XcodeSDK::Type::iPhoneOS: sdks_spec.AppendPathComponent("iPhoneOS.platform"); break; default: @@ -1325,11 +1281,11 @@ FileSpec PlatformDarwin::GetSDKDirectoryForModules(SDKType sdk_type) { sdks_spec.AppendPathComponent("Developer"); sdks_spec.AppendPathComponent("SDKs"); - if (sdk_type == SDKType::MacOSX) { + if (sdk_type == XcodeSDK::Type::MacOSX) { llvm::VersionTuple version = HostInfo::GetOSVersion(); if (!version.empty()) { - if (SDKSupportsModules(SDKType::MacOSX, version)) { + if (XcodeSDK::SDKSupportsModules(XcodeSDK::Type::MacOSX, version)) { // If the Xcode SDKs are not available then try to use the // Command Line Tools one which is only for MacOSX. if (!FileSystem::Instance().Exists(sdks_spec)) { @@ -1498,7 +1454,7 @@ PlatformDarwin::ExtractCrashInfoAnnotations(Process &process) { } void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( - Target *target, std::vector &options, SDKType sdk_type) { + Target *target, std::vector &options, XcodeSDK::Type sdk_type) { const std::vector apple_arguments = { "-x", "objective-c++", "-fobjc-arc", "-fblocks", "-D_ISO646_H", "-D__ISO646_H", @@ -1509,7 +1465,7 @@ void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( StreamString minimum_version_option; bool use_current_os_version = false; switch (sdk_type) { - case SDKType::iPhoneOS: + case XcodeSDK::Type::iPhoneOS: #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) use_current_os_version = true; #else @@ -1517,11 +1473,11 @@ void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( #endif break; - case SDKType::iPhoneSimulator: + case XcodeSDK::Type::iPhoneSimulator: use_current_os_version = false; break; - case SDKType::MacOSX: + case XcodeSDK::Type::MacOSX: #if defined(__i386__) || defined(__x86_64__) use_current_os_version = true; #else @@ -1548,15 +1504,15 @@ void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( // Only add the version-min options if we got a version from somewhere if (!version.empty()) { switch (sdk_type) { - case SDKType::iPhoneOS: + case XcodeSDK::Type::iPhoneOS: minimum_version_option.PutCString("-mios-version-min="); minimum_version_option.PutCString(version.getAsString()); break; - case SDKType::iPhoneSimulator: + case XcodeSDK::Type::iPhoneSimulator: minimum_version_option.PutCString("-mios-simulator-version-min="); minimum_version_option.PutCString(version.getAsString()); break; - case SDKType::MacOSX: + case XcodeSDK::Type::MacOSX: minimum_version_option.PutCString("-mmacosx-version-min="); minimum_version_option.PutCString(version.getAsString()); break; @@ -1805,70 +1761,11 @@ PlatformDarwin::FindXcodeContentsDirectoryInPath(llvm::StringRef path) { return {}; } -llvm::StringRef PlatformDarwin::GetSDKNameForType(SDKType type) { - switch (type) { - case MacOSX: - return "macosx"; - case iPhoneSimulator: - return "iphonesimulator"; - case iPhoneOS: - return "iphoneos"; - case AppleTVSimulator: - return "appletvsimulator"; - case AppleTVOS: - return "appletvos"; - case WatchSimulator: - return "watchsimulator"; - case watchOS: - return "watchos"; - case bridgeOS: - return "bridgeos"; - case Linux: - return "linux"; - case numSDKTypes: - case unknown: - return ""; - } - llvm_unreachable("unhandled switch case"); -} - -FileSpec PlatformDarwin::GetXcodeSDK(SDKType type) { - std::string xcrun_cmd = - "xcrun --show-sdk-path --sdk " + GetSDKNameForType(type).str(); - - int status = 0; - int signo = 0; - std::string output_str; - lldb_private::Status error = - Host::RunShellCommand(xcrun_cmd.c_str(), FileSpec(), &status, &signo, - &output_str, std::chrono::seconds(15)); - - // Check that xcrun return something useful. - if (status != 0 || output_str.empty()) - return {}; - - // Convert to a StringRef so we can manipulate the string without modifying - // the underlying data. - llvm::StringRef output(output_str); - - // Remove any trailing newline characters. - output = output.rtrim(); - - // Strip any leading newline characters and everything before them. - const size_t last_newline = output.rfind('\n'); - if (last_newline != llvm::StringRef::npos) - output = output.substr(last_newline + 1); - - // Whatever is left in output should be a valid path. - if (!FileSystem::Instance().Exists(output)) - return {}; - - // Find the contents dir in the xcrun provided path. - std::string xcode_contents_dir = FindXcodeContentsDirectoryInPath(output); - if (xcode_contents_dir.empty()) - return {}; - - return FileSpec(xcode_contents_dir); +llvm::StringRef PlatformDarwin::GetSDKPath(XcodeSDK sdk) { + std::string &path = m_sdk_path[sdk.GetString()]; + if (path.empty()) + path = HostInfo::GetXcodeSDK(sdk); + return path; } FileSpec PlatformDarwin::GetXcodeContentsDirectory() { @@ -1899,7 +1796,8 @@ FileSpec PlatformDarwin::GetXcodeContentsDirectory() { } } - if (FileSpec fspec = GetXcodeSDK(SDKType::MacOSX)) { + FileSpec fspec(HostInfo::GetXcodeSDK(XcodeSDK::GetAnyMacOS())); + if (fspec) { if (FileSystem::Instance().Exists(fspec)) { std::string xcode_contents_dir = FindXcodeContentsDirectoryInPath(fspec.GetPath()); diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h index d1b960d2d5535..91301d40e567f 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h @@ -12,8 +12,10 @@ #include "Plugins/Platform/POSIX/PlatformPOSIX.h" #include "lldb/Host/FileSystem.h" +#include "lldb/Utility/ConstString.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/StructuredData.h" +#include "lldb/Utility/XcodeSDK.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/FileSystem.h" @@ -85,25 +87,11 @@ class PlatformDarwin : public PlatformPOSIX { static std::tuple ParseVersionBuildDir(llvm::StringRef str); - enum SDKType : int { - MacOSX = 0, - iPhoneSimulator, - iPhoneOS, - AppleTVSimulator, - AppleTVOS, - WatchSimulator, - watchOS, - bridgeOS, - Linux, - numSDKTypes, - unknown = -1 - }; - llvm::Expected FetchExtendedCrashInformation(lldb_private::Process &process) override; - static llvm::StringRef GetSDKNameForType(SDKType type); - static lldb_private::FileSpec GetXcodeSDK(SDKType type); + llvm::StringRef GetSDKPath(lldb_private::XcodeSDK sdk) override; + static lldb_private::FileSpec GetXcodeContentsDirectory(); static lldb_private::FileSpec GetXcodeDeveloperDirectory(); @@ -152,14 +140,9 @@ class PlatformDarwin : public PlatformPOSIX { const lldb_private::FileSpecList *module_search_paths_ptr, lldb::ModuleSP *old_module_sp_ptr, bool *did_create_ptr); - static bool SDKSupportsModules(SDKType sdk_type, llvm::VersionTuple version); - - static bool SDKSupportsModules(SDKType desired_type, - const lldb_private::FileSpec &sdk_path); - struct SDKEnumeratorInfo { lldb_private::FileSpec found_path; - SDKType sdk_type; + lldb_private::XcodeSDK::Type sdk_type; }; static lldb_private::FileSystem::EnumerateDirectoryResult @@ -167,17 +150,15 @@ class PlatformDarwin : public PlatformPOSIX { llvm::StringRef path); static lldb_private::FileSpec - FindSDKInXcodeForModules(SDKType sdk_type, + FindSDKInXcodeForModules(lldb_private::XcodeSDK::Type sdk_type, const lldb_private::FileSpec &sdks_spec); static lldb_private::FileSpec - GetSDKDirectoryForModules(PlatformDarwin::SDKType sdk_type); - - void - AddClangModuleCompilationOptionsForSDKType(lldb_private::Target *target, - std::vector &options, - SDKType sdk_type); + GetSDKDirectoryForModules(lldb_private::XcodeSDK::Type sdk_type); + void AddClangModuleCompilationOptionsForSDKType( + lldb_private::Target *target, std::vector &options, + lldb_private::XcodeSDK::Type sdk_type); lldb_private::Status FindBundleBinaryInExecSearchPaths( const lldb_private::ModuleSpec &module_spec, @@ -189,6 +170,8 @@ class PlatformDarwin : public PlatformPOSIX { llvm::StringRef component); static std::string FindXcodeContentsDirectoryInPath(llvm::StringRef path); + std::string m_developer_directory; + llvm::StringMap m_sdk_path; private: DISALLOW_COPY_AND_ASSIGN(PlatformDarwin); diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp index a5cb449bcbd6e..0de249eb0bb85 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp @@ -178,7 +178,8 @@ ConstString PlatformMacOSX::GetSDKDirectory(lldb_private::Target &target) { } // Use the default SDK as a fallback. - if (FileSpec fspec = GetXcodeSDK(SDKType::MacOSX)) { + FileSpec fspec(HostInfo::GetXcodeSDK(lldb_private::XcodeSDK::GetAnyMacOS())); + if (fspec) { if (FileSystem::Instance().Exists(fspec)) return ConstString(fspec.GetPath()); } diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h index 5e942f090c943..a4baf9274a8e1 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h @@ -73,7 +73,7 @@ class PlatformMacOSX : public PlatformDarwin { AddClangModuleCompilationOptions(lldb_private::Target *target, std::vector &options) override { return PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( - target, options, PlatformDarwin::SDKType::MacOSX); + target, options, lldb_private::XcodeSDK::Type::MacOSX); } private: diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h index 5e0b7d92bbd4d..5b2bb55b6585a 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h @@ -45,7 +45,7 @@ class PlatformRemoteDarwinDevice : public PlatformDarwin { AddClangModuleCompilationOptions(lldb_private::Target *target, std::vector &options) override { return PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( - target, options, PlatformDarwin::SDKType::iPhoneOS); + target, options, lldb_private::XcodeSDK::Type::iPhoneOS); } protected: diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h b/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h index d766929b2b891..948488a2853cd 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulator.h @@ -71,7 +71,7 @@ class PlatformiOSSimulator : public PlatformAppleSimulator { AddClangModuleCompilationOptions(lldb_private::Target *target, std::vector &options) override { return PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( - target, options, PlatformDarwin::SDKType::iPhoneSimulator); + target, options, lldb_private::XcodeSDK::Type::iPhoneSimulator); } protected: diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h index d53ed756fe05d..1ac286a8a52d5 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -12,6 +12,7 @@ #include "DWARFDIE.h" #include "DWARFDebugInfoEntry.h" #include "lldb/lldb-enumerations.h" +#include "lldb/Utility/XcodeSDK.h" #include "llvm/Support/RWMutex.h" #include diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 234b849bc6818..36ca1bdee6ac3 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -724,6 +724,12 @@ lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) { if (module_sp) { const DWARFDIE cu_die = dwarf_cu.DIE(); if (cu_die) { + if (const char *sdk = + cu_die.GetAttributeValueAsString(DW_AT_APPLE_sdk, nullptr)) { + const char *sysroot = + cu_die.GetAttributeValueAsString(DW_AT_LLVM_sysroot, ""); + module_sp->RegisterXcodeSDK(sdk, sysroot); + } FileSpec cu_file_spec(cu_die.GetName(), dwarf_cu.GetPathStyle()); MakeAbsoluteAndRemap(cu_file_spec, dwarf_cu, module_sp); diff --git a/lldb/source/Utility/CMakeLists.txt b/lldb/source/Utility/CMakeLists.txt index df486e2c0a4ca..0d82640019a27 100644 --- a/lldb/source/Utility/CMakeLists.txt +++ b/lldb/source/Utility/CMakeLists.txt @@ -58,6 +58,7 @@ add_lldb_library(lldbUtility UserIDResolver.cpp VASprintf.cpp VMRange.cpp + XcodeSDK.cpp LINK_LIBS ${LLDB_SYSTEM_LIBS} diff --git a/lldb/source/Utility/XcodeSDK.cpp b/lldb/source/Utility/XcodeSDK.cpp new file mode 100644 index 0000000000000..f2403f10de553 --- /dev/null +++ b/lldb/source/Utility/XcodeSDK.cpp @@ -0,0 +1,163 @@ +//===-- XcodeSDK.cpp ------------------------------------------------------===// +// +// 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 "lldb/Utility/FileSpec.h" +#include "lldb/Utility/XcodeSDK.h" + +#include "lldb/lldb-types.h" + +using namespace lldb; +using namespace lldb_private; + +XcodeSDK &XcodeSDK::operator=(XcodeSDK other) { + m_name = other.m_name; + return *this; +} + +bool XcodeSDK::operator==(XcodeSDK other) { + return m_name == other.m_name; +} + +static XcodeSDK::Type ParseSDKName(llvm::StringRef &name) { + if (name.consume_front("MacOSX")) + return XcodeSDK::MacOSX; + if (name.consume_front("iPhoneSimulator")) + return XcodeSDK::iPhoneSimulator; + if (name.consume_front("iPhoneOS")) + return XcodeSDK::iPhoneOS; + if (name.consume_front("AppleTVSimulator")) + return XcodeSDK::AppleTVSimulator; + if (name.consume_front("AppleTVOS")) + return XcodeSDK::AppleTVOS; + if (name.consume_front("WatchSimulator")) + return XcodeSDK::WatchSimulator; + if (name.consume_front("WatchOS")) + return XcodeSDK::watchOS; + if (name.consume_front("bridgeOS")) + return XcodeSDK::bridgeOS; + if (name.consume_front("Linux")) + return XcodeSDK::Linux; + static_assert(XcodeSDK::Linux == XcodeSDK::numSDKTypes - 1, + "New SDK type was added, update this list!"); + return XcodeSDK::unknown; +} + +static llvm::VersionTuple ParseSDKVersion(llvm::StringRef &name) { + unsigned i = 0; + while (i < name.size() && name[i] >= '0' && name[i] <= '9') + ++i; + if (i == name.size() || name[i++] != '.') + return {}; + while (i < name.size() && name[i] >= '0' && name[i] <= '9') + ++i; + if (i == name.size() || name[i++] != '.') + return {}; + + llvm::VersionTuple version; + version.tryParse(name.slice(0, i - 1)); + name = name.drop_front(i); + return version; +} + + +std::tuple XcodeSDK::Parse() const { + llvm::StringRef input(m_name); + XcodeSDK::Type sdk = ParseSDKName(input); + llvm::VersionTuple version = ParseSDKVersion(input); + return {sdk, version}; +} + +llvm::VersionTuple XcodeSDK::GetVersion() const { + llvm::StringRef input(m_name); + ParseSDKName(input); + return ParseSDKVersion(input); +} + +XcodeSDK::Type XcodeSDK::GetType() const { + llvm::StringRef input(m_name); + return ParseSDKName(input); +} + +llvm::StringRef XcodeSDK::GetString() const { return m_name; } + +void XcodeSDK::Merge(XcodeSDK other) { + // The "bigger" SDK always wins. + if (Parse() < other.Parse()) + *this = other; +} + +llvm::StringRef XcodeSDK::GetSDKNameForType(XcodeSDK::Type type) { + switch (type) { + case MacOSX: + return "macosx"; + case iPhoneSimulator: + return "iphonesimulator"; + case iPhoneOS: + return "iphoneos"; + case AppleTVSimulator: + return "appletvsimulator"; + case AppleTVOS: + return "appletvos"; + case WatchSimulator: + return "watchsimulator"; + case watchOS: + return "watchos"; + case bridgeOS: + return "bridgeos"; + case Linux: + return "linux"; + case numSDKTypes: + case unknown: + return ""; + } + llvm_unreachable("unhandled switch case"); +} + +bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type sdk_type, + llvm::VersionTuple version) { + switch (sdk_type) { + case Type::MacOSX: + return version >= llvm::VersionTuple(10, 10); + case Type::iPhoneOS: + case Type::iPhoneSimulator: + case Type::AppleTVOS: + case Type::AppleTVSimulator: + return version >= llvm::VersionTuple(8); + case Type::watchOS: + case Type::WatchSimulator: + return version >= llvm::VersionTuple(6); + default: + return false; + } + + return false; +} + +bool XcodeSDK::SDKSupportsModules(XcodeSDK::Type desired_type, + const FileSpec &sdk_path) { + ConstString last_path_component = sdk_path.GetLastPathComponent(); + + if (last_path_component) { + const llvm::StringRef sdk_name = last_path_component.GetStringRef(); + + const std::string sdk_name_lower = sdk_name.lower(); + const llvm::StringRef sdk_string = GetSDKNameForType(desired_type); + if (!llvm::StringRef(sdk_name_lower).startswith(sdk_string)) + return false; + + auto version_part = sdk_name.drop_front(sdk_string.size()); + version_part.consume_back(".sdk"); + + llvm::VersionTuple version; + if (version.tryParse(version_part)) + return false; + return SDKSupportsModules(desired_type, version); + } + + return false; +} diff --git a/lldb/unittests/Platform/PlatformDarwinTest.cpp b/lldb/unittests/Platform/PlatformDarwinTest.cpp index 0aea200fe967e..74ad2318ecffd 100644 --- a/lldb/unittests/Platform/PlatformDarwinTest.cpp +++ b/lldb/unittests/Platform/PlatformDarwinTest.cpp @@ -21,10 +21,6 @@ struct PlatformDarwinTester : public PlatformDarwin { public: using PlatformDarwin::FindComponentInPath; using PlatformDarwin::FindXcodeContentsDirectoryInPath; - static bool SDKSupportsModules(SDKType desired_type, - const lldb_private::FileSpec &sdk_path) { - return PlatformDarwin::SDKSupportsModules(desired_type, sdk_path); - } }; TEST(PlatformDarwinTest, TestParseVersionBuildDir) { @@ -53,24 +49,6 @@ TEST(PlatformDarwinTest, TestParseVersionBuildDir) { std::tie(V, D) = PlatformDarwin::ParseVersionBuildDir("3.4.5"); EXPECT_EQ(llvm::VersionTuple(3, 4, 5), V); - - std::string base = "/Applications/Xcode.app/Contents/Developer/Platforms/"; - EXPECT_TRUE(PlatformDarwinTester::SDKSupportsModules( - PlatformDarwin::SDKType::iPhoneSimulator, - FileSpec( - base + - "iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator12.0.sdk"))); - EXPECT_FALSE(PlatformDarwinTester::SDKSupportsModules( - PlatformDarwin::SDKType::iPhoneSimulator, - FileSpec( - base + - "iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator7.2.sdk"))); - EXPECT_TRUE(PlatformDarwinTester::SDKSupportsModules( - PlatformDarwin::SDKType::MacOSX, - FileSpec(base + "MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk"))); - EXPECT_FALSE(PlatformDarwinTester::SDKSupportsModules( - PlatformDarwin::SDKType::MacOSX, - FileSpec(base + "MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk"))); } TEST(PlatformDarwinTest, FindXcodeContentsDirectoryInPath) { @@ -111,29 +89,6 @@ TEST(PlatformDarwinTest, FindXcodeContentsDirectoryInPath) { no_capitalization)); } -TEST(PlatformDarwinTest, GetSDKNameForType) { - EXPECT_EQ("macosx", - PlatformDarwin::GetSDKNameForType(PlatformDarwin::SDKType::MacOSX)); - EXPECT_EQ("iphonesimulator", PlatformDarwin::GetSDKNameForType( - PlatformDarwin::SDKType::iPhoneSimulator)); - EXPECT_EQ("iphoneos", PlatformDarwin::GetSDKNameForType( - PlatformDarwin::SDKType::iPhoneOS)); - EXPECT_EQ("appletvsimulator", PlatformDarwin::GetSDKNameForType( - PlatformDarwin::SDKType::AppleTVSimulator)); - EXPECT_EQ("appletvos", PlatformDarwin::GetSDKNameForType( - PlatformDarwin::SDKType::AppleTVOS)); - EXPECT_EQ("watchsimulator", PlatformDarwin::GetSDKNameForType( - PlatformDarwin::SDKType::WatchSimulator)); - EXPECT_EQ("watchos", PlatformDarwin::GetSDKNameForType( - PlatformDarwin::SDKType::watchOS)); - EXPECT_EQ("linux", - PlatformDarwin::GetSDKNameForType(PlatformDarwin::SDKType::Linux)); - EXPECT_EQ("", PlatformDarwin::GetSDKNameForType( - PlatformDarwin::SDKType::numSDKTypes)); - EXPECT_EQ( - "", PlatformDarwin::GetSDKNameForType(PlatformDarwin::SDKType::unknown)); -} - TEST(PlatformDarwinTest, FindComponentInPath) { EXPECT_EQ("/path/to/foo", PlatformDarwinTester::FindComponentInPath("/path/to/foo/", "foo")); diff --git a/lldb/unittests/Utility/CMakeLists.txt b/lldb/unittests/Utility/CMakeLists.txt index 8dc13327b9b0e..876fb9268c3e4 100644 --- a/lldb/unittests/Utility/CMakeLists.txt +++ b/lldb/unittests/Utility/CMakeLists.txt @@ -41,6 +41,7 @@ add_lldb_unittest(UtilityTests UUIDTest.cpp VASprintfTest.cpp VMRangeTest.cpp + XcodeSDKTest.cpp LINK_LIBS lldbUtility diff --git a/lldb/unittests/Utility/XcodeSDKTest.cpp b/lldb/unittests/Utility/XcodeSDKTest.cpp new file mode 100644 index 0000000000000..a316516a16758 --- /dev/null +++ b/lldb/unittests/Utility/XcodeSDKTest.cpp @@ -0,0 +1,86 @@ +//===-- XcodeSDKTest.cpp --------------------------------------------------===// +// +// 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 "gtest/gtest.h" + +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/XcodeSDK.h" + +#include "llvm/ADT/StringRef.h" + +#include + +using namespace lldb_private; + +TEST(XcodeSDKTest, ParseTest) { + EXPECT_EQ(XcodeSDK::GetAnyMacOS().GetType(), XcodeSDK::MacOSX); + EXPECT_EQ(XcodeSDK("MacOSX.sdk").GetType(), XcodeSDK::MacOSX); + EXPECT_EQ(XcodeSDK("iPhoneSimulator.sdk").GetType(), XcodeSDK::iPhoneSimulator); + EXPECT_EQ(XcodeSDK("iPhoneOS.sdk").GetType(), XcodeSDK::iPhoneOS); + EXPECT_EQ(XcodeSDK("AppleTVSimulator.sdk").GetType(), XcodeSDK::AppleTVSimulator); + EXPECT_EQ(XcodeSDK("AppleTVOS.sdk").GetType(), XcodeSDK::AppleTVOS); + EXPECT_EQ(XcodeSDK("WatchSimulator.sdk").GetType(), XcodeSDK::WatchSimulator); + EXPECT_EQ(XcodeSDK("WatchOS.sdk").GetType(), XcodeSDK::watchOS); + EXPECT_EQ(XcodeSDK("Linux.sdk").GetType(), XcodeSDK::Linux); + EXPECT_EQ(XcodeSDK("MacOSX.sdk").GetVersion(), llvm::VersionTuple()); + EXPECT_EQ(XcodeSDK("MacOSX10.9.sdk").GetVersion(), llvm::VersionTuple(10, 9)); + EXPECT_EQ(XcodeSDK("MacOSX10.15.4.sdk").GetVersion(), llvm::VersionTuple(10, 15)); + EXPECT_EQ(XcodeSDK().GetType(), XcodeSDK::unknown); + EXPECT_EQ(XcodeSDK().GetVersion(), llvm::VersionTuple()); +} + +TEST(XcodeSDKTest, MergeTest) { + XcodeSDK sdk("MacOSX.sdk"); + sdk.Merge(XcodeSDK("WatchOS.sdk")); + // This doesn't make any particular sense and shouldn't happen in practice, we + // just want to guarantee a well-defined behavior when choosing one + // SDK to fit all CUs in an lldb::Module. + // -> The higher number wins. + EXPECT_EQ(sdk.GetType(), XcodeSDK::watchOS); + sdk.Merge(XcodeSDK("WatchOS1.1.sdk")); + EXPECT_EQ(sdk.GetVersion(), llvm::VersionTuple(1, 1)); + sdk.Merge(XcodeSDK("WatchOS2.0.sdk")); + EXPECT_EQ(sdk.GetVersion(), llvm::VersionTuple(2, 0)); +} + +TEST(XcodeSDKTest, SDKSupportsModules) { + std::string base = "/Applications/Xcode.app/Contents/Developer/Platforms/"; + EXPECT_TRUE(XcodeSDK::SDKSupportsModules( + XcodeSDK::Type::iPhoneSimulator, + FileSpec( + base + + "iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator12.0.sdk"))); + EXPECT_FALSE(XcodeSDK::SDKSupportsModules( + XcodeSDK::Type::iPhoneSimulator, + FileSpec( + base + + "iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator7.2.sdk"))); + EXPECT_TRUE(XcodeSDK::SDKSupportsModules( + XcodeSDK::Type::MacOSX, + FileSpec(base + "MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk"))); + EXPECT_FALSE(XcodeSDK::SDKSupportsModules( + XcodeSDK::Type::MacOSX, + FileSpec(base + "MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk"))); +} + +TEST(XcodeSDKTest, GetSDKNameForType) { + EXPECT_EQ("macosx", XcodeSDK::GetSDKNameForType(XcodeSDK::Type::MacOSX)); + EXPECT_EQ("iphonesimulator", + XcodeSDK::GetSDKNameForType(XcodeSDK::Type::iPhoneSimulator)); + EXPECT_EQ("iphoneos", XcodeSDK::GetSDKNameForType(XcodeSDK::Type::iPhoneOS)); + EXPECT_EQ("appletvsimulator", + XcodeSDK::GetSDKNameForType(XcodeSDK::Type::AppleTVSimulator)); + EXPECT_EQ("appletvos", + XcodeSDK::GetSDKNameForType(XcodeSDK::Type::AppleTVOS)); + EXPECT_EQ("watchsimulator", + XcodeSDK::GetSDKNameForType(XcodeSDK::Type::WatchSimulator)); + EXPECT_EQ("watchos", XcodeSDK::GetSDKNameForType(XcodeSDK::Type::watchOS)); + EXPECT_EQ("linux", XcodeSDK::GetSDKNameForType(XcodeSDK::Type::Linux)); + EXPECT_EQ("", XcodeSDK::GetSDKNameForType(XcodeSDK::Type::numSDKTypes)); + EXPECT_EQ("", XcodeSDK::GetSDKNameForType(XcodeSDK::Type::unknown)); +} From abe0c69b299ac0a1dcae2384ae4da03e4406a648 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Mon, 6 Apr 2020 17:28:53 -0700 Subject: [PATCH 245/286] Add missing include (cherry picked from commit 469580a9677473f4ee19d80861f7a5da4e0f316d) --- lldb/include/lldb/Target/Platform.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/include/lldb/Target/Platform.h b/lldb/include/lldb/Target/Platform.h index 0e37e36498df3..521f7c8f4afe1 100644 --- a/lldb/include/lldb/Target/Platform.h +++ b/lldb/include/lldb/Target/Platform.h @@ -26,6 +26,7 @@ #include "lldb/Utility/StructuredData.h" #include "lldb/Utility/Timeout.h" #include "lldb/Utility/UserIDResolver.h" +#include "lldb/Utility/XcodeSDK.h" #include "lldb/lldb-private-forward.h" #include "lldb/lldb-public.h" #include "llvm/Support/VersionTuple.h" From ec30e0029d1f38169f37b81845a5ffe547ab6386 Mon Sep 17 00:00:00 2001 From: Eric Christopher Date: Fri, 3 Apr 2020 17:58:59 -0700 Subject: [PATCH 246/286] Fix unused variable, format, and format string warnings. NFC. (cherry picked from commit 3ccd454c102b069d2230a18cfe16b84a5f005fc8) --- lldb/include/lldb/Target/ThreadPlanStack.h | 2 +- lldb/source/Commands/CommandObjectThread.cpp | 1 - lldb/source/Target/ThreadPlan.cpp | 2 +- lldb/source/Target/ThreadPlanStack.cpp | 6 +----- lldb/source/Target/ThreadPlanStepRange.cpp | 1 - 5 files changed, 3 insertions(+), 9 deletions(-) diff --git a/lldb/include/lldb/Target/ThreadPlanStack.h b/lldb/include/lldb/Target/ThreadPlanStack.h index 6018f2d8925fe..342195346806b 100644 --- a/lldb/include/lldb/Target/ThreadPlanStack.h +++ b/lldb/include/lldb/Target/ThreadPlanStack.h @@ -125,7 +125,7 @@ class ThreadPlanStackMap { void AddThread(Thread &thread) { lldb::tid_t tid = thread.GetID(); - auto result = m_plans_list.emplace(tid, thread); + m_plans_list.emplace(tid, thread); } bool RemoveTID(lldb::tid_t tid) { diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp index 0f64219a1dbef..a9c81176e1666 100644 --- a/lldb/source/Commands/CommandObjectThread.cpp +++ b/lldb/source/Commands/CommandObjectThread.cpp @@ -2061,7 +2061,6 @@ class CommandObjectThreadPlanPrune : public CommandObjectParsed { return true; } - bool success; const size_t num_args = args.GetArgumentCount(); std::lock_guard guard( diff --git a/lldb/source/Target/ThreadPlan.cpp b/lldb/source/Target/ThreadPlan.cpp index 9d393ff4fd843..48bba704d06e7 100644 --- a/lldb/source/Target/ThreadPlan.cpp +++ b/lldb/source/Target/ThreadPlan.cpp @@ -24,7 +24,7 @@ ThreadPlan::ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread, : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()), m_stop_vote(stop_vote), m_run_vote(run_vote), m_takes_iteration_count(false), m_could_not_resolve_hw_bp(false), - m_kind(kind), m_thread(&thread), m_name(name), m_plan_complete_mutex(), + m_thread(&thread), m_kind(kind), m_name(name), m_plan_complete_mutex(), m_cached_plan_explains_stop(eLazyBoolCalculate), m_plan_complete(false), m_plan_private(false), m_okay_to_discard(true), m_is_master_plan(false), m_plan_succeeded(true) { diff --git a/lldb/source/Target/ThreadPlanStack.cpp b/lldb/source/Target/ThreadPlanStack.cpp index ec9ee6c3fc5d2..2472a2f488744 100644 --- a/lldb/source/Target/ThreadPlanStack.cpp +++ b/lldb/source/Target/ThreadPlanStack.cpp @@ -39,9 +39,6 @@ ThreadPlanStack::ThreadPlanStack(const Thread &thread, bool make_null) { void ThreadPlanStack::DumpThreadPlans(Stream &s, lldb::DescriptionLevel desc_level, bool include_internal) const { - - uint32_t stack_size; - s.IndentMore(); PrintOneStack(s, "Active plan stack", m_plans, desc_level, include_internal); PrintOneStack(s, "Completed plan stack", m_completed_plans, desc_level, @@ -73,7 +70,7 @@ void ThreadPlanStack::PrintOneStack(Stream &s, llvm::StringRef stack_name, if (include_internal || any_public) { int print_idx = 0; s.Indent(); - s.Printf("%s:\n", stack_name); + s << stack_name << ":\n"; for (auto plan : stack) { if (!include_internal && plan->GetPrivate()) continue; @@ -270,7 +267,6 @@ lldb::ThreadPlanSP ThreadPlanStack::GetCompletedPlan(bool skip_private) const { lldb::ThreadPlanSP ThreadPlanStack::GetPlanByIndex(uint32_t plan_idx, bool skip_private) const { uint32_t idx = 0; - ThreadPlan *up_to_plan_ptr = nullptr; for (lldb::ThreadPlanSP plan_sp : m_plans) { if (skip_private && plan_sp->GetPrivate()) diff --git a/lldb/source/Target/ThreadPlanStepRange.cpp b/lldb/source/Target/ThreadPlanStepRange.cpp index 3a0e1eb686c4e..dd0ae95ea97aa 100644 --- a/lldb/source/Target/ThreadPlanStepRange.cpp +++ b/lldb/source/Target/ThreadPlanStepRange.cpp @@ -86,7 +86,6 @@ void ThreadPlanStepRange::AddRange(const AddressRange &new_range) { } void ThreadPlanStepRange::DumpRanges(Stream *s) { - Thread &thread = GetThread(); size_t num_ranges = m_address_ranges.size(); if (num_ranges == 1) { m_address_ranges[0].Dump(s, &GetTarget(), Address::DumpStyleLoadAddress); From ecd83eed8f8c60e63eb45bd416d7ac07e4ce1797 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Mon, 13 Apr 2020 12:59:42 -0700 Subject: [PATCH 247/286] Adapt to upstream changes (XcodeSDK). --- lldb/source/Symbol/SwiftASTContext.cpp | 128 ++++++++----------------- 1 file changed, 42 insertions(+), 86 deletions(-) diff --git a/lldb/source/Symbol/SwiftASTContext.cpp b/lldb/source/Symbol/SwiftASTContext.cpp index 12a72bb0c1a6e..cb0d2a4acb466 100644 --- a/lldb/source/Symbol/SwiftASTContext.cpp +++ b/lldb/source/Symbol/SwiftASTContext.cpp @@ -118,6 +118,7 @@ #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/Status.h" +#include "lldb/Utility/XcodeSDK.h" #include "llvm/ADT/ScopeExit.h" #include "Plugins/Platform/MacOSX/PlatformDarwin.h" @@ -950,7 +951,7 @@ uint32_t SwiftASTContext::GetPluginVersion() { return 1; } namespace { struct SDKTypeMinVersion { - PlatformDarwin::SDKType sdk_type; + XcodeSDK::Type sdk_type; unsigned min_version_major; unsigned min_version_minor; }; @@ -964,7 +965,7 @@ static SDKTypeMinVersion GetSDKType(const llvm::Triple &target, // Only Darwin platforms know the concept of an SDK. auto host_os = host.getOS(); if (host_os != llvm::Triple::OSType::MacOSX) - return {PlatformDarwin::SDKType::unknown, 0, 0}; + return {XcodeSDK::Type::unknown, 0, 0}; auto is_simulator = [&]() -> bool { return target.getEnvironment() == llvm::Triple::Simulator || @@ -974,21 +975,21 @@ static SDKTypeMinVersion GetSDKType(const llvm::Triple &target, switch (target.getOS()) { case llvm::Triple::OSType::MacOSX: case llvm::Triple::OSType::Darwin: - return {PlatformDarwin::SDKType::MacOSX, 10, 10}; + return {XcodeSDK::Type::MacOSX, 10, 10}; case llvm::Triple::OSType::IOS: if (is_simulator()) - return {PlatformDarwin::SDKType::iPhoneSimulator, 8, 0}; - return {PlatformDarwin::SDKType::iPhoneOS, 8, 0}; + return {XcodeSDK::Type::iPhoneSimulator, 8, 0}; + return {XcodeSDK::Type::iPhoneOS, 8, 0}; case llvm::Triple::OSType::TvOS: if (is_simulator()) - return {PlatformDarwin::SDKType::AppleTVSimulator, 9, 0}; - return {PlatformDarwin::SDKType::AppleTVOS, 9, 0}; + return {XcodeSDK::Type::AppleTVSimulator, 9, 0}; + return {XcodeSDK::Type::AppleTVOS, 9, 0}; case llvm::Triple::OSType::WatchOS: if (is_simulator()) - return {PlatformDarwin::SDKType::WatchSimulator, 2, 0}; - return {PlatformDarwin::SDKType::watchOS, 2, 0}; + return {XcodeSDK::Type::WatchSimulator, 2, 0}; + return {XcodeSDK::Type::watchOS, 2, 0}; default: - return {PlatformDarwin::SDKType::unknown, 0, 0}; + return {XcodeSDK::Type::unknown, 0, 0}; } } @@ -997,7 +998,7 @@ static SDKTypeMinVersion GetSDKType(const llvm::Triple &target, StringRef SwiftASTContext::GetSwiftStdlibOSDir(const llvm::Triple &target, const llvm::Triple &host) { auto sdk = GetSDKType(target, host); - llvm::StringRef sdk_name = PlatformDarwin::GetSDKNameForType(sdk.sdk_type); + llvm::StringRef sdk_name = XcodeSDK::GetSDKNameForType(sdk.sdk_type); if (!sdk_name.empty()) return sdk_name; return target.getOSName(); @@ -2342,7 +2343,7 @@ namespace { struct SDKEnumeratorInfo { FileSpec found_path; - PlatformDarwin::SDKType sdk_type; + XcodeSDK::Type sdk_type; uint32_t least_major; uint32_t least_minor; }; @@ -2350,91 +2351,46 @@ struct SDKEnumeratorInfo { } // anonymous namespace static bool SDKSupportsSwift(const FileSpec &sdk_path, - PlatformDarwin::SDKType desired_type) { + XcodeSDK::Type desired_type) { ConstString last_path_component = sdk_path.GetLastPathComponent(); if (last_path_component) { const llvm::StringRef sdk_name_raw = last_path_component.GetStringRef(); - std::string sdk_name_lower = sdk_name_raw.lower(); - const llvm::StringRef sdk_name(sdk_name_lower); - - llvm::StringRef version_part; - - PlatformDarwin::SDKType sdk_type = PlatformDarwin::SDKType::unknown; - - if (desired_type == PlatformDarwin::SDKType::unknown) { - for (int i = (int)PlatformDarwin::SDKType::MacOSX; - i < PlatformDarwin::SDKType::numSDKTypes; ++i) { - PlatformDarwin::SDKType this_type = - static_cast(i); - llvm::StringRef this_sdk_name = - PlatformDarwin::GetSDKNameForType(this_type); - if (sdk_name.startswith(this_sdk_name)) { - version_part = sdk_name.drop_front(this_sdk_name.size()); - sdk_type = this_type; - break; - } - } - - // For non-Darwin SDKs assume Swift is supported - if (sdk_type == PlatformDarwin::SDKType::unknown) - return true; - } else { - llvm::StringRef desired_sdk_name = - PlatformDarwin::GetSDKNameForType(desired_type); - if (sdk_name.startswith(desired_sdk_name)) { - version_part = sdk_name.drop_front(desired_sdk_name.size()); - sdk_type = desired_type; - } else { - return false; - } - } + XcodeSDK sdk(sdk_name_raw); + XcodeSDK::Type sdk_type = sdk.GetType(); - const size_t major_dot_offset = version_part.find('.'); - if (major_dot_offset == llvm::StringRef::npos) - return false; - - const llvm::StringRef major_version = - version_part.slice(0, major_dot_offset); - const llvm::StringRef minor_part = - version_part.drop_front(major_dot_offset + 1); - - const size_t minor_dot_offset = minor_part.find('.'); - if (minor_dot_offset == llvm::StringRef::npos) - return false; - - const llvm::StringRef minor_version = minor_part.slice(0, minor_dot_offset); - - unsigned int major = 0; - unsigned int minor = 0; - - if (major_version.getAsInteger(10, major)) - return false; + // For non-Darwin SDKs assume Swift is supported. + if (desired_type == XcodeSDK::Type::unknown && + sdk_type == XcodeSDK::Type::unknown) + return true; - if (minor_version.getAsInteger(10, minor)) + if (sdk_type != desired_type) return false; + llvm::VersionTuple sdk_version = sdk.GetVersion(); + unsigned major = sdk_version.getMajor(); + unsigned minor = sdk_version.getMinor().getValueOr(0); switch (sdk_type) { - case PlatformDarwin::SDKType::MacOSX: + case XcodeSDK::Type::MacOSX: if (major > 10 || (major == 10 && minor >= 10)) return true; break; - case PlatformDarwin::SDKType::iPhoneOS: - case PlatformDarwin::SDKType::iPhoneSimulator: + case XcodeSDK::Type::iPhoneOS: + case XcodeSDK::Type::iPhoneSimulator: if (major >= 8) return true; break; - case PlatformDarwin::SDKType::AppleTVSimulator: - case PlatformDarwin::SDKType::AppleTVOS: + case XcodeSDK::Type::AppleTVSimulator: + case XcodeSDK::Type::AppleTVOS: if (major >= 9) return true; break; - case PlatformDarwin::SDKType::WatchSimulator: - case PlatformDarwin::SDKType::watchOS: + case XcodeSDK::Type::WatchSimulator: + case XcodeSDK::Type::watchOS: if (major >= 2) return true; break; - case PlatformDarwin::SDKType::Linux: + case XcodeSDK::Type::Linux: return true; default: return false; @@ -2458,7 +2414,7 @@ DirectoryEnumerator(void *baton, llvm::sys::fs::file_type file_type, }; static ConstString EnumerateSDKsForVersion(FileSpec sdks_spec, - PlatformDarwin::SDKType sdk_type, + XcodeSDK::Type sdk_type, uint32_t least_major, uint32_t least_minor) { if (!IsDirectory(sdks_spec)) @@ -2484,24 +2440,24 @@ static ConstString EnumerateSDKsForVersion(FileSpec sdks_spec, return ConstString(); } -static ConstString GetSDKDirectory(PlatformDarwin::SDKType sdk_type, +static ConstString GetSDKDirectory(XcodeSDK::Type sdk_type, uint32_t least_major, uint32_t least_minor) { using namespace llvm::sys; - if (sdk_type != PlatformDarwin::SDKType::MacOSX) { + if (sdk_type != XcodeSDK::Type::MacOSX) { // Look inside Xcode for the required installed iOS SDK version. llvm::SmallString<256> sdks_path( PlatformDarwin::GetXcodeContentsDirectory().GetPath()); path::append(sdks_path, "Developer", "Platforms"); - if (sdk_type == PlatformDarwin::SDKType::iPhoneSimulator) { + if (sdk_type == XcodeSDK::Type::iPhoneSimulator) { path::append(sdks_path, "iPhoneSimulator.platform"); - } else if (sdk_type == PlatformDarwin::SDKType::AppleTVSimulator) { + } else if (sdk_type == XcodeSDK::Type::AppleTVSimulator) { path::append(sdks_path, "AppleTVSimulator.platform"); - } else if (sdk_type == PlatformDarwin::SDKType::AppleTVOS) { + } else if (sdk_type == XcodeSDK::Type::AppleTVOS) { path::append(sdks_path, "AppleTVOS.platform"); - } else if (sdk_type == PlatformDarwin::SDKType::WatchSimulator) { + } else if (sdk_type == XcodeSDK::Type::WatchSimulator) { path::append(sdks_path, "WatchSimulator.platform"); - } else if (sdk_type == PlatformDarwin::SDKType::watchOS) { + } else if (sdk_type == XcodeSDK::Type::watchOS) { // For now, we need to be prepared to handle either capitalization of // this path. llvm::SmallString<256> candidate_path = sdks_path; @@ -2718,7 +2674,7 @@ void SwiftASTContext::InitializeSearchPathOptions( FileSpec platform_sdk(m_platform_sdk_path.c_str()); if (FileSystem::Instance().Exists(platform_sdk) && - SDKSupportsSwift(platform_sdk, PlatformDarwin::SDKType::unknown)) { + SDKSupportsSwift(platform_sdk, XcodeSDK::Type::unknown)) { invocation.setSDKPath(m_platform_sdk_path.c_str()); set_sdk = true; } @@ -2737,7 +2693,7 @@ void SwiftASTContext::InitializeSearchPathOptions( if (!set_sdk) { auto sdk = GetSDKType(triple, HostInfo::GetArchitecture().GetTriple()); // Explicitly leave the SDKPath blank on other platforms. - if (sdk.sdk_type != PlatformDarwin::SDKType::unknown) { + if (sdk.sdk_type != XcodeSDK::Type::unknown) { auto dir = GetSDKDirectory(sdk.sdk_type, sdk.min_version_major, sdk.min_version_minor); // Note that calling setSDKPath() also recomputes all paths that From 10d1b56387c51fde3c358f2fbf049543e42ecc2c Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Mon, 13 Apr 2020 14:11:08 -0700 Subject: [PATCH 248/286] Implement TypeSystemSwiftTypeRef::IsFunctionPointerType() (NFC) --- lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp | 4 +++- lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp index 6d7310197c33f..039a9ec12b335 100644 --- a/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp +++ b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp @@ -514,7 +514,9 @@ TypeSystemSwiftTypeRef::GetFunctionArgumentAtIndex(void *type, ReconstructType(type), index)); } bool TypeSystemSwiftTypeRef::IsFunctionPointerType(void *type) { - return m_swift_ast_context->IsFunctionPointerType(ReconstructType(type)); + auto impl = [&]() -> bool { return IsFunctionType(type, nullptr); }; + VALIDATE_AND_RETURN( + impl, m_swift_ast_context->IsFunctionPointerType(ReconstructType(type))); } bool TypeSystemSwiftTypeRef::IsIntegerType(void *type, bool &is_signed) { return m_swift_ast_context->IsIntegerType(ReconstructType(type), is_signed); diff --git a/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp b/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp index 7bd52f9db6682..dc536aba3a559 100644 --- a/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp +++ b/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp @@ -115,6 +115,7 @@ TEST_F(TestTypeSystemSwiftTypeRef, Function) { b.Node(Node::Kind::Tuple))))))); CompilerType void_void = GetCompilerType(b.Mangle(n)); ASSERT_TRUE(void_void.IsFunctionType(nullptr)); + ASSERT_TRUE(void_void.IsFunctionPointerType()); ASSERT_EQ(void_void.GetNumberOfFunctionArguments(), 0); } { From f8655c34491bbd470effc32728e13b1e34449607 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Fri, 10 Apr 2020 10:34:08 -0700 Subject: [PATCH 249/286] Attempt to fix a compile error reported with older compilers and libstdc++ (cherry picked from commit f5be71b44500b18d636b1f540422dda4012ac192) --- lldb/source/Utility/XcodeSDK.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lldb/source/Utility/XcodeSDK.cpp b/lldb/source/Utility/XcodeSDK.cpp index f2403f10de553..7ad0090f85e2d 100644 --- a/lldb/source/Utility/XcodeSDK.cpp +++ b/lldb/source/Utility/XcodeSDK.cpp @@ -69,7 +69,8 @@ std::tuple XcodeSDK::Parse() const { llvm::StringRef input(m_name); XcodeSDK::Type sdk = ParseSDKName(input); llvm::VersionTuple version = ParseSDKVersion(input); - return {sdk, version}; + return std::make_tuple( + std::move(sdk), std::move(version)); } llvm::VersionTuple XcodeSDK::GetVersion() const { From 0bdf7efda2508c718261b11c8e1d359a0a1b544c Mon Sep 17 00:00:00 2001 From: Walter Erquinigo Date: Fri, 3 Apr 2020 19:49:07 -0700 Subject: [PATCH 250/286] Fix LLDB debug builds Summary: A recent change in ThreadPlans introduced this little compilation error. Seems to be related to the work around https://reviews.llvm.org/D76814. Reviewers: clayborg, labath, jingham Reviewed By: jingham Subscribers: lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D77450 --- lldb/source/Target/ThreadPlan.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/source/Target/ThreadPlan.cpp b/lldb/source/Target/ThreadPlan.cpp index 48bba704d06e7..76dcc63f65783 100644 --- a/lldb/source/Target/ThreadPlan.cpp +++ b/lldb/source/Target/ThreadPlan.cpp @@ -240,7 +240,7 @@ bool ThreadPlanNull::DoPlanExplainsStop(Event *event_ptr) { fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); + LLVM_PRETTY_FUNCTION, GetThread().GetID(), GetThread().GetProtocolID()); #else Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); if (log) From 3c59cc0ea2c9170865c38ec004e44f49ca1619eb Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Mon, 13 Apr 2020 15:47:35 -0700 Subject: [PATCH 251/286] Implement TypeSystemSwiftTypeRef::IsPointerType() (NFC) --- lldb/include/lldb/Symbol/SwiftASTContext.h | 6 ++ lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp | 98 +++++++++---------- .../Symbol/TestTypeSystemSwiftTypeRef.cpp | 46 +++++++++ 3 files changed, 98 insertions(+), 52 deletions(-) diff --git a/lldb/include/lldb/Symbol/SwiftASTContext.h b/lldb/include/lldb/Symbol/SwiftASTContext.h index dc11cac892ff5..061a50231c441 100644 --- a/lldb/include/lldb/Symbol/SwiftASTContext.h +++ b/lldb/include/lldb/Symbol/SwiftASTContext.h @@ -421,6 +421,12 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift { CompilerType RemangleAsType(swift::Demangle::Demangler &Dem, swift::Demangle::NodePointer node); + /// Demangle the mangled name of the canonical type of \p type and + /// drill into the Global(TypeMangling(Type())). + /// + /// \return the child of Type or a nullptr. + swift::Demangle::NodePointer + DemangleCanonicalType(swift::Demangle::Demangler &Dem, void *opaque_type); /// The sibling SwiftASTContext. SwiftASTContext *m_swift_ast_context = nullptr; }; diff --git a/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp index 039a9ec12b335..8bea18145f7fd 100644 --- a/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp +++ b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp @@ -337,26 +337,34 @@ TypeSystemSwiftTypeRef::RemangleAsType(swift::Demangle::Demangler &Dem, return GetTypeFromMangledTypename(mangled_element); } +swift::Demangle::NodePointer +TypeSystemSwiftTypeRef::DemangleCanonicalType(swift::Demangle::Demangler &Dem, + void *opaque_type) { + using namespace swift::Demangle; + NodePointer node = + GetCanonicalDemangleTree(GetModule(), Dem, AsMangledName(opaque_type)); + + if (!node || node->getNumChildren() != 1 || + node->getKind() != Node::Kind::Global) + return nullptr; + node = node->getFirstChild(); + if (node->getNumChildren() != 1 || + node->getKind() != Node::Kind::TypeMangling) + return nullptr; + node = node->getFirstChild(); + if (node->getNumChildren() != 1 || node->getKind() != Node::Kind::Type) + return nullptr; + node = node->getFirstChild(); + return node; +} + bool TypeSystemSwiftTypeRef::IsArrayType(void *type, CompilerType *element_type, uint64_t *size, bool *is_incomplete) { auto impl = [&]() { using namespace swift::Demangle; Demangler Dem; - NodePointer node = - GetCanonicalDemangleTree(GetModule(), Dem, AsMangledName(type)); - - if (!node || node->getNumChildren() != 1 || - node->getKind() != Node::Kind::Global) - return false; - node = node->getFirstChild(); - if (node->getNumChildren() != 1 || - node->getKind() != Node::Kind::TypeMangling) - return false; - node = node->getFirstChild(); - if (node->getNumChildren() != 1 || node->getKind() != Node::Kind::Type) - return false; - node = node->getFirstChild(); - if (node->getNumChildren() != 2 || + NodePointer node = DemangleCanonicalType(Dem, type); + if (!node || node->getNumChildren() != 2 || node->getKind() != Node::Kind::BoundGenericStructure) return false; auto elem_node = node->getChild(1); @@ -405,33 +413,13 @@ bool TypeSystemSwiftTypeRef::IsFloatingPointType(void *type, uint32_t &count, is_complex); } -/// Drill into a function type. -static NodePointer GetFunctionTypeNode(NodePointer node) { - using namespace swift::Demangle; - if (!node || node->getNumChildren() != 1 || - node->getKind() != Node::Kind::Global) - return nullptr; - node = node->getFirstChild(); - if (node->getNumChildren() != 1 || - node->getKind() != Node::Kind::TypeMangling) - return nullptr; - node = node->getFirstChild(); - if (node->getNumChildren() != 1 || node->getKind() != Node::Kind::Type) - return nullptr; - node = node->getFirstChild(); - if (node->getKind() != Node::Kind::FunctionType && - node->getKind() != Node::Kind::ImplFunctionType) - return nullptr; - return node; -} - bool TypeSystemSwiftTypeRef::IsFunctionType(void *type, bool *is_variadic_ptr) { auto impl = [&]() -> bool { using namespace swift::Demangle; Demangler Dem; - NodePointer node = - GetCanonicalDemangleTree(GetModule(), Dem, AsMangledName(type)); - return GetFunctionTypeNode(node); + NodePointer node = DemangleCanonicalType(Dem, type); + return node && (node->getKind() == Node::Kind::FunctionType || + node->getKind() == Node::Kind::ImplFunctionType); }; VALIDATE_AND_RETURN(impl, m_swift_ast_context->IsFunctionType( ReconstructType(type), nullptr)); @@ -440,12 +428,9 @@ size_t TypeSystemSwiftTypeRef::GetNumberOfFunctionArguments(void *type) { auto impl = [&]() -> size_t { using namespace swift::Demangle; Demangler Dem; - NodePointer node = - GetCanonicalDemangleTree(GetModule(), Dem, AsMangledName(type)); - if (!node) - return 0; - node = GetFunctionTypeNode(node); - if (!node) + NodePointer node = DemangleCanonicalType(Dem, type); + if (!node || (node->getKind() != Node::Kind::FunctionType && + node->getKind() != Node::Kind::ImplFunctionType)) return 0; unsigned num_args = 0; for (NodePointer child : *node) { @@ -473,12 +458,9 @@ TypeSystemSwiftTypeRef::GetFunctionArgumentAtIndex(void *type, auto impl = [&]() -> CompilerType { using namespace swift::Demangle; Demangler Dem; - NodePointer node = - GetCanonicalDemangleTree(GetModule(), Dem, AsMangledName(type)); - if (!node) - return {}; - node = GetFunctionTypeNode(node); - if (!node) + NodePointer node = DemangleCanonicalType(Dem, type); + if (!node || (node->getKind() != Node::Kind::FunctionType && + node->getKind() != Node::Kind::ImplFunctionType)) return {}; unsigned num_args = 0; for (NodePointer child : *node) { @@ -530,8 +512,20 @@ bool TypeSystemSwiftTypeRef::IsPossibleDynamicType(void *type, } bool TypeSystemSwiftTypeRef::IsPointerType(void *type, CompilerType *pointee_type) { - return m_swift_ast_context->IsPointerType(ReconstructType(type), - pointee_type); + auto impl = [&]() { + using namespace swift::Demangle; + Demangler Dem; + NodePointer node = DemangleCanonicalType(Dem, type); + if (!node || node->getKind() != Node::Kind::BuiltinTypeName || + !node->hasText()) + return false; + return ((node->getText() == swift::BUILTIN_TYPE_NAME_RAWPOINTER) || + (node->getText() == swift::BUILTIN_TYPE_NAME_UNSAFEVALUEBUFFER) || + (node->getText() == swift::BUILTIN_TYPE_NAME_NATIVEOBJECT) || + (node->getText() == swift::BUILTIN_TYPE_NAME_BRIDGEOBJECT)); + }; + VALIDATE_AND_RETURN(impl, m_swift_ast_context->IsPointerType(ReconstructType(type), + pointee_type)); } bool TypeSystemSwiftTypeRef::IsScalarType(void *type) { return m_swift_ast_context->IsScalarType(ReconstructType(type)); diff --git a/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp b/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp index dc536aba3a559..80945981d5698 100644 --- a/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp +++ b/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp @@ -177,3 +177,49 @@ TEST_F(TestTypeSystemSwiftTypeRef, Function) { ASSERT_EQ(two_args.GetFunctionArgumentAtIndex(1), void_type); } } + +TEST_F(TestTypeSystemSwiftTypeRef, Pointer) { + using namespace swift::Demangle; + Demangler dem; + NodeBuilder b(dem); + { + NodePointer n = + b.Node(Node::Kind::Global, + b.Node(Node::Kind::TypeMangling, + b.Node(Node::Kind::Type, + b.Node(Node::Kind::BuiltinTypeName, + swift::BUILTIN_TYPE_NAME_RAWPOINTER)))); + CompilerType p = GetCompilerType(b.Mangle(n)); + ASSERT_TRUE(p.IsPointerType(nullptr)); + } + { + NodePointer n = + b.Node(Node::Kind::Global, + b.Node(Node::Kind::TypeMangling, + b.Node(Node::Kind::Type, + b.Node(Node::Kind::BuiltinTypeName, + swift::BUILTIN_TYPE_NAME_UNSAFEVALUEBUFFER)))); + CompilerType p = GetCompilerType(b.Mangle(n)); + ASSERT_TRUE(p.IsPointerType(nullptr)); + } + { + NodePointer n = + b.Node(Node::Kind::Global, + b.Node(Node::Kind::TypeMangling, + b.Node(Node::Kind::Type, + b.Node(Node::Kind::BuiltinTypeName, + swift::BUILTIN_TYPE_NAME_NATIVEOBJECT)))); + CompilerType p = GetCompilerType(b.Mangle(n)); + ASSERT_TRUE(p.IsPointerType(nullptr)); + } + { + NodePointer n = + b.Node(Node::Kind::Global, + b.Node(Node::Kind::TypeMangling, + b.Node(Node::Kind::Type, + b.Node(Node::Kind::BuiltinTypeName, + swift::BUILTIN_TYPE_NAME_BRIDGEOBJECT)))); + CompilerType p = GetCompilerType(b.Mangle(n)); + ASSERT_TRUE(p.IsPointerType(nullptr)); + } +} From 6a3b6b56f94fe6cd9e1e624f0f941599c8eb150c Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Mon, 6 Apr 2020 17:25:47 -0700 Subject: [PATCH 252/286] [Sanitizer Common] Show command used to launch symbolizer process at high verbosity level. Summary: In preparation for writing a test for a bug fix we need to be able to see the command used to launch the symbolizer process. This feature will likely be useful for debugging how the Sanitizers use the symbolizer in general. This patch causes the command line used to launch the process to be shown at verbosity level 3 and higher. A small test case is included. Reviewers: kubamracek, yln, vitalybuka, eugenis, kcc Subscribers: #sanitizers, llvm-commits Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D77622 (cherry picked from commit 2169568d9f535a5ffa921d7ec0869c0f8b18f6ac) --- .../sanitizer_symbolizer_posix_libcdep.cpp | 10 ++++++++++ .../TestCases/symbolize_debug_argv.cpp | 9 +++++++++ 2 files changed, 19 insertions(+) create mode 100644 compiler-rt/test/sanitizer_common/TestCases/symbolize_debug_argv.cpp diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp index 4c3cd966dd5a0..f1dff2408e113 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp @@ -151,6 +151,16 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() { GetArgV(path_, argv); pid_t pid; + // Report how symbolizer is being launched for debugging purposes. + if (Verbosity() >= 3) { + // Only use `Report` for first line so subsequent prints don't get prefixed + // with current PID. + Report("Launching Symbolizer process: "); + for (unsigned index = 0; index < kArgVMax && argv[index]; ++index) + Printf("%s ", argv[index]); + Printf("\n"); + } + if (use_posix_spawn_) { #if SANITIZER_MAC fd_t fd = internal_spawn(argv, const_cast(GetEnvP()), &pid); diff --git a/compiler-rt/test/sanitizer_common/TestCases/symbolize_debug_argv.cpp b/compiler-rt/test/sanitizer_common/TestCases/symbolize_debug_argv.cpp new file mode 100644 index 0000000000000..262e50bf7be2c --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/symbolize_debug_argv.cpp @@ -0,0 +1,9 @@ +// RUN: %clangxx %s -g -o %t +// RUN: %env_tool_opts=verbosity=3 %run %t 2>&1 | FileCheck %s +#include + +int main(int argc, char **argv) { + // CHECK: Launching Symbolizer process: {{.+}} + __sanitizer_print_stack_trace(); + return 0; +} From bcffddf04b818412d52b46fd02a5205be5d96251 Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Mon, 6 Apr 2020 18:57:54 -0700 Subject: [PATCH 253/286] [Darwin] Fix a bug where the symbolizer would examine the wrong process. Summary: Previously `AtosSymbolizer` would set the PID to examine in the constructor which is called early on during sanitizer init. This can lead to incorrect behaviour in the case of a fork() because if the symbolizer is launched in the child it will be told examine the parent process rather than the child. To fix this the PID is determined just before the symbolizer is launched. A test case is included that triggers the buggy behaviour that existed prior to this patch. The test observes the PID that `atos` was called on. It also examines the symbolized stacktrace. Prior to this patch `atos` failed to symbolize the stacktrace giving output that looked like... ``` #0 0x100fc3bb5 in __sanitizer_print_stack_trace asan_stack.cpp:86 #1 0x10490dd36 in PrintStack+0x56 (/path/to/print-stack-trace-in-code-loaded-after-fork.cpp.tmp_shared_lib.dylib:x86_64+0xd36) #2 0x100f6f986 in main+0x4a6 (/path/to/print-stack-trace-in-code-loaded-after-fork.cpp.tmp_loader:x86_64+0x100001986) #3 0x7fff714f1cc8 in start+0x0 (/usr/lib/system/libdyld.dylib:x86_64+0x1acc8) ``` After this patch stackframes `#1` and `#2` are fully symbolized. This patch is also a pre-requisite refactor for rdar://problem/58789439. Reviewers: kubamracek, yln Subscribers: #sanitizers, llvm-commits Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D77623 (cherry picked from commit 8efc3ccaf808caeba395f71449524830f7fe1d09) --- .../sanitizer_symbolizer_mac.cpp | 13 ++-- ...-stack-trace-in-code-loaded-after-fork.cpp | 60 +++++++++++++++++++ 2 files changed, 68 insertions(+), 5 deletions(-) create mode 100644 compiler-rt/test/sanitizer_common/TestCases/Darwin/print-stack-trace-in-code-loaded-after-fork.cpp diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp index f26efe5c50b55..1379ed82d03d1 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp @@ -52,16 +52,19 @@ bool DlAddrSymbolizer::SymbolizeData(uptr addr, DataInfo *datainfo) { class AtosSymbolizerProcess : public SymbolizerProcess { public: - explicit AtosSymbolizerProcess(const char *path, pid_t parent_pid) + explicit AtosSymbolizerProcess(const char *path) : SymbolizerProcess(path, /*use_posix_spawn*/ true) { - // Put the string command line argument in the object so that it outlives - // the call to GetArgV. - internal_snprintf(pid_str_, sizeof(pid_str_), "%d", parent_pid); + pid_str_[0] = '\0'; } private: bool StartSymbolizerSubprocess() override { // Configure sandbox before starting atos process. + + // Put the string command line argument in the object so that it outlives + // the call to GetArgV. + internal_snprintf(pid_str_, sizeof(pid_str_), "%d", internal_getpid()); + return SymbolizerProcess::StartSymbolizerSubprocess(); } @@ -138,7 +141,7 @@ static bool ParseCommandOutput(const char *str, uptr addr, char **out_name, } AtosSymbolizer::AtosSymbolizer(const char *path, LowLevelAllocator *allocator) - : process_(new(*allocator) AtosSymbolizerProcess(path, getpid())) {} + : process_(new (*allocator) AtosSymbolizerProcess(path)) {} bool AtosSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { if (!process_) return false; diff --git a/compiler-rt/test/sanitizer_common/TestCases/Darwin/print-stack-trace-in-code-loaded-after-fork.cpp b/compiler-rt/test/sanitizer_common/TestCases/Darwin/print-stack-trace-in-code-loaded-after-fork.cpp new file mode 100644 index 0000000000000..db4cdf8f9b6da --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/Darwin/print-stack-trace-in-code-loaded-after-fork.cpp @@ -0,0 +1,60 @@ +// RUN: %clangxx %s -g -DSHARED_LIB -shared -o %t_shared_lib.dylib +// RUN: %clangxx %s -g -USHARED_LIB -o %t_loader +// RUN: %env_tool_opts=verbosity=3 %run %t_loader %t_shared_lib.dylib > %t_loader_output.txt 2>&1 +// RUN: FileCheck -input-file=%t_loader_output.txt %s +// RUN: FileCheck -check-prefix=CHECK-STACKTRACE -input-file=%t_loader_output.txt %s + +#include + +#ifdef SHARED_LIB +#include + +extern "C" void PrintStack() { + fprintf(stderr, "Calling __sanitizer_print_stack_trace\n"); + // CHECK-STACKTRACE: #0{{( *0x.* *in *)?}} __sanitizer_print_stack_trace + // CHECK-STACKTRACE: #1{{( *0x.* *in *)?}} PrintStack {{.*}}print-stack-trace-in-code-loaded-after-fork.cpp:[[@LINE+1]] + __sanitizer_print_stack_trace(); +} +#else +#include +#include +#include +#include +#include + +typedef void (*PrintStackFnPtrTy)(void); + +int main(int argc, char **argv) { + assert(argc == 2); + pid_t pid = fork(); + if (pid != 0) { + // Parent + pid_t parent_pid = getpid(); + fprintf(stderr, "parent: %d\n", parent_pid); + int status = 0; + pid_t child = waitpid(pid, &status, /*options=*/0); + assert(pid == child); + bool clean_exit = WIFEXITED(status) && WEXITSTATUS(status) == 0; + return !clean_exit; + } + // Child. + pid = getpid(); + // CHECK: child: [[CHILD_PID:[0-9]+]] + fprintf(stderr, "child: %d\n", pid); + // We load new code into the child process that isn't loaded into the parent. + // When we symbolize in `PrintStack` if the symbolizer is told to symbolize + // the parent (an old bug) rather than the child then symbolization will + // fail. + const char *library_to_load = argv[1]; + void *handle = dlopen(library_to_load, RTLD_NOW | RTLD_LOCAL); + assert(handle); + PrintStackFnPtrTy PrintStackFnPtr = (PrintStackFnPtrTy)dlsym(handle, "PrintStack"); + assert(PrintStackFnPtr); + // Check that the symbolizer is told examine the child process. + // CHECK: Launching Symbolizer process: {{.+}}atos -p [[CHILD_PID]] + // CHECK-STACKTRACE: #2{{( *0x.* *in *)?}} main {{.*}}print-stack-trace-in-code-loaded-after-fork.cpp:[[@LINE+1]] + PrintStackFnPtr(); + return 0; +} + +#endif From c5b600e0d508ae2d8edf296e3452dabdbe2e9c42 Mon Sep 17 00:00:00 2001 From: Bruno Cardoso Lopes Date: Mon, 13 Apr 2020 16:28:49 -0700 Subject: [PATCH 254/286] [Modules] Add more x86 textual headers to the module map These headers are not supposed to be included directly because they are non-modular by nature. This should also prevent other non modular include warnings. rdar://57860248 --- clang/lib/Headers/module.modulemap | 50 ++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/clang/lib/Headers/module.modulemap b/clang/lib/Headers/module.modulemap index 7954a77a41258..d6887bc63997f 100644 --- a/clang/lib/Headers/module.modulemap +++ b/clang/lib/Headers/module.modulemap @@ -40,6 +40,47 @@ module _Builtin_intrinsics [system] [extern_c] { textual header "avx512fintrin.h" textual header "avx512erintrin.h" textual header "fmaintrin.h" + textual header "adxintrin.h" + textual header "avx512bf16intrin.h" + textual header "avx512bitalgintrin.h" + textual header "avx512bwintrin.h" + textual header "avx512cdintrin.h" + textual header "avx512dqintrin.h" + textual header "avx512ifmaintrin.h" + textual header "avx512ifmavlintrin.h" + textual header "avx512pfintrin.h" + textual header "avx512vbmi2intrin.h" + textual header "avx512vbmiintrin.h" + textual header "avx512vbmivlintrin.h" + textual header "avx512vlbf16intrin.h" + textual header "avx512vlbitalgintrin.h" + textual header "avx512vlbwintrin.h" + textual header "avx512vlcdintrin.h" + textual header "avx512vldqintrin.h" + textual header "avx512vlintrin.h" + textual header "avx512vlvbmi2intrin.h" + textual header "avx512vlvnniintrin.h" + textual header "avx512vlvp2intersectintrin.h" + textual header "avx512vnniintrin.h" + textual header "avx512vp2intersectintrin.h" + textual header "avx512vpopcntdqintrin.h" + textual header "avx512vpopcntdqvlintrin.h" + textual header "cetintrin.h" + textual header "clflushoptintrin.h" + textual header "clwbintrin.h" + textual header "enqcmdintrin.h" + textual header "fxsrintrin.h" + textual header "gfniintrin.h" + textual header "pkuintrin.h" + textual header "rtmintrin.h" + textual header "shaintrin.h" + textual header "vaesintrin.h" + textual header "vpclmulqdqintrin.h" + textual header "xsavecintrin.h" + textual header "xsaveintrin.h" + textual header "xsaveoptintrin.h" + textual header "xsavesintrin.h" + textual header "xtestintrin.h" header "x86intrin.h" textual header "bmiintrin.h" @@ -57,6 +98,15 @@ module _Builtin_intrinsics [system] [extern_c] { textual header "sgxintrin.h" textual header "ptwriteintrin.h" textual header "invpcidintrin.h" + textual header "ia32intrin.h" + textual header "lwpintrin.h" + textual header "prfchwintrin.h" + textual header "rdseedintrin.h" + textual header "tbmintrin.h" + textual header "lwpintrin.h" + textual header "prfchwintrin.h" + textual header "rdseedintrin.h" + textual header "tbmintrin.h" textual header "__wmmintrin_aes.h" textual header "__wmmintrin_pclmul.h" From 84a6f7ce5b202203a5b086c58a4c85ee3b890599 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Mon, 13 Apr 2020 16:23:50 -0700 Subject: [PATCH 255/286] Implement TypeSystemSwiftTypeRef::IsVoidType() (NFC) --- lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp | 10 +++++++++- .../Symbol/TestTypeSystemSwiftTypeRef.cpp | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp index 8bea18145f7fd..6f4a01d3488c2 100644 --- a/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp +++ b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp @@ -531,7 +531,15 @@ bool TypeSystemSwiftTypeRef::IsScalarType(void *type) { return m_swift_ast_context->IsScalarType(ReconstructType(type)); } bool TypeSystemSwiftTypeRef::IsVoidType(void *type) { - return m_swift_ast_context->IsVoidType(ReconstructType(type)); + auto impl = [&]() { + using namespace swift::Demangle; + Demangler Dem; + NodePointer node = DemangleCanonicalType(Dem, type); + return node && node->getNumChildren() == 0 && + node->getKind() == Node::Kind::Tuple; + }; + VALIDATE_AND_RETURN(impl, + m_swift_ast_context->IsVoidType(ReconstructType(type))); } bool TypeSystemSwiftTypeRef::CanPassInRegisters(const CompilerType &type) { return m_swift_ast_context->CanPassInRegisters( diff --git a/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp b/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp index 80945981d5698..78dc8668006b3 100644 --- a/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp +++ b/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp @@ -223,3 +223,17 @@ TEST_F(TestTypeSystemSwiftTypeRef, Pointer) { ASSERT_TRUE(p.IsPointerType(nullptr)); } } + +TEST_F(TestTypeSystemSwiftTypeRef, Void) { + using namespace swift::Demangle; + Demangler dem; + NodeBuilder b(dem); + { + NodePointer n = + b.Node(Node::Kind::Global, + b.Node(Node::Kind::TypeMangling, + b.Node(Node::Kind::Type, b.Node(Node::Kind::Tuple)))); + CompilerType v = GetCompilerType(b.Mangle(n)); + ASSERT_TRUE(v.IsVoidType()); + } +} From cbe1f4677b27efea5d5499e92762b287de7ffd7a Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Mon, 13 Apr 2020 16:34:05 -0700 Subject: [PATCH 256/286] Remove specific implementations of CanPassInRegisters (NFC) --- lldb/include/lldb/Symbol/SwiftASTContext.h | 9 ++++++--- lldb/source/Symbol/SwiftASTContext.cpp | 7 ------- lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp | 4 ---- 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/lldb/include/lldb/Symbol/SwiftASTContext.h b/lldb/include/lldb/Symbol/SwiftASTContext.h index 061a50231c441..5cd9fccc68cf4 100644 --- a/lldb/include/lldb/Symbol/SwiftASTContext.h +++ b/lldb/include/lldb/Symbol/SwiftASTContext.h @@ -187,6 +187,12 @@ class TypeSystemSwift : public TypeSystem { } bool IsPolymorphicClass(void *type) override { return false; } bool IsBeingDefined(void *type) override { return false; } + bool CanPassInRegisters(const CompilerType &type) override { + // FIXME: Implement this. There was an abort() here to figure out which + // tests where hitting this code. At least TestSwiftReturns and + // TestSwiftStepping were failing because of this Darwin. + return false; + } unsigned GetTypeQualifiers(void *type) override { return 0; } CompilerType GetTypeForDecl(void *opaque_decl) override { llvm_unreachable("GetTypeForDecl not implemented"); @@ -285,7 +291,6 @@ class TypeSystemSwiftTypeRef : public TypeSystemSwift { bool IsPointerType(void *type, CompilerType *pointee_type) override; bool IsScalarType(void *type) override; bool IsVoidType(void *type) override; - bool CanPassInRegisters(const CompilerType &type) override; // Type Completion bool GetCompleteType(void *type) override; // AST related queries @@ -813,8 +818,6 @@ class SwiftASTContext : public TypeSystemSwift { bool IsVoidType(void *type) override; - bool CanPassInRegisters(const CompilerType &type) override; - static bool IsGenericType(const CompilerType &compiler_type); bool IsErrorType(CompilerType compiler_type) override; diff --git a/lldb/source/Symbol/SwiftASTContext.cpp b/lldb/source/Symbol/SwiftASTContext.cpp index 12a72bb0c1a6e..e3de67459b948 100644 --- a/lldb/source/Symbol/SwiftASTContext.cpp +++ b/lldb/source/Symbol/SwiftASTContext.cpp @@ -5427,13 +5427,6 @@ bool SwiftASTContext::IsVoidType(void *type) { return type == GetASTContext()->TheEmptyTupleType.getPointer(); } -bool SwiftASTContext::CanPassInRegisters(const CompilerType &type) { - // FIXME: Implement this. There was an abort() here to figure out which tests - // where hitting this code. At least TestSwiftReturns and TestSwiftStepping - // were failing because of this Darwin. - return false; -} - bool SwiftASTContext::IsGenericType(const CompilerType &compiler_type) { if (swift::Type swift_type = ::GetSwiftType(compiler_type)) return swift_type->hasTypeParameter(); // is(); diff --git a/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp index 6f4a01d3488c2..e36a98c2c1691 100644 --- a/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp +++ b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp @@ -541,10 +541,6 @@ bool TypeSystemSwiftTypeRef::IsVoidType(void *type) { VALIDATE_AND_RETURN(impl, m_swift_ast_context->IsVoidType(ReconstructType(type))); } -bool TypeSystemSwiftTypeRef::CanPassInRegisters(const CompilerType &type) { - return m_swift_ast_context->CanPassInRegisters( - {m_swift_ast_context, ReconstructType(type.GetOpaqueQualType())}); -} // Type Completion bool TypeSystemSwiftTypeRef::GetCompleteType(void *type) { return m_swift_ast_context->GetCompleteType(ReconstructType(type)); From 9d8f72498f31300f06c15792957d3fea2317322e Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Mon, 13 Apr 2020 17:13:49 -0700 Subject: [PATCH 257/286] Implement TypeSystemSwiftTypeRef::IsReferenceType() (NFC) --- lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp | 26 +++++++++++++++++-- .../Symbol/TestTypeSystemSwiftTypeRef.cpp | 23 ++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp index e36a98c2c1691..bdeb00f42add0 100644 --- a/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp +++ b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp @@ -812,8 +812,30 @@ TypeSystemSwiftTypeRef::GetDirectBaseClassAtIndex(void *type, size_t idx, bool TypeSystemSwiftTypeRef::IsReferenceType(void *type, CompilerType *pointee_type, bool *is_rvalue) { - return m_swift_ast_context->IsReferenceType(ReconstructType(type), - pointee_type, is_rvalue); + auto impl = [&]() { + using namespace swift::Demangle; + Demangler Dem; + NodePointer node = DemangleCanonicalType(Dem, type); + if (!node || node->getNumChildren() != 1 || + node->getKind() != Node::Kind::InOut) + return false; + + if (pointee_type) { + NodePointer referenced = node->getFirstChild(); + auto type = Dem.createNode(Node::Kind::Type); + type->addChild(referenced, Dem); + *pointee_type = RemangleAsType(Dem, type); + } + + if (is_rvalue) + *is_rvalue = false; + + return true; + }; + + VALIDATE_AND_RETURN( + impl, m_swift_ast_context->IsReferenceType(ReconstructType(type), + pointee_type, is_rvalue)); } bool TypeSystemSwiftTypeRef::ShouldTreatScalarValueAsAddress( lldb::opaque_compiler_type_t type) { diff --git a/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp b/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp index 78dc8668006b3..088b837c876f3 100644 --- a/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp +++ b/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp @@ -237,3 +237,26 @@ TEST_F(TestTypeSystemSwiftTypeRef, Void) { ASSERT_TRUE(v.IsVoidType()); } } + +TEST_F(TestTypeSystemSwiftTypeRef, Reference) { + using namespace swift::Demangle; + Demangler dem; + NodeBuilder b(dem); + { + NodePointer n = + b.Node(Node::Kind::Global, + b.Node(Node::Kind::TypeMangling, + b.Node(Node::Kind::Type, + b.Node(Node::Kind::InOut, b.IntType())))); + CompilerType ref = GetCompilerType(b.Mangle(n)); + ASSERT_TRUE(ref.IsReferenceType(nullptr, nullptr)); + CompilerType pointee; + bool is_rvalue = true; + ASSERT_TRUE(ref.IsReferenceType(&pointee, &is_rvalue)); + NodePointer int_node = b.Node( + Node::Kind::Global, b.Node(Node::Kind::TypeMangling, b.IntType())); + CompilerType int_type = GetCompilerType(b.Mangle(int_node)); + ASSERT_EQ(int_type, pointee); + ASSERT_FALSE(is_rvalue); + } +} From 46781d45a0fd17aac6bffb9ff2bd08bff78230db Mon Sep 17 00:00:00 2001 From: Vedant Kumar Date: Mon, 13 Apr 2020 17:42:22 -0700 Subject: [PATCH 258/286] [lldb/DataFormatters] SwiftHashedContainer: Validate bucket count Fix an issue causing IsValid() on SwiftHashedContainer instances to return the wrong result when m_scale is corrupt, or when the bucket count is 64. rdar://61718223 --- .../Plugins/Language/Swift/SwiftHashedContainer.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lldb/source/Plugins/Language/Swift/SwiftHashedContainer.cpp b/lldb/source/Plugins/Language/Swift/SwiftHashedContainer.cpp index 71036f15840dd..1b986941fbc96 100644 --- a/lldb/source/Plugins/Language/Swift/SwiftHashedContainer.cpp +++ b/lldb/source/Plugins/Language/Swift/SwiftHashedContainer.cpp @@ -530,7 +530,7 @@ bool NativeHashedStorageHandler::IsValid() { && (m_keys_ptr != LLDB_INVALID_ADDRESS) && (m_value_stride == 0 || m_values_ptr != LLDB_INVALID_ADDRESS) // Check counts. - && (m_count <= GetBucketCount()) + && ((m_scale < (sizeof(size_t) * 8)) && (m_count <= GetBucketCount())) // Buffers are tail-allocated in this order: metadata, keys, values && (m_metadata_ptr < m_keys_ptr) && (m_value_stride == 0 || m_keys_ptr < m_values_ptr); @@ -569,13 +569,15 @@ NativeHashedStorageHandler::UpdateBuckets() { size_t wordCount = GetWordCount(); for (size_t wordIndex = 0; wordIndex < wordCount; wordIndex++) { Status error; - auto word = GetMetadataWord(wordIndex, error); + uint64_t word = GetMetadataWord(wordIndex, error); if (error.Fail()) { return FailBuckets(); } if (wordCount == 1) { // Mask off out-of-bounds bits from first partial word. - word &= (1ULL << bucketCount) - 1; + if (bucketCount > (sizeof(uint64_t) * 8)) + return FailBuckets(); + word &= llvm::maskTrailingOnes(bucketCount); } for (size_t bit = 0; bit < wordWidth; bit++) { if ((word & (1ULL << bit)) != 0) { From deba551d77f93630357931cf61f71d131fff9f41 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Mon, 13 Apr 2020 17:44:01 -0700 Subject: [PATCH 259/286] Simplify test (NFC) --- .../Symbol/TestTypeSystemSwiftTypeRef.cpp | 163 +++++++----------- 1 file changed, 59 insertions(+), 104 deletions(-) diff --git a/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp b/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp index 088b837c876f3..6775f68e65b61 100644 --- a/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp +++ b/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp @@ -23,7 +23,8 @@ using namespace llvm; struct TestTypeSystemSwiftTypeRef : public testing::Test { TypeSystemSwiftTypeRef m_swift_ts = TypeSystemSwiftTypeRef(nullptr); - CompilerType GetCompilerType(const std::string &mangled_name) { + + CompilerType GetCompilerType(std::string mangled_name) { ConstString internalized(mangled_name); return m_swift_ts.GetTypeFromMangledTypename(internalized); } @@ -64,6 +65,16 @@ class NodeBuilder { Node(Node::Kind::Module, swift::STDLIB_NAME), Node(Node::Kind::Identifier, swift::BUILTIN_TYPE_NAME_INT))); } + NodePointer GlobalTypeMangling(NodePointer type) { + assert(type && type->getKind() == Node::Kind::Type); + return Node(Node::Kind::Global, Node(Node::Kind::TypeMangling, type)); + } + NodePointer GlobalType(NodePointer type) { + assert(type && type->getKind() != Node::Kind::Type && + type->getKind() != Node::Kind::TypeMangling && + type->getKind() != Node::Kind::Global); + return GlobalTypeMangling(Node(Node::Kind::Type, type)); + } std::string Mangle(NodePointer node) { return mangleNode(node); } }; @@ -72,18 +83,13 @@ TEST_F(TestTypeSystemSwiftTypeRef, Array) { using namespace swift::Demangle; Demangler dem; NodeBuilder b(dem); - NodePointer n = b.Node( - Node::Kind::Global, - b.Node( - Node::Kind::TypeMangling, - b.Node(Node::Kind::Type, - b.Node(Node::Kind::BoundGenericStructure, - b.Node(Node::Kind::Type, - b.Node(Node::Kind::Structure, - b.Node(Node::Kind::Module, - swift::STDLIB_NAME), - b.Node(Node::Kind::Identifier, "Array"))), - b.Node(Node::Kind::TypeList, b.IntType()))))); + NodePointer n = b.GlobalType( + b.Node(Node::Kind::BoundGenericStructure, + b.Node(Node::Kind::Type, + b.Node(Node::Kind::Structure, + b.Node(Node::Kind::Module, swift::STDLIB_NAME), + b.Node(Node::Kind::Identifier, "Array"))), + b.Node(Node::Kind::TypeList, b.IntType()))); CompilerType int_array = GetCompilerType(b.Mangle(n)); ASSERT_TRUE(int_array.IsArrayType(nullptr, nullptr, nullptr)); } @@ -92,61 +98,39 @@ TEST_F(TestTypeSystemSwiftTypeRef, Function) { using namespace swift::Demangle; Demangler dem; NodeBuilder b(dem); - NodePointer int_node = - b.Node(Node::Kind::Global, b.Node(Node::Kind::TypeMangling, - b.Node(Node::Kind::Type, b.IntType()))); + NodePointer int_node = b.GlobalTypeMangling(b.IntType()); CompilerType int_type = GetCompilerType(b.Mangle(int_node)); - NodePointer void_node = - b.Node(Node::Kind::Global, - b.Node(Node::Kind::TypeMangling, - b.Node(Node::Kind::Type, b.Node(Node::Kind::Tuple)))); + NodePointer void_node = b.GlobalType(b.Node(Node::Kind::Tuple)); CompilerType void_type = GetCompilerType(b.Mangle(void_node)); { - NodePointer n = b.Node( - Node::Kind::Global, - b.Node(Node::Kind::TypeMangling, - b.Node(Node::Kind::Type, - b.Node(Node::Kind::FunctionType, - b.Node(Node::Kind::ArgumentTuple, - b.Node(Node::Kind::Type, - b.Node(Node::Kind::Tuple))), - b.Node(Node::Kind::ReturnType, - b.Node(Node::Kind::Type, - b.Node(Node::Kind::Tuple))))))); + NodePointer n = b.GlobalType( + b.Node(Node::Kind::FunctionType, + b.Node(Node::Kind::ArgumentTuple, + b.Node(Node::Kind::Type, b.Node(Node::Kind::Tuple))), + b.Node(Node::Kind::ReturnType, + b.Node(Node::Kind::Type, b.Node(Node::Kind::Tuple))))); CompilerType void_void = GetCompilerType(b.Mangle(n)); ASSERT_TRUE(void_void.IsFunctionType(nullptr)); ASSERT_TRUE(void_void.IsFunctionPointerType()); ASSERT_EQ(void_void.GetNumberOfFunctionArguments(), 0); } { - NodePointer n = - b.Node(Node::Kind::Global, - b.Node(Node::Kind::TypeMangling, - b.Node(Node::Kind::Type, - b.Node(Node::Kind::ImplFunctionType, - b.Node(Node::Kind::ImplEscaping), - b.Node(Node::Kind::ImplConvention, - "@callee_guaranteed"))))); + NodePointer n = b.GlobalType( + b.Node(Node::Kind::ImplFunctionType, b.Node(Node::Kind::ImplEscaping), + b.Node(Node::Kind::ImplConvention, "@callee_guaranteed"))); CompilerType impl_void_void = GetCompilerType(b.Mangle(n)); ASSERT_TRUE(impl_void_void.IsFunctionType(nullptr)); ASSERT_EQ(impl_void_void.GetNumberOfFunctionArguments(), 0); } { - NodePointer n = b.Node( - Node::Kind::Global, - b.Node( - Node::Kind::TypeMangling, - b.Node( - Node::Kind::Type, - b.Node(Node::Kind::ImplFunctionType, - b.Node(Node::Kind::ImplEscaping), - b.Node(Node::Kind::ImplConvention, "@callee_guaranteed"), - b.Node(Node::Kind::ImplParameter, - b.Node(Node::Kind::ImplConvention, "@unowned"), - b.IntType()), - b.Node(Node::Kind::ImplParameter, - b.Node(Node::Kind::ImplConvention, "@unowned"), - b.Node(Node::Kind::Tuple)))))); + NodePointer n = b.GlobalType(b.Node( + Node::Kind::ImplFunctionType, b.Node(Node::Kind::ImplEscaping), + b.Node(Node::Kind::ImplConvention, "@callee_guaranteed"), + b.Node(Node::Kind::ImplParameter, + b.Node(Node::Kind::ImplConvention, "@unowned"), b.IntType()), + b.Node(Node::Kind::ImplParameter, + b.Node(Node::Kind::ImplConvention, "@unowned"), + b.Node(Node::Kind::Tuple)))); CompilerType impl_two_args = GetCompilerType(b.Mangle(n)); ASSERT_TRUE(impl_two_args.IsFunctionType(nullptr)); ASSERT_EQ(impl_two_args.GetNumberOfFunctionArguments(), 2); @@ -154,22 +138,16 @@ TEST_F(TestTypeSystemSwiftTypeRef, Function) { ASSERT_EQ(impl_two_args.GetFunctionArgumentAtIndex(1), void_type); } { - NodePointer n = b.Node( - Node::Kind::Global, - b.Node( - Node::Kind::TypeMangling, - b.Node(Node::Kind::Type, - b.Node(Node::Kind::FunctionType, - b.Node(Node::Kind::ArgumentTuple, - b.Node(Node::Kind::Type, - b.Node(Node::Kind::Tuple, - b.Node(Node::Kind::TupleElement, - b.IntType()), - b.Node(Node::Kind::TupleElement, - b.Node(Node::Kind::Tuple))))), - b.Node(Node::Kind::ReturnType, - b.Node(Node::Kind::Type, - b.Node(Node::Kind::Tuple))))))); + NodePointer n = b.GlobalType(b.Node( + Node::Kind::FunctionType, + b.Node(Node::Kind::ArgumentTuple, + b.Node(Node::Kind::Type, + b.Node(Node::Kind::Tuple, + b.Node(Node::Kind::TupleElement, b.IntType()), + b.Node(Node::Kind::TupleElement, + b.Node(Node::Kind::Tuple))))), + b.Node(Node::Kind::ReturnType, + b.Node(Node::Kind::Type, b.Node(Node::Kind::Tuple))))); CompilerType two_args = GetCompilerType(b.Mangle(n)); ASSERT_TRUE(two_args.IsFunctionType(nullptr)); ASSERT_EQ(two_args.GetNumberOfFunctionArguments(), 2); @@ -183,42 +161,27 @@ TEST_F(TestTypeSystemSwiftTypeRef, Pointer) { Demangler dem; NodeBuilder b(dem); { - NodePointer n = - b.Node(Node::Kind::Global, - b.Node(Node::Kind::TypeMangling, - b.Node(Node::Kind::Type, - b.Node(Node::Kind::BuiltinTypeName, - swift::BUILTIN_TYPE_NAME_RAWPOINTER)))); + NodePointer n = b.GlobalType(b.Node(Node::Kind::BuiltinTypeName, + swift::BUILTIN_TYPE_NAME_RAWPOINTER)); CompilerType p = GetCompilerType(b.Mangle(n)); ASSERT_TRUE(p.IsPointerType(nullptr)); } { NodePointer n = - b.Node(Node::Kind::Global, - b.Node(Node::Kind::TypeMangling, - b.Node(Node::Kind::Type, - b.Node(Node::Kind::BuiltinTypeName, - swift::BUILTIN_TYPE_NAME_UNSAFEVALUEBUFFER)))); + b.GlobalType(b.Node(Node::Kind::BuiltinTypeName, + swift::BUILTIN_TYPE_NAME_UNSAFEVALUEBUFFER)); CompilerType p = GetCompilerType(b.Mangle(n)); ASSERT_TRUE(p.IsPointerType(nullptr)); } { - NodePointer n = - b.Node(Node::Kind::Global, - b.Node(Node::Kind::TypeMangling, - b.Node(Node::Kind::Type, - b.Node(Node::Kind::BuiltinTypeName, - swift::BUILTIN_TYPE_NAME_NATIVEOBJECT)))); + NodePointer n = b.GlobalType(b.Node(Node::Kind::BuiltinTypeName, + swift::BUILTIN_TYPE_NAME_NATIVEOBJECT)); CompilerType p = GetCompilerType(b.Mangle(n)); ASSERT_TRUE(p.IsPointerType(nullptr)); } { - NodePointer n = - b.Node(Node::Kind::Global, - b.Node(Node::Kind::TypeMangling, - b.Node(Node::Kind::Type, - b.Node(Node::Kind::BuiltinTypeName, - swift::BUILTIN_TYPE_NAME_BRIDGEOBJECT)))); + NodePointer n = b.GlobalType(b.Node(Node::Kind::BuiltinTypeName, + swift::BUILTIN_TYPE_NAME_BRIDGEOBJECT)); CompilerType p = GetCompilerType(b.Mangle(n)); ASSERT_TRUE(p.IsPointerType(nullptr)); } @@ -229,10 +192,7 @@ TEST_F(TestTypeSystemSwiftTypeRef, Void) { Demangler dem; NodeBuilder b(dem); { - NodePointer n = - b.Node(Node::Kind::Global, - b.Node(Node::Kind::TypeMangling, - b.Node(Node::Kind::Type, b.Node(Node::Kind::Tuple)))); + NodePointer n = b.GlobalType(b.Node(Node::Kind::Tuple)); CompilerType v = GetCompilerType(b.Mangle(n)); ASSERT_TRUE(v.IsVoidType()); } @@ -243,18 +203,13 @@ TEST_F(TestTypeSystemSwiftTypeRef, Reference) { Demangler dem; NodeBuilder b(dem); { - NodePointer n = - b.Node(Node::Kind::Global, - b.Node(Node::Kind::TypeMangling, - b.Node(Node::Kind::Type, - b.Node(Node::Kind::InOut, b.IntType())))); + NodePointer n = b.GlobalType(b.Node(Node::Kind::InOut, b.IntType())); CompilerType ref = GetCompilerType(b.Mangle(n)); ASSERT_TRUE(ref.IsReferenceType(nullptr, nullptr)); CompilerType pointee; bool is_rvalue = true; ASSERT_TRUE(ref.IsReferenceType(&pointee, &is_rvalue)); - NodePointer int_node = b.Node( - Node::Kind::Global, b.Node(Node::Kind::TypeMangling, b.IntType())); + NodePointer int_node = b.GlobalTypeMangling(b.IntType()); CompilerType int_type = GetCompilerType(b.Mangle(int_node)); ASSERT_EQ(int_type, pointee); ASSERT_FALSE(is_rvalue); From dd616f37807a38bf36ae852bd05716c2fc4c51bc Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Mon, 13 Apr 2020 17:56:28 -0700 Subject: [PATCH 260/286] Implement TypeSystemSwiftTypeRef::GetFunctionArgumentTypeAtIndex() (NFC) --- lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp | 5 +++-- lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp index bdeb00f42add0..5109ae794f805 100644 --- a/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp +++ b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp @@ -584,8 +584,9 @@ int TypeSystemSwiftTypeRef::GetFunctionArgumentCount(void *type) { } CompilerType TypeSystemSwiftTypeRef::GetFunctionArgumentTypeAtIndex(void *type, size_t idx) { - return m_swift_ast_context->GetFunctionArgumentTypeAtIndex( - ReconstructType(type), idx); + auto impl = [&] { return GetFunctionArgumentAtIndex(type, idx); }; + VALIDATE_AND_RETURN(impl, m_swift_ast_context->GetFunctionArgumentTypeAtIndex( + ReconstructType(type), idx)); } CompilerType TypeSystemSwiftTypeRef::GetFunctionReturnType(void *type) { return m_swift_ast_context->GetFunctionReturnType(ReconstructType(type)); diff --git a/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp b/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp index 6775f68e65b61..9b948d2585276 100644 --- a/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp +++ b/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp @@ -136,6 +136,8 @@ TEST_F(TestTypeSystemSwiftTypeRef, Function) { ASSERT_EQ(impl_two_args.GetNumberOfFunctionArguments(), 2); ASSERT_EQ(impl_two_args.GetFunctionArgumentAtIndex(0), int_type); ASSERT_EQ(impl_two_args.GetFunctionArgumentAtIndex(1), void_type); + ASSERT_EQ(impl_two_args.GetFunctionArgumentTypeAtIndex(0), int_type); + ASSERT_EQ(impl_two_args.GetFunctionArgumentTypeAtIndex(1), void_type); } { NodePointer n = b.GlobalType(b.Node( @@ -153,6 +155,8 @@ TEST_F(TestTypeSystemSwiftTypeRef, Function) { ASSERT_EQ(two_args.GetNumberOfFunctionArguments(), 2); ASSERT_EQ(two_args.GetFunctionArgumentAtIndex(0), int_type); ASSERT_EQ(two_args.GetFunctionArgumentAtIndex(1), void_type); + ASSERT_EQ(two_args.GetFunctionArgumentTypeAtIndex(0), int_type); + ASSERT_EQ(two_args.GetFunctionArgumentTypeAtIndex(1), void_type); } } From b4616a1ee43c6a697da393391b4fdd587ad8363b Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Mon, 13 Apr 2020 18:34:58 -0700 Subject: [PATCH 261/286] Implement TypeSystemSwiftTypeRef::GetFunctionReturnType() (NFC) --- lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp | 30 ++++++++++++++++++- .../Symbol/TestTypeSystemSwiftTypeRef.cpp | 22 ++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp index 5109ae794f805..5a05cd872aa75 100644 --- a/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp +++ b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp @@ -589,7 +589,35 @@ TypeSystemSwiftTypeRef::GetFunctionArgumentTypeAtIndex(void *type, size_t idx) { ReconstructType(type), idx)); } CompilerType TypeSystemSwiftTypeRef::GetFunctionReturnType(void *type) { - return m_swift_ast_context->GetFunctionReturnType(ReconstructType(type)); + auto impl = [&]() -> CompilerType { + using namespace swift::Demangle; + Demangler Dem; + NodePointer node = DemangleCanonicalType(Dem, type); + if (!node || (node->getKind() != Node::Kind::FunctionType && + node->getKind() != Node::Kind::ImplFunctionType)) + return {}; + unsigned num_args = 0; + for (NodePointer child : *node) { + if (child->getKind() == Node::Kind::ImplResult) { + for (NodePointer type : *child) + if (type->getKind() == Node::Kind::Type) + return RemangleAsType(Dem, type); + } + if (child->getKind() == Node::Kind::ReturnType && + child->getNumChildren() == 1) { + NodePointer type = child->getFirstChild(); + if (type->getKind() == Node::Kind::Type) + return RemangleAsType(Dem, type); + } + } + // Else this is a void / "()" type. + NodePointer type = Dem.createNode(Node::Kind::Type); + NodePointer tuple = Dem.createNode(Node::Kind::Tuple); + type->addChild(tuple, Dem); + return RemangleAsType(Dem, type); + }; + VALIDATE_AND_RETURN( + impl, m_swift_ast_context->GetFunctionReturnType(ReconstructType(type))); } size_t TypeSystemSwiftTypeRef::GetNumMemberFunctions(void *type) { return m_swift_ast_context->GetNumMemberFunctions(ReconstructType(type)); diff --git a/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp b/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp index 9b948d2585276..6b81b9f110c97 100644 --- a/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp +++ b/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp @@ -138,6 +138,7 @@ TEST_F(TestTypeSystemSwiftTypeRef, Function) { ASSERT_EQ(impl_two_args.GetFunctionArgumentAtIndex(1), void_type); ASSERT_EQ(impl_two_args.GetFunctionArgumentTypeAtIndex(0), int_type); ASSERT_EQ(impl_two_args.GetFunctionArgumentTypeAtIndex(1), void_type); + ASSERT_EQ(impl_two_args.GetFunctionReturnType(), void_type); } { NodePointer n = b.GlobalType(b.Node( @@ -157,6 +158,27 @@ TEST_F(TestTypeSystemSwiftTypeRef, Function) { ASSERT_EQ(two_args.GetFunctionArgumentAtIndex(1), void_type); ASSERT_EQ(two_args.GetFunctionArgumentTypeAtIndex(0), int_type); ASSERT_EQ(two_args.GetFunctionArgumentTypeAtIndex(1), void_type); + ASSERT_EQ(two_args.GetFunctionReturnType(), void_type); + } + { + NodePointer n = b.GlobalType(b.Node( + Node::Kind::FunctionType, + b.Node(Node::Kind::ArgumentTuple, + b.Node(Node::Kind::Type, b.Node(Node::Kind::Tuple))), + b.Node(Node::Kind::ReturnType, b.Node(Node::Kind::Type, b.IntType())))); + CompilerType void_int = GetCompilerType(b.Mangle(n)); + ASSERT_TRUE(void_int.IsFunctionType(nullptr)); + ASSERT_EQ(void_int.GetFunctionReturnType(), int_type); + } + { + NodePointer n = b.GlobalType(b.Node( + Node::Kind::ImplFunctionType, b.Node(Node::Kind::ImplEscaping), + b.Node(Node::Kind::ImplConvention, "@callee_guaranteed"), + b.Node(Node::Kind::ImplResult, + b.Node(Node::Kind::ImplConvention, "@unowned"), b.IntType()))); + CompilerType impl_void_int = GetCompilerType(b.Mangle(n)); + ASSERT_TRUE(impl_void_int.IsFunctionType(nullptr)); + ASSERT_EQ(impl_void_int.GetFunctionReturnType(), int_type); } } From e495fd9a47e9cc6e8271b45c281d95442312f6bf Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Mon, 13 Apr 2020 18:41:25 -0700 Subject: [PATCH 262/286] Implement TypeSystemSwiftTypeRef::GetFunctionArgumentCount() (NFC) --- lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp index 5a05cd872aa75..1949ade4138ed 100644 --- a/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp +++ b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp @@ -580,7 +580,9 @@ CompilerType TypeSystemSwiftTypeRef::GetCanonicalType(void *type) { return m_swift_ast_context->GetCanonicalType(ReconstructType(type)); } int TypeSystemSwiftTypeRef::GetFunctionArgumentCount(void *type) { - return m_swift_ast_context->GetFunctionArgumentCount(ReconstructType(type)); + auto impl = [&]() { return GetNumberOfFunctionArguments(type); }; + VALIDATE_AND_RETURN(impl, m_swift_ast_context->GetFunctionArgumentCount( + ReconstructType(type))); } CompilerType TypeSystemSwiftTypeRef::GetFunctionArgumentTypeAtIndex(void *type, size_t idx) { From ba8cca0196bb8edbb68738c984e7fbc34ce24d1f Mon Sep 17 00:00:00 2001 From: Raphael Isemann Date: Wed, 29 Jan 2020 09:07:55 +0100 Subject: [PATCH 263/286] [lldb] Complete return types of CXXMethodDecls to prevent crashing due to covariant return types Summary: Currently we crash in Clang's CodeGen when we call functions with covariant return types with this assert: ``` Assertion failed: (DD && "queried property of class with no definition"), function data, file clang/include/clang/AST/DeclCXX.h, line 433. ``` when calling `clang::CXXRecordDecl::isDerivedFrom` from the `ItaniumVTableBuilder`. Clang seems to assume that the underlying record decls of covariant return types are already completed. This is true during a normal Clang invocation as there the type checker will complete both decls when checking if the overloaded function is valid (i.e., the return types are covariant). When we minimally import our AST into the expression in LLDB we don't do this type checking (which would complete the record decls) and we end up trying to access the invalid record decls from CodeGen which makes us trigger the assert. This patch just completes the underlying types of ptr/ref return types of virtual function so that the underlying records are complete and we behave as Clang expects us to do. Fixes rdar://38048657 Reviewers: lhames, shafik Reviewed By: shafik Subscribers: abidh, JDevlieghere, lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D73024 (cherry picked from commit a5fb2e371ec2b585ca56cbc1a116912aabe347d3) --- .../lang/cpp/covariant-return-types/Makefile | 3 ++ .../TestCovariantReturnTypes.py | 40 +++++++++++++++++++ .../lang/cpp/covariant-return-types/main.cpp | 40 +++++++++++++++++++ .../Clang/ClangASTImporter.cpp | 22 ++++++++++ 4 files changed, 105 insertions(+) create mode 100644 lldb/packages/Python/lldbsuite/test/lang/cpp/covariant-return-types/Makefile create mode 100644 lldb/packages/Python/lldbsuite/test/lang/cpp/covariant-return-types/TestCovariantReturnTypes.py create mode 100644 lldb/packages/Python/lldbsuite/test/lang/cpp/covariant-return-types/main.cpp diff --git a/lldb/packages/Python/lldbsuite/test/lang/cpp/covariant-return-types/Makefile b/lldb/packages/Python/lldbsuite/test/lang/cpp/covariant-return-types/Makefile new file mode 100644 index 0000000000000..99998b20bcb05 --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/lang/cpp/covariant-return-types/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/packages/Python/lldbsuite/test/lang/cpp/covariant-return-types/TestCovariantReturnTypes.py b/lldb/packages/Python/lldbsuite/test/lang/cpp/covariant-return-types/TestCovariantReturnTypes.py new file mode 100644 index 0000000000000..86a6ddd6e47b6 --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/lang/cpp/covariant-return-types/TestCovariantReturnTypes.py @@ -0,0 +1,40 @@ +import lldb +from lldbsuite.test.lldbtest import * +import lldbsuite.test.lldbutil as lldbutil + +class TestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + NO_DEBUG_INFO_TESTCASE = True + + def test(self): + self.build() + lldbutil.run_to_source_breakpoint(self,"// break here", lldb.SBFileSpec("main.cpp")) + + # Test covariant return types for pointers to class that contains the called function. + self.expect_expr("derived.getPtr()", result_type="Derived *") + self.expect_expr("base_ptr_to_derived->getPtr()", result_type="Base *") + self.expect_expr("base.getPtr()", result_type="Base *") + # The same tests with reference types. LLDB drops the reference when it turns the + # result into a SBValue so check for the the underlying type of the result. + self.expect_expr("derived.getRef()", result_type="Derived") + self.expect_expr("base_ptr_to_derived->getRef()", result_type="Base") + self.expect_expr("base.getRef()", result_type="Base") + + # Test covariant return types for pointers to class that does *not* contain the called function. + self.expect_expr("derived.getOtherPtr()", result_type="OtherDerived *") + self.expect_expr("base_ptr_to_derived->getOtherPtr()", result_type="OtherBase *") + self.expect_expr("base.getOtherPtr()", result_type="OtherBase *") + # The same tests with reference types. LLDB drops the reference when it turns the + # result into a SBValue so check for the the underlying type of the result. + self.expect_expr("derived.getOtherRef()", result_type="OtherDerived") + self.expect_expr("base_ptr_to_derived->getOtherRef()", result_type="OtherBase") + self.expect_expr("base.getOtherRef()", result_type="OtherBase") + + # Test that we call the right function and get the right value back. + self.expect_expr("derived.getOtherPtr()->value()", result_summary='"derived"') + self.expect_expr("base_ptr_to_derived->getOtherPtr()->value()", result_summary='"derived"') + self.expect_expr("base.getOtherPtr()->value()", result_summary='"base"') + self.expect_expr("derived.getOtherRef().value()", result_summary='"derived"') + self.expect_expr("base_ptr_to_derived->getOtherRef().value()", result_summary='"derived"') + self.expect_expr("base.getOtherRef().value()", result_summary='"base"') diff --git a/lldb/packages/Python/lldbsuite/test/lang/cpp/covariant-return-types/main.cpp b/lldb/packages/Python/lldbsuite/test/lang/cpp/covariant-return-types/main.cpp new file mode 100644 index 0000000000000..2a6fc682c39a4 --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/lang/cpp/covariant-return-types/main.cpp @@ -0,0 +1,40 @@ +struct OtherBase { + // Allow checking actual type from the test by giving + // this class and the subclass unique values here. + virtual const char *value() { return "base"; } +}; +struct OtherDerived : public OtherBase { + const char *value() override { return "derived"; } +}; + +// Those have to be globals as they would be completed if they +// are members (which would make this test always pass). +OtherBase other_base; +OtherDerived other_derived; + +struct Base { + // Function with covariant return type that is same class. + virtual Base* getPtr() { return this; } + virtual Base& getRef() { return *this; } + // Function with covariant return type that is a different class. + virtual OtherBase* getOtherPtr() { return &other_base; } + virtual OtherBase& getOtherRef() { return other_base; } +}; + +struct Derived : public Base { + Derived* getPtr() override { return this; } + Derived& getRef() override { return *this; } + OtherDerived* getOtherPtr() override { return &other_derived; } + OtherDerived& getOtherRef() override { return other_derived; } +}; + +int main() { + Derived derived; + Base base; + Base *base_ptr_to_derived = &derived; + (void)base_ptr_to_derived->getPtr(); + (void)base_ptr_to_derived->getRef(); + (void)base_ptr_to_derived->getOtherPtr(); + (void)base_ptr_to_derived->getOtherRef(); + return 0; // break here +} diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp index 85b6c42fa91f1..38926cf9c0594 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp @@ -1021,6 +1021,25 @@ RemapModule(OptionalClangModuleID from_id, module->IsExplicit); } +/// Takes a CXXMethodDecl and completes the return type if necessary. This +/// is currently only necessary for virtual functions with covariant return +/// types where Clang's CodeGen expects that the underlying records are already +/// completed. +static void MaybeCompleteReturnType(ClangASTImporter &importer, + CXXMethodDecl *to_method) { + if (!to_method->isVirtual()) + return; + QualType return_type = to_method->getReturnType(); + if (!return_type->isPointerType() && !return_type->isReferenceType()) + return; + + clang::RecordDecl *rd = return_type->getPointeeType()->getAsRecordDecl(); + if (!rd) + return; + + importer.CompleteTagDecl(rd); +} + void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from, clang::Decl *to) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); @@ -1190,6 +1209,9 @@ void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from, } } } + + if (clang::CXXMethodDecl *to_method = dyn_cast(to)) + MaybeCompleteReturnType(m_master, to_method); } clang::Decl * From 58d95fb2f55074d0376983155fd8d916a53308c8 Mon Sep 17 00:00:00 2001 From: Pavel Labath Date: Thu, 26 Mar 2020 13:23:51 +0100 Subject: [PATCH 264/286] [lldb] Fix another crash in covariant type handling Summary: D73024 seems to have fixed one set crash, but it introduced another. Namely, if a class contains a covariant method returning itself, the logic in MaybeCompleteReturnType could cause us to attempt a recursive import, which would result in an assertion failure in clang::DeclContext::removeDecl. For some reason, this only manifested itself if the class contained at least two member variables, and the class itself was imported as a result of a recursive covariant import. This patch fixes the crash by not attempting to import classes which are already completed in MaybeCompleteReturnType. However, it's not clear to me if this is the right fix, or if this should be handled automatically by functions lower in the stack. Reviewers: teemperor, shafik Subscribers: lldb-commits Tags: #lldb Differential Revision: https://reviews.llvm.org/D76840 (cherry picked from commit 7b00eeb53de06c7979fd2a88436c3387d0492ee8) --- .../TestCovariantReturnTypes.py | 2 ++ .../lang/cpp/covariant-return-types/main.cpp | 19 +++++++++++++++++++ .../Clang/ClangASTImporter.cpp | 2 ++ 3 files changed, 23 insertions(+) diff --git a/lldb/packages/Python/lldbsuite/test/lang/cpp/covariant-return-types/TestCovariantReturnTypes.py b/lldb/packages/Python/lldbsuite/test/lang/cpp/covariant-return-types/TestCovariantReturnTypes.py index 86a6ddd6e47b6..6f2b3eafd2e9c 100644 --- a/lldb/packages/Python/lldbsuite/test/lang/cpp/covariant-return-types/TestCovariantReturnTypes.py +++ b/lldb/packages/Python/lldbsuite/test/lang/cpp/covariant-return-types/TestCovariantReturnTypes.py @@ -38,3 +38,5 @@ def test(self): self.expect_expr("derived.getOtherRef().value()", result_summary='"derived"') self.expect_expr("base_ptr_to_derived->getOtherRef().value()", result_summary='"derived"') self.expect_expr("base.getOtherRef().value()", result_summary='"base"') + + self.expect_expr("referencing_derived.getOther()->get()->a", result_value='42') diff --git a/lldb/packages/Python/lldbsuite/test/lang/cpp/covariant-return-types/main.cpp b/lldb/packages/Python/lldbsuite/test/lang/cpp/covariant-return-types/main.cpp index 2a6fc682c39a4..ea05043d6cf9e 100644 --- a/lldb/packages/Python/lldbsuite/test/lang/cpp/covariant-return-types/main.cpp +++ b/lldb/packages/Python/lldbsuite/test/lang/cpp/covariant-return-types/main.cpp @@ -28,6 +28,23 @@ struct Derived : public Base { OtherDerived& getOtherRef() override { return other_derived; } }; +// A regression test for a class with at least two members containing a +// covariant function, which is referenced through another covariant function. +struct BaseWithMembers { + int a = 42; + int b = 47; + virtual BaseWithMembers *get() { return this; } +}; +struct DerivedWithMembers: BaseWithMembers { + DerivedWithMembers *get() override { return this; } +}; +struct ReferencingBase { + virtual BaseWithMembers *getOther() { return new BaseWithMembers(); } +}; +struct ReferencingDerived: ReferencingBase { + DerivedWithMembers *getOther() { return new DerivedWithMembers(); } +}; + int main() { Derived derived; Base base; @@ -36,5 +53,7 @@ int main() { (void)base_ptr_to_derived->getRef(); (void)base_ptr_to_derived->getOtherPtr(); (void)base_ptr_to_derived->getOtherRef(); + + ReferencingDerived referencing_derived; return 0; // break here } diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp index 38926cf9c0594..0a511174ab5bb 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp @@ -1036,6 +1036,8 @@ static void MaybeCompleteReturnType(ClangASTImporter &importer, clang::RecordDecl *rd = return_type->getPointeeType()->getAsRecordDecl(); if (!rd) return; + if (rd->getDefinition()) + return; importer.CompleteTagDecl(rd); } From 9af107295570abd8a6ba3c23fb4fd146d5f9f448 Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Sun, 12 Apr 2020 17:22:34 -0700 Subject: [PATCH 265/286] [lldb] Update for removal of SourceFile::addImports Additional modules to implicitly import now need to be provided upfront when constructing the ModuleDecl. To enable this change, split `PerformUserImport` into `GetImplicitImports`, which retrieves the necessary modules to import, and `CacheUserImports`, which deals with caching the imports from the parsed source file such that they're available to future expression evaluations. This commit also renames `PerformAutoImport` to `GetCompileUnitImports` to better match the other two methods. --- lldb/include/lldb/Symbol/SwiftASTContext.h | 43 ++++-- .../Swift/SwiftExpressionParser.cpp | 47 +++--- .../ExpressionParser/Swift/SwiftREPL.cpp | 14 +- lldb/source/Symbol/SwiftASTContext.cpp | 135 +++++++++--------- lldb/source/Target/SwiftLanguageRuntime.cpp | 3 +- lldb/source/Target/Target.cpp | 4 +- 6 files changed, 140 insertions(+), 106 deletions(-) diff --git a/lldb/include/lldb/Symbol/SwiftASTContext.h b/lldb/include/lldb/Symbol/SwiftASTContext.h index 5cd9fccc68cf4..bcdd62a59a5bd 100644 --- a/lldb/include/lldb/Symbol/SwiftASTContext.h +++ b/lldb/include/lldb/Symbol/SwiftASTContext.h @@ -39,6 +39,7 @@ enum class IRGenDebugInfoLevel : unsigned; class CanType; class DependencyTracker; class DWARFImporterDelegate; +struct ImplicitImportInfo; class IRGenOptions; class NominalTypeDecl; class SearchPathOptions; @@ -595,7 +596,13 @@ class SwiftASTContext : public TypeSystemSwift { /// \return the ExtraArgs of the ClangImporterOptions. const std::vector &GetClangArguments(); - swift::ModuleDecl *CreateModule(const SourceModule &module, Status &error); + /// Attempt to create a Swift module, returning \c nullptr and setting + /// \p error if unsuccessful. + /// + /// \param importInfo Information about which modules should be implicitly + /// imported by each file of the module. + swift::ModuleDecl *CreateModule(const SourceModule &module, Status &error, + swift::ImplicitImportInfo importInfo); // This function should only be called when all search paths // for all items in a swift::ASTContext have been setup to @@ -1064,16 +1071,30 @@ class SwiftASTContext : public TypeSystemSwift { void SetCachedType(ConstString mangled, const lldb::TypeSP &type_sp) override; - static bool PerformUserImport(SwiftASTContext &swift_ast_context, - SymbolContext &sc, - ExecutionContextScope &exe_scope, - lldb::StackFrameWP &stack_frame_wp, - swift::SourceFile &source_file, Status &error); - - static bool PerformAutoImport(SwiftASTContext &swift_ast_context, - SymbolContext &sc, - lldb::StackFrameWP &stack_frame_wp, - swift::SourceFile *source_file, Status &error); + /// Retrieves the modules that need to be implicitly imported in a given + /// execution scope. This includes the modules imported by both the compile + /// unit as well as any imports from previous expression evaluations. + static bool + GetImplicitImports(SwiftASTContext &swift_ast_context, SymbolContext &sc, + ExecutionContextScope &exe_scope, + lldb::StackFrameWP &stack_frame_wp, + llvm::SmallVectorImpl &modules, + Status &error); + + /// Cache the user's imports from a SourceFile in a given execution scope such + /// that they are carried over into future expression evaluations. + static bool CacheUserImports(SwiftASTContext &swift_ast_context, + SymbolContext &sc, + ExecutionContextScope &exe_scope, + lldb::StackFrameWP &stack_frame_wp, + swift::SourceFile &source_file, Status &error); + + /// Retrieve the modules imported by the compilation unit. + static bool + GetCompileUnitImports(SwiftASTContext &swift_ast_context, SymbolContext &sc, + lldb::StackFrameWP &stack_frame_wp, + llvm::SmallVectorImpl &modules, + Status &error); protected: /// This map uses the string value of ConstStrings as the key, and the diff --git a/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp index 7d7197e3ae316..6e4bf518a79f1 100644 --- a/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp +++ b/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp @@ -1196,13 +1196,28 @@ static llvm::Expected ParseAndImport( snprintf(expr_name_buf, sizeof(expr_name_buf), "__lldb_expr_%u", options.GetExpressionNumber()); + // Gather the modules that need to be implicitly imported. + // The Swift stdlib needs to be imported before the SwiftLanguageRuntime can + // be used. + Status implicit_import_error; + llvm::SmallVector additional_imports; + if (!SwiftASTContext::GetImplicitImports(*swift_ast_context, sc, exe_scope, + stack_frame_wp, additional_imports, + implicit_import_error)) { + return make_error(llvm::Twine("in implicit-import:\n") + + implicit_import_error.AsCString()); + } + + swift::ImplicitImportInfo importInfo; + importInfo.StdlibKind = swift::ImplicitStdlibKind::Stdlib; + for (auto *module : additional_imports) + importInfo.AdditionalModules.emplace_back(module, /*exported*/ false); + auto module_id = ast_context->getIdentifier(expr_name_buf); - auto &module = *swift::ModuleDecl::create(module_id, *ast_context); - const auto implicit_import_kind = - swift::SourceFile::ImplicitModuleImportKind::Stdlib; + auto &module = *swift::ModuleDecl::create(module_id, *ast_context, + importInfo); swift::SourceFileKind source_file_kind = swift::SourceFileKind::Library; - if (playground || repl) { source_file_kind = swift::SourceFileKind::Main; } @@ -1210,21 +1225,11 @@ static llvm::Expected ParseAndImport( // Create the source file. Note, we disable delayed parsing for the // swift expression parser. swift::SourceFile *source_file = new (*ast_context) swift::SourceFile( - module, source_file_kind, buffer_id, implicit_import_kind, - /*Keep tokens*/ false, /*KeepSyntaxTree*/ false, + module, source_file_kind, buffer_id, /*Keep tokens*/ false, + /*KeepSyntaxTree*/ false, swift::SourceFile::ParsingFlags::DisableDelayedBodies); module.addFile(*source_file); - - // The Swift stdlib needs to be imported before the - // SwiftLanguageRuntime can be used. - Status auto_import_error; - if (!SwiftASTContext::PerformAutoImport(*swift_ast_context, sc, - stack_frame_wp, source_file, - auto_import_error)) - return make_error(llvm::Twine("in auto-import:\n") + - auto_import_error.AsCString()); - // Swift Modules that rely on shared libraries (not frameworks) // don't record the link information in the swiftmodule file, so we // can't really make them work without outside information. @@ -1331,16 +1336,16 @@ static llvm::Expected ParseAndImport( if (swift_ast_context->HasErrors()) return make_error(); - // Do the auto-importing after Name Binding, that's when the Imports - // for the source file are figured out. + // Cache the source file's imports such that they're accessible to future + // expression evaluations. { std::lock_guard global_context_locker( IRExecutionUnit::GetLLVMGlobalContextMutex()); Status auto_import_error; - if (!SwiftASTContext::PerformUserImport(*swift_ast_context, sc, exe_scope, - stack_frame_wp, *source_file, - auto_import_error)) { + if (!SwiftASTContext::CacheUserImports(*swift_ast_context, sc, exe_scope, + stack_frame_wp, *source_file, + auto_import_error)) { return make_error(llvm::Twine("in user-import:\n") + auto_import_error.AsCString()); } diff --git a/lldb/source/Plugins/ExpressionParser/Swift/SwiftREPL.cpp b/lldb/source/Plugins/ExpressionParser/Swift/SwiftREPL.cpp index 2a1b288de9b08..69790b0e8588d 100644 --- a/lldb/source/Plugins/ExpressionParser/Swift/SwiftREPL.cpp +++ b/lldb/source/Plugins/ExpressionParser/Swift/SwiftREPL.cpp @@ -566,18 +566,16 @@ void SwiftREPL::CompleteCode(const std::string ¤t_code, repl_module = swift_ast->GetModule(completion_module_info, error); if (repl_module == nullptr) { - repl_module = swift_ast->CreateModule(completion_module_info, error); - const swift::SourceFile::ImplicitModuleImportKind implicit_import_kind = - swift::SourceFile::ImplicitModuleImportKind::Stdlib; + swift::ImplicitImportInfo importInfo; + importInfo.StdlibKind = swift::ImplicitStdlibKind::Stdlib; + repl_module = swift_ast->CreateModule(completion_module_info, error, + importInfo); llvm::Optional bufferID; swift::SourceFile *repl_source_file = new (*ast) swift::SourceFile(*repl_module, swift::SourceFileKind::REPL, bufferID, - implicit_import_kind, /*Keep tokens*/false); - - // Given this file is empty and only exists to import the standard - // library, we can go ahead and just mark it as having been type checked. - repl_source_file->ASTStage = swift::SourceFile::TypeChecked; + /*Keep tokens*/false); repl_module->addFile(*repl_source_file); + swift::performImportResolution(*repl_source_file); m_completion_module_initialized = true; } if (repl_module) { diff --git a/lldb/source/Symbol/SwiftASTContext.cpp b/lldb/source/Symbol/SwiftASTContext.cpp index 70b94e9459114..2fc7484628424 100644 --- a/lldb/source/Symbol/SwiftASTContext.cpp +++ b/lldb/source/Symbol/SwiftASTContext.cpp @@ -3611,8 +3611,9 @@ SwiftASTContext::GetCachedModule(const SourceModule &module) { return nullptr; } -swift::ModuleDecl *SwiftASTContext::CreateModule(const SourceModule &module, - Status &error) { +swift::ModuleDecl * +SwiftASTContext::CreateModule(const SourceModule &module, Status &error, + swift::ImplicitImportInfo importInfo) { VALID_OR_RETURN(nullptr); if (!module.path.size()) { error.SetErrorStringWithFormat("invalid module name (empty)"); @@ -3633,7 +3634,7 @@ swift::ModuleDecl *SwiftASTContext::CreateModule(const SourceModule &module, swift::Identifier module_id( ast->getIdentifier(module.path.front().GetCString())); - auto *module_decl = swift::ModuleDecl::create(module_id, *ast); + auto *module_decl = swift::ModuleDecl::create(module_id, *ast, importInfo); if (!module_decl) { error.SetErrorStringWithFormat("failed to create module for \"%s\"", module.path.front().GetCString()); @@ -8353,14 +8354,12 @@ static void GetNameFromModule(swift::ModuleDecl *module, std::string &result) { } } -static bool -LoadOneModule(const SourceModule &module, SwiftASTContext &swift_ast_context, - lldb::StackFrameWP &stack_frame_wp, - llvm::SmallVectorImpl - &additional_imports, - Status &error) { +static swift::ModuleDecl *LoadOneModule(const SourceModule &module, + SwiftASTContext &swift_ast_context, + lldb::StackFrameWP &stack_frame_wp, + Status &error) { if (!module.path.size()) - return false; + return nullptr; error.Clear(); ConstString toplevel = module.path.front(); @@ -8399,7 +8398,7 @@ LoadOneModule(const SourceModule &module, SwiftASTContext &swift_ast_context, toplevel.AsCString(), error.AsCString()); if (!swift_module || swift_ast_context.HasFatalErrors()) { - return false; + return nullptr; } } @@ -8410,23 +8409,42 @@ LoadOneModule(const SourceModule &module, SwiftASTContext &swift_ast_context, LOG_PRINTF(LIBLLDB_LOG_EXPRESSIONS, "Imported module %s from {%s}", module.path.front().AsCString(), ss.GetData()); } + return swift_module; +} + +bool SwiftASTContext::GetImplicitImports( + SwiftASTContext &swift_ast_context, SymbolContext &sc, + ExecutionContextScope &exe_scope, lldb::StackFrameWP &stack_frame_wp, + llvm::SmallVectorImpl &modules, Status &error) { + if (!GetCompileUnitImports(swift_ast_context, sc, stack_frame_wp, modules, + error)) { + return false; + } + + auto *persistent_expression_state = + sc.target_sp->GetSwiftPersistentExpressionState(exe_scope); - additional_imports.push_back(swift::SourceFile::ImportedModuleDesc( - std::make_pair(swift::ModuleDecl::AccessPathTy(), swift_module), - swift::SourceFile::ImportOptions())); + // Get the hand-loaded modules from the SwiftPersistentExpressionState. + for (ConstString name : persistent_expression_state->GetHandLoadedModules()) { + SourceModule module_info; + module_info.path.push_back(name); + auto *module = LoadOneModule(module_info, swift_ast_context, stack_frame_wp, + error); + if (!module) + return false; + + modules.push_back(module); + } return true; } -bool SwiftASTContext::PerformUserImport(SwiftASTContext &swift_ast_context, - SymbolContext &sc, - ExecutionContextScope &exe_scope, - lldb::StackFrameWP &stack_frame_wp, - swift::SourceFile &source_file, - Status &error) { +bool SwiftASTContext::CacheUserImports(SwiftASTContext &swift_ast_context, + SymbolContext &sc, + ExecutionContextScope &exe_scope, + lldb::StackFrameWP &stack_frame_wp, + swift::SourceFile &source_file, + Status &error) { llvm::SmallString<1> m_description; - llvm::SmallVector - additional_imports; - llvm::SmallVector parsed_imports; swift::ModuleDecl::ImportFilter import_filter; @@ -8450,7 +8468,7 @@ bool SwiftASTContext::PerformUserImport(SwiftASTContext &swift_ast_context, "Performing auto import on found module: %s.\n", module_name.c_str()); if (!LoadOneModule(module_info, swift_ast_context, stack_frame_wp, - additional_imports, error)) + error)) return false; // How do we tell we are in REPL or playground mode? @@ -8458,54 +8476,43 @@ bool SwiftASTContext::PerformUserImport(SwiftASTContext &swift_ast_context, } } } - // Finally get the hand-loaded modules from the - // SwiftPersistentExpressionState and load them into this context: - for (ConstString name : persistent_expression_state->GetHandLoadedModules()) { - SourceModule module_info; - module_info.path.push_back(name); - if (!LoadOneModule(module_info, swift_ast_context, stack_frame_wp, - additional_imports, error)) - return false; - } - - source_file.addImports(additional_imports); return true; } -bool SwiftASTContext::PerformAutoImport(SwiftASTContext &swift_ast_context, - SymbolContext &sc, - lldb::StackFrameWP &stack_frame_wp, - swift::SourceFile *source_file, - Status &error) { - llvm::SmallVector - additional_imports; - - // Import the Swift standard library and its dependecies. +bool SwiftASTContext::GetCompileUnitImports( + SwiftASTContext &swift_ast_context, SymbolContext &sc, + lldb::StackFrameWP &stack_frame_wp, + llvm::SmallVectorImpl &modules, Status &error) { + // Import the Swift standard library and its dependencies. SourceModule swift_module; swift_module.path.push_back(ConstString("Swift")); - if (!LoadOneModule(swift_module, swift_ast_context, stack_frame_wp, - additional_imports, error)) + auto *stdlib = + LoadOneModule(swift_module, swift_ast_context, stack_frame_wp, error); + if (!stdlib) return false; + modules.push_back(stdlib); + CompileUnit *compile_unit = sc.comp_unit; - if (compile_unit && compile_unit->GetLanguage() == lldb::eLanguageTypeSwift) - for (const SourceModule &module : compile_unit->GetImportedModules()) { - // When building the Swift stdlib with debug info these will - // show up in "Swift.o", but we already imported them and - // manually importing them will fail. - if (module.path.size() && - llvm::StringSwitch(module.path.front().GetStringRef()) - .Cases("Swift", "SwiftShims", "Builtin", true) - .Default(false)) - continue; + if (!compile_unit || compile_unit->GetLanguage() != lldb::eLanguageTypeSwift) + return true; - if (!LoadOneModule(module, swift_ast_context, stack_frame_wp, - additional_imports, error)) - return false; - } - // source_file might be NULL outside of the expression parser, where - // we don't need to notify the source file of additional imports. - if (source_file) - source_file->addImports(additional_imports); + for (const SourceModule &module : compile_unit->GetImportedModules()) { + // When building the Swift stdlib with debug info these will + // show up in "Swift.o", but we already imported them and + // manually importing them will fail. + if (module.path.size() && + llvm::StringSwitch(module.path.front().GetStringRef()) + .Cases("Swift", "SwiftShims", "Builtin", true) + .Default(false)) + continue; + + auto *loaded_module = + LoadOneModule(module, swift_ast_context, stack_frame_wp, error); + if (!loaded_module) + return false; + + modules.push_back(loaded_module); + } return true; } diff --git a/lldb/source/Target/SwiftLanguageRuntime.cpp b/lldb/source/Target/SwiftLanguageRuntime.cpp index a2f4cb4818379..d9e59f809ff37 100644 --- a/lldb/source/Target/SwiftLanguageRuntime.cpp +++ b/lldb/source/Target/SwiftLanguageRuntime.cpp @@ -1198,7 +1198,8 @@ void SwiftLanguageRuntime::RegisterGlobalError(Target &target, ConstString name, Status module_creation_error; swift::ModuleDecl *module_decl = - ast_context->CreateModule(module_info, module_creation_error); + ast_context->CreateModule(module_info, module_creation_error, + /*importInfo*/ {}); if (module_creation_error.Success() && module_decl) { const bool is_static = false; diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index 035f15b3a01f0..ada11357234d8 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -2499,7 +2499,9 @@ SwiftASTContextReader Target::GetScratchSwiftASTContext( !swift_ast_ctx->HasFatalErrors()) { StackFrameWP frame_wp(frame_sp); SymbolContext sc = frame_sp->GetSymbolContext(lldb::eSymbolContextEverything); - swift_ast_ctx->PerformAutoImport(*swift_ast_ctx, sc, frame_wp, nullptr, error); + llvm::SmallVector modules; + swift_ast_ctx->GetCompileUnitImports(*swift_ast_ctx, sc, frame_wp, modules, + error); } return SwiftASTContextReader(GetSwiftScratchContextLock(), swift_ast_ctx); From f53d12b2b0b7ea677ff6aeedcb303e8cd8ec2fbc Mon Sep 17 00:00:00 2001 From: Hamish Knight Date: Tue, 14 Apr 2020 16:26:28 -0700 Subject: [PATCH 266/286] [lldb] Resolve imports before manipulating AST Imports need to be resolved before the SwiftASTManipulator is run, as it can query interface types. --- .../ExpressionParser/Swift/SwiftExpressionParser.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp index 6e4bf518a79f1..03da08b60d391 100644 --- a/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp +++ b/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp @@ -1280,6 +1280,13 @@ static llvm::Expected ParseAndImport( // inserting them in. swift_ast_context->AddDebuggerClient(external_lookup); + if (swift_ast_context->HasErrors()) + return make_error(); + + // Resolve the file's imports, including the implicit ones returned from + // GetImplicitImports. + swift::performImportResolution(*source_file); + if (swift_ast_context->HasErrors()) return make_error(); @@ -1331,11 +1338,6 @@ static llvm::Expected ParseAndImport( stack_frame_sp.reset(); } - swift::performImportResolution(*source_file); - - if (swift_ast_context->HasErrors()) - return make_error(); - // Cache the source file's imports such that they're accessible to future // expression evaluations. { From 1be5d83869c512eae5c77e5e1f9e952a8f9ab6b5 Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Wed, 15 Apr 2020 09:14:57 -0700 Subject: [PATCH 267/286] Bug where insn-based unwind plans on arm64 could be wrong (#1082) Fix a bug where UnwindAssemblyInstEmulation would confuse which register is used to compute the Canonical Frame Address after it had branched over a mid-function epilogue (where the CFA reg changes from $fp to $sp in the process of epiloguing). Reinstate the correct CFA register after we forward the unwind rule for branch targets. The failure mode was that UnwindAssemblyInstEmulation would think CFA was set in terms of $sp after one of these epilogues, and if it sees modifications to $sp after the branch target, it would change the CFA offset in the unwind rule -- even though the CFA is defined in terms of $fp and the $sp changes are irrelevant to correct calculation. Differential Revision: https://reviews.llvm.org/D78077 (cherry picked from commit 1cd92e480c12c03ab9a381b29e4e3964892afa01) --- .../UnwindAssemblyInstEmulation.cpp | 46 ++++++-- .../ARM64/TestArm64InstEmulation.cpp | 100 ++++++++++++++++++ 2 files changed, 137 insertions(+), 9 deletions(-) diff --git a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp index 4aa9fb634b61a..04ce23908fd16 100644 --- a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp +++ b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp @@ -123,18 +123,12 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly( // Add the initial state to the save list with offset 0. saved_unwind_states.insert({0, {last_row, m_register_values}}); - // cache the pc register number (in whatever register numbering this - // UnwindPlan uses) for quick reference during instruction parsing. - RegisterInfo pc_reg_info; - m_inst_emulator_up->GetRegisterInfo( - eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc_reg_info); - - // cache the return address register number (in whatever register + // cache the stack pointer register number (in whatever register // numbering this UnwindPlan uses) for quick reference during // instruction parsing. - RegisterInfo ra_reg_info; + RegisterInfo sp_reg_info; m_inst_emulator_up->GetRegisterInfo( - eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, ra_reg_info); + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp_reg_info); // The architecture dependent condition code of the last processed // instruction. @@ -165,6 +159,23 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly( *newrow = *it->second.first; m_curr_row.reset(newrow); m_register_values = it->second.second; + // re-set the CFA register ivars to match the + // new m_curr_row. + if (sp_reg_info.name && + m_curr_row->GetCFAValue().IsRegisterPlusOffset()) { + uint32_t row_cfa_regnum = + m_curr_row->GetCFAValue().GetRegisterNumber(); + lldb::RegisterKind row_kind = + m_unwind_plan_ptr->GetRegisterKind(); + // set m_cfa_reg_info to the row's CFA reg. + m_inst_emulator_up->GetRegisterInfo(row_kind, row_cfa_regnum, + m_cfa_reg_info); + // set m_fp_is_cfa. + if (sp_reg_info.kinds[row_kind] == row_cfa_regnum) + m_fp_is_cfa = false; + else + m_fp_is_cfa = true; + } } m_inst_emulator_up->SetInstruction(inst->GetOpcode(), @@ -195,6 +206,23 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly( std::make_shared(*saved_state.first); m_curr_row->SetOffset(current_offset); m_register_values = saved_state.second; + // re-set the CFA register ivars to match the + // new m_curr_row. + if (sp_reg_info.name && + m_curr_row->GetCFAValue().IsRegisterPlusOffset()) { + uint32_t row_cfa_regnum = + m_curr_row->GetCFAValue().GetRegisterNumber(); + lldb::RegisterKind row_kind = + m_unwind_plan_ptr->GetRegisterKind(); + // set m_cfa_reg_info to the row's CFA reg. + m_inst_emulator_up->GetRegisterInfo(row_kind, row_cfa_regnum, + m_cfa_reg_info); + // set m_fp_is_cfa. + if (sp_reg_info.kinds[row_kind] == row_cfa_regnum) + m_fp_is_cfa = false; + else + m_fp_is_cfa = true; + } bool replace_existing = true; // The last instruction might already // created a row for this offset and diff --git a/lldb/unittests/UnwindAssembly/ARM64/TestArm64InstEmulation.cpp b/lldb/unittests/UnwindAssembly/ARM64/TestArm64InstEmulation.cpp index d853e6fb43c0d..6920bacc741f6 100644 --- a/lldb/unittests/UnwindAssembly/ARM64/TestArm64InstEmulation.cpp +++ b/lldb/unittests/UnwindAssembly/ARM64/TestArm64InstEmulation.cpp @@ -679,3 +679,103 @@ TEST_F(TestArm64InstEmulation, TestRegisterDoubleSpills) { EXPECT_TRUE(regloc.IsSame()); } } + +TEST_F(TestArm64InstEmulation, TestCFARegisterTrackedAcrossJumps) { + ArchSpec arch("arm64-apple-ios10"); + std::unique_ptr engine( + static_cast( + UnwindAssemblyInstEmulation::CreateInstance(arch))); + ASSERT_NE(nullptr, engine); + + UnwindPlan::RowSP row_sp; + AddressRange sample_range; + UnwindPlan unwind_plan(eRegisterKindLLDB); + UnwindPlan::Row::RegisterLocation regloc; + + uint8_t data[] = { + // prologue + 0xf4, 0x4f, 0xbe, 0xa9, // 0: 0xa9be4ff4 stp x20, x19, [sp, #-0x20]! + 0xfd, 0x7b, 0x01, 0xa9, // 4: 0xa9017bfd stp x29, x30, [sp, #0x10] + 0xfd, 0x43, 0x00, 0x91, // 8: 0x910043fd add x29, sp, #0x10 + 0xff, 0x43, 0x00, 0xd1, // 12: 0xd10043ff sub sp, sp, #0x10 + // conditional branch over a mid-function epilogue + 0xeb, 0x00, 0x00, 0x54, // 16: 0x540000eb b.lt <+44> + // mid-function epilogue + 0x1f, 0x20, 0x03, 0xd5, // 20: 0xd503201f nop + 0xe0, 0x03, 0x13, 0xaa, // 24: 0xaa1303e0 mov x0, x19 + 0xbf, 0x43, 0x00, 0xd1, // 28: 0xd10043bf sub sp, x29, #0x10 + 0xfd, 0x7b, 0x41, 0xa9, // 32: 0xa9417bfd ldp x29, x30, [sp, #0x10] + 0xf4, 0x4f, 0xc2, 0xa8, // 36: 0xa8c24ff4 ldp x20, x19, [sp], #0x20 + 0xc0, 0x03, 0x5f, 0xd6, // 40: 0xd65f03c0 ret + // unwind state restored, we're using a frame pointer, let's change the + // stack pointer and see no change in how the CFA is computed + 0x1f, 0x20, 0x03, 0xd5, // 44: 0xd503201f nop + 0xff, 0x43, 0x00, 0xd1, // 48: 0xd10043ff sub sp, sp, #0x10 + 0x1f, 0x20, 0x03, 0xd5, // 52: 0xd503201f nop + // final epilogue + 0xe0, 0x03, 0x13, 0xaa, // 56: 0xaa1303e0 mov x0, x19 + 0xbf, 0x43, 0x00, 0xd1, // 60: 0xd10043bf sub sp, x29, #0x10 + 0xfd, 0x7b, 0x41, 0xa9, // 64: 0xa9417bfd ldp x29, x30, [sp, #0x10] + 0xf4, 0x4f, 0xc2, 0xa8, // 68: 0xa8c24ff4 ldp x20, x19, [sp], #0x20 + 0xc0, 0x03, 0x5f, 0xd6, // 72: 0xd65f03c0 ret + + 0x1f, 0x20, 0x03, 0xd5, // 52: 0xd503201f nop + }; + + // UnwindPlan we expect: + // row[0]: 0: CFA=sp +0 => + // row[1]: 4: CFA=sp+32 => x19=[CFA-24] x20=[CFA-32] + // row[2]: 8: CFA=sp+32 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8] + // row[3]: 12: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8] + // row[4]: 32: CFA=sp+32 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8] + // row[5]: 36: CFA=sp+32 => x19=[CFA-24] x20=[CFA-32] fp= lr= + // row[6]: 40: CFA=sp +0 => x19= x20= fp= lr= + // row[7]: 44: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8] + // row[8]: 64: CFA=sp+32 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8] + // row[9]: 68: CFA=sp+32 => x19=[CFA-24] x20=[CFA-32] fp= lr= + // row[10]: 72: CFA=sp +0 => x19= x20= fp= lr= + + // The specific bug we're looking for is this incorrect CFA definition, + // where the InstEmulation is using the $sp value mixed in with $fp, + // it looks like this: + // + // row[7]: 44: CFA=fp+16 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8] + // row[8]: 52: CFA=fp+64 => x19=[CFA-24] x20=[CFA-32] fp=[CFA-16] lr=[CFA-8] + // row[9]: 68: CFA=fp+64 => x19=[CFA-24] x20=[CFA-32] fp= lr= + + sample_range = AddressRange(0x1000, sizeof(data)); + + EXPECT_TRUE(engine->GetNonCallSiteUnwindPlanFromAssembly( + sample_range, data, sizeof(data), unwind_plan)); + + // Confirm CFA at mid-func epilogue 'ret' is $sp+0 + row_sp = unwind_plan.GetRowForFunctionOffset(40); + EXPECT_EQ(40ull, row_sp->GetOffset()); + EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64); + EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); + EXPECT_EQ(0, row_sp->GetCFAValue().GetOffset()); + + // After the 'ret', confirm we're back to the correct CFA of $fp+16 + row_sp = unwind_plan.GetRowForFunctionOffset(44); + EXPECT_EQ(44ull, row_sp->GetOffset()); + EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64); + EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); + EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); + + // Confirm that we have no additional UnwindPlan rows before the + // real epilogue -- we still get the Row at offset 44. + row_sp = unwind_plan.GetRowForFunctionOffset(60); + EXPECT_EQ(44ull, row_sp->GetOffset()); + EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_fp_arm64); + EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); + EXPECT_EQ(16, row_sp->GetCFAValue().GetOffset()); + + // And in the epilogue, confirm that we start by switching back to + // defining the CFA in terms of $sp. + row_sp = unwind_plan.GetRowForFunctionOffset(64); + EXPECT_EQ(64ull, row_sp->GetOffset()); + EXPECT_TRUE(row_sp->GetCFAValue().GetRegisterNumber() == gpr_sp_arm64); + EXPECT_TRUE(row_sp->GetCFAValue().IsRegisterPlusOffset() == true); + EXPECT_EQ(32, row_sp->GetCFAValue().GetOffset()); +} + From e6d4bac4326f83181808ee392763e469d0ce52a1 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Wed, 15 Apr 2020 10:51:28 -0700 Subject: [PATCH 268/286] Temporarily revert "Preserve the owning module information from DWARF in the synthesized AST" This reverts commit 3c58b0f0909004864366d18bbf58c5765fcfeaf9 while investigating a downstream Swift DWARFImporter problem. --- lldb/include/lldb/Symbol/CompilerType.h | 10 +- lldb/include/lldb/Symbol/TypeSystem.h | 5 +- .../Clang/ClangASTImporter.cpp | 30 --- .../Clang/ClangExpressionDeclMap.cpp | 2 +- .../Clang/ClangExternalASTSourceCallbacks.cpp | 28 -- .../Clang/ClangExternalASTSourceCallbacks.h | 23 +- .../Plugins/Language/ObjC/NSDictionary.cpp | 5 +- .../AppleObjCTypeEncodingParser.cpp | 3 +- .../SymbolFile/DWARF/DWARFASTParserClang.cpp | 92 +++---- .../SymbolFile/DWARF/DWARFASTParserClang.h | 5 - .../SymbolFile/NativePDB/PdbAstBuilder.cpp | 26 +- .../Plugins/SymbolFile/PDB/PDBASTParser.cpp | 25 +- .../MacOSX/SystemRuntimeMacOSX.cpp | 5 +- .../TypeSystem/Clang/TypeSystemClang.cpp | 246 +++++------------- .../TypeSystem/Clang/TypeSystemClang.h | 95 ++----- lldb/source/Symbol/CompilerType.cpp | 8 +- lldb/source/Symbol/Type.cpp | 4 +- lldb/source/Symbol/TypeSystem.cpp | 3 +- .../DWARF/Inputs/ModuleOwnership/A.h | 29 --- .../DWARF/Inputs/ModuleOwnership/B.h | 8 - .../Inputs/ModuleOwnership/module.modulemap | 6 - .../test/Shell/SymbolFile/DWARF/lit.local.cfg | 2 +- .../SymbolFile/DWARF/module-ownership.mm | 42 --- lldb/unittests/Symbol/TestTypeSystemClang.cpp | 48 ++-- .../TestingSupport/Symbol/ClangTestUtils.h | 1 - 25 files changed, 175 insertions(+), 576 deletions(-) delete mode 100644 lldb/test/Shell/SymbolFile/DWARF/Inputs/ModuleOwnership/A.h delete mode 100644 lldb/test/Shell/SymbolFile/DWARF/Inputs/ModuleOwnership/B.h delete mode 100644 lldb/test/Shell/SymbolFile/DWARF/Inputs/ModuleOwnership/module.modulemap delete mode 100644 lldb/test/Shell/SymbolFile/DWARF/module-ownership.mm diff --git a/lldb/include/lldb/Symbol/CompilerType.h b/lldb/include/lldb/Symbol/CompilerType.h index 37ae382ed2128..0f185e5013446 100644 --- a/lldb/include/lldb/Symbol/CompilerType.h +++ b/lldb/include/lldb/Symbol/CompilerType.h @@ -237,13 +237,11 @@ class CompilerType { // an invalid type. CompilerType AddRestrictModifier() const; - /// Create a typedef to this type using "name" as the name of the typedef this - /// type is valid and the type system supports typedefs, else return an - /// invalid type. - /// \param payload The typesystem-specific \p lldb::Type payload. + // Create a typedef to this type using "name" as the name of the typedef this + // type is valid and the type system supports typedefs, else return an + // invalid type. CompilerType CreateTypedef(const char *name, - const CompilerDeclContext &decl_ctx, - uint32_t payload) const; + const CompilerDeclContext &decl_ctx) const; // If the current object represents a typedef type, get the underlying type CompilerType GetTypedefedType() const; diff --git a/lldb/include/lldb/Symbol/TypeSystem.h b/lldb/include/lldb/Symbol/TypeSystem.h index 96bdf3a1c5bf7..d16e772b1c6c4 100644 --- a/lldb/include/lldb/Symbol/TypeSystem.h +++ b/lldb/include/lldb/Symbol/TypeSystem.h @@ -259,12 +259,9 @@ class TypeSystem : public PluginInterface { virtual CompilerType AddRestrictModifier(lldb::opaque_compiler_type_t type); - /// \param opaque_payload The m_payload field of Type, which may - /// carry TypeSystem-specific extra information. virtual CompilerType CreateTypedef(lldb::opaque_compiler_type_t type, const char *name, - const CompilerDeclContext &decl_ctx, - uint32_t opaque_payload); + const CompilerDeclContext &decl_ctx); // Exploring the type diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp index 0a511174ab5bb..7e7e5c8a216a7 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp @@ -18,7 +18,6 @@ #include "Plugins/ExpressionParser/Clang/ClangASTImporter.h" #include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h" -#include "Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h" #include "Plugins/ExpressionParser/Clang/ClangUtil.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" @@ -1006,21 +1005,6 @@ void ClangASTImporter::ASTImporterDelegate::ImportDefinitionTo( } } -/// Recreate a module with its parents in \p to_source and return its id. -static OptionalClangModuleID -RemapModule(OptionalClangModuleID from_id, - ClangExternalASTSourceCallbacks &from_source, - ClangExternalASTSourceCallbacks &to_source) { - if (!from_id.HasValue()) - return {}; - clang::Module *module = from_source.getModule(from_id.GetValue()); - OptionalClangModuleID parent = RemapModule( - from_source.GetIDForModule(module->Parent), from_source, to_source); - TypeSystemClang &to_ts = to_source.GetTypeSystem(); - return to_ts.GetOrCreateClangModule(module->Name, parent, module->IsFramework, - module->IsExplicit); -} - /// Takes a CXXMethodDecl and completes the return type if necessary. This /// is currently only necessary for virtual functions with covariant return /// types where Clang's CodeGen expects that the underlying records are already @@ -1051,20 +1035,6 @@ void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from, if (m_decls_to_ignore.find(to) != m_decls_to_ignore.end()) return clang::ASTImporter::Imported(from, to); - // Transfer module ownership information. - auto *from_source = llvm::dyn_cast_or_null( - getFromContext().getExternalSource()); - // Can also be a ClangASTSourceProxy. - auto *to_source = llvm::dyn_cast_or_null( - getToContext().getExternalSource()); - if (from_source && to_source) { - OptionalClangModuleID from_id(from->getOwningModuleID()); - OptionalClangModuleID to_id = - RemapModule(from_id, *from_source, *to_source); - TypeSystemClang &to_ts = to_source->GetTypeSystem(); - to_ts.SetOwningModule(to, to_id); - } - lldb::user_id_t user_id = LLDB_INVALID_UID; ClangASTMetadata *metadata = m_master.GetDeclMetadata(from); if (metadata) diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp index fd66b6bde0908..0a829f89f1942 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp @@ -1017,7 +1017,7 @@ void ClangExpressionDeclMap::LookupLocalVarNamespace( clang::NamespaceDecl *namespace_decl = m_clang_ast_context->GetUniqueNamespaceDeclaration( - g_lldb_local_vars_namespace_cstr, nullptr, OptionalClangModuleID()); + g_lldb_local_vars_namespace_cstr, nullptr); if (!namespace_decl) return; diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp index 4552bc5ccf8ef..db9d265ba9a2c 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.cpp @@ -13,8 +13,6 @@ using namespace lldb_private; -char ClangExternalASTSourceCallbacks::ID; - void ClangExternalASTSourceCallbacks::CompleteType(clang::TagDecl *tag_decl) { m_ast.CompleteTagDecl(tag_decl); } @@ -45,29 +43,3 @@ void ClangExternalASTSourceCallbacks::FindExternalLexicalDecls( CompleteType(tag_decl); } } - -OptionalClangModuleID -ClangExternalASTSourceCallbacks::RegisterModule(clang::Module *module) { - m_modules.push_back(module); - unsigned id = m_modules.size(); - m_ids.insert({module, id}); - return OptionalClangModuleID(id); -} - -llvm::Optional -ClangExternalASTSourceCallbacks::getSourceDescriptor(unsigned id) { - if (clang::Module *module = getModule(id)) - return {*module}; - return {}; -} - -clang::Module *ClangExternalASTSourceCallbacks::getModule(unsigned id) { - if (id && id <= m_modules.size()) - return m_modules[id - 1]; - return nullptr; -} - -OptionalClangModuleID -ClangExternalASTSourceCallbacks::GetIDForModule(clang::Module *module) { - return OptionalClangModuleID(m_ids[module]); -} diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h index 5be15bb3f5540..98e9f5adbdbf1 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExternalASTSourceCallbacks.h @@ -10,19 +10,14 @@ #define liblldb_ClangExternalASTSourceCallbacks_h_ #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" -#include "clang/Basic/Module.h" +#include "clang/AST/ExternalASTSource.h" namespace lldb_private { -class ClangExternalASTSourceCallbacks : public clang::ExternalASTSource { - /// LLVM RTTI support. - static char ID; +class TypeSystemClang; +class ClangExternalASTSourceCallbacks : public clang::ExternalASTSource { public: - /// LLVM RTTI support. - bool isA(const void *ClassID) const override { return ClassID == &ID; } - static bool classof(const clang::ExternalASTSource *s) { return s->isA(&ID); } - ClangExternalASTSourceCallbacks(TypeSystemClang &ast) : m_ast(ast) {} void FindExternalLexicalDecls( @@ -42,20 +37,8 @@ class ClangExternalASTSourceCallbacks : public clang::ExternalASTSource { llvm::DenseMap &VirtualBaseOffsets) override; - TypeSystemClang &GetTypeSystem() const { return m_ast; } - - /// Module-related methods. - /// \{ - llvm::Optional - getSourceDescriptor(unsigned ID) override; - clang::Module *getModule(unsigned ID) override; - OptionalClangModuleID RegisterModule(clang::Module *module); - OptionalClangModuleID GetIDForModule(clang::Module *module); - /// \} private: TypeSystemClang &m_ast; - std::vector m_modules; - llvm::DenseMap m_ids; }; } // namespace lldb_private diff --git a/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp b/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp index 0e163d56dcec1..d2cb3d19516ca 100644 --- a/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp +++ b/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp @@ -76,9 +76,8 @@ static CompilerType GetLLDBNSPairType(TargetSP target_sp) { if (!compiler_type) { compiler_type = target_ast_context->CreateRecordType( - nullptr, OptionalClangModuleID(), lldb::eAccessPublic, - g___lldb_autogen_nspair.GetCString(), clang::TTK_Struct, - lldb::eLanguageTypeC); + nullptr, lldb::eAccessPublic, g___lldb_autogen_nspair.GetCString(), + clang::TTK_Struct, lldb::eLanguageTypeC); if (compiler_type) { TypeSystemClang::StartTagDeclarationDefinition(compiler_type); diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp index a918c0a686472..2bc6cfd9a7fc9 100644 --- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp +++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp @@ -123,8 +123,7 @@ clang::QualType AppleObjCTypeEncodingParser::BuildAggregate( return clang::QualType(); // This is where we bail out. Sorry! CompilerType union_type(ast_ctx.CreateRecordType( - nullptr, OptionalClangModuleID(), lldb::eAccessPublic, name, kind, - lldb::eLanguageTypeC)); + nullptr, lldb::eAccessPublic, name, kind, lldb::eLanguageTypeC)); if (union_type) { TypeSystemClang::StartTagDeclarationDefinition(union_type); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index 25f18fe56e3bb..f3077c4cdfade 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -212,15 +212,14 @@ TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc, TypeSP type_sp(new Type( die.GetID(), dwarf, pcm_type_sp->GetName(), pcm_type_sp->GetByteSize(), nullptr, LLDB_INVALID_UID, Type::eEncodingInvalid, - &pcm_type_sp->GetDeclaration(), type, Type::ResolveState::Forward, - TypePayloadClang(GetOwningClangModule(die)))); + &pcm_type_sp->GetDeclaration(), type, Type::ResolveState::Forward)); dwarf->GetTypeList().Insert(type_sp); dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); clang::TagDecl *tag_decl = TypeSystemClang::GetAsTagDecl(type); - if (tag_decl) { + if (tag_decl) LinkDeclContextToDIE(tag_decl, die); - } else { + else { clang::DeclContext *defn_decl_ctx = GetCachedClangDeclContextForDIE(die); if (defn_decl_ctx) LinkDeclContextToDIE(defn_decl_ctx, die); @@ -709,7 +708,7 @@ DWARFASTParserClang::ParseTypeModifier(const SymbolContext &sc, type_sp = std::make_shared( die.GetID(), dwarf, attrs.name, attrs.byte_size, nullptr, dwarf->GetUID(attrs.type.Reference()), encoding_data_type, &attrs.decl, - clang_type, resolve_state, TypePayloadClang(GetOwningClangModule(die))); + clang_type, resolve_state); dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); return type_sp; @@ -792,8 +791,7 @@ TypeSP DWARFASTParserClang::ParseEnum(const SymbolContext &sc, clang_type = m_ast.CreateEnumerationType( attrs.name.GetCString(), GetClangDeclContextContainingDIE(die, nullptr), - GetOwningClangModule(die), attrs.decl, enumerator_clang_type, - attrs.is_scoped_enum); + attrs.decl, enumerator_clang_type, attrs.is_scoped_enum); } else { enumerator_clang_type = m_ast.GetEnumerationIntegerType(clang_type.GetOpaqueQualType()); @@ -804,8 +802,7 @@ TypeSP DWARFASTParserClang::ParseEnum(const SymbolContext &sc, type_sp = std::make_shared( die.GetID(), dwarf, attrs.name, attrs.byte_size, nullptr, dwarf->GetUID(attrs.type.Reference()), Type::eEncodingIsUID, &attrs.decl, - clang_type, Type::ResolveState::Forward, - TypePayloadClang(GetOwningClangModule(die))); + clang_type, Type::ResolveState::Forward); if (TypeSystemClang::StartTagDeclarationDefinition(clang_type)) { if (die.HasChildren()) { @@ -1189,8 +1186,7 @@ TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, function_decl = m_ast.CreateFunctionDeclaration( ignore_containing_context ? m_ast.GetTranslationUnitDecl() : containing_decl_ctx, - GetOwningClangModule(die), name, clang_type, attrs.storage, - attrs.is_inline); + name, clang_type, attrs.storage, attrs.is_inline); if (has_template_params) { TypeSystemClang::TemplateParameterInfos template_param_infos; @@ -1198,12 +1194,12 @@ TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, template_function_decl = m_ast.CreateFunctionDeclaration( ignore_containing_context ? m_ast.GetTranslationUnitDecl() : containing_decl_ctx, - GetOwningClangModule(die), attrs.name.GetCString(), clang_type, - attrs.storage, attrs.is_inline); + name, clang_type, attrs.storage, attrs.is_inline); + clang::FunctionTemplateDecl *func_template_decl = - m_ast.CreateFunctionTemplateDecl( - containing_decl_ctx, GetOwningClangModule(die), - template_function_decl, name, template_param_infos); + m_ast.CreateFunctionTemplateDecl(containing_decl_ctx, + template_function_decl, name, + template_param_infos); m_ast.CreateFunctionTemplateSpecializationInfo( template_function_decl, func_template_decl, template_param_infos); } @@ -1601,9 +1597,9 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, TypeSystemClang::TemplateParameterInfos template_param_infos; if (ParseTemplateParameterInfos(die, template_param_infos)) { clang::ClassTemplateDecl *class_template_decl = - m_ast.ParseClassTemplateDecl( - decl_ctx, GetOwningClangModule(die), attrs.accessibility, - attrs.name.GetCString(), tag_decl_kind, template_param_infos); + m_ast.ParseClassTemplateDecl(decl_ctx, attrs.accessibility, + attrs.name.GetCString(), tag_decl_kind, + template_param_infos); if (!class_template_decl) { if (log) { dwarf->GetObjectFile()->GetModule()->LogMessage( @@ -1618,8 +1614,8 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, clang::ClassTemplateSpecializationDecl *class_specialization_decl = m_ast.CreateClassTemplateSpecializationDecl( - decl_ctx, GetOwningClangModule(die), class_template_decl, - tag_decl_kind, template_param_infos); + decl_ctx, class_template_decl, tag_decl_kind, + template_param_infos); clang_type = m_ast.CreateClassTemplateSpecializationType( class_specialization_decl); clang_type_was_created = true; @@ -1632,9 +1628,8 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, if (!clang_type_was_created) { clang_type_was_created = true; clang_type = m_ast.CreateRecordType( - decl_ctx, GetOwningClangModule(die), attrs.accessibility, - attrs.name.GetCString(), tag_decl_kind, attrs.class_language, - &metadata, attrs.exports_symbols); + decl_ctx, attrs.accessibility, attrs.name.GetCString(), tag_decl_kind, + attrs.class_language, &metadata, attrs.exports_symbols); } } @@ -1646,7 +1641,7 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, die.GetID(), dwarf, attrs.name, attrs.byte_size, nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, &attrs.decl, clang_type, Type::ResolveState::Forward, - TypePayloadClang(OptionalClangModuleID(), attrs.is_complete_objc_class)); + TypePayloadClang(attrs.is_complete_objc_class)); // Add our type to the unique type map so we don't end up creating many // copies of the same type over and over in the ASTContext for our @@ -3139,9 +3134,9 @@ size_t DWARFASTParserClang::ParseChildParameters( function_param_types.push_back(type->GetForwardCompilerType()); clang::ParmVarDecl *param_var_decl = - m_ast.CreateParameterDeclaration( - containing_decl_ctx, GetOwningClangModule(die), name, - type->GetForwardCompilerType(), storage); + m_ast.CreateParameterDeclaration(containing_decl_ctx, name, + type->GetForwardCompilerType(), + storage); assert(param_var_decl); function_param_decls.push_back(param_var_decl); @@ -3339,7 +3334,7 @@ clang::Decl *DWARFASTParserClang::GetClangDeclForDIE(const DWARFDIE &die) { TypeSystemClang::DeclContextGetAsDeclContext( dwarf->GetDeclContextContainingUID(die.GetID())); decl = m_ast.CreateVariableDeclaration( - decl_context, GetOwningClangModule(die), name, + decl_context, name, ClangUtil::GetQualType(type->GetForwardCompilerType())); } break; @@ -3356,8 +3351,8 @@ clang::Decl *DWARFASTParserClang::GetClangDeclForDIE(const DWARFDIE &die) { if (clang::NamedDecl *clang_imported_decl = llvm::dyn_cast( (clang::Decl *)imported_decl.GetOpaqueDecl())) - decl = m_ast.CreateUsingDeclaration( - decl_context, OptionalClangModuleID(), clang_imported_decl); + decl = + m_ast.CreateUsingDeclaration(decl_context, clang_imported_decl); } } break; @@ -3375,8 +3370,7 @@ clang::Decl *DWARFASTParserClang::GetClangDeclForDIE(const DWARFDIE &die) { if (clang::NamespaceDecl *ns_decl = TypeSystemClang::DeclContextGetAsNamespaceDecl( imported_decl_ctx)) - decl = m_ast.CreateUsingDirectiveDeclaration( - decl_context, OptionalClangModuleID(), ns_decl); + decl = m_ast.CreateUsingDirectiveDeclaration(decl_context, ns_decl); } } break; @@ -3434,32 +3428,6 @@ DWARFASTParserClang::GetClangDeclContextForDIE(const DWARFDIE &die) { return nullptr; } -OptionalClangModuleID -DWARFASTParserClang::GetOwningClangModule(const DWARFDIE &die) { - if (!die.IsValid()) - return {}; - - for (DWARFDIE parent = die.GetParent(); parent.IsValid(); - parent = parent.GetParent()) { - const dw_tag_t tag = parent.Tag(); - if (tag == DW_TAG_module) { - DWARFDIE module_die = parent; - auto it = m_die_to_module.find(module_die.GetDIE()); - if (it != m_die_to_module.end()) - return it->second; - const char *name = module_die.GetAttributeValueAsString(DW_AT_name, 0); - if (!name) - return {}; - - OptionalClangModuleID id = - m_ast.GetOrCreateClangModule(name, GetOwningClangModule(module_die)); - m_die_to_module.insert({module_die.GetDIE(), id}); - return id; - } - } - return {}; -} - static bool IsSubroutine(const DWARFDIE &die) { switch (die.Tag()) { case DW_TAG_subprogram: @@ -3532,8 +3500,7 @@ clang::BlockDecl *DWARFASTParserClang::ResolveBlockDIE(const DWARFDIE &die) { DWARFDIE decl_context_die; clang::DeclContext *decl_context = GetClangDeclContextContainingDIE(die, &decl_context_die); - decl = - m_ast.CreateBlockDeclaration(decl_context, GetOwningClangModule(die)); + decl = m_ast.CreateBlockDeclaration(decl_context); if (decl) LinkDeclContextToDIE((clang::DeclContext *)decl, die); @@ -3561,8 +3528,7 @@ DWARFASTParserClang::ResolveNamespaceDIE(const DWARFDIE &die) { die.GetAttributeValueAsUnsigned(DW_AT_export_symbols, 0) != 0; namespace_decl = m_ast.GetUniqueNamespaceDeclaration( - namespace_name, containing_decl_ctx, GetOwningClangModule(die), - is_inline); + namespace_name, containing_decl_ctx, is_inline); Log *log = nullptr; // (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO)); if (log) { diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h index c93789ee830ff..9282131301f5d 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h @@ -79,9 +79,6 @@ class DWARFASTParserClang : public DWARFASTParser { DIEToDeclContextMap; typedef std::multimap DeclContextToDIEMap; - typedef llvm::DenseMap - DIEToModuleMap; typedef llvm::DenseMap DIEToDeclMap; typedef llvm::DenseMap DeclToDIEMap; @@ -91,7 +88,6 @@ class DWARFASTParserClang : public DWARFASTParser { DeclToDIEMap m_decl_to_die; DIEToDeclContextMap m_die_to_decl_ctx; DeclContextToDIEMap m_decl_ctx_to_die; - DIEToModuleMap m_die_to_module; std::unique_ptr m_clang_ast_importer_up; /// @} @@ -145,7 +141,6 @@ class DWARFASTParserClang : public DWARFASTParser { clang::DeclContext *GetClangDeclContextContainingDIE(const DWARFDIE &die, DWARFDIE *decl_ctx_die); - lldb_private::OptionalClangModuleID GetOwningClangModule(const DWARFDIE &die); bool CopyUniqueClassMethodTypes(const DWARFDIE &src_class_die, const DWARFDIE &dst_class_die, diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp index 005205c52a841..03cd8ffc53921 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp @@ -776,9 +776,8 @@ clang::QualType PdbAstBuilder::CreateRecordType(PdbTypeSymId id, metadata.SetUserID(toOpaqueUid(id)); metadata.SetIsDynamicCXXType(false); - CompilerType ct = - m_clang.CreateRecordType(context, OptionalClangModuleID(), access, uname, - ttk, lldb::eLanguageTypeC_plus_plus, &metadata); + CompilerType ct = m_clang.CreateRecordType( + context, access, uname, ttk, lldb::eLanguageTypeC_plus_plus, &metadata); lldbassert(ct.IsValid()); @@ -805,8 +804,7 @@ clang::NamespaceDecl * PdbAstBuilder::GetOrCreateNamespaceDecl(const char *name, clang::DeclContext &context) { return m_clang.GetUniqueNamespaceDeclaration( - IsAnonymousNamespaceName(name) ? nullptr : name, &context, - OptionalClangModuleID()); + IsAnonymousNamespaceName(name) ? nullptr : name, &context); } clang::BlockDecl * @@ -816,8 +814,7 @@ PdbAstBuilder::GetOrCreateBlockDecl(PdbCompilandSymId block_id) { clang::DeclContext *scope = GetParentDeclContext(block_id); - clang::BlockDecl *block_decl = - m_clang.CreateBlockDeclaration(scope, OptionalClangModuleID()); + clang::BlockDecl *block_decl = m_clang.CreateBlockDeclaration(scope); m_uid_to_decl.insert({toOpaqueUid(block_id), block_decl}); DeclStatus status; @@ -834,7 +831,7 @@ clang::VarDecl *PdbAstBuilder::CreateVariableDecl(PdbSymUid uid, CVSymbol sym, clang::QualType qt = GetOrCreateType(var_info.type); clang::VarDecl *var_decl = m_clang.CreateVariableDeclaration( - &scope, OptionalClangModuleID(), var_info.name.str().c_str(), qt); + &scope, var_info.name.str().c_str(), qt); m_uid_to_decl[toOpaqueUid(uid)] = var_decl; DeclStatus status; @@ -882,7 +879,7 @@ PdbAstBuilder::GetOrCreateTypedefDecl(PdbGlobalSymId id) { std::string uname = DropNameScope(udt.Name); CompilerType ct = m_clang.CreateTypedefType(ToCompilerType(qt), uname.c_str(), - ToCompilerDeclContext(*scope), 0); + ToCompilerDeclContext(*scope)); clang::TypedefNameDecl *tnd = m_clang.GetAsTypedefDecl(ct); DeclStatus status; status.resolved = true; @@ -1015,8 +1012,7 @@ PdbAstBuilder::GetOrCreateFunctionDecl(PdbCompilandSymId func_id) { proc_name.consume_front("::"); clang::FunctionDecl *function_decl = m_clang.CreateFunctionDeclaration( - parent, OptionalClangModuleID(), proc_name.str().c_str(), func_ct, - storage, false); + parent, proc_name.str().c_str(), func_ct, storage, false); lldbassert(m_uid_to_decl.count(toOpaqueUid(func_id)) == 0); m_uid_to_decl[toOpaqueUid(func_id)] = function_decl; @@ -1084,8 +1080,8 @@ void PdbAstBuilder::CreateFunctionParameters(PdbCompilandSymId func_id, CompilerType param_type_ct = m_clang.GetType(qt); clang::ParmVarDecl *param = m_clang.CreateParameterDeclaration( - &function_decl, OptionalClangModuleID(), param_name.str().c_str(), - param_type_ct, clang::SC_None, true); + &function_decl, param_name.str().c_str(), param_type_ct, + clang::SC_None, true); lldbassert(m_uid_to_decl.count(toOpaqueUid(param_uid)) == 0); m_uid_to_decl[toOpaqueUid(param_uid)] = param; @@ -1106,8 +1102,8 @@ clang::QualType PdbAstBuilder::CreateEnumType(PdbTypeSymId id, Declaration declaration; CompilerType enum_ct = m_clang.CreateEnumerationType( - uname.c_str(), decl_context, OptionalClangModuleID(), declaration, - ToCompilerType(underlying_type), er.isScoped()); + uname.c_str(), decl_context, declaration, ToCompilerType(underlying_type), + er.isScoped()); TypeSystemClang::StartTagDeclarationDefinition(enum_ct); TypeSystemClang::SetHasExternalStorage(enum_ct.GetOpaqueQualType(), true); diff --git a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp index 47f097862c790..8f1a40a82150e 100644 --- a/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp +++ b/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp @@ -408,9 +408,9 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { metadata.SetUserID(type.getSymIndexId()); metadata.SetIsDynamicCXXType(false); - clang_type = m_ast.CreateRecordType( - decl_context, OptionalClangModuleID(), access, name, tag_type_kind, - lldb::eLanguageTypeC_plus_plus, &metadata); + clang_type = + m_ast.CreateRecordType(decl_context, access, name, tag_type_kind, + lldb::eLanguageTypeC_plus_plus, &metadata); assert(clang_type.IsValid()); auto record_decl = @@ -496,8 +496,7 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { // Class). Set it false for now. bool isScoped = false; - ast_enum = m_ast.CreateEnumerationType(name.c_str(), decl_context, - OptionalClangModuleID(), decl, + ast_enum = m_ast.CreateEnumerationType(name.c_str(), decl_context, decl, builtin_type, isScoped); auto enum_decl = TypeSystemClang::GetAsEnumDecl(ast_enum); @@ -550,7 +549,7 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { CompilerType target_ast_type = target_type->GetFullCompilerType(); ast_typedef = m_ast.CreateTypedefType( - target_ast_type, name.c_str(), m_ast.CreateDeclContext(decl_ctx), 0); + target_ast_type, name.c_str(), m_ast.CreateDeclContext(decl_ctx)); if (!ast_typedef) return nullptr; @@ -899,7 +898,7 @@ PDBASTParser::GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol) { return nullptr; decl = m_ast.CreateVariableDeclaration( - decl_context, OptionalClangModuleID(), name.c_str(), + decl_context, name.c_str(), ClangUtil::GetQualType(type->GetLayoutCompilerType())); } @@ -924,8 +923,8 @@ PDBASTParser::GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol) { : clang::StorageClass::SC_None; auto decl = m_ast.CreateFunctionDeclaration( - decl_context, OptionalClangModuleID(), name.c_str(), - type->GetForwardCompilerType(), storage, func->hasInlineAttribute()); + decl_context, name.c_str(), type->GetForwardCompilerType(), storage, + func->hasInlineAttribute()); std::vector params; if (std::unique_ptr sig = func->getSignature()) { @@ -938,8 +937,8 @@ PDBASTParser::GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol) { continue; clang::ParmVarDecl *param = m_ast.CreateParameterDeclaration( - decl, OptionalClangModuleID(), nullptr, - arg_type->GetForwardCompilerType(), clang::SC_None, true); + decl, nullptr, arg_type->GetForwardCompilerType(), + clang::SC_None, true); if (param) params.push_back(param); } @@ -1053,8 +1052,8 @@ clang::DeclContext *PDBASTParser::GetDeclContextContainingSymbol( IsAnonymousNamespaceName(namespace_name) ? nullptr : namespace_name.data(); clang::NamespaceDecl *namespace_decl = - m_ast.GetUniqueNamespaceDeclaration( - namespace_name_c_str, curr_context, OptionalClangModuleID()); + m_ast.GetUniqueNamespaceDeclaration(namespace_name_c_str, + curr_context); m_parent_to_namespaces[curr_context].insert(namespace_decl); m_namespaces.insert(namespace_decl); diff --git a/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp b/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp index 1778e4aafaa25..41a7a525385b7 100644 --- a/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp +++ b/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp @@ -417,9 +417,8 @@ void SystemRuntimeMacOSX::ReadLibdispatchTSDIndexes() { CompilerType uint16 = ast_ctx->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 16); CompilerType dispatch_tsd_indexes_s = ast_ctx->CreateRecordType( - nullptr, OptionalClangModuleID(), lldb::eAccessPublic, - "__lldb_dispatch_tsd_indexes_s", clang::TTK_Struct, - lldb::eLanguageTypeC); + nullptr, lldb::eAccessPublic, "__lldb_dispatch_tsd_indexes_s", + clang::TTK_Struct, lldb::eLanguageTypeC); TypeSystemClang::StartTagDeclarationDefinition(dispatch_tsd_indexes_s); TypeSystemClang::AddFieldToRecordType(dispatch_tsd_indexes_s, diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index d7fb89eafb657..7b6a39756e3c7 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -34,9 +34,6 @@ #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TargetOptions.h" #include "clang/Frontend/FrontendOptions.h" -#include "clang/Lex/HeaderSearch.h" -#include "clang/Lex/HeaderSearchOptions.h" -#include "clang/Lex/ModuleMap.h" #include "clang/Sema/Sema.h" #include "llvm/Support/Signals.h" @@ -315,33 +312,10 @@ static ClangASTMap &GetASTMap() { return *g_map_ptr; } -TypePayloadClang::TypePayloadClang(OptionalClangModuleID owning_module, - bool is_complete_objc_class) - : m_payload(owning_module.GetValue()) { +TypePayloadClang::TypePayloadClang(bool is_complete_objc_class) { SetIsCompleteObjCClass(is_complete_objc_class); } -void TypePayloadClang::SetOwningModule(OptionalClangModuleID id) { - assert(id.GetValue() < ObjCClassBit); - bool is_complete = IsCompleteObjCClass(); - m_payload = id.GetValue(); - SetIsCompleteObjCClass(is_complete); -} - -static void SetMemberOwningModule(clang::Decl *member, - const clang::Decl *parent) { - if (!member || !parent) - return; - - OptionalClangModuleID id(parent->getOwningModuleID()); - if (!id.HasValue()) - return; - - member->setFromASTFile(); - member->setOwningModuleID(id.GetValue()); - member->setModuleOwnershipKind(clang::Decl::ModuleOwnershipKind::Visible); -} - char TypeSystemClang::ID; bool TypeSystemClang::IsOperator(llvm::StringRef name, @@ -527,10 +501,6 @@ static void ParseLangArgs(LangOptions &Opts, InputKind IK, const char *triple) { // // FIXME: This is affected by other options (-fno-inline). Opts.NoInlineDefine = !Opt; - - // This is needed to allocate the extra space for the owning module - // on each decl. - Opts.ModulesLocalVisibility = 1; } TypeSystemClang::TypeSystemClang(llvm::Triple target_triple) { @@ -1206,60 +1176,12 @@ CompilerType TypeSystemClang::GetTypeForDecl(ObjCInterfaceDecl *decl) { #pragma mark Structure, Unions, Classes -void TypeSystemClang::SetOwningModule(clang::Decl *decl, - OptionalClangModuleID owning_module) { - if (!decl || !owning_module.HasValue()) - return; - - decl->setFromASTFile(); - decl->setOwningModuleID(owning_module.GetValue()); - decl->setModuleOwnershipKind(clang::Decl::ModuleOwnershipKind::Visible); - if (auto *decl_ctx = llvm::dyn_cast(decl)) { - decl_ctx->setHasExternalVisibleStorage(); - if (auto *ns = llvm::dyn_cast(decl_ctx)) - ns->getPrimaryContext()->setMustBuildLookupTable(); - } -} - -OptionalClangModuleID -TypeSystemClang::GetOrCreateClangModule(llvm::StringRef name, - OptionalClangModuleID parent, - bool is_framework, bool is_explicit) { - // Get the external AST source which holds the modules. - auto *ast_source = llvm::dyn_cast_or_null( - getASTContext().getExternalSource()); - assert(ast_source && "external ast source was lost"); - if (!ast_source) - return {}; - - // Lazily initialize the module map. - if (!m_header_search_up) { - auto HSOpts = std::make_shared(); - m_header_search_up = std::make_unique( - HSOpts, *m_source_manager_up, *m_diagnostics_engine_up, - *m_language_options_up, m_target_info_up.get()); - m_module_map_up = std::make_unique( - *m_source_manager_up, *m_diagnostics_engine_up, *m_language_options_up, - m_target_info_up.get(), *m_header_search_up); - } - - // Get or create the module context. - bool created; - clang::Module *module; - auto parent_desc = ast_source->getSourceDescriptor(parent.GetValue()); - std::tie(module, created) = m_module_map_up->findOrCreateModule( - name, parent_desc ? parent_desc->getModuleOrNull() : nullptr, - is_framework, is_explicit); - if (!created) - return ast_source->GetIDForModule(module); - - return ast_source->RegisterModule(module); -} - -CompilerType TypeSystemClang::CreateRecordType( - clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, - AccessType access_type, llvm::StringRef name, int kind, - LanguageType language, ClangASTMetadata *metadata, bool exports_symbols) { +CompilerType TypeSystemClang::CreateRecordType(DeclContext *decl_ctx, + AccessType access_type, + llvm::StringRef name, int kind, + LanguageType language, + ClangASTMetadata *metadata, + bool exports_symbols) { ASTContext &ast = getASTContext(); if (decl_ctx == nullptr) @@ -1269,8 +1191,7 @@ CompilerType TypeSystemClang::CreateRecordType( language == eLanguageTypeObjC_plus_plus) { bool isForwardDecl = true; bool isInternal = false; - return CreateObjCClass(name, decl_ctx, owning_module, isForwardDecl, - isInternal, metadata); + return CreateObjCClass(name, decl_ctx, isForwardDecl, isInternal, metadata); } // NOTE: Eventually CXXRecordDecl will be merged back into RecordDecl and @@ -1285,7 +1206,6 @@ CompilerType TypeSystemClang::CreateRecordType( decl->setDeclContext(decl_ctx); if (has_name) decl->setDeclName(&ast.Idents.get(name)); - SetOwningModule(decl, owning_module); if (!has_name) { // In C++ a lambda is also represented as an unnamed class. This is @@ -1394,13 +1314,13 @@ static TemplateParameterList *CreateTemplateParameterList( } clang::FunctionTemplateDecl *TypeSystemClang::CreateFunctionTemplateDecl( - clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, - clang::FunctionDecl *func_decl, const char *name, - const TemplateParameterInfos &template_param_infos) { + clang::DeclContext *decl_ctx, clang::FunctionDecl *func_decl, + const char *name, const TemplateParameterInfos &template_param_infos) { // /// Create a function template node. ASTContext &ast = getASTContext(); llvm::SmallVector template_param_decls; + TemplateParameterList *template_param_list = CreateTemplateParameterList( ast, template_param_infos, template_param_decls); FunctionTemplateDecl *func_tmpl_decl = @@ -1409,7 +1329,6 @@ clang::FunctionTemplateDecl *TypeSystemClang::CreateFunctionTemplateDecl( func_tmpl_decl->setLocation(func_decl->getLocation()); func_tmpl_decl->setDeclName(func_decl->getDeclName()); func_tmpl_decl->init(func_decl, template_param_list); - SetOwningModule(func_tmpl_decl, owning_module); for (size_t i = 0, template_param_decl_count = template_param_decls.size(); i < template_param_decl_count; ++i) { @@ -1436,9 +1355,8 @@ void TypeSystemClang::CreateFunctionTemplateSpecializationInfo( } ClassTemplateDecl *TypeSystemClang::CreateClassTemplateDecl( - DeclContext *decl_ctx, OptionalClangModuleID owning_module, - lldb::AccessType access_type, const char *class_name, int kind, - const TemplateParameterInfos &template_param_infos) { + DeclContext *decl_ctx, lldb::AccessType access_type, const char *class_name, + int kind, const TemplateParameterInfos &template_param_infos) { ASTContext &ast = getASTContext(); ClassTemplateDecl *class_template_decl = nullptr; @@ -1466,7 +1384,6 @@ ClassTemplateDecl *TypeSystemClang::CreateClassTemplateDecl( // What decl context do we use here? TU? The actual decl context? template_cxx_decl->setDeclContext(decl_ctx); template_cxx_decl->setDeclName(decl_name); - SetOwningModule(template_cxx_decl, owning_module); for (size_t i = 0, template_param_decl_count = template_param_decls.size(); i < template_param_decl_count; ++i) { @@ -1484,7 +1401,6 @@ ClassTemplateDecl *TypeSystemClang::CreateClassTemplateDecl( class_template_decl->setDeclName(decl_name); class_template_decl->init(template_cxx_decl, template_param_list); template_cxx_decl->setDescribedClassTemplate(class_template_decl); - SetOwningModule(class_template_decl, owning_module); if (class_template_decl) { if (access_type != eAccessNone) @@ -1529,8 +1445,7 @@ TypeSystemClang::CreateTemplateTemplateParmDecl(const char *template_name) { ClassTemplateSpecializationDecl * TypeSystemClang::CreateClassTemplateSpecializationDecl( - DeclContext *decl_ctx, OptionalClangModuleID owning_module, - ClassTemplateDecl *class_template_decl, int kind, + DeclContext *decl_ctx, ClassTemplateDecl *class_template_decl, int kind, const TemplateParameterInfos &template_param_infos) { ASTContext &ast = getASTContext(); llvm::SmallVector args( @@ -1553,16 +1468,6 @@ TypeSystemClang::CreateClassTemplateSpecializationDecl( ast.getTypeDeclType(class_template_specialization_decl, nullptr); class_template_specialization_decl->setDeclName( class_template_decl->getDeclName()); - // FIXME: Turning this on breaks the libcxx data formatter tests. - // SetOwningModule marks the Decl as external, which prevents a - // LookupPtr from being built. Template instantiations can also not - // be found by ExternalASTSource::FindExternalVisibleDeclsByName(), - // nor can we lazily build a LookupPtr later, because template - // specializations are supposed to be hidden so - // makeDeclVisibleInContextWithFlags() is a noop, as well. - // - // SetOwningModule(class_template_specialization_decl, owning_module); - decl_ctx->addDecl(class_template_specialization_decl); class_template_specialization_decl->setSpecializationKind( TSK_ExplicitSpecialization); @@ -1681,13 +1586,14 @@ bool TypeSystemClang::RecordHasFields(const RecordDecl *record_decl) { #pragma mark Objective-C Classes -CompilerType TypeSystemClang::CreateObjCClass( - llvm::StringRef name, clang::DeclContext *decl_ctx, - OptionalClangModuleID owning_module, bool isForwardDecl, bool isInternal, - ClangASTMetadata *metadata) { +CompilerType TypeSystemClang::CreateObjCClass(llvm::StringRef name, + DeclContext *decl_ctx, + bool isForwardDecl, + bool isInternal, + ClangASTMetadata *metadata) { ASTContext &ast = getASTContext(); assert(!name.empty()); - if (!decl_ctx) + if (decl_ctx == nullptr) decl_ctx = ast.getTranslationUnitDecl(); ObjCInterfaceDecl *decl = ObjCInterfaceDecl::CreateDeserialized(ast, 0); @@ -1695,7 +1601,6 @@ CompilerType TypeSystemClang::CreateObjCClass( decl->setDeclName(&ast.Idents.get(name)); /*isForwardDecl,*/ decl->setImplicit(isInternal); - SetOwningModule(decl, owning_module); if (decl && metadata) SetMetadata(decl, *metadata); @@ -1733,12 +1638,11 @@ TypeSystemClang::GetNumBaseClasses(const CXXRecordDecl *cxx_record_decl, #pragma mark Namespace Declarations NamespaceDecl *TypeSystemClang::GetUniqueNamespaceDeclaration( - const char *name, clang::DeclContext *decl_ctx, - OptionalClangModuleID owning_module, bool is_inline) { + const char *name, clang::DeclContext *decl_ctx, bool is_inline) { NamespaceDecl *namespace_decl = nullptr; ASTContext &ast = getASTContext(); TranslationUnitDecl *translation_unit_decl = ast.getTranslationUnitDecl(); - if (!decl_ctx) + if (decl_ctx == nullptr) decl_ctx = translation_unit_decl; if (name) { @@ -1787,11 +1691,6 @@ NamespaceDecl *TypeSystemClang::GetUniqueNamespaceDeclaration( } } } - - // Note: namespaces can span multiple modules, so perhaps this isn't a good - // idea. - SetOwningModule(namespace_decl, owning_module); - #ifdef LLDB_CONFIGURATION_DEBUG VerifyDecl(namespace_decl); #endif @@ -1799,14 +1698,12 @@ NamespaceDecl *TypeSystemClang::GetUniqueNamespaceDeclaration( } clang::BlockDecl * -TypeSystemClang::CreateBlockDeclaration(clang::DeclContext *ctx, - OptionalClangModuleID owning_module) { +TypeSystemClang::CreateBlockDeclaration(clang::DeclContext *ctx) { if (ctx) { clang::BlockDecl *decl = clang::BlockDecl::CreateDeserialized(getASTContext(), 0); decl->setDeclContext(ctx); ctx->addDecl(decl); - SetOwningModule(decl, owning_module); return decl; } return nullptr; @@ -1830,8 +1727,7 @@ clang::DeclContext *FindLCABetweenDecls(clang::DeclContext *left, } clang::UsingDirectiveDecl *TypeSystemClang::CreateUsingDirectiveDeclaration( - clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, - clang::NamespaceDecl *ns_decl) { + clang::DeclContext *decl_ctx, clang::NamespaceDecl *ns_decl) { if (decl_ctx && ns_decl) { auto *translation_unit = getASTContext().getTranslationUnitDecl(); clang::UsingDirectiveDecl *using_decl = clang::UsingDirectiveDecl::Create( @@ -1841,7 +1737,6 @@ clang::UsingDirectiveDecl *TypeSystemClang::CreateUsingDirectiveDeclaration( FindLCABetweenDecls(decl_ctx, ns_decl, translation_unit)); decl_ctx->addDecl(using_decl); - SetOwningModule(using_decl, owning_module); return using_decl; } return nullptr; @@ -1849,17 +1744,14 @@ clang::UsingDirectiveDecl *TypeSystemClang::CreateUsingDirectiveDeclaration( clang::UsingDecl * TypeSystemClang::CreateUsingDeclaration(clang::DeclContext *current_decl_ctx, - OptionalClangModuleID owning_module, clang::NamedDecl *target) { - if (current_decl_ctx && target) { + if (current_decl_ctx != nullptr && target != nullptr) { clang::UsingDecl *using_decl = clang::UsingDecl::Create( getASTContext(), current_decl_ctx, clang::SourceLocation(), clang::NestedNameSpecifierLoc(), clang::DeclarationNameInfo(), false); - SetOwningModule(using_decl, owning_module); clang::UsingShadowDecl *shadow_decl = clang::UsingShadowDecl::Create( getASTContext(), current_decl_ctx, clang::SourceLocation(), using_decl, target); - SetOwningModule(shadow_decl, owning_module); using_decl->addShadowDecl(shadow_decl); current_decl_ctx->addDecl(using_decl); return using_decl; @@ -1868,8 +1760,7 @@ TypeSystemClang::CreateUsingDeclaration(clang::DeclContext *current_decl_ctx, } clang::VarDecl *TypeSystemClang::CreateVariableDeclaration( - clang::DeclContext *decl_context, OptionalClangModuleID owning_module, - const char *name, clang::QualType type) { + clang::DeclContext *decl_context, const char *name, clang::QualType type) { if (decl_context) { clang::VarDecl *var_decl = clang::VarDecl::CreateDeserialized(getASTContext(), 0); @@ -1877,7 +1768,6 @@ clang::VarDecl *TypeSystemClang::CreateVariableDeclaration( if (name && name[0]) var_decl->setDeclName(&getASTContext().Idents.getOwn(name)); var_decl->setType(type); - SetOwningModule(var_decl, owning_module); var_decl->setAccess(clang::AS_public); decl_context->addDecl(var_decl); return var_decl; @@ -1989,12 +1879,11 @@ TypeSystemClang::GetDeclarationName(const char *name, } FunctionDecl *TypeSystemClang::CreateFunctionDeclaration( - clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, - const char *name, const CompilerType &function_clang_type, int storage, - bool is_inline) { + DeclContext *decl_ctx, const char *name, + const CompilerType &function_clang_type, int storage, bool is_inline) { FunctionDecl *func_decl = nullptr; ASTContext &ast = getASTContext(); - if (!decl_ctx) + if (decl_ctx == nullptr) decl_ctx = ast.getTranslationUnitDecl(); const bool hasWrittenPrototype = true; @@ -2011,7 +1900,6 @@ FunctionDecl *TypeSystemClang::CreateFunctionDeclaration( func_decl->setHasWrittenPrototype(hasWrittenPrototype); func_decl->setConstexprKind(isConstexprSpecified ? CSK_constexpr : CSK_unspecified); - SetOwningModule(func_decl, owning_module); if (func_decl) decl_ctx->addDecl(func_decl); @@ -2062,9 +1950,8 @@ TypeSystemClang::CreateFunctionType(const CompilerType &result_type, } ParmVarDecl *TypeSystemClang::CreateParameterDeclaration( - clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, - const char *name, const CompilerType ¶m_type, int storage, - bool add_decl) { + clang::DeclContext *decl_ctx, const char *name, + const CompilerType ¶m_type, int storage, bool add_decl) { ASTContext &ast = getASTContext(); auto *decl = ParmVarDecl::CreateDeserialized(ast, 0); decl->setDeclContext(decl_ctx); @@ -2072,7 +1959,6 @@ ParmVarDecl *TypeSystemClang::CreateParameterDeclaration( decl->setDeclName(&ast.Idents.get(name)); decl->setType(ClangUtil::GetQualType(param_type)); decl->setStorageClass(static_cast(storage)); - SetOwningModule(decl, owning_module); if (add_decl) decl_ctx->addDecl(decl); @@ -2134,9 +2020,8 @@ CompilerType TypeSystemClang::CreateStructForIdentifier( return type; } - type = CreateRecordType(nullptr, OptionalClangModuleID(), lldb::eAccessPublic, - type_name.GetCString(), clang::TTK_Struct, - lldb::eLanguageTypeC); + type = CreateRecordType(nullptr, lldb::eAccessPublic, type_name.GetCString(), + clang::TTK_Struct, lldb::eLanguageTypeC); StartTagDeclarationDefinition(type); for (const auto &field : type_fields) AddFieldToRecordType(type, field.first, field.second, lldb::eAccessPublic, @@ -2161,24 +2046,24 @@ CompilerType TypeSystemClang::GetOrCreateStructForIdentifier( #pragma mark Enumeration Types -CompilerType TypeSystemClang::CreateEnumerationType( - const char *name, clang::DeclContext *decl_ctx, - OptionalClangModuleID owning_module, const Declaration &decl, - const CompilerType &integer_clang_type, bool is_scoped) { +CompilerType +TypeSystemClang::CreateEnumerationType(const char *name, DeclContext *decl_ctx, + const Declaration &decl, + const CompilerType &integer_clang_type, + bool is_scoped) { // TODO: Do something intelligent with the Declaration object passed in // like maybe filling in the SourceLocation with it... ASTContext &ast = getASTContext(); // TODO: ask about these... // const bool IsFixed = false; - EnumDecl *enum_decl = EnumDecl::CreateDeserialized(ast, 0); - enum_decl->setDeclContext(decl_ctx); - if (name && name[0]) - enum_decl->setDeclName(&ast.Idents.get(name)); - enum_decl->setScoped(is_scoped); - enum_decl->setScopedUsingClassTag(is_scoped); - enum_decl->setFixed(false); - SetOwningModule(enum_decl, owning_module); + EnumDecl *enum_decl = EnumDecl::Create( + ast, decl_ctx, SourceLocation(), SourceLocation(), + name && name[0] ? &ast.Idents.get(name) : nullptr, nullptr, + is_scoped, // IsScoped + is_scoped, // IsScopedUsingClassTag + false); // IsFixed + if (enum_decl) { if (decl_ctx) decl_ctx->addDecl(enum_decl); @@ -4366,7 +4251,7 @@ TypeSystemClang::GetNonReferenceType(lldb::opaque_compiler_type_t type) { CompilerType TypeSystemClang::CreateTypedefType( const CompilerType &type, const char *typedef_name, - const CompilerDeclContext &compiler_decl_ctx, uint32_t payload) { + const CompilerDeclContext &compiler_decl_ctx) { if (type && typedef_name && typedef_name[0]) { TypeSystemClang *ast = llvm::dyn_cast(type.GetTypeSystem()); @@ -4377,7 +4262,7 @@ CompilerType TypeSystemClang::CreateTypedefType( clang::DeclContext *decl_ctx = TypeSystemClang::DeclContextGetAsDeclContext(compiler_decl_ctx); - if (!decl_ctx) + if (decl_ctx == nullptr) decl_ctx = ast->getASTContext().getTranslationUnitDecl(); clang::TypedefDecl *decl = @@ -4386,7 +4271,6 @@ CompilerType TypeSystemClang::CreateTypedefType( decl->setDeclName(&clang_ast.Idents.get(typedef_name)); decl->setTypeSourceInfo(clang_ast.getTrivialTypeSourceInfo(qual_type)); - SetOwningModule(decl, TypePayloadClang(payload).GetOwningModule()); decl->setAccess(clang::AS_public); // TODO respect proper access specifier decl_ctx->addDecl(decl); @@ -4475,23 +4359,24 @@ TypeSystemClang::AddRestrictModifier(lldb::opaque_compiler_type_t type) { return CompilerType(); } -CompilerType TypeSystemClang::CreateTypedef( - lldb::opaque_compiler_type_t type, const char *typedef_name, - const CompilerDeclContext &compiler_decl_ctx, uint32_t payload) { +CompilerType +TypeSystemClang::CreateTypedef(lldb::opaque_compiler_type_t type, + const char *typedef_name, + const CompilerDeclContext &compiler_decl_ctx) { if (type) { clang::ASTContext &clang_ast = getASTContext(); clang::QualType qual_type(GetQualType(type)); clang::DeclContext *decl_ctx = TypeSystemClang::DeclContextGetAsDeclContext(compiler_decl_ctx); - if (!decl_ctx) + if (decl_ctx == nullptr) decl_ctx = getASTContext().getTranslationUnitDecl(); - clang::TypedefDecl *decl = clang::TypedefDecl::Create( - clang_ast, decl_ctx, clang::SourceLocation(), clang::SourceLocation(), - &clang_ast.Idents.get(typedef_name), - clang_ast.getTrivialTypeSourceInfo(qual_type)); - SetOwningModule(decl, TypePayloadClang(payload).GetOwningModule()); + clang::TypedefDecl *decl = + clang::TypedefDecl::CreateDeserialized(clang_ast, 0); + decl->setDeclContext(decl_ctx); + decl->setDeclName(&clang_ast.Idents.get(typedef_name)); + decl->setTypeSourceInfo(clang_ast.getTrivialTypeSourceInfo(qual_type)); clang::TagDecl *tdecl = nullptr; if (!qual_type.isNull()) { @@ -7048,7 +6933,6 @@ clang::FieldDecl *TypeSystemClang::AddFieldToRecordType( field->setType(ClangUtil::GetQualType(field_clang_type)); if (bit_width) field->setBitWidth(bit_width); - SetMemberOwningModule(field, record_decl); if (name.empty()) { // Determine whether this field corresponds to an anonymous struct or @@ -7092,7 +6976,6 @@ clang::FieldDecl *TypeSystemClang::AddFieldToRecordType( ivar->setBitWidth(bit_width); ivar->setSynthesize(is_synthesized); field = ivar; - SetMemberOwningModule(field, class_interface_decl); if (field) { class_interface_decl->addDecl(field); @@ -7156,7 +7039,6 @@ void TypeSystemClang::BuildIndirectFields(const CompilerType &type) { ast->getASTContext(), record_decl, clang::SourceLocation(), nested_field_decl->getIdentifier(), nested_field_decl->getType(), {chain, 2}); - SetMemberOwningModule(indirect_field, record_decl); indirect_field->setImplicit(); @@ -7187,7 +7069,6 @@ void TypeSystemClang::BuildIndirectFields(const CompilerType &type) { nested_indirect_field_decl->getIdentifier(), nested_indirect_field_decl->getType(), {chain, nested_chain_size + 1}); - SetMemberOwningModule(indirect_field, record_decl); indirect_field->setImplicit(); @@ -7254,7 +7135,6 @@ clang::VarDecl *TypeSystemClang::AddVariableToRecordType( var_decl->setDeclName(ident); var_decl->setType(ClangUtil::GetQualType(var_type)); var_decl->setStorageClass(clang::SC_Static); - SetMemberOwningModule(var_decl, record_decl); if (!var_decl) return nullptr; @@ -7392,7 +7272,6 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType( cxx_method_decl->setConstexprKind(CSK_unspecified); } } - SetMemberOwningModule(cxx_method_decl, cxx_record_decl); clang::AccessSpecifier access_specifier = TypeSystemClang::ConvertAccessTypeToAccessSpecifier(access); @@ -7569,7 +7448,6 @@ bool TypeSystemClang::AddObjCClassProperty( ? ivar_decl->getType() : ClangUtil::GetQualType(property_clang_type), prop_type_source); - SetMemberOwningModule(property_decl, class_interface_decl); if (!property_decl) return false; @@ -7661,7 +7539,6 @@ bool TypeSystemClang::AddObjCClassProperty( getter->setDefined(isDefined); getter->setDeclImplementation(impControl); getter->setRelatedResultType(HasRelatedResultType); - SetMemberOwningModule(getter, class_interface_decl); if (getter) { if (metadata) @@ -7703,7 +7580,6 @@ bool TypeSystemClang::AddObjCClassProperty( setter->setDefined(isDefined); setter->setDeclImplementation(impControl); setter->setRelatedResultType(HasRelatedResultType); - SetMemberOwningModule(setter, class_interface_decl); if (setter) { if (metadata) @@ -7833,7 +7709,6 @@ clang::ObjCMethodDecl *TypeSystemClang::AddMethodToObjCObjectType( objc_method_decl->setDefined(isDefined); objc_method_decl->setDeclImplementation(impControl); objc_method_decl->setRelatedResultType(HasRelatedResultType); - SetMemberOwningModule(objc_method_decl, class_interface_decl); if (objc_method_decl == nullptr) return nullptr; @@ -8072,7 +7947,6 @@ clang::EnumConstantDecl *TypeSystemClang::AddEnumerationValueToEnumerationType( enumerator_decl->setDeclName(&getASTContext().Idents.get(name)); enumerator_decl->setType(clang::QualType(enutype, 0)); enumerator_decl->setInitVal(value); - SetMemberOwningModule(enumerator_decl, enutype->getDecl()); if (!enumerator_decl) return nullptr; @@ -8977,14 +8851,14 @@ void TypeSystemClang::DumpTypeName(const CompilerType &type) { } clang::ClassTemplateDecl *TypeSystemClang::ParseClassTemplateDecl( - clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, - lldb::AccessType access_type, const char *parent_name, int tag_decl_kind, + clang::DeclContext *decl_ctx, lldb::AccessType access_type, + const char *parent_name, int tag_decl_kind, const TypeSystemClang::TemplateParameterInfos &template_param_infos) { if (template_param_infos.IsValid()) { std::string template_basename(parent_name); template_basename.erase(template_basename.find('<')); - return CreateClassTemplateDecl(decl_ctx, owning_module, access_type, + return CreateClassTemplateDecl(decl_ctx, access_type, template_basename.c_str(), tag_decl_kind, template_param_infos); } diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index 4eab2bea18c05..0bfdd5bd53106 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -49,30 +49,13 @@ namespace lldb_private { class Declaration; -/// A Clang module ID. -class OptionalClangModuleID { - unsigned m_id = 0; - -public: - OptionalClangModuleID() = default; - explicit OptionalClangModuleID(unsigned id) : m_id(id) {} - bool HasValue() const { return m_id != 0; } - unsigned GetValue() const { return m_id; } -}; - /// The implementation of lldb::Type's m_payload field for TypeSystemClang. class TypePayloadClang { - /// The Layout is as follows: - /// \verbatim - /// bit 0..30 ... Owning Module ID. - /// bit 31 ...... IsCompleteObjCClass. - /// \endverbatim + /// Layout: bit 31 ... IsCompleteObjCClass. Type::Payload m_payload = 0; - public: TypePayloadClang() = default; - explicit TypePayloadClang(OptionalClangModuleID owning_module, - bool is_complete_objc_class = false); + explicit TypePayloadClang(bool is_complete_objc_class); explicit TypePayloadClang(uint32_t opaque_payload) : m_payload(opaque_payload) {} operator Type::Payload() { return m_payload; } @@ -82,11 +65,6 @@ class TypePayloadClang { m_payload = is_complete_objc_class ? Flags(m_payload).Set(ObjCClassBit) : Flags(m_payload).Clear(ObjCClassBit); } - OptionalClangModuleID GetOwningModule() { - return OptionalClangModuleID(Flags(m_payload).Clear(ObjCClassBit)); - } - void SetOwningModule(OptionalClangModuleID id); - /// \} }; /// A TypeSystem implementation based on Clang. @@ -303,14 +281,7 @@ class TypeSystemClang : public TypeSystem { static uint32_t GetNumBaseClasses(const clang::CXXRecordDecl *cxx_record_decl, bool omit_empty_base_classes); - /// Synthesize a clang::Module and return its ID or a default-constructed ID. - OptionalClangModuleID GetOrCreateClangModule(llvm::StringRef name, - OptionalClangModuleID parent, - bool is_framework = false, - bool is_explicit = false); - CompilerType CreateRecordType(clang::DeclContext *decl_ctx, - OptionalClangModuleID owning_module, lldb::AccessType access_type, llvm::StringRef name, int kind, lldb::LanguageType language, @@ -336,7 +307,6 @@ class TypeSystemClang : public TypeSystem { clang::FunctionTemplateDecl * CreateFunctionTemplateDecl(clang::DeclContext *decl_ctx, - OptionalClangModuleID owning_module, clang::FunctionDecl *func_decl, const char *name, const TemplateParameterInfos &infos); @@ -346,7 +316,6 @@ class TypeSystemClang : public TypeSystem { clang::ClassTemplateDecl * CreateClassTemplateDecl(clang::DeclContext *decl_ctx, - OptionalClangModuleID owning_module, lldb::AccessType access_type, const char *class_name, int kind, const TemplateParameterInfos &infos); @@ -354,7 +323,7 @@ class TypeSystemClang : public TypeSystem { CreateTemplateTemplateParmDecl(const char *template_name); clang::ClassTemplateSpecializationDecl *CreateClassTemplateSpecializationDecl( - clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, + clang::DeclContext *decl_ctx, clang::ClassTemplateDecl *class_template_decl, int kind, const TemplateParameterInfos &infos); @@ -374,9 +343,8 @@ class TypeSystemClang : public TypeSystem { static bool RecordHasFields(const clang::RecordDecl *record_decl); CompilerType CreateObjCClass(llvm::StringRef name, - clang::DeclContext *decl_ctx, - OptionalClangModuleID owning_module, - bool isForwardDecl, bool isInternal, + clang::DeclContext *decl_ctx, bool isForwardDecl, + bool isInternal, ClangASTMetadata *metadata = nullptr); bool SetTagTypeKind(clang::QualType type, int kind) const; @@ -393,16 +361,14 @@ class TypeSystemClang : public TypeSystem { clang::NamespaceDecl * GetUniqueNamespaceDeclaration(const char *name, clang::DeclContext *decl_ctx, - OptionalClangModuleID owning_module, bool is_inline = false); // Function Types clang::FunctionDecl * - CreateFunctionDeclaration(clang::DeclContext *decl_ctx, - OptionalClangModuleID owning_module, - const char *name, const CompilerType &function_Type, - int storage, bool is_inline); + CreateFunctionDeclaration(clang::DeclContext *decl_ctx, const char *name, + const CompilerType &function_Type, int storage, + bool is_inline); CompilerType CreateFunctionType(const CompilerType &result_type, const CompilerType *args, unsigned num_args, @@ -416,11 +382,11 @@ class TypeSystemClang : public TypeSystem { type_quals, clang::CC_C); } - clang::ParmVarDecl * - CreateParameterDeclaration(clang::DeclContext *decl_ctx, - OptionalClangModuleID owning_module, - const char *name, const CompilerType ¶m_type, - int storage, bool add_decl = false); + clang::ParmVarDecl *CreateParameterDeclaration(clang::DeclContext *decl_ctx, + const char *name, + const CompilerType ¶m_type, + int storage, + bool add_decl=false); void SetFunctionParameters(clang::FunctionDecl *function_decl, clang::ParmVarDecl **params, unsigned num_params); @@ -435,7 +401,6 @@ class TypeSystemClang : public TypeSystem { // Enumeration Types CompilerType CreateEnumerationType(const char *name, clang::DeclContext *decl_ctx, - OptionalClangModuleID owning_module, const Declaration &decl, const CompilerType &integer_qual_type, bool is_scoped); @@ -492,10 +457,6 @@ class TypeSystemClang : public TypeSystem { /// TypeSystemClang. CompilerDeclContext CreateDeclContext(clang::DeclContext *ctx); - /// Set the owning module for \p decl. - static void SetOwningModule(clang::Decl *decl, - OptionalClangModuleID owning_module); - std::vector DeclContextFindDeclByName(void *opaque_decl_ctx, ConstString name, const bool ignore_using_decls) override; @@ -658,13 +619,11 @@ class TypeSystemClang : public TypeSystem { // Creating related types - /// Using the current type, create a new typedef to that type using - /// "typedef_name" as the name and "decl_ctx" as the decl context. - /// \param payload is an opaque TypePayloadClang. + // Using the current type, create a new typedef to that type using + // "typedef_name" as the name and "decl_ctx" as the decl context. static CompilerType CreateTypedefType(const CompilerType &type, const char *typedef_name, - const CompilerDeclContext &compiler_decl_ctx, - uint32_t opaque_payload); + const CompilerDeclContext &compiler_decl_ctx); CompilerType GetArrayElementType(lldb::opaque_compiler_type_t type, uint64_t *stride) override; @@ -715,8 +674,7 @@ class TypeSystemClang : public TypeSystem { CompilerType CreateTypedef(lldb::opaque_compiler_type_t type, const char *name, - const CompilerDeclContext &decl_ctx, - uint32_t opaque_payload) override; + const CompilerDeclContext &decl_ctx) override; // If the current object represents a typedef type, get the underlying type CompilerType GetTypedefedType(lldb::opaque_compiler_type_t type) override; @@ -972,24 +930,20 @@ class TypeSystemClang : public TypeSystem { GetAsObjCInterfaceDecl(const CompilerType &type); clang::ClassTemplateDecl *ParseClassTemplateDecl( - clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, - lldb::AccessType access_type, const char *parent_name, int tag_decl_kind, + clang::DeclContext *decl_ctx, lldb::AccessType access_type, + const char *parent_name, int tag_decl_kind, const TypeSystemClang::TemplateParameterInfos &template_param_infos); - clang::BlockDecl *CreateBlockDeclaration(clang::DeclContext *ctx, - OptionalClangModuleID owning_module); + clang::BlockDecl *CreateBlockDeclaration(clang::DeclContext *ctx); clang::UsingDirectiveDecl * CreateUsingDirectiveDeclaration(clang::DeclContext *decl_ctx, - OptionalClangModuleID owning_module, clang::NamespaceDecl *ns_decl); clang::UsingDecl *CreateUsingDeclaration(clang::DeclContext *current_decl_ctx, - OptionalClangModuleID owning_module, clang::NamedDecl *target); clang::VarDecl *CreateVariableDeclaration(clang::DeclContext *decl_context, - OptionalClangModuleID owning_module, const char *name, clang::QualType type); @@ -1012,13 +966,6 @@ class TypeSystemClang : public TypeSystem { clang::DeclarationName GetDeclarationName(const char *name, const CompilerType &function_clang_type); - clang::LangOptions *GetLangOpts() const { - return m_language_options_up.get(); - } - clang::SourceManager *GetSourceMgr() const { - return m_source_manager_up.get(); - } - private: const clang::ClassTemplateSpecializationDecl * GetAsTemplateSpecialization(lldb::opaque_compiler_type_t type); @@ -1036,8 +983,6 @@ class TypeSystemClang : public TypeSystem { std::unique_ptr m_identifier_table_up; std::unique_ptr m_selector_table_up; std::unique_ptr m_builtins_up; - std::unique_ptr m_header_search_up; - std::unique_ptr m_module_map_up; std::unique_ptr m_dwarf_ast_parser_up; std::unique_ptr m_pdb_ast_parser_up; std::unique_ptr m_mangle_ctx_up; diff --git a/lldb/source/Symbol/CompilerType.cpp b/lldb/source/Symbol/CompilerType.cpp index 79fadea36f66b..0d56e86410585 100644 --- a/lldb/source/Symbol/CompilerType.cpp +++ b/lldb/source/Symbol/CompilerType.cpp @@ -452,11 +452,11 @@ CompilerType CompilerType::AddRestrictModifier() const { return CompilerType(); } -CompilerType CompilerType::CreateTypedef(const char *name, - const CompilerDeclContext &decl_ctx, - uint32_t payload) const { +CompilerType +CompilerType::CreateTypedef(const char *name, + const CompilerDeclContext &decl_ctx) const { if (IsValid()) - return m_type_system->CreateTypedef(m_type, name, decl_ctx, payload); + return m_type_system->CreateTypedef(m_type, name, decl_ctx); else return CompilerType(); } diff --git a/lldb/source/Symbol/Type.cpp b/lldb/source/Symbol/Type.cpp index 45ce9c67092ae..b3dbbfba4a7f8 100644 --- a/lldb/source/Symbol/Type.cpp +++ b/lldb/source/Symbol/Type.cpp @@ -505,7 +505,7 @@ bool Type::ResolveClangType(ResolveState compiler_type_resolve_state) { case eEncodingIsTypedefUID: m_compiler_type = encoding_type->GetForwardCompilerType().CreateTypedef( m_name.AsCString("__lldb_invalid_typedef_name"), - GetSymbolFile()->GetDeclContextContainingUID(GetID()), m_payload); + GetSymbolFile()->GetDeclContextContainingUID(GetID())); m_name.Clear(); break; @@ -563,7 +563,7 @@ bool Type::ResolveClangType(ResolveState compiler_type_resolve_state) { case eEncodingIsTypedefUID: m_compiler_type = void_compiler_type.CreateTypedef( m_name.AsCString("__lldb_invalid_typedef_name"), - GetSymbolFile()->GetDeclContextContainingUID(GetID()), m_payload); + GetSymbolFile()->GetDeclContextContainingUID(GetID())); break; case eEncodingIsPointerUID: diff --git a/lldb/source/Symbol/TypeSystem.cpp b/lldb/source/Symbol/TypeSystem.cpp index 4b8fc9b9b3e8d..049c42f1c785d 100644 --- a/lldb/source/Symbol/TypeSystem.cpp +++ b/lldb/source/Symbol/TypeSystem.cpp @@ -113,8 +113,7 @@ TypeSystem::AddRestrictModifier(lldb::opaque_compiler_type_t type) { CompilerType TypeSystem::CreateTypedef(lldb::opaque_compiler_type_t type, const char *name, - const CompilerDeclContext &decl_ctx, - uint32_t opaque_payload) { + const CompilerDeclContext &decl_ctx) { return CompilerType(); } diff --git a/lldb/test/Shell/SymbolFile/DWARF/Inputs/ModuleOwnership/A.h b/lldb/test/Shell/SymbolFile/DWARF/Inputs/ModuleOwnership/A.h deleted file mode 100644 index 4b223cafdcbaf..0000000000000 --- a/lldb/test/Shell/SymbolFile/DWARF/Inputs/ModuleOwnership/A.h +++ /dev/null @@ -1,29 +0,0 @@ -#include "B.h" // -*- ObjC -*- - -typedef int Typedef; - -struct TopLevelStruct { - int a; -}; - -typedef struct Struct_s { - int a; -} Struct; - -struct Nested { - StructB fromb; -}; - -typedef enum Enum_e { a = 0 } Enum; - -@interface SomeClass { -} -@end - -template struct Template { T field; }; -extern template struct Template; - -namespace Namespace { -template struct InNamespace { T field; }; -extern template struct InNamespace; -} diff --git a/lldb/test/Shell/SymbolFile/DWARF/Inputs/ModuleOwnership/B.h b/lldb/test/Shell/SymbolFile/DWARF/Inputs/ModuleOwnership/B.h deleted file mode 100644 index 23d8347a23227..0000000000000 --- a/lldb/test/Shell/SymbolFile/DWARF/Inputs/ModuleOwnership/B.h +++ /dev/null @@ -1,8 +0,0 @@ -typedef struct { - int b; -} StructB; - -namespace Namespace { -template struct AlsoInNamespace { T field; }; -extern template struct AlsoInNamespace; -} // namespace Namespace diff --git a/lldb/test/Shell/SymbolFile/DWARF/Inputs/ModuleOwnership/module.modulemap b/lldb/test/Shell/SymbolFile/DWARF/Inputs/ModuleOwnership/module.modulemap deleted file mode 100644 index b9940a8f53bfa..0000000000000 --- a/lldb/test/Shell/SymbolFile/DWARF/Inputs/ModuleOwnership/module.modulemap +++ /dev/null @@ -1,6 +0,0 @@ -module A { - header "A.h" - module B { - header "B.h" - } -} diff --git a/lldb/test/Shell/SymbolFile/DWARF/lit.local.cfg b/lldb/test/Shell/SymbolFile/DWARF/lit.local.cfg index 84376e61665b9..8c4600c6922b4 100644 --- a/lldb/test/Shell/SymbolFile/DWARF/lit.local.cfg +++ b/lldb/test/Shell/SymbolFile/DWARF/lit.local.cfg @@ -1 +1 @@ -config.suffixes = ['.cpp', '.m', '.mm', '.s', '.test', '.ll'] +config.suffixes = ['.cpp', '.m', '.s', '.test', '.ll'] diff --git a/lldb/test/Shell/SymbolFile/DWARF/module-ownership.mm b/lldb/test/Shell/SymbolFile/DWARF/module-ownership.mm deleted file mode 100644 index 6a876d1ea5786..0000000000000 --- a/lldb/test/Shell/SymbolFile/DWARF/module-ownership.mm +++ /dev/null @@ -1,42 +0,0 @@ -// RUN: %clang --target=x86_64-apple-macosx -g -gmodules \ -// RUN: -fmodules -fmodules-cache-path=%t.cache \ -// RUN: -c -o %t.o %s -I%S/Inputs -// RUN: lldb-test symbols -dump-clang-ast %t.o | FileCheck %s -// Verify that the owning module information from DWARF is preserved in the AST. - -@import A; - -Typedef t1; -// CHECK-DAG: TypedefDecl {{.*}} imported in A Typedef - -TopLevelStruct s1; -// CHECK-DAG: CXXRecordDecl {{.*}} imported in A struct TopLevelStruct -// CHECK-DAG: -FieldDecl {{.*}} in A a 'int' - -Struct s2; -// CHECK-DAG: CXXRecordDecl {{.*}} imported in A struct - -StructB s3; -// CHECK-DAG: CXXRecordDecl {{.*}} imported in A.B struct -// CHECK-DAG: -FieldDecl {{.*}} in A.B b 'int' - -Nested s4; -// CHECK-DAG: CXXRecordDecl {{.*}} imported in A struct Nested -// CHECK-DAG: -FieldDecl {{.*}} in A fromb 'StructB' - -Enum e1; -// CHECK-DAG: EnumDecl {{.*}} imported in A {{.*}} Enum_e -// FIXME: -EnumConstantDecl {{.*}} imported in A a - -SomeClass *obj1; -// CHECK-DAG: ObjCInterfaceDecl {{.*}} imported in A {{.*}} SomeClass - -// Template specializations are not yet supported, so they lack the ownership info: -Template t2; -// CHECK-DAG: ClassTemplateSpecializationDecl {{.*}} struct Template - -Namespace::InNamespace t3; -// CHECK-DAG: ClassTemplateSpecializationDecl {{.*}} struct InNamespace - -Namespace::AlsoInNamespace t4; -// CHECK-DAG: ClassTemplateSpecializationDecl {{.*}} struct AlsoInNamespace diff --git a/lldb/unittests/Symbol/TestTypeSystemClang.cpp b/lldb/unittests/Symbol/TestTypeSystemClang.cpp index 3aef16788645d..8b716be955e80 100644 --- a/lldb/unittests/Symbol/TestTypeSystemClang.cpp +++ b/lldb/unittests/Symbol/TestTypeSystemClang.cpp @@ -14,7 +14,6 @@ #include "lldb/Host/HostInfo.h" #include "lldb/Symbol/Declaration.h" #include "clang/AST/DeclCXX.h" -#include "clang/AST/DeclObjC.h" #include "clang/AST/ExprCXX.h" #include "gtest/gtest.h" @@ -227,8 +226,8 @@ TEST_F(TestTypeSystemClang, TestIsClangType) { TypeSystemClang::GetOpaqueCompilerType(&context, lldb::eBasicTypeBool); CompilerType bool_type(m_ast.get(), bool_ctype); CompilerType record_type = m_ast->CreateRecordType( - nullptr, OptionalClangModuleID(100), lldb::eAccessPublic, "FooRecord", - clang::TTK_Struct, lldb::eLanguageTypeC_plus_plus, nullptr); + nullptr, lldb::eAccessPublic, "FooRecord", clang::TTK_Struct, + lldb::eLanguageTypeC_plus_plus, nullptr); // Clang builtin type and record type should pass EXPECT_TRUE(ClangUtil::IsClangType(bool_type)); EXPECT_TRUE(ClangUtil::IsClangType(record_type)); @@ -239,8 +238,8 @@ TEST_F(TestTypeSystemClang, TestIsClangType) { TEST_F(TestTypeSystemClang, TestRemoveFastQualifiers) { CompilerType record_type = m_ast->CreateRecordType( - nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "FooRecord", - clang::TTK_Struct, lldb::eLanguageTypeC_plus_plus, nullptr); + nullptr, lldb::eAccessPublic, "FooRecord", clang::TTK_Struct, + lldb::eLanguageTypeC_plus_plus, nullptr); QualType qt; qt = ClangUtil::GetQualType(record_type); @@ -311,8 +310,8 @@ TEST_F(TestTypeSystemClang, TestRecordHasFields) { // Test that a record with no fields returns false CompilerType empty_base = m_ast->CreateRecordType( - nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "EmptyBase", - clang::TTK_Struct, lldb::eLanguageTypeC_plus_plus, nullptr); + nullptr, lldb::eAccessPublic, "EmptyBase", clang::TTK_Struct, + lldb::eLanguageTypeC_plus_plus, nullptr); TypeSystemClang::StartTagDeclarationDefinition(empty_base); TypeSystemClang::CompleteTagDeclarationDefinition(empty_base); @@ -322,8 +321,8 @@ TEST_F(TestTypeSystemClang, TestRecordHasFields) { // Test that a record with direct fields returns true CompilerType non_empty_base = m_ast->CreateRecordType( - nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "NonEmptyBase", - clang::TTK_Struct, lldb::eLanguageTypeC_plus_plus, nullptr); + nullptr, lldb::eAccessPublic, "NonEmptyBase", clang::TTK_Struct, + lldb::eLanguageTypeC_plus_plus, nullptr); TypeSystemClang::StartTagDeclarationDefinition(non_empty_base); FieldDecl *non_empty_base_field_decl = m_ast->AddFieldToRecordType( non_empty_base, "MyField", int_type, eAccessPublic, 0); @@ -338,8 +337,8 @@ TEST_F(TestTypeSystemClang, TestRecordHasFields) { // Test that a record with no direct fields, but fields in a base returns true CompilerType empty_derived = m_ast->CreateRecordType( - nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "EmptyDerived", - clang::TTK_Struct, lldb::eLanguageTypeC_plus_plus, nullptr); + nullptr, lldb::eAccessPublic, "EmptyDerived", clang::TTK_Struct, + lldb::eLanguageTypeC_plus_plus, nullptr); TypeSystemClang::StartTagDeclarationDefinition(empty_derived); std::unique_ptr non_empty_base_spec = m_ast->CreateBaseClassSpecifier(non_empty_base.GetOpaqueQualType(), @@ -361,8 +360,8 @@ TEST_F(TestTypeSystemClang, TestRecordHasFields) { // Test that a record with no direct fields, but fields in a virtual base // returns true CompilerType empty_derived2 = m_ast->CreateRecordType( - nullptr, OptionalClangModuleID(), lldb::eAccessPublic, "EmptyDerived2", - clang::TTK_Struct, lldb::eLanguageTypeC_plus_plus, nullptr); + nullptr, lldb::eAccessPublic, "EmptyDerived2", clang::TTK_Struct, + lldb::eLanguageTypeC_plus_plus, nullptr); TypeSystemClang::StartTagDeclarationDefinition(empty_derived2); std::unique_ptr non_empty_vbase_spec = m_ast->CreateBaseClassSpecifier(non_empty_base.GetOpaqueQualType(), @@ -393,15 +392,13 @@ TEST_F(TestTypeSystemClang, TemplateArguments) { // template struct foo; ClassTemplateDecl *decl = m_ast->CreateClassTemplateDecl( - m_ast->GetTranslationUnitDecl(), OptionalClangModuleID(), eAccessPublic, - "foo", TTK_Struct, infos); + m_ast->GetTranslationUnitDecl(), eAccessPublic, "foo", TTK_Struct, infos); ASSERT_NE(decl, nullptr); // foo ClassTemplateSpecializationDecl *spec_decl = m_ast->CreateClassTemplateSpecializationDecl( - m_ast->GetTranslationUnitDecl(), OptionalClangModuleID(), decl, - TTK_Struct, infos); + m_ast->GetTranslationUnitDecl(), decl, TTK_Struct, infos); ASSERT_NE(spec_decl, nullptr); CompilerType type = m_ast->CreateClassTemplateSpecializationType(spec_decl); ASSERT_TRUE(type); @@ -410,8 +407,7 @@ TEST_F(TestTypeSystemClang, TemplateArguments) { // typedef foo foo_def; CompilerType typedef_type = m_ast->CreateTypedefType( - type, "foo_def", - m_ast->CreateDeclContext(m_ast->GetTranslationUnitDecl()), 0); + type, "foo_def", m_ast->CreateDeclContext(m_ast->GetTranslationUnitDecl())); CompilerType auto_type( m_ast.get(), @@ -485,14 +481,13 @@ TEST_F(TestTypeSystemClang, TestFunctionTemplateConstruction) { // Prepare the declarations/types we need for the template. CompilerType clang_type = m_ast->CreateFunctionType(int_type, nullptr, 0U, false, 0U); - FunctionDecl *func = m_ast->CreateFunctionDeclaration( - TU, OptionalClangModuleID(), "foo", clang_type, 0, false); + FunctionDecl *func = + m_ast->CreateFunctionDeclaration(TU, "foo", clang_type, 0, false); TypeSystemClang::TemplateParameterInfos empty_params; // Create the actual function template. clang::FunctionTemplateDecl *func_template = - m_ast->CreateFunctionTemplateDecl(TU, OptionalClangModuleID(), func, - "foo", empty_params); + m_ast->CreateFunctionTemplateDecl(TU, func, "foo", empty_params); EXPECT_EQ(TU, func_template->getDeclContext()); EXPECT_EQ("foo", func_template->getName()); @@ -516,14 +511,13 @@ TEST_F(TestTypeSystemClang, TestFunctionTemplateInRecordConstruction) { // We create the FunctionDecl for the template in the TU DeclContext because: // 1. FunctionDecls can't be in a Record (only CXXMethodDecls can). // 2. It is mirroring the behavior of DWARFASTParserClang::ParseSubroutine. - FunctionDecl *func = m_ast->CreateFunctionDeclaration( - TU, OptionalClangModuleID(), "foo", clang_type, 0, false); + FunctionDecl *func = + m_ast->CreateFunctionDeclaration(TU, "foo", clang_type, 0, false); TypeSystemClang::TemplateParameterInfos empty_params; // Create the actual function template. clang::FunctionTemplateDecl *func_template = - m_ast->CreateFunctionTemplateDecl(record, OptionalClangModuleID(), func, - "foo", empty_params); + m_ast->CreateFunctionTemplateDecl(record, func, "foo", empty_params); EXPECT_EQ(record, func_template->getDeclContext()); EXPECT_EQ("foo", func_template->getName()); diff --git a/lldb/unittests/TestingSupport/Symbol/ClangTestUtils.h b/lldb/unittests/TestingSupport/Symbol/ClangTestUtils.h index 1fc262746278b..896996512fcf7 100644 --- a/lldb/unittests/TestingSupport/Symbol/ClangTestUtils.h +++ b/lldb/unittests/TestingSupport/Symbol/ClangTestUtils.h @@ -27,7 +27,6 @@ inline std::unique_ptr createAST() { inline CompilerType createRecord(TypeSystemClang &ast, llvm::StringRef name) { return ast.CreateRecordType(ast.getASTContext().getTranslationUnitDecl(), - OptionalClangModuleID(), lldb::AccessType::eAccessPublic, name, 0, lldb::LanguageType::eLanguageTypeC); } From ec5d6803fa6e2ca629ddde94e8b0404db36b1542 Mon Sep 17 00:00:00 2001 From: Davide Italiano Date: Wed, 15 Apr 2020 12:28:34 -0700 Subject: [PATCH 269/286] [LICM] Try to merge debug locations when sinking. The current strategy LICM uses when sinking for debuginfo is that of picking the debug location of one of the uses. This causes stepping to be wrong sometimes, see, e.g. PR45523. This patch introduces a generalization of getMergedLocation(), that operates on a vector of locations instead of two, and try to merge all them together, and use the new API in LICM. --- llvm/include/llvm/IR/DebugInfoMetadata.h | 7 + llvm/lib/IR/DebugInfoMetadata.cpp | 15 ++ llvm/lib/Transforms/Scalar/LICM.cpp | 10 +- .../LICM/sink-debuginfo-preserve.ll | 147 ++++++++++++++++++ 4 files changed, 174 insertions(+), 5 deletions(-) create mode 100644 llvm/test/Transforms/LICM/sink-debuginfo-preserve.ll diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h index d20b618be50ea..a70c98b2a7946 100644 --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -1601,6 +1601,13 @@ class DILocation : public MDNode { static const DILocation *getMergedLocation(const DILocation *LocA, const DILocation *LocB); + /// Try to combine the vector of locations passed as input in a single one. + /// This function applies getMergedLocation() repeatedly left-to-right. + /// + /// \p Locs: The locations to be merged. + static + const DILocation *getMergedLocations(ArrayRef Locs); + /// Returns the base discriminator for a given encoded discriminator \p D. static unsigned getBaseDiscriminatorFromDiscriminator(unsigned D) { return getUnsignedFromPrefixEncoding(D); diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp index 46c0b84e3ddcc..da266d2845f06 100644 --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -75,6 +75,21 @@ DILocation *DILocation::getImpl(LLVMContext &Context, unsigned Line, Storage, Context.pImpl->DILocations); } +const +DILocation *DILocation::getMergedLocations(ArrayRef Locs) { + if (Locs.empty()) + return nullptr; + if (Locs.size() == 1) + return Locs[0]; + auto *Merged = Locs[0]; + for (auto I = std::next(Locs.begin()), E = Locs.end(); I != E; ++I) { + Merged = getMergedLocation(Merged, *I); + if (Merged == nullptr) + break; + } + return Merged; +} + const DILocation *DILocation::getMergedLocation(const DILocation *LocA, const DILocation *LocB) { if (!LocA || !LocB) diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp index a0d3cf5b44cab..5c5325a71da6d 100644 --- a/llvm/lib/Transforms/Scalar/LICM.cpp +++ b/llvm/lib/Transforms/Scalar/LICM.cpp @@ -2157,11 +2157,11 @@ bool llvm::promoteLoopAccessesToScalars( }); ++NumPromoted; - // Grab a debug location for the inserted loads/stores; given that the - // inserted loads/stores have little relation to the original loads/stores, - // this code just arbitrarily picks a location from one, since any debug - // location is better than none. - DebugLoc DL = LoopUses[0]->getDebugLoc(); + // Look at all the loop uses, and try to merge their locations. + std::vector LoopUsesLocs; + for (auto U : LoopUses) + LoopUsesLocs.push_back(U->getDebugLoc().get()); + auto DL = DebugLoc(DILocation::getMergedLocations(LoopUsesLocs)); // We use the SSAUpdater interface to insert phi nodes as required. SmallVector NewPHIs; diff --git a/llvm/test/Transforms/LICM/sink-debuginfo-preserve.ll b/llvm/test/Transforms/LICM/sink-debuginfo-preserve.ll new file mode 100644 index 0000000000000..9bb7edccf243e --- /dev/null +++ b/llvm/test/Transforms/LICM/sink-debuginfo-preserve.ll @@ -0,0 +1,147 @@ +; RUN: opt -S -licm < %s | FileCheck %s + +; LICM is trying to merge the two `store` in block %14 and %17, but given their +; locations disagree, it sets a line zero location instead instead of picking a +; random one (the DILocation picked the nearest enclosing scope of the two stores). + +; Original C testcase. +; volatile int a; +; extern int g; +; int g; +; void f1() { +; while (a) { +; g = 0; +; if (a) +; g = 0; +; } +; } + +; CHECK: %.lcssa = phi i32 +; CHECK-NEXT: store i32 %.lcssa, i32* getelementptr inbounds ([2 x i32], [2 x i32]* @g_390, i64 0, i64 1), align 4, !dbg [[storeLocation:![0-9]+]] +; CHECK: [[storeLocation]] = !DILocation(line: 0 + +target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.15.0" + +@b = global i32 0, align 4, !dbg !0 +@c = global i32 0, align 4, !dbg !10 +@g_390 = local_unnamed_addr global [2 x i32] zeroinitializer, align 4, !dbg !12 +@a = local_unnamed_addr global i32 0, align 4, !dbg !6 + +define i32 @main() local_unnamed_addr !dbg !22 { + %1 = load volatile i32, i32* @b, align 4, !dbg !37, !tbaa !40 + %2 = icmp sgt i32 %1, -9, !dbg !44 + br i1 %2, label %3, label %5, !dbg !45 + +3: ; preds = %0 + br label %9, !dbg !45 + +4: ; preds = %9 + br label %5, !dbg !45 + +5: ; preds = %4, %0 + %6 = load volatile i32, i32* @c, align 4, !dbg !46, !tbaa !40 + %7 = icmp slt i32 %6, 6, !dbg !47 + br i1 %7, label %8, label %24, !dbg !48 + +8: ; preds = %5 + br label %14, !dbg !48 + +9: ; preds = %3, %9 + %10 = load volatile i32, i32* @b, align 4, !dbg !49, !tbaa !40 + %11 = add nsw i32 %10, -1, !dbg !49 + store volatile i32 %11, i32* @b, align 4, !dbg !49, !tbaa !40 + %12 = load volatile i32, i32* @b, align 4, !dbg !37, !tbaa !40 + %13 = icmp sgt i32 %12, -9, !dbg !44 + br i1 %13, label %9, label %4, !dbg !45, !llvm.loop !50 + +14: ; preds = %8, %18 + store i32 0, i32* getelementptr inbounds ([2 x i32], [2 x i32]* @g_390, i64 0, i64 1), align 4, !dbg !53, !tbaa !40 + %15 = load volatile i32, i32* @b, align 4, !dbg !54, !tbaa !40 + %16 = icmp eq i32 %15, 0, !dbg !54 + br i1 %16, label %17, label %18, !dbg !55 + +17: ; preds = %14 + store i32 0, i32* getelementptr inbounds ([2 x i32], [2 x i32]* @g_390, i64 0, i64 1), align 4, !dbg !56, !tbaa !40 + br label %18 + +18: ; preds = %14, %17 + %19 = load volatile i32, i32* @c, align 4, !dbg !57, !tbaa !40 + %20 = add nsw i32 %19, 1, !dbg !57 + store volatile i32 %20, i32* @c, align 4, !dbg !57, !tbaa !40 + %21 = load volatile i32, i32* @c, align 4, !dbg !46, !tbaa !40 + %22 = icmp slt i32 %21, 6, !dbg !47 + br i1 %22, label %14, label %23, !dbg !48, !llvm.loop !58 + +23: ; preds = %18 + br label %24, !dbg !48 + +24: ; preds = %23, %5 + ret i32 0, !dbg !60 +} + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!17, !18, !19, !20} +!llvm.ident = !{!21} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "b", scope: !2, file: !3, line: 1, type: !8, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 11.0.0 (https://github.com/llvm/llvm-project d3588d0814c4cbc7fca677b4d9634f6e1428a331)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, nameTableKind: None, sysroot: "/") +!3 = !DIFile(filename: "a.c", directory: "/Users/davide/work/build/bin") +!4 = !{} +!5 = !{!6, !0, !10, !12} +!6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression()) +!7 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 1, type: !8, isLocal: false, isDefinition: true) +!8 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !9) +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !DIGlobalVariableExpression(var: !11, expr: !DIExpression()) +!11 = distinct !DIGlobalVariable(name: "c", scope: !2, file: !3, line: 1, type: !8, isLocal: false, isDefinition: true) +!12 = !DIGlobalVariableExpression(var: !13, expr: !DIExpression()) +!13 = distinct !DIGlobalVariable(name: "g_390", scope: !2, file: !3, line: 2, type: !14, isLocal: false, isDefinition: true) +!14 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 64, elements: !15) +!15 = !{!16} +!16 = !DISubrange(count: 2) +!17 = !{i32 7, !"Dwarf Version", i32 4} +!18 = !{i32 2, !"Debug Info Version", i32 3} +!19 = !{i32 1, !"wchar_size", i32 4} +!20 = !{i32 7, !"PIC Level", i32 2} +!21 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project d3588d0814c4cbc7fca677b4d9634f6e1428a331)"} +!22 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 3, type: !23, scopeLine: 3, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !25) +!23 = !DISubroutineType(types: !24) +!24 = !{!9} +!25 = !{!26} +!26 = !DILocalVariable(name: "l_1546", scope: !27, file: !3, line: 11, type: !32) +!27 = distinct !DILexicalBlock(scope: !28, file: !3, line: 10, column: 10) +!28 = distinct !DILexicalBlock(scope: !29, file: !3, line: 8, column: 9) +!29 = distinct !DILexicalBlock(scope: !30, file: !3, line: 6, column: 23) +!30 = distinct !DILexicalBlock(scope: !31, file: !3, line: 6, column: 3) +!31 = distinct !DILexicalBlock(scope: !22, file: !3, line: 6, column: 3) +!32 = !DICompositeType(tag: DW_TAG_array_type, baseType: !33, size: 288, elements: !34) +!33 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) +!34 = !{!35, !36, !35} +!35 = !DISubrange(count: 3) +!36 = !DISubrange(count: 4) +!37 = !DILocation(line: 4, column: 10, scope: !38) +!38 = distinct !DILexicalBlock(scope: !39, file: !3, line: 4, column: 3) +!39 = distinct !DILexicalBlock(scope: !22, file: !3, line: 4, column: 3) +!40 = !{!41, !41, i64 0} +!41 = !{!"int", !42, i64 0} +!42 = !{!"omnipotent char", !43, i64 0} +!43 = !{!"Simple C/C++ TBAA"} +!44 = !DILocation(line: 4, column: 12, scope: !38) +!45 = !DILocation(line: 4, column: 3, scope: !39) +!46 = !DILocation(line: 6, column: 10, scope: !30) +!47 = !DILocation(line: 6, column: 12, scope: !30) +!48 = !DILocation(line: 6, column: 3, scope: !31) +!49 = !DILocation(line: 4, column: 19, scope: !38) +!50 = distinct !{!50, !45, !51, !52} +!51 = !DILocation(line: 5, column: 5, scope: !39) +!52 = !{!"llvm.loop.unroll.disable"} +!53 = !DILocation(line: 7, column: 14, scope: !29) +!54 = !DILocation(line: 8, column: 9, scope: !28) +!55 = !DILocation(line: 8, column: 9, scope: !29) +!56 = !DILocation(line: 12, column: 16, scope: !27) +!57 = !DILocation(line: 6, column: 19, scope: !30) +!58 = distinct !{!58, !48, !59, !52} +!59 = !DILocation(line: 14, column: 3, scope: !31) +!60 = !DILocation(line: 15, column: 1, scope: !22) From 05f5e2a8024683b27af61a2b878af097579f1d8a Mon Sep 17 00:00:00 2001 From: Amara Emerson Date: Mon, 24 Feb 2020 14:27:32 -0800 Subject: [PATCH 270/286] [AArch64][GlobalISel] Fixup <32b heterogeneous regbanks of G_PHIs just before selection. Since all types <32b on gpr end up being assigned gpr32 regclasses, we can end up with PHIs here which try to select between a gpr32 and an fpr16. Ideally RBS shouldn't be selecting heterogenous regbanks for operands if possible, but we still need to be able to deal with it here. To fix this, if we have a gpr-bank operand < 32b in size and at least one other operand is on the fpr bank, then we add cross-bank copies to homogenize the operand banks. For simplicity the bank that we choose to settle on is whatever bank the def operand has. For example: %endbb: %dst:gpr(s16) = G_PHI %in1:gpr(s16), %bb1, %in2:fpr(s16), %bb2 => %bb2: ... %in2_copy:gpr(s16) = COPY %in2:fpr(s16) ... %endbb: %dst:gpr(s16) = G_PHI %in1:gpr(s16), %bb1, %in2_copy:gpr(s16), %bb2 Differential Revision: https://reviews.llvm.org/D75086 (cherry picked from commit 65f99b5383ff3293881f59dd64cfb596c3d03aa4) --- .../AArch64/AArch64InstructionSelector.cpp | 93 +++++++++++++++ .../GlobalISel/preselect-process-phis.mir | 110 ++++++++++++++++++ 2 files changed, 203 insertions(+) create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/preselect-process-phis.mir diff --git a/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp index 193136fe53d8c..6b109ce696de6 100644 --- a/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp +++ b/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp @@ -63,6 +63,7 @@ class AArch64InstructionSelector : public InstructionSelector { // cache it here for each run of the selector. ProduceNonFlagSettingCondBr = !MF.getFunction().hasFnAttribute(Attribute::SpeculativeLoadHardening); + processPHIs(MF); } private: @@ -77,6 +78,9 @@ class AArch64InstructionSelector : public InstructionSelector { // An early selection function that runs before the selectImpl() call. bool earlySelect(MachineInstr &I) const; + // Do some preprocessing of G_PHIs before we begin selection. + void processPHIs(MachineFunction &MF); + bool earlySelectSHL(MachineInstr &I, MachineRegisterInfo &MRI) const; /// Eliminate same-sized cross-bank copies into stores before selectImpl(). @@ -4755,6 +4759,95 @@ bool AArch64InstructionSelector::isDef32(const MachineInstr &MI) const { } } + +// Perform fixups on the given PHI instruction's operands to force them all +// to be the same as the destination regbank. +static void fixupPHIOpBanks(MachineInstr &MI, MachineRegisterInfo &MRI, + const AArch64RegisterBankInfo &RBI) { + assert(MI.getOpcode() == TargetOpcode::G_PHI && "Expected a G_PHI"); + Register DstReg = MI.getOperand(0).getReg(); + const RegisterBank *DstRB = MRI.getRegBankOrNull(DstReg); + assert(DstRB && "Expected PHI dst to have regbank assigned"); + MachineIRBuilder MIB(MI); + + // Go through each operand and ensure it has the same regbank. + for (unsigned OpIdx = 1; OpIdx < MI.getNumOperands(); ++OpIdx) { + MachineOperand &MO = MI.getOperand(OpIdx); + if (!MO.isReg()) + continue; + Register OpReg = MO.getReg(); + const RegisterBank *RB = MRI.getRegBankOrNull(OpReg); + if (RB != DstRB) { + // Insert a cross-bank copy. + auto *OpDef = MRI.getVRegDef(OpReg); + const LLT &Ty = MRI.getType(OpReg); + MIB.setInsertPt(*OpDef->getParent(), std::next(OpDef->getIterator())); + auto Copy = MIB.buildCopy(Ty, OpReg); + MRI.setRegBank(Copy.getReg(0), *DstRB); + MO.setReg(Copy.getReg(0)); + } + } +} + +void AArch64InstructionSelector::processPHIs(MachineFunction &MF) { + // We're looking for PHIs, build a list so we don't invalidate iterators. + MachineRegisterInfo &MRI = MF.getRegInfo(); + SmallVector Phis; + for (auto &BB : MF) { + for (auto &MI : BB) { + if (MI.getOpcode() == TargetOpcode::G_PHI) + Phis.emplace_back(&MI); + } + } + + for (auto *MI : Phis) { + // We need to do some work here if the operand types are < 16 bit and they + // are split across fpr/gpr banks. Since all types <32b on gpr + // end up being assigned gpr32 regclasses, we can end up with PHIs here + // which try to select between a gpr32 and an fpr16. Ideally RBS shouldn't + // be selecting heterogenous regbanks for operands if possible, but we + // still need to be able to deal with it here. + // + // To fix this, if we have a gpr-bank operand < 32b in size and at least + // one other operand is on the fpr bank, then we add cross-bank copies + // to homogenize the operand banks. For simplicity the bank that we choose + // to settle on is whatever bank the def operand has. For example: + // + // %endbb: + // %dst:gpr(s16) = G_PHI %in1:gpr(s16), %bb1, %in2:fpr(s16), %bb2 + // => + // %bb2: + // ... + // %in2_copy:gpr(s16) = COPY %in2:fpr(s16) + // ... + // %endbb: + // %dst:gpr(s16) = G_PHI %in1:gpr(s16), %bb1, %in2_copy:gpr(s16), %bb2 + bool HasGPROp = false, HasFPROp = false; + for (unsigned OpIdx = 1; OpIdx < MI->getNumOperands(); ++OpIdx) { + const auto &MO = MI->getOperand(OpIdx); + if (!MO.isReg()) + continue; + const LLT &Ty = MRI.getType(MO.getReg()); + if (!Ty.isValid() || !Ty.isScalar()) + break; + if (Ty.getSizeInBits() >= 32) + break; + const RegisterBank *RB = MRI.getRegBankOrNull(MO.getReg()); + // If for some reason we don't have a regbank yet. Don't try anything. + if (!RB) + break; + + if (RB->getID() == AArch64::GPRRegBankID) + HasGPROp = true; + else + HasFPROp = true; + } + // We have heterogenous regbanks, need to fixup. + if (HasGPROp && HasFPROp) + fixupPHIOpBanks(*MI, MRI, RBI); + } +} + namespace llvm { InstructionSelector * createAArch64InstructionSelector(const AArch64TargetMachine &TM, diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/preselect-process-phis.mir b/llvm/test/CodeGen/AArch64/GlobalISel/preselect-process-phis.mir new file mode 100644 index 0000000000000..1b7c074018996 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/GlobalISel/preselect-process-phis.mir @@ -0,0 +1,110 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py +# RUN: llc -verify-machineinstrs -mtriple aarch64--- -run-pass=instruction-select -global-isel %s -o - | FileCheck %s +--- +name: test_loop_phi_fpr_to_gpr +alignment: 4 +legalized: true +regBankSelected: true +selected: false +failedISel: false +tracksRegLiveness: true +liveins: [] +machineFunctionInfo: {} +body: | + ; CHECK-LABEL: name: test_loop_phi_fpr_to_gpr + ; CHECK: bb.0: + ; CHECK: successors: %bb.1(0x80000000) + ; CHECK: [[DEF:%[0-9]+]]:gpr32 = IMPLICIT_DEF + ; CHECK: [[DEF1:%[0-9]+]]:gpr64common = IMPLICIT_DEF + ; CHECK: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 2143289344 + ; CHECK: [[COPY:%[0-9]+]]:fpr32 = COPY [[MOVi32imm]] + ; CHECK: bb.1: + ; CHECK: successors: %bb.2(0x80000000) + ; CHECK: [[DEF2:%[0-9]+]]:gpr32 = IMPLICIT_DEF + ; CHECK: $wzr = ANDSWri [[DEF]], 0, implicit-def $nzcv + ; CHECK: [[CSELWr:%[0-9]+]]:gpr32 = CSELWr [[DEF2]], [[DEF2]], 1, implicit $nzcv + ; CHECK: bb.2: + ; CHECK: successors: %bb.2(0x80000000) + ; CHECK: [[PHI:%[0-9]+]]:gpr32 = PHI [[CSELWr]], %bb.1, %8, %bb.2 + ; CHECK: [[FCVTHSr:%[0-9]+]]:fpr16 = FCVTHSr [[COPY]] + ; CHECK: [[SUBREG_TO_REG:%[0-9]+]]:fpr32 = SUBREG_TO_REG 0, [[FCVTHSr]], %subreg.hsub + ; CHECK: [[COPY1:%[0-9]+]]:gpr32all = COPY [[SUBREG_TO_REG]] + ; CHECK: STRHHui [[PHI]], [[DEF1]], 0 :: (store 2 into `half* undef`) + ; CHECK: B %bb.2 + bb.0: + successors: %bb.1(0x80000000) + + %0:gpr(s1) = G_IMPLICIT_DEF + %4:gpr(p0) = G_IMPLICIT_DEF + %8:fpr(s32) = G_FCONSTANT float 0x7FF8000000000000 + + bb.1: + successors: %bb.2(0x80000000) + + %6:gpr(s32) = G_IMPLICIT_DEF + %7:gpr(s32) = G_SELECT %0(s1), %6, %6 + %1:gpr(s16) = G_TRUNC %7(s32) + + bb.2: + successors: %bb.2(0x80000000) + + %3:gpr(s16) = G_PHI %1(s16), %bb.1, %5(s16), %bb.2 + %5:fpr(s16) = G_FPTRUNC %8(s32) + G_STORE %3(s16), %4(p0) :: (store 2 into `half* undef`) + G_BR %bb.2 + +... +--- +name: test_loop_phi_gpr_to_fpr +alignment: 4 +legalized: true +regBankSelected: true +selected: false +failedISel: false +tracksRegLiveness: true +liveins: [] +machineFunctionInfo: {} +body: | + ; CHECK-LABEL: name: test_loop_phi_gpr_to_fpr + ; CHECK: bb.0: + ; CHECK: successors: %bb.1(0x80000000) + ; CHECK: [[DEF:%[0-9]+]]:gpr32 = IMPLICIT_DEF + ; CHECK: [[DEF1:%[0-9]+]]:gpr64common = IMPLICIT_DEF + ; CHECK: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 2143289344 + ; CHECK: [[COPY:%[0-9]+]]:fpr32 = COPY [[MOVi32imm]] + ; CHECK: bb.1: + ; CHECK: successors: %bb.2(0x80000000) + ; CHECK: [[DEF2:%[0-9]+]]:gpr32 = IMPLICIT_DEF + ; CHECK: $wzr = ANDSWri [[DEF]], 0, implicit-def $nzcv + ; CHECK: [[CSELWr:%[0-9]+]]:gpr32 = CSELWr [[DEF2]], [[DEF2]], 1, implicit $nzcv + ; CHECK: [[COPY1:%[0-9]+]]:fpr32 = COPY [[CSELWr]] + ; CHECK: [[COPY2:%[0-9]+]]:fpr16 = COPY [[COPY1]].hsub + ; CHECK: bb.2: + ; CHECK: successors: %bb.2(0x80000000) + ; CHECK: [[PHI:%[0-9]+]]:fpr16 = PHI %7, %bb.2, [[COPY2]], %bb.1 + ; CHECK: [[FCVTHSr:%[0-9]+]]:fpr16 = FCVTHSr [[COPY]] + ; CHECK: STRHui [[PHI]], [[DEF1]], 0 :: (store 2 into `half* undef`) + ; CHECK: B %bb.2 + bb.0: + successors: %bb.1(0x80000000) + + %0:gpr(s1) = G_IMPLICIT_DEF + %4:gpr(p0) = G_IMPLICIT_DEF + %8:fpr(s32) = G_FCONSTANT float 0x7FF8000000000000 + + bb.1: + successors: %bb.2(0x80000000) + + %6:gpr(s32) = G_IMPLICIT_DEF + %7:gpr(s32) = G_SELECT %0(s1), %6, %6 + %1:gpr(s16) = G_TRUNC %7(s32) + + bb.2: + successors: %bb.2(0x80000000) + + %3:fpr(s16) = G_PHI %5(s16), %bb.2, %1(s16), %bb.1 + %5:fpr(s16) = G_FPTRUNC %8(s32) + G_STORE %3(s16), %4(p0) :: (store 2 into `half* undef`) + G_BR %bb.2 + +... From 4b97308d8fe80881f6c505b9a6c621a58c716fb3 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Thu, 16 Apr 2020 12:00:59 -0700 Subject: [PATCH 271/286] Update for the removal of the LLVMContext parameter --- .../ExpressionParser/Swift/SwiftExpressionParser.cpp | 12 ++++++++---- lldb/source/Symbol/SwiftASTContext.cpp | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp index 7d7197e3ae316..88a1019160b31 100644 --- a/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp +++ b/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp @@ -58,6 +58,7 @@ #include "swift/AST/DiagnosticEngine.h" #include "swift/AST/DiagnosticConsumer.h" #include "swift/AST/IRGenOptions.h" +#include "swift/AST/IRGenRequests.h" #include "swift/AST/Module.h" #include "swift/AST/ModuleLoader.h" #include "swift/Demangling/Demangle.h" @@ -1659,11 +1660,15 @@ unsigned SwiftExpressionParser::Parse(DiagnosticManager &diagnostic_manager, std::lock_guard global_context_locker( IRExecutionUnit::GetLLVMGlobalContextMutex()); - m_module = swift::performIRGeneration( + auto GenModule = swift::performIRGeneration( swift_ast_ctx->GetIRGenOptions(), &parsed_expr->module, std::move(sil_module), "lldb_module", swift::PrimarySpecificPaths("", parsed_expr->main_filename), - SwiftASTContext::GetGlobalLLVMContext(), llvm::ArrayRef()); + llvm::ArrayRef()); + + auto ContextAndModule = std::move(GenModule).release(); + m_llvm_context.reset(ContextAndModule.first); + m_module.reset(ContextAndModule.second); } if (swift_ast_ctx->HasErrors()) { @@ -1813,10 +1818,9 @@ Status SwiftExpressionParser::PrepareForExecution( std::vector features; - std::unique_ptr llvm_context_up; // m_module is handed off here. m_execution_unit_sp.reset( - new IRExecutionUnit(llvm_context_up, m_module, function_name, + new IRExecutionUnit(m_llvm_context, m_module, function_name, exe_ctx.GetTargetSP(), sc, features)); // TODO: figure out some way to work ClangExpressionDeclMap into diff --git a/lldb/source/Symbol/SwiftASTContext.cpp b/lldb/source/Symbol/SwiftASTContext.cpp index 70b94e9459114..eb79cd5414564 100644 --- a/lldb/source/Symbol/SwiftASTContext.cpp +++ b/lldb/source/Symbol/SwiftASTContext.cpp @@ -4885,7 +4885,7 @@ swift::irgen::IRGenModule &SwiftASTContext::GetIRGenModule() { IRExecutionUnit::GetLLVMGlobalContextMutex()); m_ir_gen_module_ap.reset(new swift::irgen::IRGenModule( ir_generator, ir_generator.createTargetMachine(), nullptr, - GetGlobalLLVMContext(), ir_gen_opts.ModuleName, PSPs.OutputFilename, + ir_gen_opts.ModuleName, PSPs.OutputFilename, PSPs.MainInputFilenameForDebugInfo, "")); llvm::Module *llvm_module = m_ir_gen_module_ap->getModule(); llvm_module->setDataLayout(data_layout.getStringRepresentation()); From f1a1c4b8c0caae1d493cb51fd2283c87df7e97cc Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Thu, 16 Apr 2020 23:44:45 -0700 Subject: [PATCH 272/286] Remove attach-failed-due-to-SIP checks which were not working (#1092) The SIP debugserver was calling in attach_failed_due_to_sip haven't worked for a while; remove them. To check this properly we'd need debugsever to call out to codesign(1) to inspect the entitlements, or the equivalant API, and I'm not interested in adding that at this point. SIP is has been the default on macOS for a couple of releases and it's expected behavior now. (cherry picked from commit 7fa342bd2a6be51998c399f145143d8f45da1f4d) --- lldb/tools/debugserver/source/RNBRemote.cpp | 31 --------------------- 1 file changed, 31 deletions(-) diff --git a/lldb/tools/debugserver/source/RNBRemote.cpp b/lldb/tools/debugserver/source/RNBRemote.cpp index 8eed06381d3a0..df358065f8775 100644 --- a/lldb/tools/debugserver/source/RNBRemote.cpp +++ b/lldb/tools/debugserver/source/RNBRemote.cpp @@ -3663,30 +3663,6 @@ static bool process_does_not_exist (nub_process_t pid) { return true; // process does not exist } -static bool attach_failed_due_to_sip (nub_process_t pid) { - bool retval = false; -#if defined(__APPLE__) && \ - (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101000) - - // csr_check(CSR_ALLOW_TASK_FOR_PID) will be nonzero if System Integrity - // Protection is in effect. - if (csr_check(CSR_ALLOW_TASK_FOR_PID) == 0) - return false; - - if (rootless_allows_task_for_pid(pid) == 0) - retval = true; - - int csops_flags = 0; - int csops_ret = ::csops(pid, CS_OPS_STATUS, &csops_flags, - sizeof(csops_flags)); - if (csops_ret != -1 && (csops_flags & CS_RESTRICT)) { - retval = true; - } -#endif - - return retval; -} - // my_uid and process_uid are only initialized if this function // returns true -- that there was a uid mismatch -- and those // id's may want to be used in the error message. @@ -4065,13 +4041,6 @@ rnb_err_t RNBRemote::HandlePacket_v(const char *p) { "processes."); return SendPacket(return_message.c_str()); } - if (attach_failed_due_to_sip (pid_attaching_to)) { - DNBLogError("Attach failed because of SIP protection."); - std::string return_message = "E96;"; - return_message += cstring_to_asciihex_string("cannot attach " - "to process due to System Integrity Protection"); - return SendPacket(return_message.c_str()); - } } std::string error_explainer = "attach failed"; From 5f8d7b22f5168b7b99cb4f55f182b2985b0d78de Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Fri, 17 Apr 2020 14:34:52 -0700 Subject: [PATCH 273/286] Verify that the ShouldStopHere callback actually can produce a step out plan. I have two reports of lldb crashing because the callback said it had a way to get out from here, but then failed to produce a plan to do so. I don't know why this happens, but in any case, we should stop in response to the failure, not crash. --- lldb/source/Target/ThreadPlanStepOut.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lldb/source/Target/ThreadPlanStepOut.cpp b/lldb/source/Target/ThreadPlanStepOut.cpp index ecd5722c5e17b..9770715c32dbc 100644 --- a/lldb/source/Target/ThreadPlanStepOut.cpp +++ b/lldb/source/Target/ThreadPlanStepOut.cpp @@ -407,6 +407,14 @@ bool ThreadPlanStepOut::ShouldStop(Event *event_ptr) { } else { m_step_out_further_plan_sp = QueueStepOutFromHerePlan(m_flags, eFrameCompareOlder, m_status); + // I have a few reports of getting here and not being able to + // actually generate a step out from here plan. That shouldn't happen + // because the ShouldStopHere callback shouldn't return true if it + // can't make a step out plan. So far I don't know how that can + // happen, but it's better to just stop here than to crash. + if (!m_step_out_further_plan_sp) + return true; + if (m_step_out_further_plan_sp->GetKind() == eKindStepOut) { // If we are planning to step out further, then the frame we are going From 1711bf6dfde353547420dbf041ddcfa9eb81d676 Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Tue, 14 Apr 2020 21:49:50 -0700 Subject: [PATCH 274/286] [NFC] Introduce a `LateInitialize()` method to `SymbolizerTool` that is called during the LateInitialize stage of the sanitizer runtimes. Summary: This is implemented by adding a `Symbolizer::LateInitializeTools()` method that iterates over the registered tools and calls the `LateInitialize()` method on them. `Symbolizer::LateInitializeTools()` is now called from the various `Symbolizer::LateInitialize()` implementations. The default implementation of `SymbolizerTool::LateInitialize()` does nothing so this change should be NFC. This change allows `SymbolizerTool` implementations to perform any initialization that they need to perform at the LateInitialize stage of a sanitizer runtime init. rdar://problem/58789439 Reviewers: kubamracek, yln, vitalybuka, cryptoad, phosek, rnk Subscribers: #sanitizers, llvm-commits Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D78178 (cherry picked from commit fccea7f372cbd33376d2c776f34a0c6925982981) --- compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.cpp | 6 ++++++ compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h | 3 +++ .../lib/sanitizer_common/sanitizer_symbolizer_internal.h | 5 +++++ .../lib/sanitizer_common/sanitizer_symbolizer_markup.cpp | 4 +++- .../sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp | 2 +- .../lib/sanitizer_common/sanitizer_symbolizer_win.cpp | 2 +- 6 files changed, 19 insertions(+), 3 deletions(-) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.cpp index ce2ece5f4d512..0c4b84c767aa1 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.cpp @@ -126,4 +126,10 @@ Symbolizer::SymbolizerScope::~SymbolizerScope() { sym_->end_hook_(); } +void Symbolizer::LateInitializeTools() { + for (auto &tool : tools_) { + tool.LateInitialize(); + } +} + } // namespace __sanitizer diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h index 51648e2d0e8d7..2476b0ea7bf7d 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer.h @@ -209,6 +209,9 @@ class Symbolizer final { private: const Symbolizer *sym_; }; + + // Calls `LateInitialize()` on all items in `tools_`. + void LateInitializeTools(); }; #ifdef SANITIZER_WINDOWS diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h index 0639543308422..e4c351e667b4d 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_internal.h @@ -69,6 +69,11 @@ class SymbolizerTool { virtual const char *Demangle(const char *name) { return nullptr; } + + // Called during the LateInitialize phase of Sanitizer initialization. + // Usually this is a safe place to call code that might need to use user + // memory allocators. + virtual void LateInitialize() {} }; // SymbolizerProcess encapsulates communication between the tool and diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp index 57b4d0c9d9613..2963af953609e 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_markup.cpp @@ -94,7 +94,9 @@ Symbolizer *Symbolizer::PlatformInit() { return new (symbolizer_allocator_) Symbolizer({}); } -void Symbolizer::LateInitialize() { Symbolizer::GetOrInit(); } +void Symbolizer::LateInitialize() { + Symbolizer::GetOrInit()->LateInitializeTools(); +} void StartReportDeadlySignal() {} void ReportDeadlySignal(const SignalContext &sig, u32 tid, diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp index f1dff2408e113..d7b931bc23795 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp @@ -488,7 +488,7 @@ Symbolizer *Symbolizer::PlatformInit() { } void Symbolizer::LateInitialize() { - Symbolizer::GetOrInit(); + Symbolizer::GetOrInit()->LateInitializeTools(); InitializeSwiftDemangler(); } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cpp index 2808779156edd..373437e7ee2ad 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_win.cpp @@ -310,7 +310,7 @@ Symbolizer *Symbolizer::PlatformInit() { } void Symbolizer::LateInitialize() { - Symbolizer::GetOrInit(); + Symbolizer::GetOrInit()->LateInitializeTools(); } } // namespace __sanitizer From cf8a197fa25005a0b5dcbd6929caf7eb97788f11 Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Tue, 14 Apr 2020 22:27:49 -0700 Subject: [PATCH 275/286] [Darwin] Fix symbolization for recent simulator runtimes. Summary: Due to sandbox restrictions in the recent versions of the simulator runtime the atos program is no longer able to access the task port of a parent process without additional help. This patch fixes this by registering a task port for the parent process before spawning atos and also tells atos to look for this by setting a special environment variable. This patch is based on an Apple internal fix (rdar://problem/43693565) that unfortunately contained a bug (rdar://problem/58789439) because it used setenv() to set the special environment variable. This is not safe because in certain circumstances this can trigger a call to realloc() which can fail during symbolization leading to deadlock. A test case is included that captures this problem. The approach used to set the necessary environment variable is as follows: 1. Calling `putenv()` early during process init (but late enough that malloc/realloc works) to set a dummy value for the environment variable. 2. Just before `atos` is spawned the storage for the environment variable is modified to contain the correct PID. A flaw with this approach is that if the application messes with the atos environment variable (i.e. unsets it or changes it) between the time its set and the time we need it then symbolization will fail. We will ignore this issue for now but a `DCHECK()` is included in the patch that documents this assumption but doesn't check it at runtime to avoid calling `getenv()`. The issue reported in rdar://problem/58789439 manifested as a deadlock during symbolization in the following situation: 1. Before TSan detects an issue something outside of the runtime calls setenv() that sets a new environment variable that wasn't previously set. This triggers a call to malloc() to allocate a new environment array. This uses TSan's normal user-facing allocator. LibC stores this pointer for future use later. 2. TSan detects an issue and tries to launch the symbolizer. When we are in the symbolizer we switch to a different (internal allocator) and then we call setenv() to set a new environment variable. When this happen setenv() sees that it needs to make the environment array larger and calls realloc() on the existing enviroment array because it remembers that it previously allocated memory for it. Calling realloc() fails here because it is being called on a pointer its never seen before. The included test case closely reproduces the originally reported problem but it doesn't replicate the `((kBlockMagic)) == ((((u64*)addr)[0])` assertion failure exactly. This is due to the way TSan's normal allocator allocates the environment array the first time it is allocated. In the test program addr[0] accesses an inaccessible page and raises SIGBUS. If TSan's SIGBUS signal handler is active, the signal is caught and symbolication is attempted again which results in deadlock. In the originally reported problem the pointer is successfully derefenced but then the assert fails due to the provided pointer not coming from the active allocator. When the assert fails TSan tries to symbolicate the stacktrace while already being in the middle of symbolication which results in deadlock. rdar://problem/58789439 Reviewers: kubamracek, yln Subscribers: jfb, #sanitizers, llvm-commits Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D78179 (cherry picked from commit 861b69faee5df8d4e13ef316c7474a10e4069e81) --- .../sanitizer_symbolizer_mac.cpp | 46 +++++++++++++++++++ .../sanitizer_symbolizer_mac.h | 1 + .../Darwin/no_call_setenv_in_symbolize.cpp | 43 +++++++++++++++++ 3 files changed, 90 insertions(+) create mode 100644 compiler-rt/test/tsan/Darwin/no_call_setenv_in_symbolize.cpp diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp index 1379ed82d03d1..4623c3f76b120 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -50,6 +51,8 @@ bool DlAddrSymbolizer::SymbolizeData(uptr addr, DataInfo *datainfo) { return true; } +#define K_ATOS_ENV_VAR "__check_mach_ports_lookup" + class AtosSymbolizerProcess : public SymbolizerProcess { public: explicit AtosSymbolizerProcess(const char *path) @@ -57,6 +60,20 @@ class AtosSymbolizerProcess : public SymbolizerProcess { pid_str_[0] = '\0'; } + void LateInitialize() { + if (SANITIZER_IOSSIM) { + // `putenv()` may call malloc/realloc so it is only safe to do this + // during LateInitialize() or later (i.e. we can't do this in the + // constructor). We also can't do this in `StartSymbolizerSubprocess()` + // because in TSan we switch allocators when we're symbolizing. + // We use `putenv()` rather than `setenv()` so that we can later directly + // write into the storage without LibC getting involved to change what the + // variable is set to + int result = putenv(mach_port_env_var_entry_); + CHECK_EQ(result, 0); + } + } + private: bool StartSymbolizerSubprocess() override { // Configure sandbox before starting atos process. @@ -65,6 +82,28 @@ class AtosSymbolizerProcess : public SymbolizerProcess { // the call to GetArgV. internal_snprintf(pid_str_, sizeof(pid_str_), "%d", internal_getpid()); + if (SANITIZER_IOSSIM) { + // `atos` in the simulator is restricted in its ability to retrieve the + // task port for the target process (us) so we need to do extra work + // to pass our task port to it. + mach_port_t ports[]{mach_task_self()}; + kern_return_t ret = + mach_ports_register(mach_task_self(), ports, /*count=*/1); + CHECK_EQ(ret, KERN_SUCCESS); + + // Set environment variable that signals to `atos` that it should look + // for our task port. We can't call `setenv()` here because it might call + // malloc/realloc. To avoid that we instead update the + // `mach_port_env_var_entry_` variable with our current PID. + uptr count = internal_snprintf(mach_port_env_var_entry_, + sizeof(mach_port_env_var_entry_), + K_ATOS_ENV_VAR "=%s", pid_str_); + CHECK_GE(count, sizeof(K_ATOS_ENV_VAR) + internal_strlen(pid_str_)); + // Document our assumption but without calling `getenv()` in normal + // builds. + DCHECK_EQ(internal_strcmp(getenv(K_ATOS_ENV_VAR), pid_str_), 0); + } + return SymbolizerProcess::StartSymbolizerSubprocess(); } @@ -88,8 +127,13 @@ class AtosSymbolizerProcess : public SymbolizerProcess { } char pid_str_[16]; + // Space for `\0` in `kAtosEnvVar_` is reused for `=`. + char mach_port_env_var_entry_[sizeof(K_ATOS_ENV_VAR) + sizeof(pid_str_)] = + K_ATOS_ENV_VAR "=0"; }; +#undef K_ATOS_ENV_VAR + static bool ParseCommandOutput(const char *str, uptr addr, char **out_name, char **out_module, char **out_file, uptr *line, uptr *start_address) { @@ -191,6 +235,8 @@ bool AtosSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { return true; } +void AtosSymbolizer::LateInitialize() { process_->LateInitialize(); } + } // namespace __sanitizer #endif // SANITIZER_MAC diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.h b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.h index 68521375e64c4..8996131fc1385 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.h @@ -35,6 +35,7 @@ class AtosSymbolizer : public SymbolizerTool { bool SymbolizePC(uptr addr, SymbolizedStack *stack) override; bool SymbolizeData(uptr addr, DataInfo *info) override; + void LateInitialize() override; private: AtosSymbolizerProcess *process_; diff --git a/compiler-rt/test/tsan/Darwin/no_call_setenv_in_symbolize.cpp b/compiler-rt/test/tsan/Darwin/no_call_setenv_in_symbolize.cpp new file mode 100644 index 0000000000000..1e31693cc74d5 --- /dev/null +++ b/compiler-rt/test/tsan/Darwin/no_call_setenv_in_symbolize.cpp @@ -0,0 +1,43 @@ +// RUN: %clangxx_tsan -O1 %s -o %t +// `handle_sigbus=0` is required because when the rdar://problem/58789439 bug was +// present TSan's runtime could derefence bad memory leading to SIGBUS being raised. +// If the signal was caught TSan would deadlock because it would try to run the +// symbolizer again. +// RUN: %env_tsan_opts=handle_sigbus=0,symbolize=1 %run %t 2>&1 | FileCheck %s +// RUN: %env_tsan_opts=handle_sigbus=0,symbolize=1 __check_mach_ports_lookup=some_value %run %t 2>&1 | FileCheck %s +#include +#include +#include + +const char *kEnvName = "__UNLIKELY_ENV_VAR_NAME__"; + +int main() { + if (getenv(kEnvName)) { + fprintf(stderr, "Env var %s should not be set\n", kEnvName); + abort(); + } + + // This will set an environment variable that isn't already in + // the environment array. This will cause Darwin's Libc to + // malloc() a new array. + if (setenv(kEnvName, "some_value", /*overwrite=*/1)) { + fprintf(stderr, "Failed to set %s \n", kEnvName); + abort(); + } + + // rdar://problem/58789439 + // Now trigger symbolization. If symbolization tries to call + // to `setenv` that adds a new environment variable, then Darwin + // Libc will call `realloc()` and TSan's runtime will hit + // an assertion failure because TSan's runtime uses a different + // allocator during symbolization which leads to `realloc()` being + // called on a pointer that the allocator didn't allocate. + // + // CHECK: #{{[0-9]}} main {{.*}}no_call_setenv_in_symbolize.cpp:[[@LINE+1]] + __sanitizer_print_stack_trace(); + + // CHECK: DONE + fprintf(stderr, "DONE\n"); + + return 0; +} From a6823609073bc0b59c1256028ebab997283c46e9 Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Mon, 20 Apr 2020 00:19:16 -0700 Subject: [PATCH 276/286] Don't drop ptrauth qualifiers when constructing C++ composite types Fixes a bug in Sema where it was incorrectly rejecting the following code: ``` typedef void * __ptrauth(ptrauth_key_process_dependent_data, 1, 42) T; bool compare(T *a, T *b) { return a == b; } ``` rdar://problem/54603670 --- clang/lib/Sema/SemaExprCXX.cpp | 10 ++++++++++ clang/test/SemaCXX/ptrauth-qualifier.cpp | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index e7c70e9b57278..5ccf9fe73a348 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -6208,6 +6208,7 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, // exists. SmallVector QualifierUnion; SmallVector, 4> MemberOfClass; + SmallVector PtrAuthQualifier; QualType Composite1 = T1; QualType Composite2 = T2; unsigned NeedConstBefore = 0; @@ -6226,6 +6227,9 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, QualifierUnion.push_back( Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers()); MemberOfClass.push_back(std::make_pair(nullptr, nullptr)); + PtrAuthQualifier.resize(PtrAuthQualifier.size() + 1); + if (Composite1.getPointerAuth() == Composite2.getPointerAuth()) + PtrAuthQualifier.back() = Composite1.getPointerAuth(); continue; } @@ -6244,6 +6248,9 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers()); MemberOfClass.push_back(std::make_pair(MemPtr1->getClass(), MemPtr2->getClass())); + PtrAuthQualifier.resize(PtrAuthQualifier.size() + 1); + if (Composite1.getPointerAuth() == Composite2.getPointerAuth()) + PtrAuthQualifier.back() = Composite1.getPointerAuth(); continue; } @@ -6299,8 +6306,11 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, // Rewrap the composites as pointers or member pointers with the union CVRs. auto MOC = MemberOfClass.rbegin(); + auto PtrAuthQualIt = PtrAuthQualifier.rbegin(); for (unsigned CVR : llvm::reverse(QualifierUnion)) { Qualifiers Quals = Qualifiers::fromCVRMask(CVR); + if (PointerAuthQualifier PtrAuthQual = *PtrAuthQualIt++) + Quals.setPointerAuth(PtrAuthQual); auto Classes = *MOC++; if (Classes.first && Classes.second) { // Rebuild member pointer type diff --git a/clang/test/SemaCXX/ptrauth-qualifier.cpp b/clang/test/SemaCXX/ptrauth-qualifier.cpp index 97448d9d0c5eb..673d381577f86 100644 --- a/clang/test/SemaCXX/ptrauth-qualifier.cpp +++ b/clang/test/SemaCXX/ptrauth-qualifier.cpp @@ -120,6 +120,16 @@ namespace test_union { } } +bool test_composite_type0(bool c, int * AQ * a0, int * AQ * a1) { + auto t = c ? a0 : a1; + return a0 == a1; +} + +bool test_composite_type1(bool c, int * AQ * a0, int * AQ2 * a1) { + auto t = c ? a0 : a1; // expected-error {{incompatible operand types ('int *__ptrauth(1,1,50) *' and 'int *__ptrauth(1,1,51) *')}} + return a0 == a1; // expected-error {{comparison of distinct pointer types ('int *__ptrauth(1,1,50) *' and 'int *__ptrauth(1,1,51) *')}} +} + void test_bad_call_diag(void *AQ* ptr); // expected-note{{candidate function not viable: 1st argument ('void *__ptrauth(1,1,51) *') has __ptrauth(1,1,51) qualifier, but parameter has __ptrauth(1,1,50) qualifier}} expected-note{{candidate function not viable: 1st argument ('void **') has no ptrauth qualifier, but parameter has __ptrauth(1,1,50) qualifier}} void test_bad_call_diag2(void ** ptr); // expected-note{{1st argument ('void *__ptrauth(1,1,50) *') has __ptrauth(1,1,50) qualifier, but parameter has no ptrauth qualifier}} From 750e49cf5a6f03cb5aff0cebe1612c7894d5b56e Mon Sep 17 00:00:00 2001 From: Kadir Cetinkaya Date: Wed, 8 Jan 2020 11:21:21 +0100 Subject: [PATCH 277/286] Revert "[InstCombine] fold zext of masked bit set/clear" This reverts commit a041c4ec6f7aa659b235cb67e9231a05e0a33b7d. This looks like a non-trivial change and there has been no code reviews (at least there were no phabricator revisions attached to the commit description). It is also causing a regression in one of our downstream integration tests, we haven't been able to come up with a minimal reproducer yet. (cherry picked from commit b212eb7159b40c98b3c40619b82b996fb903282b) --- .../InstCombine/InstCombineCasts.cpp | 20 +----- llvm/test/Transforms/InstCombine/zext.ll | 65 ++++++++----------- 2 files changed, 31 insertions(+), 54 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp index b9be41840ffaf..3ba56bbe53e06 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp @@ -922,24 +922,10 @@ Instruction *InstCombiner::transformZExtICmp(ICmpInst *Cmp, ZExtInst &Zext, } } + // icmp ne A, B is equal to xor A, B when A and B only really have one bit. + // It is also profitable to transform icmp eq into not(xor(A, B)) because that + // may lead to additional simplifications. if (Cmp->isEquality() && Zext.getType() == Cmp->getOperand(0)->getType()) { - // Test if a bit is clear/set using a shifted-one mask: - // zext (icmp eq (and X, (1 << ShAmt)), 0) --> and (lshr (not X), ShAmt), 1 - // zext (icmp ne (and X, (1 << ShAmt)), 0) --> and (lshr X, ShAmt), 1 - Value *X, *ShAmt; - if (Cmp->hasOneUse() && match(Cmp->getOperand(1), m_ZeroInt()) && - match(Cmp->getOperand(0), - m_OneUse(m_c_And(m_Shl(m_One(), m_Value(ShAmt)), m_Value(X))))) { - if (Cmp->getPredicate() == ICmpInst::ICMP_EQ) - X = Builder.CreateNot(X); - Value *Lshr = Builder.CreateLShr(X, ShAmt); - Value *And1 = Builder.CreateAnd(Lshr, ConstantInt::get(X->getType(), 1)); - return replaceInstUsesWith(Zext, And1); - } - - // icmp ne A, B is equal to xor A, B when A and B only really have one bit. - // It is also profitable to transform icmp eq into not(xor(A, B)) because - // that may lead to additional simplifications. if (IntegerType *ITy = dyn_cast(Zext.getType())) { Value *LHS = Cmp->getOperand(0); Value *RHS = Cmp->getOperand(1); diff --git a/llvm/test/Transforms/InstCombine/zext.ll b/llvm/test/Transforms/InstCombine/zext.ll index 9351f5cea4dd1..1dbb9ffd7e083 100644 --- a/llvm/test/Transforms/InstCombine/zext.ll +++ b/llvm/test/Transforms/InstCombine/zext.ll @@ -177,9 +177,11 @@ declare void @use32(i32) define i32 @masked_bit_set(i32 %x, i32 %y) { ; CHECK-LABEL: @masked_bit_set( -; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 1 -; CHECK-NEXT: ret i32 [[TMP2]] +; CHECK-NEXT: [[SH1:%.*]] = shl i32 1, [[Y:%.*]] +; CHECK-NEXT: [[AND:%.*]] = and i32 [[SH1]], [[X:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[AND]], 0 +; CHECK-NEXT: [[R:%.*]] = zext i1 [[CMP]] to i32 +; CHECK-NEXT: ret i32 [[R]] ; %sh1 = shl i32 1, %y %and = and i32 %sh1, %x @@ -190,10 +192,11 @@ define i32 @masked_bit_set(i32 %x, i32 %y) { define <2 x i32> @masked_bit_clear(<2 x i32> %x, <2 x i32> %y) { ; CHECK-LABEL: @masked_bit_clear( -; CHECK-NEXT: [[TMP1:%.*]] = xor <2 x i32> [[X:%.*]], -; CHECK-NEXT: [[TMP2:%.*]] = lshr <2 x i32> [[TMP1]], [[Y:%.*]] -; CHECK-NEXT: [[TMP3:%.*]] = and <2 x i32> [[TMP2]], -; CHECK-NEXT: ret <2 x i32> [[TMP3]] +; CHECK-NEXT: [[SH1:%.*]] = shl <2 x i32> , [[Y:%.*]] +; CHECK-NEXT: [[AND:%.*]] = and <2 x i32> [[SH1]], [[X:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[AND]], zeroinitializer +; CHECK-NEXT: [[R:%.*]] = zext <2 x i1> [[CMP]] to <2 x i32> +; CHECK-NEXT: ret <2 x i32> [[R]] ; %sh1 = shl <2 x i32> , %y %and = and <2 x i32> %sh1, %x @@ -205,9 +208,11 @@ define <2 x i32> @masked_bit_clear(<2 x i32> %x, <2 x i32> %y) { define <2 x i32> @masked_bit_set_commute(<2 x i32> %px, <2 x i32> %y) { ; CHECK-LABEL: @masked_bit_set_commute( ; CHECK-NEXT: [[X:%.*]] = srem <2 x i32> , [[PX:%.*]] -; CHECK-NEXT: [[TMP1:%.*]] = lshr <2 x i32> [[X]], [[Y:%.*]] -; CHECK-NEXT: [[TMP2:%.*]] = and <2 x i32> [[TMP1]], -; CHECK-NEXT: ret <2 x i32> [[TMP2]] +; CHECK-NEXT: [[SH1:%.*]] = shl <2 x i32> , [[Y:%.*]] +; CHECK-NEXT: [[AND:%.*]] = and <2 x i32> [[X]], [[SH1]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ne <2 x i32> [[AND]], zeroinitializer +; CHECK-NEXT: [[R:%.*]] = zext <2 x i1> [[CMP]] to <2 x i32> +; CHECK-NEXT: ret <2 x i32> [[R]] ; %x = srem <2 x i32> , %px ; thwart complexity-based canonicalization %sh1 = shl <2 x i32> , %y @@ -220,10 +225,11 @@ define <2 x i32> @masked_bit_set_commute(<2 x i32> %px, <2 x i32> %y) { define i32 @masked_bit_clear_commute(i32 %px, i32 %y) { ; CHECK-LABEL: @masked_bit_clear_commute( ; CHECK-NEXT: [[X:%.*]] = srem i32 42, [[PX:%.*]] -; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X]], -1 -; CHECK-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP1]], [[Y:%.*]] -; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP2]], 1 -; CHECK-NEXT: ret i32 [[TMP3]] +; CHECK-NEXT: [[SH1:%.*]] = shl i32 1, [[Y:%.*]] +; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[SH1]] +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0 +; CHECK-NEXT: [[R:%.*]] = zext i1 [[CMP]] to i32 +; CHECK-NEXT: ret i32 [[R]] ; %x = srem i32 42, %px ; thwart complexity-based canonicalization %sh1 = shl i32 1, %y @@ -237,9 +243,10 @@ define i32 @masked_bit_set_use1(i32 %x, i32 %y) { ; CHECK-LABEL: @masked_bit_set_use1( ; CHECK-NEXT: [[SH1:%.*]] = shl i32 1, [[Y:%.*]] ; CHECK-NEXT: call void @use32(i32 [[SH1]]) -; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[X:%.*]], [[Y]] -; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 1 -; CHECK-NEXT: ret i32 [[TMP2]] +; CHECK-NEXT: [[AND:%.*]] = and i32 [[SH1]], [[X:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[AND]], 0 +; CHECK-NEXT: [[R:%.*]] = zext i1 [[CMP]] to i32 +; CHECK-NEXT: ret i32 [[R]] ; %sh1 = shl i32 1, %y call void @use32(i32 %sh1) @@ -249,8 +256,6 @@ define i32 @masked_bit_set_use1(i32 %x, i32 %y) { ret i32 %r } -; Negative test - define i32 @masked_bit_set_use2(i32 %x, i32 %y) { ; CHECK-LABEL: @masked_bit_set_use2( ; CHECK-NEXT: [[SH1:%.*]] = shl i32 1, [[Y:%.*]] @@ -268,8 +273,6 @@ define i32 @masked_bit_set_use2(i32 %x, i32 %y) { ret i32 %r } -; Negative test - define i32 @masked_bit_set_use3(i32 %x, i32 %y) { ; CHECK-LABEL: @masked_bit_set_use3( ; CHECK-NEXT: [[SH1:%.*]] = shl i32 1, [[Y:%.*]] @@ -291,10 +294,10 @@ define i32 @masked_bit_clear_use1(i32 %x, i32 %y) { ; CHECK-LABEL: @masked_bit_clear_use1( ; CHECK-NEXT: [[SH1:%.*]] = shl i32 1, [[Y:%.*]] ; CHECK-NEXT: call void @use32(i32 [[SH1]]) -; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], -1 -; CHECK-NEXT: [[TMP2:%.*]] = lshr i32 [[TMP1]], [[Y]] -; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP2]], 1 -; CHECK-NEXT: ret i32 [[TMP3]] +; CHECK-NEXT: [[AND:%.*]] = and i32 [[SH1]], [[X:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0 +; CHECK-NEXT: [[R:%.*]] = zext i1 [[CMP]] to i32 +; CHECK-NEXT: ret i32 [[R]] ; %sh1 = shl i32 1, %y call void @use32(i32 %sh1) @@ -304,8 +307,6 @@ define i32 @masked_bit_clear_use1(i32 %x, i32 %y) { ret i32 %r } -; Negative test - define i32 @masked_bit_clear_use2(i32 %x, i32 %y) { ; CHECK-LABEL: @masked_bit_clear_use2( ; CHECK-NEXT: [[SH1:%.*]] = shl i32 1, [[Y:%.*]] @@ -323,8 +324,6 @@ define i32 @masked_bit_clear_use2(i32 %x, i32 %y) { ret i32 %r } -; Negative test - define i32 @masked_bit_clear_use3(i32 %x, i32 %y) { ; CHECK-LABEL: @masked_bit_clear_use3( ; CHECK-NEXT: [[SH1:%.*]] = shl i32 1, [[Y:%.*]] @@ -342,8 +341,6 @@ define i32 @masked_bit_clear_use3(i32 %x, i32 %y) { ret i32 %r } -; Negative test - define i32 @masked_bits_set(i32 %x, i32 %y) { ; CHECK-LABEL: @masked_bits_set( ; CHECK-NEXT: [[SH1:%.*]] = shl i32 3, [[Y:%.*]] @@ -359,8 +356,6 @@ define i32 @masked_bits_set(i32 %x, i32 %y) { ret i32 %r } -; Negative test - define i32 @div_bit_set(i32 %x, i32 %y) { ; CHECK-LABEL: @div_bit_set( ; CHECK-NEXT: [[SH1:%.*]] = shl i32 1, [[Y:%.*]] @@ -376,8 +371,6 @@ define i32 @div_bit_set(i32 %x, i32 %y) { ret i32 %r } -; Negative test - define i32 @masked_bit_set_nonzero_cmp(i32 %x, i32 %y) { ; CHECK-LABEL: @masked_bit_set_nonzero_cmp( ; CHECK-NEXT: [[SH1:%.*]] = shl i32 1, [[Y:%.*]] @@ -393,8 +386,6 @@ define i32 @masked_bit_set_nonzero_cmp(i32 %x, i32 %y) { ret i32 %r } -; Negative test - define i32 @masked_bit_wrong_pred(i32 %x, i32 %y) { ; CHECK-LABEL: @masked_bit_wrong_pred( ; CHECK-NEXT: [[SH1:%.*]] = shl i32 1, [[Y:%.*]] From 87b6ab2eaffe5bd67637dc3f03f97460c41249e8 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Tue, 21 Apr 2020 08:25:44 -0700 Subject: [PATCH 278/286] [lldb/Test] Decode stdout and stderr in case it contains Unicode. Lit's to_string will just return the string when it's a `str` instance, which in Python 2 can still contain UTF-8 characters. Differential revision: https://reviews.llvm.org/D76955 (cherry picked from commit 2de52422acf04662b45599f77c14ce1b2cec2b81) --- lldb/test/API/lldbtest.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lldb/test/API/lldbtest.py b/lldb/test/API/lldbtest.py index 94c0588fd9e63..7af4ea7f5b394 100644 --- a/lldb/test/API/lldbtest.py +++ b/lldb/test/API/lldbtest.py @@ -99,6 +99,11 @@ def execute(self, test, litConfig): timeoutInfo = 'Reached timeout of {} seconds'.format( litConfig.maxIndividualTestTime) + if sys.version_info.major == 2: + # In Python 2, string objects can contain Unicode characters. + out = out.decode('utf-8') + err = err.decode('utf-8') + output = """Script:\n--\n%s\n--\nExit Code: %d\n""" % ( ' '.join(cmd), exitCode) if timeoutInfo is not None: From 07e680a59f96fc792583eb567ef1f48c4b66194b Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Thu, 26 Mar 2020 08:45:08 -0700 Subject: [PATCH 279/286] [lldb/Test] XFAIL TestDataFormatterObjCNSError except for gmodules. --- .../data-formatter-objc/TestDataFormatterObjCNSError.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSError.py b/lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSError.py index df380aefd88f4..b5e1f149354fd 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSError.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-objc/TestDataFormatterObjCNSError.py @@ -15,6 +15,7 @@ class ObjCDataFormatterNSError(ObjCDataFormatterTestCase): @skipUnlessDarwin + @expectedFailureAll(debug_info=["dwarf", "dsym", "dwo"], bugnumber="rdar://25587546") def test_nserror_with_run_command(self): """Test formatters for NSError.""" self.appkit_tester_impl(self.nserror_data_formatter_commands) From 715aa78694eb1d593b60831146143b39f9fa0034 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Fri, 27 Mar 2020 15:02:24 -0700 Subject: [PATCH 280/286] [VirtualFileSystem] Support directory entries in the YAMLVFSWriter The current implementation of the JSONWriter does not support writing out directory entries. Earlier today I added a unit test to illustrate the problem. When an entry is added to the YAMLVFSWriter and the path is a directory, it will incorrectly emit the directory as a file, and any files inside that directory will not be found by the VFS. It's possible to partially work around the issue by only adding "leaf nodes" (files) to the YAMLVFSWriter. However, this doesn't work for representing empty directories. This is a problem for clients of the VFS that want to iterate over a directory. The directory not being there is not the same as the directory being empty. This is not just a hypothetical problem. The FileCollector for example does not differentiate between file and directory paths. I temporarily worked around the issue for LLDB by ignoring directories, but I suspect this will prove problematic sooner rather than later. This patch fixes the issue by extending the JSONWriter to support writing out directory entries. We store whether an entry should be emitted as a file or directory. Differential revision: https://reviews.llvm.org/D76670 (cherry picked from commit 3ef33e69de085cb6bc028b4fc4dd39087631ac12) --- llvm/include/llvm/Support/VirtualFileSystem.h | 9 +++- llvm/lib/Support/VirtualFileSystem.cpp | 34 ++++++++++--- .../Support/VirtualFileSystemTest.cpp | 50 +++++++++++++++++++ 3 files changed, 83 insertions(+), 10 deletions(-) diff --git a/llvm/include/llvm/Support/VirtualFileSystem.h b/llvm/include/llvm/Support/VirtualFileSystem.h index e45e6e7567863..257f7586953ef 100644 --- a/llvm/include/llvm/Support/VirtualFileSystem.h +++ b/llvm/include/llvm/Support/VirtualFileSystem.h @@ -506,10 +506,12 @@ getVFSFromYAML(std::unique_ptr Buffer, struct YAMLVFSEntry { template - YAMLVFSEntry(T1 &&VPath, T2 &&RPath) - : VPath(std::forward(VPath)), RPath(std::forward(RPath)) {} + YAMLVFSEntry(T1 &&VPath, T2 &&RPath, bool IsDirectory = false) + : VPath(std::forward(VPath)), RPath(std::forward(RPath)), + IsDirectory(IsDirectory) {} std::string VPath; std::string RPath; + bool IsDirectory = false; }; class VFSFromYamlDirIterImpl; @@ -781,10 +783,13 @@ class YAMLVFSWriter { Optional UseExternalNames; std::string OverlayDir; + void addEntry(StringRef VirtualPath, StringRef RealPath, bool IsDirectory); + public: YAMLVFSWriter() = default; void addFileMapping(StringRef VirtualPath, StringRef RealPath); + void addDirectoryMapping(StringRef VirtualPath, StringRef RealPath); void setCaseSensitivity(bool CaseSensitive) { IsCaseSensitive = CaseSensitive; diff --git a/llvm/lib/Support/VirtualFileSystem.cpp b/llvm/lib/Support/VirtualFileSystem.cpp index edd4234fe5016..2b899e90e0ae7 100644 --- a/llvm/lib/Support/VirtualFileSystem.cpp +++ b/llvm/lib/Support/VirtualFileSystem.cpp @@ -1894,11 +1894,21 @@ UniqueID vfs::getNextVirtualUniqueID() { return UniqueID(std::numeric_limits::max(), ID); } -void YAMLVFSWriter::addFileMapping(StringRef VirtualPath, StringRef RealPath) { +void YAMLVFSWriter::addEntry(StringRef VirtualPath, StringRef RealPath, + bool IsDirectory) { assert(sys::path::is_absolute(VirtualPath) && "virtual path not absolute"); assert(sys::path::is_absolute(RealPath) && "real path not absolute"); assert(!pathHasTraversal(VirtualPath) && "path traversal is not supported"); - Mappings.emplace_back(VirtualPath, RealPath); + Mappings.emplace_back(VirtualPath, RealPath, IsDirectory); +} + +void YAMLVFSWriter::addFileMapping(StringRef VirtualPath, StringRef RealPath) { + addEntry(VirtualPath, RealPath, /*IsDirectory=*/false); +} + +void YAMLVFSWriter::addDirectoryMapping(StringRef VirtualPath, + StringRef RealPath) { + addEntry(VirtualPath, RealPath, /*IsDirectory=*/true); } namespace { @@ -1999,7 +2009,10 @@ void JSONWriter::write(ArrayRef Entries, if (!Entries.empty()) { const YAMLVFSEntry &Entry = Entries.front(); - startDirectory(path::parent_path(Entry.VPath)); + bool first_entry_is_directory = Entry.IsDirectory; + StringRef Dir = + first_entry_is_directory ? Entry.VPath : path::parent_path(Entry.VPath); + startDirectory(Dir); StringRef RPath = Entry.RPath; if (UseOverlayRelative) { @@ -2009,13 +2022,18 @@ void JSONWriter::write(ArrayRef Entries, RPath = RPath.slice(OverlayDirLen, RPath.size()); } - writeEntry(path::filename(Entry.VPath), RPath); + if (!first_entry_is_directory) + writeEntry(path::filename(Entry.VPath), RPath); for (const auto &Entry : Entries.slice(1)) { - StringRef Dir = path::parent_path(Entry.VPath); - if (Dir == DirStack.back()) - OS << ",\n"; - else { + StringRef Dir = + Entry.IsDirectory ? Entry.VPath : path::parent_path(Entry.VPath); + if (Dir == DirStack.back()) { + if (!first_entry_is_directory) { + OS << ",\n"; + first_entry_is_directory = false; + } + } else { while (!DirStack.empty() && !containedIn(DirStack.back(), Dir)) { OS << "\n"; endDirectory(); diff --git a/llvm/unittests/Support/VirtualFileSystemTest.cpp b/llvm/unittests/Support/VirtualFileSystemTest.cpp index d61652bc0c50f..bd62811ae734a 100644 --- a/llvm/unittests/Support/VirtualFileSystemTest.cpp +++ b/llvm/unittests/Support/VirtualFileSystemTest.cpp @@ -2189,3 +2189,53 @@ TEST_F(VFSFromYAMLTest, WorkingDirectoryFallthroughInvalid) { Status = FS->status("foo/a"); ASSERT_TRUE(Status.getError()); } + +TEST_F(VFSFromYAMLTest, YAMLVFSWriterTest) { + ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true); + ScopedDir _a(TestDirectory + "/a"); + ScopedFile _ab(TestDirectory + "/a/b", ""); + ScopedDir _c(TestDirectory + "/c"); + ScopedFile _cd(TestDirectory + "/c/d", ""); + ScopedDir _e(TestDirectory + "/e"); + ScopedDir _ef(TestDirectory + "/e/f"); + ScopedDir _g(TestDirectory + "/g"); + ScopedFile _h(TestDirectory + "/h", ""); + + vfs::YAMLVFSWriter VFSWriter; + VFSWriter.addDirectoryMapping(_a.Path, "//root/a"); + VFSWriter.addFileMapping(_ab.Path, "//root/a/b"); + VFSWriter.addFileMapping(_cd.Path, "//root/c/d"); + VFSWriter.addDirectoryMapping(_e.Path, "//root/e"); + VFSWriter.addDirectoryMapping(_ef.Path, "//root/e/f"); + VFSWriter.addFileMapping(_g.Path, "//root/g"); + VFSWriter.addDirectoryMapping(_h.Path, "//root/h"); + + std::string Buffer; + raw_string_ostream OS(Buffer); + VFSWriter.write(OS); + OS.flush(); + + IntrusiveRefCntPtr Lower(new ErrorDummyFileSystem()); + Lower->addDirectory("//root/"); + Lower->addDirectory("//root/a"); + Lower->addRegularFile("//root/a/b"); + Lower->addDirectory("//root/b"); + Lower->addDirectory("//root/c"); + Lower->addRegularFile("//root/c/d"); + Lower->addDirectory("//root/e"); + Lower->addDirectory("//root/e/f"); + Lower->addDirectory("//root/g"); + Lower->addRegularFile("//root/h"); + + IntrusiveRefCntPtr FS = getFromYAMLRawString(Buffer, Lower); + ASSERT_TRUE(FS.get() != nullptr); + + EXPECT_TRUE(FS->exists(_a.Path)); + EXPECT_TRUE(FS->exists(_ab.Path)); + EXPECT_TRUE(FS->exists(_c.Path)); + EXPECT_TRUE(FS->exists(_cd.Path)); + EXPECT_TRUE(FS->exists(_e.Path)); + EXPECT_TRUE(FS->exists(_ef.Path)); + EXPECT_TRUE(FS->exists(_g.Path)); + EXPECT_TRUE(FS->exists(_h.Path)); +} From 83dca65091967b4590cff8ac79227514e3c9c0b4 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Mon, 30 Mar 2020 12:58:21 -0700 Subject: [PATCH 281/286] Re-land "[FileCollector] Add a method to add a whole directory and it contents." Extend the FileCollector's API with addDirectory which adds a directory and its contents to the VFS mapping. Differential revision: https://reviews.llvm.org/D76671 (cherry picked from commit 4151f2d04ad8d829e16b83be734908fc38f977e9) --- llvm/include/llvm/Support/FileCollector.h | 18 +++++-- llvm/lib/Support/FileCollector.cpp | 56 ++++++++++++-------- llvm/unittests/Support/FileCollectorTest.cpp | 35 ++++++++++++ 3 files changed, 83 insertions(+), 26 deletions(-) diff --git a/llvm/include/llvm/Support/FileCollector.h b/llvm/include/llvm/Support/FileCollector.h index 079fe3efab9d3..1b6383ef8cc2d 100644 --- a/llvm/include/llvm/Support/FileCollector.h +++ b/llvm/include/llvm/Support/FileCollector.h @@ -18,7 +18,7 @@ #include namespace llvm { - +class FileCollectorFileSystem; /// Collects files into a directory and generates a mapping that can be used by /// the VFS. class FileCollector { @@ -26,9 +26,10 @@ class FileCollector { FileCollector(std::string Root, std::string OverlayRoot); void addFile(const Twine &file); + void addDirectory(const Twine &Dir); /// Write the yaml mapping (for the VFS) to the given file. - std::error_code writeMapping(StringRef mapping_file); + std::error_code writeMapping(StringRef MappingFile); /// Copy the files into the root directory. /// @@ -44,7 +45,7 @@ class FileCollector { std::shared_ptr Collector); private: - void addFileImpl(StringRef SrcPath); + friend FileCollectorFileSystem; bool markAsSeen(StringRef Path) { if (Path.empty()) @@ -55,10 +56,19 @@ class FileCollector { bool getRealPath(StringRef SrcPath, SmallVectorImpl &Result); void addFileToMapping(StringRef VirtualPath, StringRef RealPath) { - VFSWriter.addFileMapping(VirtualPath, RealPath); + if (sys::fs::is_directory(VirtualPath)) + VFSWriter.addDirectoryMapping(VirtualPath, RealPath); + else + VFSWriter.addFileMapping(VirtualPath, RealPath); } protected: + void addFileImpl(StringRef SrcPath); + + llvm::vfs::directory_iterator + addDirectoryImpl(const llvm::Twine &Dir, + IntrusiveRefCntPtr FS, std::error_code &EC); + /// Synchronizes adding files. std::mutex Mutex; diff --git a/llvm/lib/Support/FileCollector.cpp b/llvm/lib/Support/FileCollector.cpp index 47fca64137223..9d2485c151d67 100644 --- a/llvm/lib/Support/FileCollector.cpp +++ b/llvm/lib/Support/FileCollector.cpp @@ -61,13 +61,19 @@ bool FileCollector::getRealPath(StringRef SrcPath, return true; } -void FileCollector::addFile(const Twine &file) { +void FileCollector::addFile(const Twine &File) { std::lock_guard lock(Mutex); - std::string FileStr = file.str(); + std::string FileStr = File.str(); if (markAsSeen(FileStr)) addFileImpl(FileStr); } +void FileCollector::addDirectory(const Twine &Dir) { + assert(sys::fs::is_directory(Dir)); + std::error_code EC; + addDirectoryImpl(Dir, vfs::getRealFileSystem(), EC); +} + void FileCollector::addFileImpl(StringRef SrcPath) { // We need an absolute src path to append to the root. SmallString<256> AbsoluteSrc = SrcPath; @@ -101,6 +107,27 @@ void FileCollector::addFileImpl(StringRef SrcPath) { addFileToMapping(VirtualPath, DstPath); } +llvm::vfs::directory_iterator +FileCollector::addDirectoryImpl(const llvm::Twine &Dir, + IntrusiveRefCntPtr FS, + std::error_code &EC) { + auto It = FS->dir_begin(Dir, EC); + if (EC) + return It; + addFile(Dir); + for (; !EC && It != llvm::vfs::directory_iterator(); It.increment(EC)) { + if (It->type() == sys::fs::file_type::regular_file || + It->type() == sys::fs::file_type::directory_file || + It->type() == sys::fs::file_type::symlink_file) { + addFile(It->path()); + } + } + if (EC) + return It; + // Return a new iterator. + return FS->dir_begin(Dir, EC); +} + /// Set the access and modification time for the given file from the given /// status object. static std::error_code @@ -171,7 +198,7 @@ std::error_code FileCollector::copyFiles(bool StopOnError) { return {}; } -std::error_code FileCollector::writeMapping(StringRef mapping_file) { +std::error_code FileCollector::writeMapping(StringRef MappingFile) { std::lock_guard lock(Mutex); VFSWriter.setOverlayDir(OverlayRoot); @@ -179,7 +206,7 @@ std::error_code FileCollector::writeMapping(StringRef mapping_file) { VFSWriter.setUseExternalNames(false); std::error_code EC; - raw_fd_ostream os(mapping_file, EC, sys::fs::OF_Text); + raw_fd_ostream os(MappingFile, EC, sys::fs::OF_Text); if (EC) return EC; @@ -188,7 +215,7 @@ std::error_code FileCollector::writeMapping(StringRef mapping_file) { return {}; } -namespace { +namespace llvm { class FileCollectorFileSystem : public vfs::FileSystem { public: @@ -213,22 +240,7 @@ class FileCollectorFileSystem : public vfs::FileSystem { llvm::vfs::directory_iterator dir_begin(const llvm::Twine &Dir, std::error_code &EC) override { - auto It = FS->dir_begin(Dir, EC); - if (EC) - return It; - // Collect everything that's listed in case the user needs it. - Collector->addFile(Dir); - for (; !EC && It != llvm::vfs::directory_iterator(); It.increment(EC)) { - if (It->type() == sys::fs::file_type::regular_file || - It->type() == sys::fs::file_type::directory_file || - It->type() == sys::fs::file_type::symlink_file) { - Collector->addFile(It->path()); - } - } - if (EC) - return It; - // Return a new iterator. - return FS->dir_begin(Dir, EC); + return Collector->addDirectoryImpl(Dir, FS, EC); } std::error_code getRealPath(const Twine &Path, @@ -259,7 +271,7 @@ class FileCollectorFileSystem : public vfs::FileSystem { std::shared_ptr Collector; }; -} // end anonymous namespace +} // namespace llvm IntrusiveRefCntPtr FileCollector::createCollectorVFS(IntrusiveRefCntPtr BaseFS, diff --git a/llvm/unittests/Support/FileCollectorTest.cpp b/llvm/unittests/Support/FileCollectorTest.cpp index c6aeedd3865d3..c2c8bd53be388 100644 --- a/llvm/unittests/Support/FileCollectorTest.cpp +++ b/llvm/unittests/Support/FileCollectorTest.cpp @@ -120,6 +120,41 @@ TEST(FileCollectorTest, addFile) { EXPECT_FALSE(FileCollector.hasSeen("/path/to/d")); } +TEST(FileCollectorTest, addDirectory) { + ScopedDir file_root("file_root", true); + + llvm::SmallString<128> aaa = file_root.Path; + llvm::sys::path::append(aaa, "aaa"); + ScopedFile a(aaa.str()); + + llvm::SmallString<128> bbb = file_root.Path; + llvm::sys::path::append(bbb, "bbb"); + ScopedFile b(bbb.str()); + + llvm::SmallString<128> ccc = file_root.Path; + llvm::sys::path::append(ccc, "ccc"); + ScopedFile c(ccc.str()); + + std::string root_fs = std::string(file_root.Path.str()); + TestingFileCollector FileCollector(root_fs, root_fs); + + FileCollector.addDirectory(file_root.Path); + + // Make sure the root is correct. + EXPECT_EQ(FileCollector.Root, root_fs); + + // Make sure we've seen all the added files. + EXPECT_TRUE(FileCollector.hasSeen(a.Path)); + EXPECT_TRUE(FileCollector.hasSeen(b.Path)); + EXPECT_TRUE(FileCollector.hasSeen(c.Path)); + + // Make sure we've only seen the added files. + llvm::SmallString<128> ddd = file_root.Path; + llvm::sys::path::append(ddd, "ddd"); + ScopedFile d(ddd.str()); + EXPECT_FALSE(FileCollector.hasSeen(d.Path)); +} + TEST(FileCollectorTest, copyFiles) { ScopedDir file_root("file_root", true); ScopedFile a(file_root + "/aaa"); From 1d9a5bea33c6b9b94bb1a930df1655e3dd4188e7 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Mon, 30 Mar 2020 15:09:03 -0700 Subject: [PATCH 282/286] [lldb/Reproducers] Always collect the whole dSYM in the reproducer The FileCollector in LLDB collects every files that's used during a debug session when capture is enabled. This ensures that the reproducer only contains the files necessary to reproduce. This approach is not a good fit for the dSYM bundle, which is a directory on disk, but should be treated as a single unit. On macOS LLDB have automatically find the matching dSYM for a binary by its UUID. Having a incomplete dSYM in a reproducer can break debugging even when reproducers are disabled. This patch adds a was to specify a directory of interest to the reproducers. It is called from SymbolVendorMacOSX with the path of the dSYMs used by LLDB. Differential revision: https://reviews.llvm.org/D76672 (cherry picked from commit 38ddb49e5242920e44a982cff7bbe2e86bd23a69) --- lldb/include/lldb/Utility/Reproducer.h | 2 + .../MacOSX/SymbolVendorMacOSX.cpp | 247 +++++++++--------- lldb/source/Utility/Reproducer.cpp | 5 + lldb/test/Shell/Reproducer/TestDSYM.test | 11 + 4 files changed, 145 insertions(+), 120 deletions(-) create mode 100644 lldb/test/Shell/Reproducer/TestDSYM.test diff --git a/lldb/include/lldb/Utility/Reproducer.h b/lldb/include/lldb/Utility/Reproducer.h index 873ec3c76b529..cdf089d547cfd 100644 --- a/lldb/include/lldb/Utility/Reproducer.h +++ b/lldb/include/lldb/Utility/Reproducer.h @@ -98,6 +98,8 @@ class FileProvider : public Provider { return m_collector; } + void recordInterestingDirectory(const llvm::Twine &dir); + void Keep() override { auto mapping = GetRoot().CopyByAppendingPathComponent(Info::file); // Temporary files that are removed during execution can cause copy errors. diff --git a/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp b/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp index bb37d777906c7..090c139685f08 100644 --- a/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp +++ b/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp @@ -20,6 +20,7 @@ #include "lldb/Symbol/LocateSymbolFile.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/Target.h" +#include "lldb/Utility/Reproducer.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/Timer.h" @@ -143,6 +144,11 @@ SymbolVendorMacOSX::CreateInstance(const lldb::ModuleSP &module_sp, } if (dsym_fspec) { + // Compute dSYM root. + std::string dsym_root = dsym_fspec.GetPath(); + const size_t pos = dsym_root.find("/Contents/Resources/"); + dsym_root = pos != std::string::npos ? dsym_root.substr(0, pos) : ""; + DataBufferSP dsym_file_data_sp; lldb::offset_t dsym_file_data_offset = 0; dsym_objfile_sp = @@ -152,136 +158,132 @@ SymbolVendorMacOSX::CreateInstance(const lldb::ModuleSP &module_sp, if (UUIDsMatch(module_sp.get(), dsym_objfile_sp.get(), feedback_strm)) { // We need a XML parser if we hope to parse a plist... if (XMLDocument::XMLEnabled()) { - char dsym_path[PATH_MAX]; - if (module_sp->GetSourceMappingList().IsEmpty() && - dsym_fspec.GetPath(dsym_path, sizeof(dsym_path))) { + if (module_sp->GetSourceMappingList().IsEmpty()) { lldb_private::UUID dsym_uuid = dsym_objfile_sp->GetUUID(); if (dsym_uuid) { std::string uuid_str = dsym_uuid.GetAsString(); - if (!uuid_str.empty()) { - char *resources = strstr(dsym_path, "/Contents/Resources/"); - if (resources) { - char dsym_uuid_plist_path[PATH_MAX]; - resources[strlen("/Contents/Resources/")] = '\0'; - snprintf(dsym_uuid_plist_path, sizeof(dsym_uuid_plist_path), - "%s%s.plist", dsym_path, uuid_str.c_str()); - FileSpec dsym_uuid_plist_spec(dsym_uuid_plist_path); - if (FileSystem::Instance().Exists(dsym_uuid_plist_spec)) { - ApplePropertyList plist(dsym_uuid_plist_path); - if (plist) { - std::string DBGBuildSourcePath; - std::string DBGSourcePath; - - // DBGSourcePathRemapping is a dictionary in the plist - // with keys which are DBGBuildSourcePath file paths and - // values which are DBGSourcePath file paths - - StructuredData::ObjectSP plist_sp = - plist.GetStructuredData(); - if (plist_sp.get() && plist_sp->GetAsDictionary() && - plist_sp->GetAsDictionary()->HasKey( - "DBGSourcePathRemapping") && - plist_sp->GetAsDictionary() - ->GetValueForKey("DBGSourcePathRemapping") - ->GetAsDictionary()) { - - // If DBGVersion 1 or DBGVersion missing, ignore DBGSourcePathRemapping. - // If DBGVersion 2, strip last two components of path remappings from - // entries to fix an issue with a specific set of - // DBGSourcePathRemapping entries that lldb worked - // with. - // If DBGVersion 3, trust & use the source path remappings as-is. - // - - bool new_style_source_remapping_dictionary = false; - bool do_truncate_remapping_names = false; - std::string original_DBGSourcePath_value = - DBGSourcePath; - if (plist_sp->GetAsDictionary()->HasKey("DBGVersion")) { - std::string version_string = - plist_sp->GetAsDictionary() - ->GetValueForKey("DBGVersion") - ->GetStringValue(""); - if (!version_string.empty() && - isdigit(version_string[0])) { - int version_number = atoi(version_string.c_str()); - if (version_number > 1) { - new_style_source_remapping_dictionary = true; - } - if (version_number == 2) { - do_truncate_remapping_names = true; - } + if (!uuid_str.empty() && !dsym_root.empty()) { + char dsym_uuid_plist_path[PATH_MAX]; + snprintf(dsym_uuid_plist_path, sizeof(dsym_uuid_plist_path), + "%s/Contents/Resources/%s.plist", dsym_root.c_str(), + uuid_str.c_str()); + FileSpec dsym_uuid_plist_spec(dsym_uuid_plist_path); + if (FileSystem::Instance().Exists(dsym_uuid_plist_spec)) { + ApplePropertyList plist(dsym_uuid_plist_path); + if (plist) { + std::string DBGBuildSourcePath; + std::string DBGSourcePath; + + // DBGSourcePathRemapping is a dictionary in the plist + // with keys which are DBGBuildSourcePath file paths and + // values which are DBGSourcePath file paths + + StructuredData::ObjectSP plist_sp = + plist.GetStructuredData(); + if (plist_sp.get() && plist_sp->GetAsDictionary() && + plist_sp->GetAsDictionary()->HasKey( + "DBGSourcePathRemapping") && + plist_sp->GetAsDictionary() + ->GetValueForKey("DBGSourcePathRemapping") + ->GetAsDictionary()) { + + // If DBGVersion 1 or DBGVersion missing, ignore + // DBGSourcePathRemapping. If DBGVersion 2, strip last two + // components of path remappings from + // entries to fix an issue with a + // specific set of DBGSourcePathRemapping + // entries that lldb worked with. + // If DBGVersion 3, trust & use the source path remappings + // as-is. + // + + bool new_style_source_remapping_dictionary = false; + bool do_truncate_remapping_names = false; + std::string original_DBGSourcePath_value = DBGSourcePath; + if (plist_sp->GetAsDictionary()->HasKey("DBGVersion")) { + std::string version_string = + std::string(plist_sp->GetAsDictionary() + ->GetValueForKey("DBGVersion") + ->GetStringValue("")); + if (!version_string.empty() && + isdigit(version_string[0])) { + int version_number = atoi(version_string.c_str()); + if (version_number > 1) { + new_style_source_remapping_dictionary = true; + } + if (version_number == 2) { + do_truncate_remapping_names = true; } } + } - StructuredData::Dictionary *remappings_dict = - plist_sp->GetAsDictionary() - ->GetValueForKey("DBGSourcePathRemapping") - ->GetAsDictionary(); - remappings_dict->ForEach( - [&module_sp, new_style_source_remapping_dictionary, - original_DBGSourcePath_value, do_truncate_remapping_names]( - ConstString key, - StructuredData::Object *object) -> bool { - if (object && object->GetAsString()) { - - // key is DBGBuildSourcePath - // object is DBGSourcePath - std::string DBGSourcePath = - object->GetStringValue(); - if (!new_style_source_remapping_dictionary && - !original_DBGSourcePath_value.empty()) { - DBGSourcePath = original_DBGSourcePath_value; - } - if (DBGSourcePath[0] == '~') { - FileSpec resolved_source_path( - DBGSourcePath.c_str()); - FileSystem::Instance().Resolve( - resolved_source_path); - DBGSourcePath = - resolved_source_path.GetPath(); - } + StructuredData::Dictionary *remappings_dict = + plist_sp->GetAsDictionary() + ->GetValueForKey("DBGSourcePathRemapping") + ->GetAsDictionary(); + remappings_dict->ForEach( + [&module_sp, new_style_source_remapping_dictionary, + original_DBGSourcePath_value, + do_truncate_remapping_names]( + ConstString key, + StructuredData::Object *object) -> bool { + if (object && object->GetAsString()) { + + // key is DBGBuildSourcePath + // object is DBGSourcePath + std::string DBGSourcePath = + std::string(object->GetStringValue()); + if (!new_style_source_remapping_dictionary && + !original_DBGSourcePath_value.empty()) { + DBGSourcePath = original_DBGSourcePath_value; + } + if (DBGSourcePath[0] == '~') { + FileSpec resolved_source_path( + DBGSourcePath.c_str()); + FileSystem::Instance().Resolve( + resolved_source_path); + DBGSourcePath = resolved_source_path.GetPath(); + } + module_sp->GetSourceMappingList().Append( + key, ConstString(DBGSourcePath), true); + // With version 2 of DBGSourcePathRemapping, we + // can chop off the last two filename parts + // from the source remapping and get a more + // general source remapping that still works. + // Add this as another option in addition to + // the full source path remap. + if (do_truncate_remapping_names) { + FileSpec build_path(key.AsCString()); + FileSpec source_path(DBGSourcePath.c_str()); + build_path.RemoveLastPathComponent(); + build_path.RemoveLastPathComponent(); + source_path.RemoveLastPathComponent(); + source_path.RemoveLastPathComponent(); module_sp->GetSourceMappingList().Append( - key, ConstString(DBGSourcePath), true); - // With version 2 of DBGSourcePathRemapping, we - // can chop off the last two filename parts - // from the source remapping and get a more - // general source remapping that still works. - // Add this as another option in addition to - // the full source path remap. - if (do_truncate_remapping_names) { - FileSpec build_path(key.AsCString()); - FileSpec source_path(DBGSourcePath.c_str()); - build_path.RemoveLastPathComponent(); - build_path.RemoveLastPathComponent(); - source_path.RemoveLastPathComponent(); - source_path.RemoveLastPathComponent(); - module_sp->GetSourceMappingList().Append( - ConstString(build_path.GetPath().c_str()), - ConstString(source_path.GetPath().c_str()), true); - } + ConstString(build_path.GetPath().c_str()), + ConstString(source_path.GetPath().c_str()), + true); } - return true; - }); - } + } + return true; + }); + } - // If we have a DBGBuildSourcePath + DBGSourcePath pair, - // append those to the source path remappings. - - plist.GetValueAsString("DBGBuildSourcePath", - DBGBuildSourcePath); - plist.GetValueAsString("DBGSourcePath", DBGSourcePath); - if (!DBGBuildSourcePath.empty() && - !DBGSourcePath.empty()) { - if (DBGSourcePath[0] == '~') { - FileSpec resolved_source_path(DBGSourcePath.c_str()); - FileSystem::Instance().Resolve(resolved_source_path); - DBGSourcePath = resolved_source_path.GetPath(); - } - module_sp->GetSourceMappingList().Append( - ConstString(DBGBuildSourcePath), - ConstString(DBGSourcePath), true); + // If we have a DBGBuildSourcePath + DBGSourcePath pair, + // append those to the source path remappings. + + plist.GetValueAsString("DBGBuildSourcePath", + DBGBuildSourcePath); + plist.GetValueAsString("DBGSourcePath", DBGSourcePath); + if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty()) { + if (DBGSourcePath[0] == '~') { + FileSpec resolved_source_path(DBGSourcePath.c_str()); + FileSystem::Instance().Resolve(resolved_source_path); + DBGSourcePath = resolved_source_path.GetPath(); } + module_sp->GetSourceMappingList().Append( + ConstString(DBGBuildSourcePath), + ConstString(DBGSourcePath), true); } } } @@ -291,6 +293,11 @@ SymbolVendorMacOSX::CreateInstance(const lldb::ModuleSP &module_sp, } symbol_vendor->AddSymbolFileRepresentation(dsym_objfile_sp); + if (repro::Generator *g = + repro::Reproducer::Instance().GetGenerator()) { + repro::FileProvider &fp = g->GetOrCreate(); + fp.recordInterestingDirectory(dsym_root); + } return symbol_vendor; } } diff --git a/lldb/source/Utility/Reproducer.cpp b/lldb/source/Utility/Reproducer.cpp index 8987cfdac5565..6e3b8d269caf3 100644 --- a/lldb/source/Utility/Reproducer.cpp +++ b/lldb/source/Utility/Reproducer.cpp @@ -321,6 +321,11 @@ void WorkingDirectoryProvider::Keep() { os << m_cwd << "\n"; } +void FileProvider::recordInterestingDirectory(const llvm::Twine &dir) { + if (m_collector) + m_collector->addDirectory(dir); +} + void ProviderBase::anchor() {} char CommandProvider::ID = 0; char FileProvider::ID = 0; diff --git a/lldb/test/Shell/Reproducer/TestDSYM.test b/lldb/test/Shell/Reproducer/TestDSYM.test new file mode 100644 index 0000000000000..bddacda3242f9 --- /dev/null +++ b/lldb/test/Shell/Reproducer/TestDSYM.test @@ -0,0 +1,11 @@ +# REQUIRES: system-darwin +# Ensure that the reproducers captures the whole dSYM bundle. + +# RUN: rm -rf %t.repro +# RUN: %clang_host %S/Inputs/simple.c -g -o %t.out +# RUN: touch %t.out.dSYM/foo.bar + +# RUN: %lldb -x -b --capture --capture-path %t.repro %t.out -o 'b main' -o 'run' -o 'reproducer generate' + +# RUN: %lldb -b -o 'reproducer dump -p files -f %t.repro' | FileCheck %s --check-prefix FILES +# FILES: foo.bar From 724a15c66fecbbe15a2962c2c390db0150db8790 Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Thu, 16 Apr 2020 17:06:48 -0700 Subject: [PATCH 283/286] Implement TypeSystemSwiftTypeRef::GetArrayElementType() (NFC) --- lldb/source/Symbol/SwiftASTContext.cpp | 4 +- lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp | 45 ++++++++++++++----- .../Symbol/TestTypeSystemSwiftTypeRef.cpp | 3 ++ 3 files changed, 41 insertions(+), 11 deletions(-) diff --git a/lldb/source/Symbol/SwiftASTContext.cpp b/lldb/source/Symbol/SwiftASTContext.cpp index 70b94e9459114..d270f44e3930e 100644 --- a/lldb/source/Symbol/SwiftASTContext.cpp +++ b/lldb/source/Symbol/SwiftASTContext.cpp @@ -5175,7 +5175,9 @@ bool SwiftASTContext::IsArrayType(void *type, CompilerType *element_type_ptr, swift_can_type->getAs(); if (struct_type) { swift::StructDecl *struct_decl = struct_type->getDecl(); - if (strcmp(struct_decl->getName().get(), "Array") != 0) + llvm::StringRef name = struct_decl->getName().get(); + // This is sketchy, but it matches the behavior of GetArrayElementType(). + if (name != "Array" && name != "NativeArray" && name != "ArraySlice") return false; if (!struct_decl->getModuleContext()->isStdlibModule()) return false; diff --git a/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp index 1949ade4138ed..6786c8c7a72be 100644 --- a/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp +++ b/lldb/source/Symbol/TypeSystemSwiftTypeRef.cpp @@ -67,7 +67,7 @@ GetCanonicalNode(lldb_private::Module *M, swift::Demangle::Demangler &Dem, swift::STDLIB_NAME); e->addChild(module, Dem); NodePointer optional = - Dem.createNodeWithAllocatedText(Node::Kind::Module, "Optional"); + Dem.createNodeWithAllocatedText(Node::Kind::Identifier, "Optional"); e->addChild(optional, Dem); type->addChild(e, Dem); canonical->addChild(type, Dem); @@ -93,7 +93,7 @@ GetCanonicalNode(lldb_private::Module *M, swift::Demangle::Demangler &Dem, swift::STDLIB_NAME); structure->addChild(module, Dem); NodePointer array = - Dem.createNodeWithAllocatedText(Node::Kind::Module, "Array"); + Dem.createNodeWithAllocatedText(Node::Kind::Identifier, "Array"); structure->addChild(array, Dem); type->addChild(structure, Dem); canonical->addChild(type, Dem); @@ -121,7 +121,7 @@ GetCanonicalNode(lldb_private::Module *M, swift::Demangle::Demangler &Dem, swift::STDLIB_NAME); structure->addChild(module, Dem); NodePointer dict = - Dem.createNodeWithAllocatedText(Node::Kind::Module, "Dictionary"); + Dem.createNodeWithAllocatedText(Node::Kind::Identifier, "Dictionary"); structure->addChild(dict, Dem); type->addChild(structure, Dem); canonical->addChild(type, Dem); @@ -307,7 +307,24 @@ bool TypeSystemSwiftTypeRef::Verify(lldb::opaque_compiler_type_t type) { return true; const char *str = reinterpret_cast(type); - return SwiftLanguageRuntime::IsSwiftMangledName(str); + if (!SwiftLanguageRuntime::IsSwiftMangledName(str)) + return false; + + // Finally, check that the mangled name is canonical. + using namespace swift::Demangle; + Demangler dem; + NodePointer node = dem.demangleSymbol(str); + std::string remangled = mangleNode(node); + return remangled == std::string(str); +} + +namespace { +template bool Equivalent(T l, T r) { return l == r; } +/// Compare two swift types from different type systems by comparing their +/// (canonicalized) mangled name. +template <> bool Equivalent(CompilerType l, CompilerType r) { + return l.GetMangledTypeName() == r.GetMangledTypeName(); +} } #endif @@ -316,7 +333,7 @@ bool TypeSystemSwiftTypeRef::Verify(lldb::opaque_compiler_type_t type) { do { \ auto result = IMPL(); \ if (m_swift_ast_context) \ - assert(result == (EXPECTED) && \ + assert(Equivalent(result, (EXPECTED)) && \ "TypeSystemSwiftTypeRef diverges from SwiftASTContext"); \ return result; \ } while (0) @@ -341,6 +358,8 @@ swift::Demangle::NodePointer TypeSystemSwiftTypeRef::DemangleCanonicalType(swift::Demangle::Demangler &Dem, void *opaque_type) { using namespace swift::Demangle; + if (!opaque_type) + return nullptr; NodePointer node = GetCanonicalDemangleTree(GetModule(), Dem, AsMangledName(opaque_type)); @@ -379,14 +398,15 @@ bool TypeSystemSwiftTypeRef::IsArrayType(void *type, CompilerType *element_type, node->getChild(0)->getText() != swift::STDLIB_NAME || node->getChild(1)->getKind() != Node::Kind::Identifier || !node->getChild(1)->hasText() || - node->getChild(1)->getText() != "Array") + (node->getChild(1)->getText() != "Array" && + node->getChild(1)->getText() != "NativeArray" && + node->getChild(1)->getText() != "ArraySlice")) return false; if (elem_node->getNumChildren() != 1 || elem_node->getKind() != Node::Kind::TypeList) return false; elem_node = elem_node->getFirstChild(); - if (element_type) *element_type = RemangleAsType(Dem, elem_node); @@ -573,14 +593,19 @@ lldb::TypeClass TypeSystemSwiftTypeRef::GetTypeClass(void *type) { // Creating related types CompilerType TypeSystemSwiftTypeRef::GetArrayElementType(void *type, uint64_t *stride) { - return m_swift_ast_context->GetArrayElementType(ReconstructType(type), - stride); + auto impl = [&]() { + CompilerType element_type; + IsArrayType(type, &element_type, nullptr, nullptr); + return element_type; + }; + VALIDATE_AND_RETURN(impl, m_swift_ast_context->GetArrayElementType( + ReconstructType(type), nullptr)); } CompilerType TypeSystemSwiftTypeRef::GetCanonicalType(void *type) { return m_swift_ast_context->GetCanonicalType(ReconstructType(type)); } int TypeSystemSwiftTypeRef::GetFunctionArgumentCount(void *type) { - auto impl = [&]() { return GetNumberOfFunctionArguments(type); }; + auto impl = [&]() -> int { return GetNumberOfFunctionArguments(type); }; VALIDATE_AND_RETURN(impl, m_swift_ast_context->GetFunctionArgumentCount( ReconstructType(type))); } diff --git a/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp b/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp index 6b81b9f110c97..55261d494d953 100644 --- a/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp +++ b/lldb/unittests/Symbol/TestTypeSystemSwiftTypeRef.cpp @@ -92,6 +92,9 @@ TEST_F(TestTypeSystemSwiftTypeRef, Array) { b.Node(Node::Kind::TypeList, b.IntType()))); CompilerType int_array = GetCompilerType(b.Mangle(n)); ASSERT_TRUE(int_array.IsArrayType(nullptr, nullptr, nullptr)); + NodePointer int_node = b.GlobalTypeMangling(b.IntType()); + CompilerType int_type = GetCompilerType(b.Mangle(int_node)); + ASSERT_EQ(int_array.GetArrayElementType(nullptr), int_type); } TEST_F(TestTypeSystemSwiftTypeRef, Function) { From c9e31f78b125d69677ac4d02d80ed7eccb07dc7f Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Tue, 21 Apr 2020 11:14:30 -0700 Subject: [PATCH 284/286] [apple/stable/20200108] Fix ambiguity Fix error: conditional expression is ambiguous; 'const std::string' (aka 'const basic_string, allocator >') can be converted to 'llvm::StringRef' and vice versa. --- llvm/lib/Support/VirtualFileSystem.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/llvm/lib/Support/VirtualFileSystem.cpp b/llvm/lib/Support/VirtualFileSystem.cpp index 2b899e90e0ae7..ba35d251d6bb2 100644 --- a/llvm/lib/Support/VirtualFileSystem.cpp +++ b/llvm/lib/Support/VirtualFileSystem.cpp @@ -2010,8 +2010,8 @@ void JSONWriter::write(ArrayRef Entries, if (!Entries.empty()) { const YAMLVFSEntry &Entry = Entries.front(); bool first_entry_is_directory = Entry.IsDirectory; - StringRef Dir = - first_entry_is_directory ? Entry.VPath : path::parent_path(Entry.VPath); + StringRef Dir = first_entry_is_directory ? StringRef(Entry.VPath) + : path::parent_path(Entry.VPath); startDirectory(Dir); StringRef RPath = Entry.RPath; @@ -2026,8 +2026,8 @@ void JSONWriter::write(ArrayRef Entries, writeEntry(path::filename(Entry.VPath), RPath); for (const auto &Entry : Entries.slice(1)) { - StringRef Dir = - Entry.IsDirectory ? Entry.VPath : path::parent_path(Entry.VPath); + StringRef Dir = Entry.IsDirectory ? StringRef(Entry.VPath) + : path::parent_path(Entry.VPath); if (Dir == DirStack.back()) { if (!first_entry_is_directory) { OS << ",\n"; From e8a928d0b5479f017a905f7bea9499a5c08b43b1 Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Mon, 20 Apr 2020 17:22:35 -0700 Subject: [PATCH 285/286] Unbreak ASan runtime in the simulators. Summary: 861b69faee5df8d4e13ef316c7474a10e4069e81 (rdar://problem/58789439) while fixing symbolization for TSan completely broke ASan's runtime for the simulators. The problem with the previous patch is that the memory passed to `putenv()` was poisoned and when passed to `putenv()` it tripped an interceptor for `strchr()` which saw the memory was poisoned and raised an ASan issue. The memory was poisoned because `AtosSymbolizerProcess` objects are created using ASan's internal allocator. Memory from this allocator gets poisoned with `kAsanInternalHeapMagic`. To workaround this, this patch makes the memory for the environment variable entry a global variable that isn't poisoned. This pass also adds a `DCHECK(getenv(K_ATOS_ENV_VAR))` because the following DCHECK would crash because `internal_strcmp()` doesn't work on nullptr. rdar://problem/62067724 Reviewers: kubamracek, yln Subscribers: #sanitizers, llvm-commits Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D78525 (cherry picked from commit 7039773b240b6eee00b5be5bc325c5c57501788a) --- .../sanitizer_symbolizer_mac.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp index 4623c3f76b120..cc233408d0ceb 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_mac.cpp @@ -53,6 +53,11 @@ bool DlAddrSymbolizer::SymbolizeData(uptr addr, DataInfo *datainfo) { #define K_ATOS_ENV_VAR "__check_mach_ports_lookup" +// This cannot live in `AtosSymbolizerProcess` because instances of that object +// are allocated by the internal allocator which under ASan is poisoned with +// kAsanInternalHeapMagic. +static char kAtosMachPortEnvEntry[] = K_ATOS_ENV_VAR "=000000000000000"; + class AtosSymbolizerProcess : public SymbolizerProcess { public: explicit AtosSymbolizerProcess(const char *path) @@ -69,7 +74,7 @@ class AtosSymbolizerProcess : public SymbolizerProcess { // We use `putenv()` rather than `setenv()` so that we can later directly // write into the storage without LibC getting involved to change what the // variable is set to - int result = putenv(mach_port_env_var_entry_); + int result = putenv(kAtosMachPortEnvEntry); CHECK_EQ(result, 0); } } @@ -95,12 +100,13 @@ class AtosSymbolizerProcess : public SymbolizerProcess { // for our task port. We can't call `setenv()` here because it might call // malloc/realloc. To avoid that we instead update the // `mach_port_env_var_entry_` variable with our current PID. - uptr count = internal_snprintf(mach_port_env_var_entry_, - sizeof(mach_port_env_var_entry_), + uptr count = internal_snprintf(kAtosMachPortEnvEntry, + sizeof(kAtosMachPortEnvEntry), K_ATOS_ENV_VAR "=%s", pid_str_); CHECK_GE(count, sizeof(K_ATOS_ENV_VAR) + internal_strlen(pid_str_)); // Document our assumption but without calling `getenv()` in normal // builds. + DCHECK(getenv(K_ATOS_ENV_VAR)); DCHECK_EQ(internal_strcmp(getenv(K_ATOS_ENV_VAR), pid_str_), 0); } @@ -127,9 +133,10 @@ class AtosSymbolizerProcess : public SymbolizerProcess { } char pid_str_[16]; - // Space for `\0` in `kAtosEnvVar_` is reused for `=`. - char mach_port_env_var_entry_[sizeof(K_ATOS_ENV_VAR) + sizeof(pid_str_)] = - K_ATOS_ENV_VAR "=0"; + // Space for `\0` in `K_ATOS_ENV_VAR` is reused for `=`. + static_assert(sizeof(kAtosMachPortEnvEntry) == + (sizeof(K_ATOS_ENV_VAR) + sizeof(pid_str_)), + "sizes should match"); }; #undef K_ATOS_ENV_VAR From b5749104908b85d6058821fa0a6a9f7297e6a8d9 Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Mon, 20 Apr 2020 18:27:43 -0700 Subject: [PATCH 286/286] Add missing call to `Symbolizer::LateInitialize()` in UBSan's standalone init. Summary: This fixes symbolization in Standalone UBSan mode for the Darwin simulators. 861b69faee5df8d4e13ef316c7474a10e4069e81 (rdar://problem/58789439) tried to fix symbolization for all sanitizers on Darwin simulators but unfortunately it only fixed the problem for TSan. For UBSan in standalone mode the fix wasn't sufficient because UBSan's standalone init doesn't call `Symbolizer::LateInitialize()` like ASan and TSan do. This meant that `AtosSymbolizerProcess::LateInitialize()` was never being called before `AtosSymbolizerProcess::StartSymbolizerSubprocess()` which breaks an invariant we expect to hold. The missing call to `Symbolizer::LateInitialize()` during UBSan's standalone init seems like an accidently omission so this patch simply adds it. rdar://problem/62083617 Reviewers: vitalybuka, kubamracek, yln, samsonov Subscribers: #sanitizers, llvm-commits Tags: #sanitizers Differential Revision: https://reviews.llvm.org/D78530 (cherry picked from commit 564530e50ad4870801a2080a08645cc1cc2df805) --- compiler-rt/lib/ubsan/ubsan_init.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler-rt/lib/ubsan/ubsan_init.cpp b/compiler-rt/lib/ubsan/ubsan_init.cpp index 1a3b7d3726743..26b6227aa484b 100644 --- a/compiler-rt/lib/ubsan/ubsan_init.cpp +++ b/compiler-rt/lib/ubsan/ubsan_init.cpp @@ -41,6 +41,7 @@ static void CommonStandaloneInit() { AndroidLogInit(); InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir); CommonInit(); + Symbolizer::LateInitialize(); } void __ubsan::InitAsStandalone() {