JDevlieghere created this revision. JDevlieghere added reviewers: aprantl, dexonsmith, dblaikie, labath.
As brought up during the discussion of the DWARF5 accelerator tables, there is currently no way to associate Objective-C methods with the interface they belong to, other than the .apple_objc accelerator table. After due consideration we came to the conclusion that it makes more sense to follow Pavel's suggestion of just emitting this information in the .debug_info section. One concern was that categories were emitted in the .apple_names as well, but it turns out that LLDB doesn't rely on the accelerator tables for this information. This patch changes the codegen behavior to emit subprograms for structure types, like we do for C++. This will result in the DW_TAG_subprogram being nested as a child under its DW_TAG_structure_type. This behavior is only enabled for DWARF5 and later, so we can have a unique code path in LLDB with regards to obtaining the class methods. For more background please refer to the discussion on the mailing list: http://lists.llvm.org/pipermail/llvm-dev/2018-June/123986.html Repository: rC Clang https://reviews.llvm.org/D48241 Files: clang/lib/CodeGen/CGDebugInfo.cpp clang/lib/CodeGen/CGDebugInfo.h clang/test/CodeGenObjC/debug-info-synthesis.m
Index: clang/test/CodeGenObjC/debug-info-synthesis.m =================================================================== --- clang/test/CodeGenObjC/debug-info-synthesis.m +++ clang/test/CodeGenObjC/debug-info-synthesis.m @@ -1,4 +1,6 @@ // RUN: %clang_cc1 -emit-llvm -debug-info-kind=limited -w -triple x86_64-apple-darwin10 %s -o - | FileCheck %s +// RUN: %clang_cc1 -dwarf-version=5 -emit-llvm -debug-info-kind=limited -w -triple x86_64-apple-darwin10 %s -o - | FileCheck %s --check-prefix CHECK --check-prefix DWARF5 + # 1 "foo.m" 1 # 1 "foo.m" 2 # 1 "./foo.h" 1 @@ -30,8 +32,13 @@ } } +// DWARF5: ![[STRUCT:.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Foo" // CHECK: ![[FILE:.*]] = !DIFile(filename: "{{[^"]+}}foo.h" -// CHECK: !DISubprogram(name: "-[Foo setDict:]" +// DWARF5: !DISubprogram(name: "-[Foo setDict:]" +// DWARF5-SAME: scope: ![[STRUCT]], +// DWARF5-SAME: line: 8, +// DWARF5-SAME: isLocal: true, isDefinition: false +// CHECK: distinct !DISubprogram(name: "-[Foo setDict:]" // CHECK-SAME: file: ![[FILE]], // CHECK-SAME: line: 8, // CHECK-SAME: isLocal: true, isDefinition: true Index: clang/lib/CodeGen/CGDebugInfo.h =================================================================== --- clang/lib/CodeGen/CGDebugInfo.h +++ clang/lib/CodeGen/CGDebugInfo.h @@ -98,6 +98,27 @@ /// Cache of previously constructed interfaces which may change. llvm::SmallVector<ObjCInterfaceCacheEntry, 32> ObjCInterfaceCache; + struct ObjCMethodCacheEntry { + struct MethodData { + const ObjCMethodDecl *MD; + llvm::DISubprogram *DIMethodDecl; + MethodData(const ObjCMethodDecl *MD, llvm::DISubprogram *DIMethodDecl) + : MD(MD), DIMethodDecl(DIMethodDecl) {} + }; + + // Keep track of the interface so we can update its elements with its + // methods. + llvm::DICompositeType *DIInterfaceDecl; + std::vector<MethodData> Methods; + + ObjCMethodCacheEntry(llvm::DICompositeType *DIInterfaceDecl = nullptr) + : DIInterfaceDecl(DIInterfaceDecl) {} + }; + + /// Cache of forward declarations for method + llvm::DenseMap<const ObjCInterfaceDecl *, ObjCMethodCacheEntry> + ObjCMethodCache; + /// Cache of references to clang modules and precompiled headers. llvm::DenseMap<const Module *, llvm::TrackingMDRef> ModuleCache; Index: clang/lib/CodeGen/CGDebugInfo.cpp =================================================================== --- clang/lib/CodeGen/CGDebugInfo.cpp +++ clang/lib/CodeGen/CGDebugInfo.cpp @@ -2231,6 +2231,13 @@ Mod ? Mod : Unit, ID->getName(), DefUnit, Line, Size, Align, Flags, nullptr, llvm::DINodeArray(), RuntimeLang); + if (CGM.getCodeGenOpts().DwarfVersion >= 5) { + // Remember the DICompositeType in the ObjCMethodCache. + assert(ObjCMethodCache[ID].DIInterfaceDecl == nullptr || + ObjCMethodCache[ID].DIInterfaceDecl == RealDecl); + ObjCMethodCache[ID].DIInterfaceDecl = RealDecl; + } + QualType QTy(Ty, 0); TypeCache[QTy.getAsOpaquePtr()].reset(RealDecl); @@ -3346,6 +3353,21 @@ if (HasDecl && isa<FunctionDecl>(D)) DeclCache[D->getCanonicalDecl()].reset(SP); + if (CGM.getCodeGenOpts().DwarfVersion >= 5) { + // Starting with DWARF5, we create declarations for the interface's + // methods. + if (const auto *OMD = dyn_cast_or_null<ObjCMethodDecl>(D)) { + const ObjCInterfaceDecl *ID = OMD->getClassInterface(); + llvm::DISubprogram *FD = DBuilder.createFunction( + ObjCMethodCache[ID].DIInterfaceDecl, Name, LinkageName, Unit, LineNo, + getOrCreateFunctionType(D, FnType, Unit), Fn->hasLocalLinkage(), + false /*definition*/, ScopeLine, Flags, CGM.getLangOpts().Optimize, + TParamsArray.get()); + DBuilder.finalizeSubprogram(FD); + ObjCMethodCache[ID].Methods.emplace_back(OMD, FD); + } + } + // Push the function onto the lexical block stack. LexicalBlockStack.emplace_back(SP); @@ -4213,6 +4235,27 @@ DBuilder.replaceTemporary(llvm::TempDIType(E.Decl), Ty); } + if (CGM.getCodeGenOpts().DwarfVersion >= 5) { + // Add methods to interface. + for (auto p : ObjCMethodCache) { + llvm::DICompositeType *RealDecl = p.second.DIInterfaceDecl; + if (!RealDecl) + continue; + if (p.second.Methods.empty()) + continue; + + SmallVector<llvm::Metadata *, 16> EltTys; + for (auto *E : RealDecl->getElements()) { + EltTys.push_back(E); + } + for (auto &M : p.second.Methods) { + EltTys.push_back(M.DIMethodDecl); + } + llvm::DINodeArray Elements = DBuilder.getOrCreateArray(EltTys); + DBuilder.replaceArrays(RealDecl, Elements); + } + } + for (auto p : ReplaceMap) { assert(p.second); auto *Ty = cast<llvm::DIType>(p.second);
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits