diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp index 71a15c26d6928..5c6e2fb942dee 100644 --- a/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/clang/lib/Driver/ToolChains/Darwin.cpp @@ -2098,21 +2098,42 @@ void DarwinClang::AddClangCXXStdlibIncludeArgs( switch (GetCXXStdlibType(DriverArgs)) { case ToolChain::CST_Libcxx: { - // On Darwin, libc++ is installed alongside the compiler in - // include/c++/v1, so get from '/bin' to '/include/c++/v1'. - { - llvm::SmallString<128> P = llvm::StringRef(getDriver().getInstalledDir()); - // Note that P can be relative, so we have to '..' and not parent_path. - llvm::sys::path::append(P, "..", "include", "c++", "v1"); - addSystemInclude(DriverArgs, CC1Args, P); + // On Darwin, libc++ can be installed in one of the following two places: + // 1. Alongside the compiler in /include/c++/v1 + // 2. In a SDK (or a custom sysroot) in /usr/include/c++/v1 + // + // The precendence of paths is as listed above, i.e. we take the first path + // that exists. Also note that we never include libc++ twice -- we take the + // first path that exists and don't send the other paths to CC1 (otherwise + // include_next could break). + + // Check for (1) + // Get from '/bin' to '/include/c++/v1'. + // Note that InstallBin can be relative, so we use '..' instead of + // parent_path. + llvm::SmallString<128> InstallBin = + llvm::StringRef(getDriver().getInstalledDir()); // /bin + llvm::sys::path::append(InstallBin, "..", "include", "c++", "v1"); + if (getVFS().exists(InstallBin)) { + addSystemInclude(DriverArgs, CC1Args, InstallBin); + return; + } else if (DriverArgs.hasArg(options::OPT_v)) { + llvm::errs() << "ignoring nonexistent directory \"" << InstallBin + << "\"\n"; } - // Also add /usr/include/c++/v1 unless -nostdinc is used, - // to match the legacy behavior in CC1. - if (!DriverArgs.hasArg(options::OPT_nostdinc)) { - llvm::SmallString<128> P = Sysroot; - llvm::sys::path::append(P, "usr", "include", "c++", "v1"); - addSystemInclude(DriverArgs, CC1Args, P); + + // Otherwise, check for (2) + llvm::SmallString<128> SysrootUsr = Sysroot; + llvm::sys::path::append(SysrootUsr, "usr", "include", "c++", "v1"); + if (getVFS().exists(SysrootUsr)) { + addSystemInclude(DriverArgs, CC1Args, SysrootUsr); + return; + } else if (DriverArgs.hasArg(options::OPT_v)) { + llvm::errs() << "ignoring nonexistent directory \"" << SysrootUsr + << "\"\n"; } + + // Otherwise, don't add any path. break; } diff --git a/clang/test/Driver/Inputs/basic_darwin_sdk_usr_cxx_v1/usr/include/c++/v1/.keep b/clang/test/Driver/Inputs/basic_darwin_sdk_usr_cxx_v1/usr/include/c++/v1/.keep new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/basic_darwin_sdk_usr_cxx_v1/usr/lib/.keep b/clang/test/Driver/Inputs/basic_darwin_sdk_usr_cxx_v1/usr/lib/.keep new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/darwin-header-search-libcxx.cpp b/clang/test/Driver/darwin-header-search-libcxx.cpp index 6bdbbd11908a1..4824525f1cf41 100644 --- a/clang/test/Driver/darwin-header-search-libcxx.cpp +++ b/clang/test/Driver/darwin-header-search-libcxx.cpp @@ -13,39 +13,57 @@ // RUN: | FileCheck --check-prefix=CHECK-LIBCXX-NONE %s // CHECK-LIBCXX-NONE: "{{[^"]*}}clang{{[^"]*}}" "-cc1" -// Check with only headers alongside the installation (those should be used, -// but we should still add /usr/include/c++/v1 after to preserve legacy). +// Check with only headers alongside the installation (those should be used). // // RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \ // RUN: -target x86_64-apple-darwin \ // RUN: -stdlib=libc++ \ // RUN: -ccc-install-dir %S/Inputs/basic_darwin_toolchain/usr/bin \ // RUN: --sysroot="" \ -// RUN: | FileCheck -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain --check-prefix=CHECK-LIBCXX-TOOLCHAIN-1 %s +// RUN: | FileCheck -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain \ +// RUN: --check-prefix=CHECK-LIBCXX-TOOLCHAIN-1 %s // CHECK-LIBCXX-TOOLCHAIN-1: "{{[^"]*}}clang{{[^"]*}}" "-cc1" // CHECK-LIBCXX-TOOLCHAIN-1: "-internal-isystem" "[[TOOLCHAIN]]/usr/bin/../include/c++/v1" -// CHECK-LIBCXX-TOOLCHAIN-1: "-internal-isystem" "/usr/include/c++/v1" +// CHECK-LIBCXX-TOOLCHAIN-1-NOT: "-internal-isystem" "/usr/include/c++/v1" // // RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \ // RUN: -target x86_64-apple-darwin \ // RUN: -stdlib=libc++ \ // RUN: -ccc-install-dir %S/Inputs/basic_darwin_toolchain/usr/bin \ // RUN: -isysroot %S/Inputs/basic_darwin_sdk_no_libcxx \ -// RUN: | FileCheck -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain --check-prefix=CHECK-LIBCXX-TOOLCHAIN-2 %s +// RUN: | FileCheck -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain \ +// RUN: -DSYSROOT=%S/Inputs/basic_darwin_sdk_no_libcxx \ +// RUN: --check-prefix=CHECK-LIBCXX-TOOLCHAIN-2 %s // CHECK-LIBCXX-TOOLCHAIN-2: "{{[^"]*}}clang{{[^"]*}}" "-cc1" // CHECK-LIBCXX-TOOLCHAIN-2: "-internal-isystem" "[[TOOLCHAIN]]/usr/bin/../include/c++/v1" +// CHECK-LIBCXX-TOOLCHAIN-2-NOT: "-internal-isystem" "[[SYSROOT]]/usr/include/c++/v1" + +// Check with only headers in the sysroot (those should be used). +// +// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \ +// RUN: -target x86_64-apple-darwin \ +// RUN: -stdlib=libc++ \ +// RUN: -ccc-install-dir %S/Inputs/basic_darwin_toolchain_no_libcxx/usr/bin \ +// RUN: -isysroot %S/Inputs/basic_darwin_sdk_usr_cxx_v1 \ +// RUN: | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr_cxx_v1 \ +// RUN: -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain_no_libcxx \ +// RUN: --check-prefix=CHECK-LIBCXX-SYSROOT-1 %s +// CHECK-LIBCXX-SYSROOT-1: "{{[^"]*}}clang{{[^"]*}}" "-cc1" +// CHECK-LIBCXX-SYSROOT-1: "-internal-isystem" "[[SYSROOT]]/usr/include/c++/v1" +// CHECK-LIBCXX-SYSROOT-1-NOT: "-internal-isystem" "[[TOOLCHAIN]]/usr/bin/../include/c++/v1" // Check with both headers in the sysroot and headers alongside the installation -// (the headers in should be added after the toolchain headers). -// Ensure that both -isysroot and --sysroot work, and that isysroot has precedence. +// (the headers in the toolchain should be preferred over the headers). +// Ensure that both -isysroot and --sysroot work, and that isysroot has precedence +// over --sysroot. // // RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \ // RUN: -target x86_64-apple-darwin \ // RUN: -stdlib=libc++ \ // RUN: -ccc-install-dir %S/Inputs/basic_darwin_toolchain/usr/bin \ // RUN: -resource-dir=%S/Inputs/resource_dir \ -// RUN: -isysroot %S/Inputs/basic_darwin_sdk_usr \ -// RUN: | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr \ +// RUN: -isysroot %S/Inputs/basic_darwin_sdk_usr_cxx_v1 \ +// RUN: | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr_cxx_v1 \ // RUN: -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain \ // RUN: --check-prefix=CHECK-LIBCXX-SYSROOT_AND_TOOLCHAIN-1 %s // @@ -54,8 +72,8 @@ // RUN: -stdlib=libc++ \ // RUN: -ccc-install-dir %S/Inputs/basic_darwin_toolchain/usr/bin \ // RUN: -resource-dir=%S/Inputs/resource_dir \ -// RUN: --sysroot %S/Inputs/basic_darwin_sdk_usr \ -// RUN: | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr \ +// RUN: --sysroot %S/Inputs/basic_darwin_sdk_usr_cxx_v1 \ +// RUN: | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr_cxx_v1 \ // RUN: -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain \ // RUN: --check-prefix=CHECK-LIBCXX-SYSROOT_AND_TOOLCHAIN-1 %s // @@ -64,32 +82,46 @@ // RUN: -stdlib=libc++ \ // RUN: -ccc-install-dir %S/Inputs/basic_darwin_toolchain/usr/bin \ // RUN: -resource-dir=%S/Inputs/resource_dir \ -// RUN: -isysroot %S/Inputs/basic_darwin_sdk_usr \ +// RUN: -isysroot %S/Inputs/basic_darwin_sdk_usr_cxx_v1 \ // RUN: --sysroot %S/Inputs/basic_darwin_sdk_no_libcxx \ -// RUN: | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr \ +// RUN: | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr_cxx_v1 \ // RUN: -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain \ // RUN: --check-prefix=CHECK-LIBCXX-SYSROOT_AND_TOOLCHAIN-1 %s // // CHECK-LIBCXX-SYSROOT_AND_TOOLCHAIN-1: "{{[^"]*}}clang{{[^"]*}}" "-cc1" // CHECK-LIBCXX-SYSROOT_AND_TOOLCHAIN-1: "-internal-isystem" "[[TOOLCHAIN]]/usr/bin/../include/c++/v1" -// CHECK-LIBCXX-SYSROOT_AND_TOOLCHAIN-1: "-internal-isystem" "[[SYSROOT]]/usr/include/c++/v1" +// CHECK-LIBCXX-SYSROOT_AND_TOOLCHAIN-1-NOT: "-internal-isystem" "[[SYSROOT]]/usr/include/c++/v1" -// Make sure that using -nostdinc will drop the sysroot C++ library include -// path, but not the toolchain one. +// Make sure that using -nostdinc does not drop any C++ library include path. +// This behavior is strange, but it is compatible with the legacy CC1 behavior. // // RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \ // RUN: -target x86_64-apple-darwin16 \ // RUN: -ccc-install-dir %S/Inputs/basic_darwin_toolchain/usr/bin \ // RUN: -resource-dir=%S/Inputs/resource_dir \ -// RUN: -isysroot %S/Inputs/basic_darwin_sdk_usr \ +// RUN: -isysroot %S/Inputs/basic_darwin_sdk_usr_cxx_v1 \ // RUN: -stdlib=platform \ // RUN: -nostdinc \ -// RUN: | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr \ +// RUN: | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr_cxx_v1 \ // RUN: -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain \ -// RUN: --check-prefix=CHECK-LIBCXX-NOSTDINC %s -// CHECK-LIBCXX-NOSTDINC: "{{[^"]*}}clang{{[^"]*}}" "-cc1" -// CHECK-LIBCXX-NOSTDINC: "-internal-isystem" "[[TOOLCHAIN]]/usr/bin/../include/c++/v1" -// CHECK-LIBCXX-NOSTDINC-NOT: "-internal-isystem" "[[SYSROOT]]/usr/include/c++/v1" +// RUN: --check-prefix=CHECK-LIBCXX-NOSTDINC-1 %s +// CHECK-LIBCXX-NOSTDINC-1: "{{[^"]*}}clang{{[^"]*}}" "-cc1" +// CHECK-LIBCXX-NOSTDINC-1-NOT: "-internal-isystem" "[[SYSROOT]]/usr/include/c++/v1" +// CHECK-LIBCXX-NOSTDINC-1: "-internal-isystem" "[[TOOLCHAIN]]/usr/bin/../include/c++/v1" +// +// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \ +// RUN: -target x86_64-apple-darwin16 \ +// RUN: -ccc-install-dir %S/Inputs/basic_darwin_toolchain/usr/bin \ +// RUN: -resource-dir=%S/Inputs/resource_dir \ +// RUN: -isysroot %S/Inputs/basic_darwin_sdk_no_libcxx \ +// RUN: -stdlib=platform \ +// RUN: -nostdinc \ +// RUN: | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_no_libcxx \ +// RUN: -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain \ +// RUN: --check-prefix=CHECK-LIBCXX-NOSTDINC-2 %s +// CHECK-LIBCXX-NOSTDINC-2: "{{[^"]*}}clang{{[^"]*}}" "-cc1" +// CHECK-LIBCXX-NOSTDINC-2: "-internal-isystem" "[[TOOLCHAIN]]/usr/bin/../include/c++/v1" +// CHECK-LIBCXX-NOSTDINC-2-NOT: "-internal-isystem" "[[SYSROOT]]/usr/include/c++/v1" // Make sure that using -nostdinc++ or -nostdlib will drop both the toolchain // C++ include path and the sysroot one. @@ -98,7 +130,7 @@ // RUN: -target x86_64-apple-darwin16 \ // RUN: -ccc-install-dir %S/Inputs/basic_darwin_toolchain/usr/bin \ // RUN: -resource-dir=%S/Inputs/resource_dir \ -// RUN: -isysroot %S/Inputs/basic_darwin_sdk_usr \ +// RUN: -isysroot %S/Inputs/basic_darwin_sdk_usr_cxx_v1 \ // RUN: -stdlib=platform \ // RUN: -nostdinc++ \ // RUN: | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr \ @@ -121,3 +153,26 @@ // CHECK-LIBCXX-NOSTDLIBINC: "{{[^"]*}}clang{{[^"]*}}" "-cc1" // CHECK-LIBCXX-NOSTDLIBINC-NOT: "-internal-isystem" "[[TOOLCHAIN]]/usr/bin/../include/c++/v1" // CHECK-LIBCXX-NOSTDLIBINC-NOT: "-internal-isystem" "[[SYSROOT]]/usr/include/c++/v1" + +// Make sure we explain that we considered a path but didn't add it when it +// doesn't exist. +// +// RUN: %clang -no-canonical-prefixes %s -fsyntax-only -v 2>&1 \ +// RUN: -target x86_64-apple-darwin \ +// RUN: -ccc-install-dir %S/Inputs/basic_darwin_toolchain_no_libcxx/usr/bin \ +// RUN: -isysroot %S/Inputs/basic_darwin_sdk \ +// RUN: -stdlib=libc++ \ +// RUN: | FileCheck -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain_no_libcxx \ +// RUN: --check-prefix=CHECK-LIBCXX-MISSING-TOOLCHAIN %s +// CHECK-LIBCXX-MISSING-TOOLCHAIN: ignoring nonexistent directory "[[TOOLCHAIN]]/usr/bin/../include/c++/v1" +// +// RUN: %clang -no-canonical-prefixes %s -fsyntax-only -v 2>&1 \ +// RUN: -target x86_64-apple-darwin \ +// RUN: -ccc-install-dir %S/Inputs/basic_darwin_toolchain_no_libcxx/usr/bin \ +// RUN: -isysroot %S/Inputs/basic_darwin_sdk_no_libcxx \ +// RUN: -stdlib=libc++ \ +// RUN: | FileCheck -DSYSROOT=%S/Inputs/basic_darwin_sdk_no_libcxx \ +// RUN: -DTOOLCHAIN=%S/Inputs/basic_darwin_toolchain_no_libcxx \ +// RUN: --check-prefix=CHECK-LIBCXX-MISSING-BOTH %s +// CHECK-LIBCXX-MISSING-BOTH: ignoring nonexistent directory "[[TOOLCHAIN]]/usr/bin/../include/c++/v1" +// CHECK-LIBCXX-MISSING-BOTH: ignoring nonexistent directory "[[SYSROOT]]/usr/include/c++/v1" diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index fc77ca9d23d6b..125c2ee26c8c3 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -9700,14 +9700,15 @@ GetSpecializedASTName(ScratchTypeSystemClang::IsolatedASTKind feature) { } TypeSystemClang &ScratchTypeSystemClang::GetIsolatedAST( - ScratchTypeSystemClang::IsolatedASTKind feature) { + ScratchTypeSystemClang::IsolatedASTKind feature_enum) { + int feature = static_cast(feature_enum); auto found_ast = m_isolated_asts.find(feature); if (found_ast != m_isolated_asts.end()) return *found_ast->second; // Couldn't find the requested sub-AST, so create it now. std::unique_ptr new_ast; - new_ast.reset(new SpecializedScratchAST(GetSpecializedASTName(feature), + new_ast.reset(new SpecializedScratchAST(GetSpecializedASTName(feature_enum), m_triple, CreateASTSource())); m_isolated_asts[feature] = std::move(new_ast); return *m_isolated_asts[feature]; diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index a927164888113..001e5f2d42f7e 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -1237,7 +1237,7 @@ class ScratchTypeSystemClang : public TypeSystemClang { /// Map from IsolatedASTKind to their actual TypeSystemClang instance. /// This map is lazily filled with sub-ASTs and should be accessed via /// `GetSubAST` (which lazily fills this map). - std::unordered_map> + std::unordered_map> m_isolated_asts; }; diff --git a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp index 14f4daa925e14..799fff597d07e 100644 --- a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp @@ -804,6 +804,7 @@ static Instruction *insertSpills(const SpillInfo &Spills, coro::Shape &Shape) { CurrentValue->getName() + Twine(".reload")); }; + SmallDenseMap DbgPtrAllocaCache; Value *GEP = nullptr, *CurrentGEP = nullptr; for (auto const &E : Spills) { // If we have not seen the value, generate a spill. @@ -896,12 +897,21 @@ static Instruction *insertSpills(const SpillInfo &Spills, coro::Shape &Shape) { if (CurrentGEP != GEP) { CurrentGEP = GEP; TinyPtrVector DIs = FindDbgDeclareUses(CurrentValue); - if (!DIs.empty()) - DIBuilder(*CurrentBlock->getParent()->getParent(), - /*AllowUnresolved*/ false) - .insertDeclare(CurrentGEP, DIs.front()->getVariable(), - DIs.front()->getExpression(), - DIs.front()->getDebugLoc(), DIs.front()); + if (!DIs.empty()) { + auto *DDI = DIs.front(); + bool AllowUnresolved = false; + // This dbg.declare is preserved for all coro-split function + // fragments. It will be unreachable in the main function, and + // processed by coro::salvageDebugInfo() by CoroCloner. + DIBuilder(*CurrentBlock->getParent()->getParent(), AllowUnresolved) + .insertDeclare(CurrentGEP, DDI->getVariable(), + DDI->getExpression(), + DDI->getDebugLoc(), + &*Builder.GetInsertPoint()); + // This dbg.declare is for the main function entry point. It + // will be deleted in all coro-split functions. + coro::salvageDebugInfo(DbgPtrAllocaCache, DDI); + } } // Replace all uses of CurrentValue in the current instruction with reload. @@ -1633,6 +1643,55 @@ static void sinkLifetimeStartMarkers(Function &F, coro::Shape &Shape, } } +void coro::salvageDebugInfo( + SmallDenseMap &DbgPtrAllocaCache, + DbgDeclareInst *DDI, bool LoadFromFramePtr) { + Function *F = DDI->getFunction(); + IRBuilder<> Builder(F->getContext()); + auto InsertPt = F->getEntryBlock().getFirstInsertionPt(); + while (isa(InsertPt)) + ++InsertPt; + Builder.SetInsertPoint(&F->getEntryBlock(), InsertPt); + DIExpression *Expr = DDI->getExpression(); + // Follow the pointer arithmetic all the way to the incoming + // function argument and convert into a DIExpression. + Value *Storage = DDI->getAddress(); + while (Storage) { + if (auto *LdInst = dyn_cast(Storage)) { + Storage = LdInst->getOperand(0); + } else if (auto *GEPInst = dyn_cast(Storage)) { + Expr = llvm::salvageDebugInfoImpl(*GEPInst, Expr, + /*WithStackValue=*/false); + Storage = GEPInst->getOperand(0); + } else if (auto *BCInst = dyn_cast(Storage)) + Storage = BCInst->getOperand(0); + else + break; + } + // Store a pointer to the coroutine frame object in an alloca so it + // is available throughout the function when producing unoptimized + // code. Extending the lifetime this way is correct because the + // variable has been declared by a dbg.declare intrinsic. + if (auto Arg = dyn_cast_or_null(Storage)) { + auto &Cached = DbgPtrAllocaCache[Storage]; + if (!Cached) { + Cached = Builder.CreateAlloca(Storage->getType(), 0, nullptr, + Arg->getName() + ".debug"); + Builder.CreateStore(Storage, Cached); + } + Storage = Cached; + Expr = DIExpression::prepend(Expr, DIExpression::DerefBefore); + } + // The FramePtr object adds one extra layer of indirection that + // needs to be unwrapped. + if (LoadFromFramePtr) + Expr = DIExpression::prepend(Expr, DIExpression::DerefBefore); + auto &VMContext = DDI->getFunction()->getContext(); + DDI->setOperand( + 0, MetadataAsValue::get(VMContext, ValueAsMetadata::get(Storage))); + DDI->setOperand(2, MetadataAsValue::get(VMContext, Expr)); +} + void coro::buildCoroutineFrame(Function &F, Shape &Shape) { eliminateSwiftError(F, Shape); diff --git a/llvm/lib/Transforms/Coroutines/CoroInternal.h b/llvm/lib/Transforms/Coroutines/CoroInternal.h index 49dc3172f66eb..cd1bc6010137f 100644 --- a/llvm/lib/Transforms/Coroutines/CoroInternal.h +++ b/llvm/lib/Transforms/Coroutines/CoroInternal.h @@ -52,6 +52,11 @@ void replaceAllCoroFrees(CoroBeginInst *CB, Value *Replacement); void replaceCoroFree(CoroIdInst *CoroId, bool Elide); void updateCallGraph(Function &Caller, ArrayRef Funcs, CallGraph &CG, CallGraphSCC &SCC); +/// Recover a dbg.declare prepared by the frontend and emit an alloca +/// holding a pointer to the coroutine frame. +void salvageDebugInfo( + SmallDenseMap &DbgPtrAllocaCache, + DbgDeclareInst *DDI, bool LoadFromCoroFrame = false); // Keeps data and helper functions for lowering coroutine intrinsics. struct LowererBase { diff --git a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp index 8f698e0a4b625..6eeb89290513b 100644 --- a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp @@ -159,6 +159,7 @@ class CoroCloner { void replaceCoroSuspends(); void replaceCoroEnds(); void replaceSwiftErrorOps(); + void salvageDebugInfo(); void handleFinalSuspend(); void maybeFreeContinuationStorage(); }; @@ -584,6 +585,24 @@ void CoroCloner::replaceSwiftErrorOps() { ::replaceSwiftErrorOps(*NewF, Shape, &VMap); } +void CoroCloner::salvageDebugInfo() { + SmallVector Worklist; + SmallDenseMap DbgPtrAllocaCache; + for (auto &BB : *NewF) + for (auto &I : BB) + if (auto *DDI = dyn_cast(&I)) + Worklist.push_back(DDI); + for (DbgDeclareInst *DDI : Worklist) { + // Remove the allocas inserted by CoroFrame for the sake of the + // cloned function. + if (isa(DDI->getAddress())) + DDI->eraseFromParent(); + else + coro::salvageDebugInfo(DbgPtrAllocaCache, DDI, + /*LoadFromFramePointer*/ true); + } +} + void CoroCloner::replaceEntryBlock() { // In the original function, the AllocaSpillBlock is a block immediately // following the allocation of the frame object which defines GEPs for @@ -853,6 +872,9 @@ void CoroCloner::create() { // Remove coro.end intrinsics. replaceCoroEnds(); + // Salvage debug info that points into the coroutine frame. + salvageDebugInfo(); + // Eliminate coro.free from the clones, replacing it with 'null' in cleanup, // to suppress deallocation code. if (Shape.ABI == coro::ABI::Switch) diff --git a/llvm/test/Transforms/Coroutines/coro-debug-frame-variable.ll b/llvm/test/Transforms/Coroutines/coro-debug-frame-variable.ll index ed6b95879e8a5..05d1d3d58bbc7 100644 --- a/llvm/test/Transforms/Coroutines/coro-debug-frame-variable.ll +++ b/llvm/test/Transforms/Coroutines/coro-debug-frame-variable.ll @@ -33,12 +33,12 @@ ; CHECK: call void @llvm.dbg.declare(metadata i32* [[JGEP]], metadata ![[JVAR:[0-9]+]], metadata !DIExpression()), !dbg ![[JDBGLOC:[0-9]+]] ; ; CHECK-LABEL: define internal fastcc void @f.resume({{.*}}) { +; CHECK: %[[DBG_PTR:.*]] = alloca %f.Frame* +; CHECK: store %f.Frame* {{.*}}, %f.Frame** %[[DBG_PTR]] ; CHECK: init.ready: -; CHECK: [[IGEP_RESUME:%.+]] = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 4 -; CHECK: call void @llvm.dbg.declare(metadata i32* [[IGEP_RESUME]], metadata ![[IVAR_RESUME:[0-9]+]], metadata !DIExpression()), !dbg ![[IDBGLOC_RESUME:[0-9]+]] +; CHECK: call void @llvm.dbg.declare(metadata %f.Frame** %[[DBG_PTR]], metadata ![[IVAR_RESUME:[0-9]+]], metadata !DIExpression(DW_OP_deref, DW_OP_deref, DW_OP_plus_uconst, 20)), !dbg ![[IDBGLOC_RESUME:[0-9]+]] ; CHECK: await.ready: -; CHECK: [[JGEP_RESUME:%.+]] = getelementptr inbounds %f.Frame, %f.Frame* %FramePtr, i32 0, i32 5 -; CHECK: call void @llvm.dbg.declare(metadata i32* [[JGEP_RESUME]], metadata ![[JVAR_RESUME:[0-9]+]], metadata !DIExpression()), !dbg ![[JDBGLOC_RESUME:[0-9]+]] +; CHECK: call void @llvm.dbg.declare(metadata %f.Frame** %[[DBG_PTR]], metadata ![[JVAR_RESUME:[0-9]+]], metadata !DIExpression(DW_OP_deref, DW_OP_deref, DW_OP_plus_uconst, 24)), !dbg ![[JDBGLOC_RESUME:[0-9]+]] ; ; CHECK: ![[IVAR]] = !DILocalVariable(name: "i" ; CHECK: ![[SCOPE:[0-9]+]] = distinct !DILexicalBlock(scope: !8, file: !1, line: 23, column: 12) diff --git a/llvm/test/Transforms/Coroutines/coro-debug.ll b/llvm/test/Transforms/Coroutines/coro-debug.ll index b624c88f99ff0..102248359860c 100644 --- a/llvm/test/Transforms/Coroutines/coro-debug.ll +++ b/llvm/test/Transforms/Coroutines/coro-debug.ll @@ -130,8 +130,10 @@ attributes #7 = { noduplicate } ; CHECK: define i8* @f(i32 %x) #0 !dbg ![[ORIG:[0-9]+]] ; CHECK: define internal fastcc void @f.resume(%f.Frame* noalias nonnull align 8 dereferenceable(32) %FramePtr) #0 !dbg ![[RESUME:[0-9]+]] ; CHECK: entry.resume: +; CHECK-NEXT: %[[DBG_PTR:.*]] = alloca %f.Frame* +; CHECK-NEXT: store %f.Frame* {{.*}}, %f.Frame** %[[DBG_PTR]] ; CHECK-NEXT: call void @coro.devirt.trigger(i8* null) -; CHECK-NEXT: call void @llvm.dbg.declare(metadata i32* %x.addr.reload.addr, metadata ![[RESUME_VAR:[0-9]+]] +; CHECK: call void @llvm.dbg.declare(metadata %f.Frame** %[[DBG_PTR]], metadata ![[RESUME_VAR:[0-9]+]], metadata !DIExpression(DW_OP_deref, DW_OP_deref, DW_OP_plus_uconst, ; 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]+]]